Something odd just happened to me while trying out my debugger on Windows XP 64 bits – whenever I stepped on or traced an instruction, the instruction pointer would go back to the same instruction the first time. The second time, it worked. So I had to step twice on each instruction to debug a program.
This was clearly wrong, but I couldn’t see anything in my code that would produce that. Furthermore, in 32 bits the exact same code was working alright!
After scratching my head for a while, I went to MSDN in search of enlightment, and found this info at the help page for ContinueDebugEvent:
DBG_CONTINUE (0x00010002L): If the thread specified by the dwThreadId parameter previously reported an EXCEPTION_DEBUG_EVENT debugging event, the function stops all exception processing and continues the thread. For any other debugging event, this flag simply continues the thread.
DBG_EXCEPTION_NOT_HANDLED (0x80010001L): If the thread specified by dwThreadId previously reported an EXCEPTION_DEBUG_EVENT debugging event, the function continues exception processing. If this is a first-chance exception event, the search and dispatch logic of the structured exception handler is used; otherwise, the process is terminated. For any other debugging event, this flag simply continues the thread.
But I remembered seeing a certain DBG_EXCEPTION_HANDLED value when porting SDK constants and structures to my Win32 API wrappers. So I looked it up and it’s value turned out to be 0x00010001L, which was exactly DBG_CONTINUE minus one, so it wasn’t not just an alias but really a different value, possibly with a different meaning.
So I tried replacing DBG_CONTINUE by DBG_EXCEPTION_HANDLED when handling exceptions in my code and, what do you know, single steping and tracing began to work again!
Apparently, when handling exception events, 32 bits Windows treats DBG_CONTINUE as an alias of DBG_EXCEPTION_HANDLED, while in 64 bits Windows it’s an alias of DBG_EXCEPTION_NOT_HANDLED. This means we can’t possibly write a debugger for 64 bits without using this undocumented value! :(
Luckily for us, DBG_EXCEPTION_HANDLED seems to work well in 32 bits Windows, at least with XP (didn’t test Windows 2000 yet), so the same code may be used for all versions of Windows. It also works with current versions of Wine, judging from this commit from 2005.
Speaking of Wine, browsing through the sources I found several other “undocumented” status codes:
However the last three don’t seem to be supported by Windows XP, as shown in the following disassembly of NTOSKRNL.EXE:
That still leaves us with two new undocumented status codes to play with :)