Debugger commands (!error, .enable_long_status) that makes my life easier

One thing you learn very quickly when writing a driver is that NTSTATUS is used almost everywhere. The consistency is nice, especially compared to user mode where errors can be an HRESULT, LONG, or DWORD (yes they are all the same underlying type, but they have different meanings, particularly for success/failure checks). The problem with any error value that is returned is that you must figure out where it came from and what the value maps to in terms of description and error name.

The first simple tool I use is the .enable_long_status command. By default, all long integers are displayed in decimal, but for some error encoding systems, you want hex instead. In this example, status is an NTSTATUS which is set to STATUS_UNSUCCESSFUL. This works for HRESULT as well since all we are doing is changing the format of the number.

0:000> dt status
status = -1073741823
0:000> .enable_long_status 1
0:000> dt status
status = 0xC0000001

I found !error awhile ago and I just refered to it in a comment on another post, so I thought it was a good time to talk about it. !error takes an error value and returns the description for it. As a bonus, it works for win32 error codes as well as NTSTATUS values. Here is the description from the docs:

!error Value [Flags]

Value Specifies one of the following error codes:

Flags If Flags is set to 1, then the error code is read as an NTSTATUS code.

And this is what the output looks like for various values:
Dump out the value as Win32
0:000> !error 1
Error code: (Win32) 0x1 (1) – Incorrect function.

Dump out the value as NTSTATUS
0:000> !error 1 1
Error code: (NTSTATUS) 0x1 – STATUS_WAIT_1

Dump out an NTSTATUS value that is not ambiguous with a Win32 value
0:000> !error c0000001
Error code: (NTSTATUS) 0xc0000001 (3221225473) – {Operation Failed} The requested operation was unsuccessful.

There are others tools and commands that you can use to get error descriptions:

  • net helpmsg
  • WPP format specifiers, %!STATUS! for NTSTATUS. I am sure there are other specifiers for other types as well (I just don’t know them offhand).
  • FormatMessage() in user mode
  • Visual Studio will do some automatic interpretation for you. IIRC, in a watch window you can apped “,err” or “,hr” to the variable name to get better error info.
  • …and I am sure there others…

Comments (5)

  1. ali says:

    >The problem with any error value that is returned is that you must figure out where it came from and what the value maps to in terms of description and error name.

    Nice tricks to track what happened bad in the very land. But don’t you think that despite where and what error we get is more relevant to what we were actually doing when we get a certain error value.

  2. yes, that is true, but even then you still might want to look up the value to see if the specific value is relevant to the call you just made.

  3. ali says:

    I agree.

    The tow API or system interface which are very popular to developers are:

    1) Deigning a single API that can return a different error values so the caller can decide what ever went wrong.

    2) Design an API that have overloaded interfaces, like accepting different parameters for different functionality

    I believe that NT is designed on first option. Return different values so caller would decide what ever happened bad.


  4. yes, certainly the ntoskrnl exports behave this way.  export drivers created by a variety of development teams have chosen both options.  I certainly prefer the simpler option (#1).