How to only break on a jump when it will be taken

Here's a question that came up a work a little bit back - thought I would share the result around.

There is a coding pattern (that I don't ever really use so I may be messing it up) that works like this:

 T1 res1;
T2 res2;
T3 res3;

res1 = GetRes1();
if (!res1) goto Cleanup;

res2 = res1.GetRes2();
if (!res2) goto Cleanup;

res3 = res2.GetRes3();

Cleanup:
if (res3) CleanupRes3(res3);
if (res2) CleanupRes3(res2);
if (res1) CleanupRes3(res1);

So what if you wanted to break when you are at Cleanup because res2 was null?  You can set a breakpoint with a conditional that will only break when the jump to Cleanup from res2 is going to be taken.  You could base it on the symbols and do the comparison yourself. However, in optimized code the debuggers understanding of local variable information is often incorrect (the compiler doesn't emit enough information in the pdb to make this possible).  In that case, it may be most convenient to make a conditional breakpoint using the x86 flags (described in detail in the help file that comes with windbg under the topic x86 Architecture).

Here's an example:

ntdll!RtlUnlockModuleSection+0x23a:
77937c71 8b4590 mov eax,dword ptr [ebp-70h]
77937c74 6683785c01 cmp word ptr [eax+5Ch],1
77937c79 7416 je ntdll!RtlUnlockModuleSection+0x25a (77937c91)

0:000> bu ntdll!RtlEncodePointer+0x21a ".if (@ZF=1) { gc } "
0:000> g
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0011f678 77945ad7 ntdll!RtlEncodePointer+0x21a
0011f6e4 7794a980 ntdll!RtlGetNtVersionNumbers+0x83
0011f6f4 00000000 ntdll!LdrInitializeThunk+0x10
eax=00000002 ebx=7ffde000 ecx=779a00dd edx=77970f34 esi=00000000 edi=779d5d14
eip=77944bef esp=0011f534 ebp=0011f678 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
ntdll!RtlEncodePointer+0x21a:
77944bef 740d je ntdll!RtlEncodePointer+0x229 (77944bfe) [br=0]

ZF=1 is the flag for a comparison (which is a subtraction that sets flags) that was equal (so a subtraction would naturally result in 0 - setting the zero flag). In this second example we're interested in breaking when it is not equal, so we used gc (to continue execution) when ZF=1.

 

Cheers!

James