singleshoot hardware/software breakpoints working + delete hardware/software breakpoints + nice callback set function for hardware breakpoints

This commit is contained in:
mrexodia 2015-12-19 05:17:04 +01:00
parent 611c5864ca
commit 439fd82767
4 changed files with 142 additions and 18 deletions

View File

@ -19,7 +19,7 @@ namespace GleeBug
auto foundInfo = _process->breakpoints.find({ BreakpointType::Software, ptr(exceptionRecord.ExceptionAddress) });
if (foundInfo == _process->breakpoints.end())
return;
const auto & info = foundInfo->second;
const auto info = foundInfo->second;
//set continue status
_continueStatus = DBG_CONTINUE;
@ -31,6 +31,8 @@ namespace GleeBug
_process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size);
_thread->StepInternal(std::bind([this, info]()
{
//only restore the bytes if the breakpoint still exists
if (_process->breakpoints.find({ BreakpointType::Software, info.address }) != _process->breakpoints.end())
_process->MemWrite(info.address, info.internal.software.newbytes, info.internal.software.size);
}));
@ -41,6 +43,10 @@ namespace GleeBug
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Software, info.address });
if (foundCallback != _process->breakpointCallbacks.end())
foundCallback->second(info);
//delete the breakpoint if it is singleshoot
if (info.singleshoot)
_process->DeleteGenericBreakpoint(info);
}
}
@ -109,17 +115,19 @@ namespace GleeBug
auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
if (foundInfo == _process->breakpoints.end())
return; //not a valid hardware breakpoint
const auto & info = foundInfo->second;
const auto info = foundInfo->second;
if (info.internal.hardware.slot != breakpointSlot)
return; //not a valid hardware breakpoint
//set continue status
_continueStatus = DBG_CONTINUE;
//delete the hardware breakpoint and do an internal step (TODO: maybe delete from all threads?)
//delete the hardware breakpoint from the thread (not the breakpoint buffer) and do an internal step (TODO: maybe delete from all threads?)
_thread->DeleteHardwareBreakpoint(breakpointSlot);
_thread->StepInternal(std::bind([this, info]()
{
//only restore if the breakpoint still exists
if (_process->breakpoints.find({ BreakpointType::Hardware, info.address }) != _process->breakpoints.end())
_thread->SetHardwareBreakpoint(info.address, info.internal.hardware.slot, info.internal.hardware.type, info.internal.hardware.size);
}));
@ -130,6 +138,10 @@ namespace GleeBug
auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
if (foundCallback != _process->breakpointCallbacks.end())
foundCallback->second(info);
//delete the breakpoint if it is singleshoot
if (info.singleshoot)
_process->DeleteGenericBreakpoint(info);
}
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)

View File

@ -55,6 +55,28 @@ namespace GleeBug
return true;
}
bool ProcessInfo::DeleteBreakpoint(ptr address)
{
//find the breakpoint
auto found = breakpoints.find({ BreakpointType::Software, address });
if (found == breakpoints.end())
return false;
const auto & info = found->second;
//restore the breakpoint bytes if the breakpoint is enabled
if (info.enabled)
{
if (!MemWrite(address, info.internal.software.oldbytes, info.internal.software.size))
return false;
FlushInstructionCache(hProcess, nullptr, 0);
}
//remove the breakpoint from the maps
breakpoints.erase(found);
breakpointCallbacks.erase({ BreakpointType::Software, address });
return true;
}
bool ProcessInfo::GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot) const
{
//find a free hardware breakpoint slot
@ -69,7 +91,7 @@ namespace GleeBug
return false;
}
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size)
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type, HardwareBreakpointSize size, bool singleshoot)
{
//check the address
if (!MemIsValidPtr(address) ||
@ -99,7 +121,7 @@ namespace GleeBug
BreakpointInfo info = {};
info.address = address;
info.enabled = true;
info.singleshoot = false;
info.singleshoot = singleshoot;
info.type = BreakpointType::Hardware;
info.internal.hardware.slot = slot;
info.internal.hardware.type = type;
@ -114,16 +136,56 @@ namespace GleeBug
return true;
}
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type, HardwareBreakpointSize size)
bool ProcessInfo::SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type, HardwareBreakpointSize size, bool singleshoot)
{
//check if a callback on this address was already found
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
return false;
//set the hardware breakpoint
if (!SetHardwareBreakpoint(address, slot, type, size))
if (!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
return false;
//insert the callback
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
return true;
}
bool ProcessInfo::DeleteHardwareBreakpoint(ptr address)
{
//find the hardware breakpoint
auto found = breakpoints.find({ BreakpointType::Hardware, address });
if (found == breakpoints.end())
return false;
const auto & info = found->second;
//delete the hardware breakpoint from the internal buffer
hardwareBreakpoints[int(info.internal.hardware.slot)].enabled = false;
//delete the hardware breakpoint from the registers
bool success = true;
for (auto & thread : threads)
{
if (!thread.second.DeleteHardwareBreakpoint(info.internal.hardware.slot))
success = false;
}
//delete the breakpoint from the maps
breakpoints.erase(found);
breakpointCallbacks.erase({ BreakpointType::Hardware, address });
return success;
}
bool ProcessInfo::DeleteGenericBreakpoint(const BreakpointInfo & info)
{
switch (info.type)
{
case BreakpointType::Software:
return DeleteBreakpoint(info.address);
case BreakpointType::Hardware:
return DeleteHardwareBreakpoint(info.address);
case BreakpointType::Memory:
return false; //TODO implement this
default:
return false;
}
}
};

View File

@ -96,6 +96,13 @@ namespace GleeBug
return SetBreakpoint(address, std::bind(callback, debugger, std::placeholders::_1), singleshoot, type);
}
/**
\brief Deletes a software breakpoint.
\param address The address to delete the breakpoint from.
\return true if the breakpoint was deleted, false otherwise.
*/
bool DeleteBreakpoint(ptr address);
/**
\brief Attempts to find a free hardware breakpoint slot.
\param [out] slot First free slot found, has no meaning when the function fails.
@ -107,22 +114,57 @@ namespace GleeBug
\brief Sets a hardware breakpoint.
\param address The address to set the hardware breakpoint on.
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
\param type The hardware breakpoint type.
\param size The hardware breakpoint size.
\param type (Optional) The hardware breakpoint type.
\param size (Optional) The hardware breakpoint size.
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
\return true if the hardware breakpoint was set, false otherwise.
*/
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte);
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false);
/**
\brief Sets a hardware breakpoint.
\param address The address to set the hardware breakpoint on.
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
\param cbBreakpoint The breakpoint callback. Can be written using BIND1(this, MyDebugger::cb).
\param type The hardware breakpoint type.
\param size The hardware breakpoint size.
\param type (Optional) The hardware breakpoint type.
\param size (Optional) The hardware breakpoint size.
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
\return true if the hardware breakpoint was set, false otherwise.
*/
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte);
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, const BreakpointCallback & cbBreakpoint, HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false);
/**
\brief Sets a hardware breakpoint.
\tparam T Generic type parameter. Must be a subclass of Debugger.
\param address The address to set the hardware breakpoint on.
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
\param debugger This pointer to a subclass of Debugger.
\param callback Pointer to the callback. Written like: &MyDebugger::cb
\param type (Optional) The hardware breakpoint type.
\param size (Optional) The hardware breakpoint size.
\param singleshoot (Optional) True to remove the breakpoint after the first hit.
\return true if the hardware breakpoint was set, false otherwise.
*/
template <typename T>
bool SetHardwareBreakpoint(ptr address, HardwareBreakpointSlot slot, T* debugger, void(T::*callback)(const BreakpointInfo & info), HardwareBreakpointType type = HardwareBreakpointType::Execute, HardwareBreakpointSize size = HardwareBreakpointSize::SizeByte, bool singleshoot = false)
{
static_cast<void>(static_cast<Debugger*>(debugger));
return SetHardwareBreakpoint(address, slot, std::bind(callback, debugger, std::placeholders::_1), type, size, singleshoot);
}
/**
\brief Deletes a hardware breakpoint.
\param address The address the hardware breakpoint is set on.
\return true if the hardware breakpoint was deleted, false otherwise.
*/
bool DeleteHardwareBreakpoint(ptr address);
/**
\brief Deletes a breakpoint.
\param info The breakpoint information.
\return true if the breakpoint was deleted, false otherwise.
*/
bool DeleteGenericBreakpoint(const BreakpointInfo & info);
};
};

View File

@ -12,6 +12,10 @@ protected:
{
printf("Reached entry breakpoint! GIP: 0x%p\n",
_registers->Gip());
if (_process->DeleteBreakpoint(info.address))
printf("Entry breakpoint deleted!\n");
else
printf("Failed to delete entry breakpoint...\n");
_thread->StepInto(std::bind([this]()
{
printf("Step after entry breakpoint! GIP: 0x%p\n",
@ -23,6 +27,10 @@ protected:
{
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
_registers->Gip());
if (_process->DeleteHardwareBreakpoint(info.address))
printf("Entry hardware breakpoint deleted!\n");
else
printf("Failed to delete entry hardware breakpoint...\n");
_thread->StepInto(std::bind([this]()
{
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
@ -45,7 +53,7 @@ protected:
HardwareBreakpointSlot slot;
if (_process->GetFreeHardwareBreakpointSlot(slot))
{
if (_process->SetHardwareBreakpoint(entry, slot, BIND1(this, MyDebugger::cbEntryHardwareBreakpoint), HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
if (_process->SetHardwareBreakpoint(entry, slot, this, &MyDebugger::cbEntryHardwareBreakpoint, HardwareBreakpointType::Execute, HardwareBreakpointSize::SizeByte))
printf("Hardware breakpoint set at 0x%p!\n", entry);
else
printf("Failed to set hardware breakpoint at 0x%p\n", entry);