|
|
Comments and Discussions
|
|
 |

|
Hello,
I've tried to understand the code and I'm at this point:
Shouldn't this section
SetBits(ct.Dr7, 16 + h->iReg*4, 2, st);
SetBits(ct.Dr7, 18 + h->iReg*4, 2, le);
be like this?
SetBits(ct.Dr7, 16 + h->iReg*2, 2, st);
SetBits(ct.Dr7, 23 + h->iReg*2, 2, le);
Thank you in advance
|
|
|
|

|
I 'll take a look, thx for the note.
|
|
|
|

|
That's because the description of the bitfields above is incomplete. Each two condition bits are followed by the respective two size bits. Example: bits 16 & 17 set the breakpoint type for register DR0, and bits 18 & 19 set the data breakpoint size for register DR0. Then it starts again for bits 20 & 21...
See wikipedia: http://en.wikipedia.org/wiki/X86_debug_register[^]
|
|
|
|

|
Are data breakpoints supposed to trigger when you're running code in the debugger? When I compile your test program and run it by double-clicking the EXE, I see the four MessageBox windows pop up in sequence as expected. If I run through the debugger, it just runs past all four try/except blocks without stopping.
For that matter, are the try/except blocks strictly necessary? It seems to me that the real power of this technique would be having the debugger break right when it hits the line that triggered the breakpoint, rather than in some except clause way up the call stack. In other words, I would expect it to behave just like the debugger's built-in data breakpoint, except controlled programatically). Breakpoints that only trigger when I'm OUTSIDE the debugger (and only from within an exception handler) don't sound terribly useful
Am I missing something?
|
|
|
|

|
Data breakpoints are triggered in any context, no matter if you are debugging or not. The try/catch simply allows the application to catch the exception and continue. When debugging, the exception goes into the debugger which (in case of VS) does NOT break because it knows there's a hardware breakpoint.
Of course the try/except is not needed. It's there only to demonstrate that the code actually throws. In real life, you set the breakpoint using SHB() and you wait for the debugger to break when the breakpoint is hit.
|
|
|
|

|
Okay, that's what I thought. However, I tried commenting out the __try, __except, and MessageBoxA() lines of test.cpp. If I run in the debugger, it seems to get stuck in SomeFunc(), as described in a previous question (I'm using VS2008). So, to work around that, I also commented out the calls to SHB(hX3) and RHB(hX3).
Now, if I run in the debugger, it once again runs past all three remaining breakpoints without stopping, and exits (normally) immediately. If I double-click the EXE, I get a "The application test64 has stopped working" dialog. Either way, not ideal.
Can you think of anything else I could be doing wrong? It's clear that this code has been working correctly for many other readers; could it be my environment (VS2008, Win64)?
|
|
|
|

|
I ran some tests on additional systems, and it looks like the problem is definitely in the 64-bit version of the test project. The 32-bit version worked correctly (except for the hang in SomeFunc() mentioned earlier) on all systems I tried, with both VS2008 and VS2010.
I'll do some more digging, but please chime in if you have any suggestions. I'm vaguely aware of some subtle differences in GetThreadContext()'s behavior on Win64 vs. Win32, but I don't recall the specifics.
|
|
|
|

|
Well, the only thing out-of-the-ordinary I noticed was that if I insert a call to GetLastError() at the very beginning of th() before calling any other function, and then build & run test64.exe in the debugger with no additional modifications, the new call to GetLastError() returns 87 (ERROR_INVALID_PARAMETER) immediately upon entering th(). None of the preceding Windows functions in the main thread return a non-successful error code.
And with that, I declare myself way out of my depth. I hope somebody else can get to the bottom of this!
|
|
|
|

|
I tried the test sample today in the Visual Studio 2008 debugger. It breaks execution as expected when calling SomeFunc() but two unexpected things happen: 1. VS fails to find the source code telling me "There is no source code available for the current location." When I show disassembly it shows me on the following line: 01021005 jmp SomeFunc (1021020h) This despite that it shows the source code just fine for the HWBRK_TYPE_READWRITE and HWBRK_TYPE_WRITE cases. 2. It gets stuck on the call to SomeFunc(). Stepping over or into the function doesn't work and resuming execution (F5) doesn't work. Each time I try to step it just seems to break again in the same place. That is, it doesn't move from the jmp instruction shown in the disassembly. Again I want to point out that when it breaks on the HWBRK_TYPE_READWRITE and HWBRK_TYPE_WRITE breakpoints I am able to step and resume execution using the VS debugger, just not with a HWBRK_TYPE_CODE breakpoint. Is this the expected behavior of HWBRK_TYPE_CODE?
|
|
|
|

