System and COM routines often set an error code, that can be retrieved by GetLastError. There are several ways to decipher this code –
(1) Use the command line net helpmsg,
(2) From the VS menu, select Tools/Error Lookup and paste the code,
and by far the most useful:
(3) keep ‘$err,hr’ on your watch window!
‘$err’ is one of several pseudoregisters – a neat feature of Visual Studio that is all but undocumented. (although some nice references can by found online). ‘hr’ is one of several format specifiers, indicating to VS that the raw hex value is to be interpreted as an HRESULT, or a windows error code.
Now off to a first cute enhancement.
Detecting the Location Where the Error is Raised
When you want to locate the code location that raises the error, your first approach might be to step through it, repeatedly bisecting it untilyou can pin-point the culprit line. Wouldn’t it be useful to be set a breakpoint exactly where the error is set?
You could try and set a breakpoint to SetLastError – and that might actually work for some non-MS COM errors, but its certainly inlined for MS internal components. There are better ways.
As noted in several places, disassembling GetLastError you get –
MOV EAX,FS:[18h] MOV EAX,DWORD PTR [EAX+34h] RET
Turns out FS:[18h] points to the current thread’s environment block, and all GetLastError does is retrieve a DWORD from a fixed offset into that block. So, you could note the memory address of that DWORD, (either by disassembling or using the undocumented NtCurrentTeb) and set a data breakpoint to it, but there’s a better way still.
As Calvin Hsia notes, you can use another pseudoregister, $tib, just for that. The address of the error code is exactly –
Note that value and place a data breakpoint there, and you’re done!
This breakpoint typically induces a lot of noise, as many Windows routines set expected errors and then re-set them. Its probably best to selectively enable it only around suspect code regions.
Pingback: g_dwLastErrorToBreakOn: Watching Errors on VS Revisited « Ofek's Visual C++ stuff
good advice, but for 64 bit you either need to change the offset from 0x34 to 0x68 or use an expression such as:
Source of the offsets: http://terminus.rewolf.pl/terminus/structures/ntdll/_TEB_combined.html
For the last NT status code you’d use: