The NT Insider

Life Support for WinDbg - New Windows NT Support Tools
New NT Support Tools (By: The NT Insider, Vol 5, Issue 5, Sep-Oct 1998 | Published: 15-Oct-98| Modified: 20-Aug-02)


Recently Microsoft released its Windows NT Support Tools to help support engineers and driver writers troubleshoot problems with Windows NT.  The tools, which can work with NT 3.51 and NT 4.0 are:

 

  • A new set of WinDbg extensions to help examine and analyze a wider range of kernel data structures;
  • A set of tools for adding memory allocation/deallocation, caller tracking, tail-checking, and statistics gathering to your system; and
  • A heuristics based kernel memory crash dump analyzer

Describing all of these new tools would take a good size book (you should see the documentation for the tools), so our focus here will be on the new WinDbg extensions and using the new commands to your advantage.  This is not to say that there isn?t other useful information in this new tool package from Microsoft, only that anything remotely related to improving the efficiency of debugging NT device drivers with WinDbg should understandably take priority.  Be sure to check out the documentation and other facilitators covered at your convenience.

New WinDbg Extension Dll

The new WinDbg extension DLL, Kdex2x86.dll (or Kdex2alp.dll for Alpha), contains 11 new Bang ?!? commands to enhance debugging.   These commands are:

 

·         Help

·         Version

·         Strct

·         Apc

·         Dpc

·         Ethread

·         Kthread

·         Idt

·         Kqueue

·         List/Singlelist

·         Smb

 

The commands help you dump a wealth of information that was previously unavailable.  While these commands may not all solve your needs, the addition of the !strct and !list/singlelist commands alone are a big win.  But before we get into a discussion of these new commands, let?s talk about how to get the new extension DLL for WinDbg loaded.

Getting Started

As with any extension DLL, you must first get WinDbg to load it.  To do this, you must first establish a WinDbg debugging session and then type in one of the following 2 commands, which will cause the new DLL to be loaded:

 

·         !kdex2x86. command [arguments]

 

When you issue this command WinDbg will load kdex2x86.dll, call the command specified, and pass into it any arguments that you specified.  Once this DLL has been loaded you can run any other command by typing:

 

!command [arguments]

 

·         !load kdex2x86.dll

 

This method also loads the extension DLL.  As in the above description, once this DLL has been loaded, you can run any other command by typing:

 

!command [arguments]

The New Commands

Now that you?ve got the new extension DLL loaded, it?s time to explore the new commands.  So let?s go.

Help

This command displays the standard help information for the new extension DLL.   If you need to find out all the new commands and their options, this is the command for you.  The standard output for this command is shown in Figure 1.

 

Help

-Display this message

Version

-Display extension DLL version

Apc [-?h] [expression]

-Dump APC or all APCs

Dpc [-?h] [expression]

-Dump DPC or all DPCs

Ethread [-?h] [expression]

-Display ETHREAD structure

Kthread [-?h] [expression]

-Display KTHREAD structure

Idt [-?h] [processornumber [ interruptnumber]]

-Dump information about IDT and handlers

Kqueue [-?h] [expression]

-Display queue of worker threads

[single]list [-?h] <expression> [count] [structname[.listnodemembername]]

-Display chain of LIST_ENTRY or SINGLE_LIST_ENTRY structures

Smb [-?hd] <expression>

-Display SMB structure from header

Strct [-?h] <structname> [fieldname] [expression]

-Display member offset and structure data

 

As you can see the commands contained within the new extension DLL are quite powerful and will return you a wealth of new information

Version

This command displays the version number of the new extension DLL.  Here at OSR, we usually use this command to make sure that we?re using the checked kdextx86.dll with a checked version of the O/S.  

Strct

Probably the most valuable command added to WinDbg to date is the !Strct command.  This command displays structure member offsets and dumps structures for approximately 142 of the structures found in ntddk.h!  When data is dumped it includes nested structures and named values for various flags contained in the structures.  Figure 2 shows what we consider the most important data structures that are supported.  For a more complete list consult the Windows NT Support Tools documentation.

 

