Tuesday, December 6, 2011

Retrieving GetLastError() in Windbg

Let's say that you are debugging some code with windbg and some error happened, but the code doesn't call GetLastError() and store it in a local variable. Don't worry, you can still find out what the error was. It is stored in the TEB (thread environment block) and there is a debugger extension for the TEB.

0:002> !teb
TEB at 7f38d000
    ExceptionList:        018bfad0
    StackBase:            018c0000
    StackLimit:           018bc000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7f38d000
    EnvironmentPointer:   00000000
    ClientId:             0000076c . 00000518
    RpcHandle:            00000000
    Tls Storage:          0115a170
    PEB Address:          7f384000
    LastErrorValue:       1168
    LastStatusValue:      c000000d
    Count Owned Locks:    0
    HardErrorMode:        0
0:002> !error c000000d
Error code: (NTSTATUS) 0xc000000d (3221225485) - An invalid parameter was passed to a service or function.
0:002> !error 0n1168
Error code: (Win32) 0x490 (1168) - Element not found.

Note LastErrorValue is in decimal and not hex so be sure to add the 0n when using !error.  There you go, there is the last error.


Friday, December 2, 2011

new nothrow

I don't use STL, and I don't C++ exceptions.  I avoid them for a few reasons: under debugger, they make it a pain to find and walk the faulting call stack after they are thrown, and mostly I lean towards a more C style of programming style personally.  Still, you need to use the new operator to create new C++ objects, and new can throw and exception in low resource conditions.  There are a few ways to change this default behavior so that it just returns NULL instead of throwing.

One way is to add this into your sources file:

    $(SDK_LIB_PATH)\nothrownew.obj       \

Another way is to add a no throw each time you use the new operator:

    ClassX *pObj = new (std::nothrow) ClassX();

    if (!pObj)
        return E_OUTOFMEMORY;