locked
How to set a hardware breakpoint? RRS feed

  • Question

  • I wrote a small debugger program in Win32 C++ that attaches to a process and receives debugger events, the code in general goes like this:

    DebugActiveProcess(pidDbg);
    
    ...
    
    while(1)
    {
    	WaitForDebugEvent(&dbgEv, INFINITE);
    
    	switch(dbgEv.dwDebugEventCode)
    	{
    		case EXCEPTION_DEBUG_EVENT:
    		
    			...
    
    			switch(dbgEv.u.Exception.ExceptionRecord.ExceptionCode)
    			{
    				case STATUS_ACCESS_VIOLATION:
    					...
    					break;
    					
    				case STATUS_SINGLE_STEP:
    				case STATUS_BREAKPOINT: 
    					
    					if(dbgEv.u.Exception.dwFirstChance == 1) {
    
    						exAddr = dbgEv.u.Exception.ExceptionRecord.ExceptionAddress;
    
    						if(exAddr == ...) {
    							setBP(...);
    						}
    						else if(exAddr == ...) {
    							clearBP(...);
    						}
    						...
    					}
    					break;
    	...
    
    	ContinueDebugEvent(dbgEv.dwProcessId, dbgEv.dwThreadId, dwContinueStatus);
    }

    I was able to set/clear software breakpoints inside setBP() and clearBP() functions (by replacing the first byte of a command with 0xCC) and they work perfectly.

    Now I want to add hardware breakpoints. The code I added to setBP() for a test goes like this:

    HANDLE hThread;
    WOW64_CONTEXT lcContext;
    ...
    hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, false, thID);
    lcContext.ContextFlags = CONTEXT_ALL;
    Wow64GetThreadContext(hThread, &lcContext);
    lcContext.Dr0 = adr;
    lcContext.Dr7 |= 1; // enable DR0 locally
    lcContext.Dr7 &= 0xFFF0FFFF; // set bits 16-17 to execution & bits 18-19 to zero.
    lcContext.Dr6 = 0; // clear DR6 before returning from the handler
    Wow64SetThreadContext(hThread, &lcContext);
    CloseHandle(hThread);
    The value of adr here is the same I use to set the CC byte for a software breakpoint.

    As far as I can see - nothing happens, the debugger loop doesn't receive any single step exceptions and the process keep running.

    What am I doing wrong here?

    Thank you!

    Friday, January 19, 2018 11:30 AM

Answers

  • FAIK Windows allows only thread-specific HWBPs.
    You tried already setting HWBP as early as in CREATE_THREAD_DEBUG_EVENT, maybe for start-up thread even in CREATE_PROCESS_DEBUG_EVENT?
    Else you may need some bookkeeping of threads, to set them later on for each particular thread.

    With kind regards

    • Edited by MaybeCompletelyW Wednesday, January 24, 2018 5:04 PM
    • Marked as answer by alikim Friday, January 26, 2018 10:57 AM
    Wednesday, January 24, 2018 5:01 PM

All replies

  • Have you tried to write an explicit value to Dr7, such as lcContext.Dr7=1?


    • Edited by Viorel_MVP Friday, January 19, 2018 6:25 PM
    Friday, January 19, 2018 6:24 PM
  • lcContext.Dr7 |= 1; // enable DR0 locally
    lcContext.Dr7 &= 0xFFF0FFFF; // set bits 16-17 to execution & bits 18-19 to zero.

    Those statements do not do what the comments say they do.  You are clearing bits 16-19.  To do what the comments say, you'd need:

        IcContext.Dr7 = ((IcContext.Dr7) & 0xFFF3FFF) | 0x00030001;


    Tim Roberts, Driver MVP Providenza & Boekelheide, Inc.

    Friday, January 19, 2018 9:49 PM
  • I can check the value after I set it and it is 1 (since the original value of DR7 is zero), so that parts works.
    • Edited by alikim Saturday, January 20, 2018 3:30 AM
    Saturday, January 20, 2018 3:27 AM
  • Well, execution bits are 00, and the length for them should also be 00, so I am effectively clearing bits 16-19.
    Saturday, January 20, 2018 3:29 AM
  • Can it be so that I have enough rights/permissions to set software breakpoints in a program but not hardware breakpoints?
    Saturday, January 20, 2018 3:37 AM
  • Can it be so that I have enough rights/permissions to set software breakpoints in a program but not hardware breakpoints?

    According to
    Wow64SetThreadContext
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms681668(v=vs.85).aspx
    you may check return value. Extended error information:  GetLastError().

    Attach windbg 'Noninvasively' to debuggee, to check register/memory after your debugger actions.  

    Results (windbg) with x86-debuggee and x86-debugger-stump:
    E.g. after setting context (SetThreadContext):
    0:000> rM 0x20
    dr0=7756dbe0 dr1=00000000 dr2=00000000
    dr3=00000000 dr6=00000000 dr7=00000001
    ntdll!LdrpDoDebuggerBreak+0x2c:
    7756dbd0 eb07            jmp     ntdll!LdrpDoDebuggerBreak+0x35 (7756dbd9)

    After apparently HWBP is hit:

    0:000> rM 0x20
    dr0=7756dbe0 dr1=00000000 dr2=00000000
    dr3=00000000 dr6=ffff0ff1 dr7=00000001
    ntdll!LdrpDoDebuggerBreak+0x3c:
    7756dbe0 e84cb5fdff      call    ntdll!_SEH_epilog4 (77549131)

    With kind regards

    Saturday, January 20, 2018 10:59 AM
  • I think I found what the problem is: I set a HWBP while suspending a thread_A but the HWBP will be hit by another thread_B that is created later somewhere down the line.

    The value of registers DR0-DR3 is preserved across all threads, so if I set it for A it will be there for B.

    But the value of DR7 is reset to zero, when I check register values at CREATE_THREAD_DEBUG_EVENT my DR0 is still set to the address but DR7 is 0.

    How do I preserve DR7 across threads or how do I set HWBP in one thread for another to hit it?
    Wednesday, January 24, 2018 2:55 PM
  • FAIK Windows allows only thread-specific HWBPs.
    You tried already setting HWBP as early as in CREATE_THREAD_DEBUG_EVENT, maybe for start-up thread even in CREATE_PROCESS_DEBUG_EVENT?
    Else you may need some bookkeeping of threads, to set them later on for each particular thread.

    With kind regards

    • Edited by MaybeCompletelyW Wednesday, January 24, 2018 5:04 PM
    • Marked as answer by alikim Friday, January 26, 2018 10:57 AM
    Wednesday, January 24, 2018 5:01 PM
  • Yes, I tried  CREATE_THREAD_DEBUG_EVENT it works but not always.

    What about another scenario: an old thread that was created before I need (and know where) to set the HWBP? 

    If that one happens to be the one to hit the BP how do I set DR7 to it?

    Wednesday, January 24, 2018 5:42 PM