CM_RESOURCE_LIST

DEVICE_DESCRIPTION

DEVICE_FLAGS

DEVICE_OBJECT

ERESOURCE

FAST_IO_DISPATCH

GUID

IO_STACK_LOCATION

IRP

KAPC

KEVENT

KDPC

MDL

SECTION_OBJECT_POINTERS

VPB

WORK_QUEUE_ITEM

CONFIGURATION_INFORMATION

FILE_OBJECT

DRIVER_OBJECT

EXCEPTION_RECORD

 

This command can either dump the field offsets of the fields within the structure or will dump the actual data of the named structure if an address is supplied.  Imagine how much you?ll learn about the internals of NT by dumping some of these structures?  For example, a dump of a File Object is shown in Figure 3.  Note that from this list dump you can see everything you need to know about an open instance of a file.  This information is invaluable for file system writers.

 

KDx86> !strct FILE_OBJECT 80854548

+0000  Structure FILE_OBJECT (Size:0x70) at 0x80854548:

+0000    Type =                 0005

+0002    Size =                 0070

+0004    DeviceObject =         808a4030

+0008    Vpb =                  808a53e8

+000c    FsContext =            e11e2758

+0010    FsContext2 =           e11e2898

+0014    SectionObjectPointer = 8086c6b0

+0018    PrivateCacheMap =      00000000

+001c    FinalStatus(NTSTATUS) = 0(STATUS_SUCCESS)

+0020    RelatedFileObject =    80850868

+0024    LockOperation =        00

+0025    DeletePending =        00

+0026    ReadAccess =           01

+0027    WriteAccess =          00

+0028    DeleteAccess =         00

+0029    SharedRead =           01

+002a    SharedWrite =          00

+002b    SharedDelete =         01

+002c    Flags =                00044042

+0030    FileName(UNICODE_STRING struct) = following

+0030      Length =               003a

+0032      MaximumLength =        003a

+0034      Buffer =               e11fff88

+0038    CurrentByteOffset(LARGE_INTEGER/ULARGE_INTEGER union) = following

+0038      None(Anonymous struct) = following

+0038        LowPart =              00000000

+003c        HighPart =             00000000

+0040    Waiters =              00000000

+0044    Busy =                 00000000

+0048    LastLock =             00000000

+004c    Lock(KEVENT struct) =  following

+004c      Header(DISPATCHER_HEADER struct) = following

+004c        Type =                 01

+004d        Absolute =             00

+004e        Size =                 04

+004f        Inserted =             00

+0050        SignalState =          00000000

+0054        WaitListHead(LIST_ENTRY struct) = following

+0054          Flink =                8085459c

+0058          Blink =                8085459c

+005c    Event(KEVENT struct) = following

+005c      Header(DISPATCHER_HEADER struct) = following

+005c        Type =                 00

+005d        Absolute =             00

+005e        Size =                 04

+005f        Inserted =             00

+0060        SignalState =          00000000

+0064        WaitListHead(LIST_ENTRY struct) = following

+0064          Flink =                808545ac

+0068          Blink =                808545ac

+006c    CompletionContext =    00000000

 

Apc

This command dumps a Kernel Asynchronous Procedure Call (KAPC) structure at a given address or all KAPC structures in the system.  While most driver writers will not deal with this structure, looking at the list of APCs in the system can be quite enlightening.

Dpc

This command dumps a Kernel Deferred Procedure Call (KDPC) structure at a given address or all KDPC structures in the system for a given processor or all processors.  If your having some problem with getting to your DPC, having this command gives you the opportunity to look at your DPC object and if queued, where it is current resides in the DPC queue.  Figure 4 shows a dump of a DPC.  As you can see, this is a medium importance DPC.  You could probably figure out who this DPC belongs to by issuing a !drivers command (!kdextx86.drivers)

 

KDx86> !dpc

+0000  Structure KDPC (Size:0x20) at 0x808b409c:

+0000    Type =                 0013

+0002    Number =               00

+0003    Importance =           01

+0004    DpcListEntry(LIST_ENTRY struct) = following

+0004      Flink =                808c8600

+0008      Blink =                808c8600

+000c    DeferredRoutine =      80016f9a

+0010    DeferredContext =      808b4028

+0014    SystemArgument1 =      00000000

+0018    SystemArgument2 =      00000000

+001c    Lock =                 808c8648

 

Ethread

This command dumps the fields for an undocumented ETHREAD (Executive Thread) structure at a given address.  We got the address of the ETHREAD dump in Figure 5 out of the PETHREAD pointer in an IRP that was queued to a driver.   As you can see there are lots of interesting fields to wonder about?

 

KDx86> !ETHREAD 8078a9c0

+0000  Structure ETHREAD (Size:0x240) at 0x8078a9c0:

+0000    Tcb(KTHREAD struct) =  following

+0000      Header(DISPATCHER_HEADER struct) = following

+0000        Type =                 06

+0001        Absolute =             00

+0002        Size =                 6c

+0003        Inserted =             00

+0004        SignalState =          00000000

+0008        WaitListHead(LIST_ENTRY struct) = following

+0008          Flink =                8078a9c8

+000c          Blink =                8078a9c8

+0010      MutantListHead(LIST_ENTRY struct) = following

+0010        Flink =                8078a9d0

+0014        Blink =                8078a9d0

+0018      InitialStack =         f7150000

+001c      StackLimit =           f714b000

+0020      Teb =                  7ffde000

+0024      TlsArray =             00000000

+0028      KernelStack =          f714fbd4

+002c      DebugActive =          00

+002d      State =                02

+002e      Alerted =              00 00

+0030      Iopl =                 00

+0031      NpxState =             0a

+0032      Saturation =           00

+0033      Priority =             0e

+0034      ApcState(KAPC_STATE struct) = following

+0034        ApcListHead[2](LIST_ENTRY struct) = following

+0034          Flink =                8078a9f4

+0038          Blink =                8078a9f4

+003c          Flink =                8078a9fc

+0040          Blink =                8078a9fc

+0044        Process =              8078a020

+0048        KernelApcInProgress =  00

+0049        KernelApcPending =     00

+004a        UserApcPending =       00

+004c      ContextSwitches =      0000011e

+0050      WaitStatus(NTSTATUS) = 0(STATUS_SUCCESS)

+0054      WaitIrql =             00

+0055      WaitMode =             00

+0056      WaitNext =             00

+0057      WaitReason =           00

+0058      WaitBlockList =        8078aa2c

+005c      WaitListEntry(LIST_ENTRY struct) = following

+005c        Flink =                801850d0

+0060        Blink =                8085d8fc

+0064      WaitTime =             00002e80

+0068      BasePriority =         08

+0069      DecrementCount =       07

+006a      PriorityDecrement =    06

+006b      Quantum =              17

+006c      WaitBlock[4](KWAIT_BLOCK struct) = following

+006c        WaitListEntry(LIST_ENTRY struct) = following

+006c          Flink =                8078a84c

+0070          Blink =                8078a84c

+0074        Thread =               8078a9c0

+0078        Object =               8078a844

+007c        NextWaitBlock =        8078aa2c

+0080        WaitKey =              0000

+0082        WaitType =             0001

+0084        WaitListEntry(LIST_ENTRY struct) = following

+0084          Flink =                f714faa0

+0088          Blink =                f714faa0

+008c        Thread =               8078a9c0

+0090        Object =               f714fa98

+0094        NextWaitBlock =        8078aa74

+0098        WaitKey =              0001

+009a        WaitType =             0000

+009c        WaitListEntry(LIST_ENTRY struct) = following

+009c          Flink =                8078abb0

+00a0          Blink =                8078abb0

+00a4        Thread =               8078a9c0

+00a8        Object =               8078aba8

+00ac        NextWaitBlock =        8078aa5c

+00b0        WaitKey =              0000

+00b2        WaitType =             0001

+00b4        WaitListEntry(LIST_ENTRY struct) = following

+00b4          Flink =                8078aab0

+00b8          Blink =                8078aab0

+00bc        Thread =               8078a9c0

