Conditional breakpoints on steroids

Imagine a situation where you’re debugging some problem and need to set a breakpoint in function that’s called very often from many points in your application (like operator[] in your array class for example). Thing is, you’re only interested in one particular codepath, as that’s where things go wrong, calls from other places are fine. If you simply set a breakpoint in line that interests you, it’ll trigger hundreds of times every frame, making it tricky to find the moment that’s interesting for us. In situations when the “interesting” code path is executed rarely, it’s almost impossible to make it work this way. Sure, you can have some helper/hacky flag that’s only enabled in offending caller function, but you can also exploit conditional breakpoints first.

First, you need to find out caller address, set a breakpoint there, go to disassembly view and check what’s the address of instruction that’s just after jumping to function that we’re interested in. It may look like this:

mov         edx,dword ptr [ecx]
mov         ecx,dword ptr [ebp-1Ch]
mov         eax,dword ptr [edx+4]
call        eax  // That's the function we want to set our final breakpoint in
cmp         esi,esp

Our address is 0x246163, as that’s the return point for our function. Now, go to the function itself and set a final breakpoint, then add condition as follows:

*((void **)ebp + 1)==0x246163

Should be fairly simple to understand, we basically read the stack trace and retrieve return address than compare it with desired one. That’s assuming x86 + __cdecl, obviously, but same pattern can be applied to other environments, refer to your platform ABI documentation.

This trick can be easily extended to going up the chain, if we want to break conditionally depending on some function that’s higher in the stack. Conditions get uglier & longer, but idea stays the same e.g.

*((void **)(*(void **)ebp)+1)==caller of caller address

Bear in mind that conditional breakpoints tend to be really slow in MSVC, so in many cases you still may need to resort to some other techniques, but this should be a good starting point, I use it for initial reconnaissance and in many cases it was enough.

Old comments

ransico 2011-04-11 04:02:11

Very nifty little trick - so simple too.

none 2011-04-12 13:25:59

this is interesting too:

VB6 Runtime Error 91 – How do I fix It? | Windows Errors Fix 2011-04-16 10:46:38

[…] Comments Leave a reply | breakpoints on steroids | .mischief.mayh&#101&#109&#46soap. […]

Philippe Beaudoin 2011-05-19 13:39:37

Out of curiosity, in which situation wouldn’t you just place the breakpoint on the calling line (here, the C++ line corresponding to the use of operator[]) and “execute into” the method itself? This seems easier to do, and you don’t have to pay the cost of the conditional breakpoint.

admin 2011-05-20 13:36:32

@Philippe: hah, good question. In my original problem I actually wanted to avoid stopping when calling from two specific functions (so my tests were caller_address!=xxxx), I was interested in others (this was a high traffic function, so I didn’t want to place so many breakpoints). Other case would be having some more conditions that depend on internal state of the function, but I guess at this point it could get really slow.

More Reading
Newer// Riddle