|
Hello there.
1. It depends on where the breakpoint is set. Sometimes the hardware breakpoint is set "deeper" in the code (at the jump command) than the software breakpoint (which is usually set at the start of the parameter pushing). Try using the call stack to see where are you coming from.
2. Yes this is expected. Once you put a software breakpoint, the compiler knows you want to proceed with F10 or F11 and temprorarily removes the breakpoint, proceeds, then sets the breakpoint again. When you use hardware breakpoints, VS doesn't know there's a breakpoint so it doesn't try to remove it. So you can't get out of the breakpoint, unless you use the cursor to set the current execution point manually.
Generally, HWBRK_TYPE_CODE is only useful if, for some reason, you can't set a software breakpoint (because for example you are trying to break read-only code and software breakpoints replace the code with the 0xCC opcode). To exit from it you must set the EIP/RIP register manually using the cursor or the watch.
|
|
|
|

|
This is great stuff I want to use. I have a question. The code comment says:
•hThread - Handle to the thread for which the breakpoint is to be set.
I'm not quite sure what this means: "for which the breakpoint is to be set". I want the breakpoint to trigger for any thread that writes to the data. The whole point is that I don't know which thread is writing to the data, and the offending thread may not exist at the time I set the breakpoint. So my concern is the breakpoint will only fire if written by this thread I specify. However it seems this is probably not what is meant, or it would not be so useful. So could you clarify what this actually means? i.e. what are the actual consequences of passing the Current thread vs some other thread handle? How should I choose what to pass to this? Why would I care? etc...
Thanks for the great article!
-rdillon
|
|
|
|

|
Hi there.
Unfortunately the debug registers are within the thread context. That means that you can't set a breakpoint "per process". Hardware breakpoints are per thread.
It's different than normal breakpoints because normal breakpoints actually change the code to 0xCC (int 3) and hence, the breakpoint hits from everywhere.
The easy way is to call the function on each thread you start.
|
|
|
|

|
Thx for the reply. Yes, that is unfortunate.
So, do you know how Visual Studio does it then when you use it to set a data breakpoint? This works on multiple threads. Does it set the debug bits on every thread (including new ones that get created after you set the data breakpoint) ?
-rrdillon
|
|
|
|

|
Yes, the debugger is notified when a new thread starts and sets the breakpoint at that time.
|
|
|
|

|
Thanks!this's helpful,thanks for your job
|
|
|
|

|
Visual studio automatically disables data breakpoints in any module that isn't "pure native", even for code that is not compiled with the CLR compiler. Can this be used as a work around to that limitation? If so, many thanks! I've downloaded your source and will give it a try.
|
|
|
|

|
I doublt it will work, but try it. The problem is that SetHardwareBreakpoint calls many native stuff, I am not sure if you can call all this in a .NET application.
|
|
|
|

|
I wouldn't try to call it from MSIL code, only from a mixed application that includes some C++/CLI files compiled with /CLR and some that aren't. I would only use this in the pure native files. The frustration is that even if you have a project that is 100% native and you add a single file that is compiled with /CLR, you lose data breakpoint functionality for the entire project. I hope this is a way around. I hope to have some time today to try it out.
|
|
|
|

|
For the record, I tried this today and was very happy to find out it's working.
|
|
|
|

|
Thanks a lot, really helpfull.Could you please let me know whats the difference between executing __asm int 3 and this methodlogy...
S Vairavan
Senior Software Engineer,
TCS,India
|
|
|
|

|
There are quite a few differences.
1. __asm int 3 is not portable; you cannot include inline assembly in x64 applications
2. int 3 is a fixed line of code; You cannot remove or reposition it.
3. int 3 is software based breakpoint. You cannot modify read-only code.
4. int 3 is only used to break the execution. The hardware breakpoints also allow to break when a specific memory address is read or write as well.
|
|
|
|

|
Nice article. Thanks. Would you mind recompile it using VS2005 and add it?
It'll be helpful.
--Nalla
|
|
|
|

|
Hi there.
Actually its a separate tool I use to generate these VCproj files, so they should be compatible with VS 2005 as long as you change
ProjectType="Visual C++"
Version="9,00"
to
ProjectType="Visual C++"
Version="8,00"
and remove the .SLN files, then open the .VCPROJ.
|
|
|
|

|
Would it be possible to instead have the breakpoint set a flag and log the program counter and register contents and resume, possibly using a pre-allocated buffer to allow the breakpoint to be hit some number of times?
If one knows that a breakpoint is going to be hit sometime in a loop, one could test the breakpoint flag in the loop and have that trigger the debugger. One could then examine the system state and, if desired, resume execution until the next time the breakpoint is hit.
|
|
|
|

|
Yes, I am going to use conditional hardware breakpoints if possible at next update. But please notice that user code is required to do that.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Simple code to introduce a hardware breakpoint mechanism.
| Type | Article |
| Licence | CPOL |
| First Posted | 23 Jul 2008 |
| Views | 52,777 |
| Downloads | 1,435 |
| Bookmarked | 71 times |
|
|