+00c0        Object =               8078aaa8

+00c4        NextWaitBlock =        8078aa74

+00c8        WaitKey =              0102

+00ca        WaitType =             0001

+00cc      LegoData =             00000000

+00d0      KernelApcDisable =     00000000

+00d4      UserAffinity =         00000003

+00d8      SystemAffinityActive = 00

+00d9      Pad =                  00 00 00 10 4a 18 80

+00e0      Queue =                00000000

+00e4      ApcQueueLock =         00000000

+00e8      Timer(KTIMER struct) = following

+00e8        Header(DISPATCHER_HEADER struct) = following

+00e8          Type =                 08

+00e9          Absolute =             00

+00ea          Size =                 0a

+00eb          Inserted =             00

+00ec          SignalState =          00000001

+00f0          WaitListHead(LIST_ENTRY struct) = following

+00f0            Flink =                8078aab0

+00f4            Blink =                8078aab0

+00f8        DueTime(LARGE_INTEGER/ULARGE_INTEGER union) = following

+00f8          None(Anonymous struct) = following

+00f8            LowPart =              6e910dc0

+00fc            HighPart =             00000000

+0100        TimerListEntry(LIST_ENTRY struct) = following

+0100          Flink =                00000000

+0104          Blink =                00000000

+0108        Dpc =                  00000000

+010c        Period =               00000000

+0110      QueueListEntry(LIST_ENTRY struct) = following

+0110        Flink =                00000000

+0114        Blink =                00000000

+0118      Affinity =             00000003

+011c      Preempted =            00

+011d      ProcessReadyQueue =    00

+011e      KernelStackResident =  01

+011f      NextProcessor =        01

+0120      CallbackStack =        00000000

+0124      Win32Thread =          e15675c8

+0128      TrapFrame =            f714ff04

+012c      ApcStatePointer =      8078a9f4 8078ab00

+0134      EnableStackSwap =      01

+0135      LargeStack =           01

+0136      ResourceIndex =        02

+0137      PreviousMode =         01

+0138      KernelTime =           00000017

+013c      UserTime =             00000005

+0140      SavedApcState(KAPC_STATE struct) = following

+0140        ApcListHead[2](LIST_ENTRY struct) = following

+0140          Flink =                00000000

+0144          Blink =                00000000

+0148          Flink =                00000000

+014c          Blink =                00000000

+0150        Process =              00000000

+0154        KernelApcInProgress =  00

+0155        KernelApcPending =     00

+0156        UserApcPending =       00

+0158      Alertable =            01

+0159      ApcStateIndex =        00

+015a      ApcQueueable =         01

+015b      AutoAlignment =        00

+015c      StackBase =            f7150000

+0160      SuspendApc(KAPC struct) = following

+0160        Type =                 0012

+0162        Size =                 0030

+0164        Spare0 =               00000000

+0168        Thread =               8078a9c0

+016c        ApcListEntry(LIST_ENTRY struct) = following

+016c          Flink =                8078a9f4

+0170          Blink =                8078a9f4

+0174        KernelRoutine =        8012c964

+0178        RundownRoutine =       00000000

+017c        NormalRoutine =        8012cfe8

+0180        NormalContext =        00000000

+0184        SystemArgument1 =      00000000

+0188        SystemArgument2 =      00000000

+018c        ApcStateIndex =        00

+018d        ApcMode =              00

+018e        Inserted =             00

+0190      SuspendSemaphore(KSEMAPHORE struct) = following

+0190        Header(DISPATCHER_HEADER struct) = following

+0190          Type =                 05

+0191          Absolute =             00

+0192          Size =                 05

+0193          Inserted =             00

+0194          SignalState =          00000000

+0198          WaitListHead(LIST_ENTRY struct) = following

+0198            Flink =                8078ab58

+019c            Blink =                8078ab58

+01a0        Limit =                00000002

+01a4      ThreadListEntry(LIST_ENTRY struct) = following

+01a4        Flink =                8078a070

+01a8        Blink =                8078a070

+01ac      FreezeCount =          00

+01ad      SuspendCount =         00

