Breaking when a function returns a specific value without depending on its call site

Jigar Mehta writes today about how to set a breakpoint in the debugger on a function and check its return value using conditionals, in another post in his fine blog, that can teach even a seasoned Windbg user a thing or two (personally I didn’t know of the “-psn” switch that allows easy attachment to a service process until reading about there).

However, Jigar’s approach requires to determine the call site of the interesting function and breaking after its return for examining the return value. This may be tolerable if you are only interested in what the function returns when invoked from a specific location, but for more general scenarios can be insufficient.

An alternative approach is to use the “gu” debugger command (go up to after the call site) and examine the return value register and potentially other output parameters at that state. For example:

0:000> bp kernel32!CreateFileW "gu; j @eax == -1 '.echo CreateFileW failed; gc' '.printf \"CreateFileW returned %p\", @$retreg; .echo; gc'"
0:000> g
ModLoad: 5cb70000 5cb96000 C:\WINDOWS\system32\ShimEng.dll
ModLoad: 74d90000 74dfb000 C:\WINDOWS\system32\USP10.dll
CreateFileW returned 000007c8
ModLoad: 74720000 7476b000 C:\WINDOWS\system32\MSCTF.dll
CreateFileW returned 00000774
CreateFileW returned 00000774
ModLoad: 755c0000 755ee000 C:\WINDOWS\system32\msctfime.ime
ModLoad: 605d0000 605d9000 C:\WINDOWS\system32\mslbui.dll

I get bonus points for using the portable @$retreg over @eax. I lose some for not figuring out how the heck to get .printf to write a newline without a trailing .echo (both \n and \r\n don’t seem to do the trick here). Of course if what you have in mind is to actually break at the breakpoint, do not append “gc” (go from conditional breakpoint) at the end of the branch of interest.