I'm currently implementing the last task for a little debug framework, namely HW Breakpoints. I referred to this article so far: http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx and a Book about writing a Debugger.
I got following two functions so far for setting a HW breakpoint:
void debuglib::breakpoints::hw_bp() {
HANDLE helper = 0;
CONTEXT co;
CURRENTCONTEXT(co);
helper = ::CreateThread(0,0,threadfunc,reinterpret_cast<void*>(co.Eip),0,0);
DWORD status = ::WaitForSingleObject(helper,INFINITE);
if (status != WAIT_OBJECT_0) {
::MessageBoxA(0, "Helper thread didn't exit cleanly", "HWBreakpoint", MB_OK);
}
::CloseHandle(helper);
}
static DWORD WINAPI debuglib::breakpoints::threadfunc(void* param) {
DWORD suspendcnt = ::SuspendThread(debuglib::process::thread());
if(suspendcnt) {
return 0;
}
CONTEXT co;
::ZeroMemory(&co,sizeof(co));
co.ContextFlags = CONTEXT_DEBUG_REGISTERS;
BOOL ok = ::GetThreadContext(debuglib::process::thread(),&co);
if(!ok) {
return 0;
}
DWORD freeDr = 0;
DWORD condition = debuglib::breakpoints::TRIGGER::CODE;
DWORD length = debuglib::breakpoints::SIZE::SIZE_1;
co.Dr0 = reinterpret_cast<DWORD>(param);
co.Dr7 = co.Dr7 | 1 << (freeDr*2);
co.Dr7 = co.Dr7 | condition << ((freeDr*4)+16);
co.Dr7 = co.Dr7 | length << ((freeDr*4)+18);
co.ContextFlags = CONTEXT_DEBUG_REGISTERS;
ok = ::SetThreadContext(debuglib::process::thread(), &co);
co.ContextFlags = CONTEXT_DEBUG_REGISTERS;
::GetThreadContext(debuglib::process::thread(),&co);
suspendcnt = ::ResumeThread(debuglib::process::thread());
if(suspendcnt == 0xFFFFFFFF) {
return 0;
}
return 1;
}
So first I'm creating a helper thread since I´m debugging the current thread. Within the callback function of the helper thread, I´m suspending the main thread. Afterwards I read the current DR values of the main thread (at the moment this is not relevant, since I always use DR0, after this works, I will check which registers are free and use up to 4 BP´s). Afterwards I used the return address of the calling function (EIP) as address to break in DR0 and set the belonging flags in DR7.
At the end I'm resuming the main thread and closing the handle of the helper thread, as it is finished.
With this code I got following problem:
If I execute the program in debug mode the programs halts at the right address, but I cannot do anything anymore, since the INT1 flag is set I guess and the VS debugger cannot single-step further?
If I execute the program without debugging it simple crashes. I tried to use __try, __except like in the mentioned project (http://www.codeproject.com/KB/debug/hardwarebreakpoint.aspx) but this does not work either.
I appreciate and help or information what I´m doing wrong and how to solve this problem.
Hardware breakpoints are actually comparators, comparing the current PC with the address in the comparator (when enabled). Hardware breakpoints are the best solution when setting breakpoints. Typically set via the debug probe (using JTAG, SWD, ...). The downside of hardware breakpoints: They are limited.
To set a hardware breakpoint, right-click on the location where you want to set the breakpoint and select Breakpoint | Set Hardware on Execution. You can also use hardware breakpoints to break on write or break on read/write (access) to a memory location.
Breakpoints are event triggers which, when the breakpoint's conditions are satisfied, will halt execution of the target and break into the debugger. Breakpoints allow the user to analyze and perhaps modify the target when execution reaches a certain point or when a certain memory location is accessed.
A breakpoint is traditionally defined as a place in your program where you want execution to stop so that you can examine program variables and data structures. A watchpoint causes your program to be executed one instruction or source line at a time, watching for the value of an expression to become true.
I don't think it's a good idea to try to make a program debug itself. Why not use the debugger development API built into windows?
Dev Center - Desktop > Learn > Reference > Diagnostics > Debugging and Error Handling > Basic Debugging > Debugging Reference > Debugging Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679303%28v=vs.85%29.aspx
On x86 hardware, single-stepping is enabled by setting the trap flag in eflags. The CPU will raise a debug exception (interrupt 1) after it completes one instruction. What I think is happening is the visual studio debugger is changing that bit of the flags, interfering with what you're trying to do.
Try running your program outside visual studio (no debugger). Does it work as expected then?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With