+01ae      IdealProcessor =       01

+01af      DisableBoost =         00

+01b0    CreateTime(LARGE_INTEGER/ULARGE_INTEGER union) = following

+01b0      None(Anonymous struct) = following

+01b0        LowPart =              2b28a268

+01b4        HighPart =             01bdebdd

+01b8    ExitTime(LARGE_INTEGER/ULARGE_INTEGER union) = following

+01b8      None(Anonymous struct) = following

+01b8        LowPart =              8078ab78

+01bc        HighPart =             8078ab78

+01b8    LpcReplyChain(LIST_ENTRY struct) = following

+01b8      Flink =                8078ab78

+01bc      Blink =                8078ab78

+01c0    ExitStatus(NTSTATUS) = 0(STATUS_SUCCESS)

+01c0    OfsChain =             00000000

+01c4    PostBlockList(LIST_ENTRY struct) = following

+01c4      Flink =                8078ab84

+01c8      Blink =                8078ab84

+01cc    TerminationPortList(LIST_ENTRY struct) = following

+01cc      Flink =                e150e388

+01d0      Blink =                e150e388

+01d4    ActiveTimerListLock =  00000000

+01d8    ActiveTimerListHead(LIST_ENTRY struct) = following

+01d8      Flink =                8078ab98

+01dc      Blink =                8078ab98

+01e0    Cid(CLIENT_ID struct) = following

+01e0      UniqueProcess =        00000075

+01e4      UniqueThread =         0000006f

+01e8    LpcReplySemaphore(KSEMAPHORE struct) = following

+01e8      Header(DISPATCHER_HEADER struct) = following

+01e8        Type =                 05

+01e9        Absolute =             00

+01ea        Size =                 05

+01eb        Inserted =             00

+01ec        SignalState =          00000000

+01f0        WaitListHead(LIST_ENTRY struct) = following

+01f0          Flink =                8078abb0

+01f4          Blink =                8078abb0

+01f8      Limit =                00000001

+01fc    LpcReplyMessage =      00000000

+0200    LpcReplyMessageId =    00000000

+0204    PerformanceCountLow =  00000000

+0208    ImpersonationInfo =    00000000

+020c    IrpList(LIST_ENTRY struct) = following

+020c      Flink =                80868858

+0210      Blink =                80868858

+0214    TopLevelIrp =          00000000

+0218    DeviceToVerify =       00000000

+021c    ReadClusterSize =      00000007

+0220    ForwardClusterOnly =   00

+0221    DisablePageFaultClustering = 00

+0222    DeadThread =           00

+0223    HasTerminated =        00

+0224    EventPair =            00000000

+0228    GrantedAccess(ACCESS_MASK) = 001f03ff( STANDARD_RIGHTS_ALL )

+022c    ThreadsProcess =       8078a020

+0230    StartAddress =         77f052cc

+0234    Win32StartAddress =    00410240

+0234    LpcReceivedMessageId = 00410240

+0238    LpcExitThreadCalled =  00

+0239    HardErrorsAreDisabled = 00

+023a    LpcReceivedMsgIdValid = 00

+023b    ActiveImpersonationInfo = 00

+023c    PerformanceCountHigh = 00000000

 

Kthread

This command dumps the fields for an undocumented KTHREAD (Kernel Thread) structure at a given address.

Idt

This command dumps the Interrupt Descriptor Table (IDT) for a given processor, including the handler for each interrupt.  Figure 6 shows a partial dump of the IDT for processor #0 on a development machine here in the OSR Lab.

 

