GetLastError on WinDBG

Today, after a series of design posts, we'll be looking at something quite different.

If you happen to be debugging a native application, you may find yourself stepping through code that calls a Win32 API and then never checks the last error, maybe because it's only looking at the result for pass/fail information. The error is there somewhere, as of course GetLastError can get it, but how to get to it?

If you're using WinDBG, part of the Debugging Tools for Windows, there are two debugger extensions you can combine to get this information. The first is !teb. This extension will provide you with information on the current thread, with an output similar to the following. Don't worry if some of the fields don't match your output - the format for this command has changed over time.

0:001> !teb
TEB at 7FFDD000
    ExceptionList:    76ffdc
    Stack Base:       770000
    Stack Limit:      76f000
    SubSystemTib:     0
 FiberData:        1e00
    ArbitraryUser:    0
    Self:             7ffdd000
    EnvironmentPtr:   0
 ClientId:         324.48c
    Real ClientId:    324.48c
    RpcHandle:        0
    Tls Storage:      0
    PEB Address:      7ffdf000
    LastErrorValue:   2
    LastStatusValue:  0
    Count Owned Locks:0
    HardErrorsMode:   0

Note the LastErrorValue field. This is the value that GetLastError reports; it lives at the thread level, which is how you can call into Win32 APIs from different threads and make sure each one gets its own value - it's a "thread global", if you will.

Once you have the error code, you can go looking in the header files for what the error means, but it might be easier to just use the !error extension. Just pass in the value you got before, and voila!

0:001> !error 0n2
Error code: (Win32) 0x2 (2) - The system cannot find the file specified.

The one gotcha: make sure that you use the right numeric base for !error. So when LastErroValue displays its value in decimal, you might want to prefix it with 0n to make sure it doesn't get interpreted as a hex value. In my sample it doesn't make a difference, but it never hurts to be diligent about it.

Enjoy!

PS: if you think you've seen my last post on (im)mutability, I'm still thinking about writing reasons why it's interesting in the first place and what are appropriate and inappropriate places to seek it.