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) }); auto foundInfo = _process->breakpoints.find({ BreakpointType::Software, ptr(exceptionRecord.ExceptionAddress) });
if (foundInfo == _process->breakpoints.end()) if (foundInfo == _process->breakpoints.end())
return; return;
const auto & info = foundInfo->second; const auto info = foundInfo->second;
//set continue status //set continue status
_continueStatus = DBG_CONTINUE; _continueStatus = DBG_CONTINUE;
@ -31,6 +31,8 @@ namespace GleeBug
_process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size); _process->MemWrite(info.address, info.internal.software.oldbytes, info.internal.software.size);
_thread->StepInternal(std::bind([this, info]() _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); _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 }); auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Software, info.address });
if (foundCallback != _process->breakpointCallbacks.end()) if (foundCallback != _process->breakpointCallbacks.end())
foundCallback->second(info); 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 }); auto foundInfo = _process->breakpoints.find({ BreakpointType::Hardware, breakpointAddress });
if (foundInfo == _process->breakpoints.end()) if (foundInfo == _process->breakpoints.end())
return; //not a valid hardware breakpoint return; //not a valid hardware breakpoint
const auto & info = foundInfo->second; const auto info = foundInfo->second;
if (info.internal.hardware.slot != breakpointSlot) if (info.internal.hardware.slot != breakpointSlot)
return; //not a valid hardware breakpoint return; //not a valid hardware breakpoint
//set continue status //set continue status
_continueStatus = DBG_CONTINUE; _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->DeleteHardwareBreakpoint(breakpointSlot);
_thread->StepInternal(std::bind([this, info]() _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); _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 }); auto foundCallback = _process->breakpointCallbacks.find({ BreakpointType::Hardware, info.address });
if (foundCallback != _process->breakpointCallbacks.end()) if (foundCallback != _process->breakpointCallbacks.end())
foundCallback->second(info); foundCallback->second(info);
//delete the breakpoint if it is singleshoot
if (info.singleshoot)
_process->DeleteGenericBreakpoint(info);
} }
void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo) void Debugger::exceptionEvent(const EXCEPTION_DEBUG_INFO & exceptionInfo)

View File

@ -55,6 +55,28 @@ namespace GleeBug
return true; 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 bool ProcessInfo::GetFreeHardwareBreakpointSlot(HardwareBreakpointSlot & slot) const
{ {
//find a free hardware breakpoint slot //find a free hardware breakpoint slot
@ -69,7 +91,7 @@ namespace GleeBug
return false; 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 //check the address
if (!MemIsValidPtr(address) || if (!MemIsValidPtr(address) ||
@ -99,7 +121,7 @@ namespace GleeBug
BreakpointInfo info = {}; BreakpointInfo info = {};
info.address = address; info.address = address;
info.enabled = true; info.enabled = true;
info.singleshoot = false; info.singleshoot = singleshoot;
info.type = BreakpointType::Hardware; info.type = BreakpointType::Hardware;
info.internal.hardware.slot = slot; info.internal.hardware.slot = slot;
info.internal.hardware.type = type; info.internal.hardware.type = type;
@ -114,16 +136,56 @@ namespace GleeBug
return true; 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 //check if a callback on this address was already found
if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end()) if (breakpointCallbacks.find({ BreakpointType::Hardware, address }) != breakpointCallbacks.end())
return false; return false;
//set the hardware breakpoint //set the hardware breakpoint
if (!SetHardwareBreakpoint(address, slot, type, size)) if (!SetHardwareBreakpoint(address, slot, type, size, singleshoot))
return false; return false;
//insert the callback //insert the callback
breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint }); breakpointCallbacks.insert({ { BreakpointType::Hardware, address }, cbBreakpoint });
return true; 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); 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. \brief Attempts to find a free hardware breakpoint slot.
\param [out] slot First free slot found, has no meaning when the function fails. \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. \brief Sets a hardware breakpoint.
\param address The address to set the hardware breakpoint on. \param address The address to set the hardware breakpoint on.
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot. \param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
\param type The hardware breakpoint type. \param type (Optional) The hardware breakpoint type.
\param size The hardware breakpoint size. \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. \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. \brief Sets a hardware breakpoint.
\param address The address to set the hardware breakpoint on. \param address The address to set the hardware breakpoint on.
\param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot. \param slot The hardware breakpoint register slot. Use ProcessInfo::GetFreeHardwareBreakpointSlot.
\param cbBreakpoint The breakpoint callback. Can be written using BIND1(this, MyDebugger::cb). \param cbBreakpoint The breakpoint callback. Can be written using BIND1(this, MyDebugger::cb).
\param type The hardware breakpoint type. \param type (Optional) The hardware breakpoint type.
\param size The hardware breakpoint size. \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. \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", printf("Reached entry breakpoint! GIP: 0x%p\n",
_registers->Gip()); _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]() _thread->StepInto(std::bind([this]()
{ {
printf("Step after entry breakpoint! GIP: 0x%p\n", printf("Step after entry breakpoint! GIP: 0x%p\n",
@ -23,6 +27,10 @@ protected:
{ {
printf("Reached entry hardware breakpoint! GIP: 0x%p\n", printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
_registers->Gip()); _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]() _thread->StepInto(std::bind([this]()
{ {
printf("Step after entry hardware breakpoint! GIP: 0x%p\n", printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
@ -45,7 +53,7 @@ protected:
HardwareBreakpointSlot slot; HardwareBreakpointSlot slot;
if (_process->GetFreeHardwareBreakpointSlot(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); printf("Hardware breakpoint set at 0x%p!\n", entry);
else else
printf("Failed to set hardware breakpoint at 0x%p\n", entry); printf("Failed to set hardware breakpoint at 0x%p\n", entry);