KDx86> !idt 0

    00: 801753fc (_KiTrap00)

    01: 80175580 (_KiTrap01)

    02: 000012de

    03: 80175890 (_KiTrap03)

    04: 80175a08 (_KiTrap04)

    05: 80175b68 (_KiTrap05)

    06: 80175ce0 (_KiTrap06)

    07: 80176250 (_KiTrap07)

    08: 00001338

    09: 801765d0 (_KiTrap09)

    0a: 801766f4 (_KiTrap0A)

    0b: 80176838 (_KiTrap0B)

    0c: 80176bac (_KiTrap0C)

    0d: 80176dd0 (_KiTrap0D)

    0e: 80177838 (_KiTrap0E)

    0f: 80177bcc (_KiTrap0F)

    10: 80177cf0 (_KiTrap10)

    11: 80177e28 (_KiTrap11)

    12: 80177bcc (_KiTrap0F)

    13: 80177bcc (_KiTrap0F)

    14: 80177bcc (_KiTrap0F)

    15: 80177bcc (_KiTrap0F)

    16: 80177bcc (_KiTrap0F)

    17: 80177bcc (_KiTrap0F)

    18: 80177bcc (_KiTrap0F)

    19: 80177bcc (_KiTrap0F)

    1a: 80177bcc (_KiTrap0F)

    1b: 80177bcc (_KiTrap0F)

    1c: 80177bcc (_KiTrap0F)

    1d: 80177bcc (_KiTrap0F)

    1e: 80177bcc (_KiTrap0F)

    1f: 80003618

    20: 00000000

    21: 00000000

    22: 00000000

    23: 00000000

    24: 00000000

    25: 00000000

    26: 00000000

    27: 00000000

    28: 00000000

    29: 00000000

    2a: 80174716 (_KiGetTickCount)

    2b: 80174820 (_KiCallbackReturn)

    2c: 80174930 (_KiSetLowWaitHighThread)

    2d: 80175768 (_KiDebugService)

    2e: 80174130 (_KiSystemService)

    2f: 80177bcc (_KiTrap0F)

    30: 80173820 (_KiUnexpectedInterrupt0)

    31: 8017382a (_KiUnexpectedInterrupt1)

    32: 80173834 (_KiUnexpectedInterrupt2)

    33: 8017383e (_KiUnexpectedInterrupt3)

    34: 80173848 (_KiUnexpectedInterrupt4)

    35: 80173852 (_KiUnexpectedInterrupt5)

    36: 8017385c (_KiUnexpectedInterrupt6)

    37: 80002e6c

    38: 80173870 (_KiUnexpectedInterrupt8)

 

Kqueue

This command dumps the fields of the undocumented KQUEUE structure.  I went looking around in nttdk.h to see if I could find a KQUEUE structure to dump and came up empty.   I suspect that this is used for Lookaside lists, but I am not positive.   Anyway, now that I can dump one, I?ll just have to find one.

List/SingleList

These commands understand the NT Kernel LIST_ENTRY and SINGLE_LIST_ENTRY constructs and will allow you to dump chains of structures starting from a given node forward, for singly linked lists, and/or backward, in the case of doubly linked lists.

 

If you use Own queuing (driver queuing) instead of system queuing, this is a great command to allow you to dump the contents of your queue(s).

Smb

The Smb command dumps NT/Lanman-style network communications blocks starting at an SMB header and chaining through all the commands associated with it.  There is no support for starting at an arbitrary point in the command chain or dumping out a particular command structure at an arbitrary place in memory.  If you?re doing network work, I?m sure you?ll have a use for this command.

Xpool

The Xpool command dumps information about managed pool blocks in the system when used in conjunction with the Pool Enhancement facility included in this package.   This command only works if you have installed the pool enhancements and the pool block management is enabled for the module(s) that you are analyzing with the command. If you?re interested in finding out more about what this command can do for you, definitely pour over the documentation.

Where to get Support Tools (V1.0)

The Microsoft Windows NT Support Tools can be obtained from the Microsoft web site at URL ftp://ftp.microsoft.com/bussys/winnt/winnt-public/tools/OEMSupportTools/.  You?ll need to read the documentation about how to install and use the included tools, but you?ll find it is time well spent.

Summary

As we?ve attempted to outline above, there are a multitude of new and powerful commands contained within kdex3x86.dll in the new Microsoft Windows NT Support Tool package.  Using WinDbg can be ?entertaining? to say the least, so this new extension is a welcome addition to any NT driver writer?s repertoire.  Bang away!

 

This article was printed from OSR Online http://www.osronline.com

Copyright 2017 OSR Open Systems Resources, Inc.