Part 1 of a beginner’s guide to debugging with NDISKD

If you haven’t already, grab the updated WDK with its new ndiskd debugger extension.  You’ll need it for today’s laboratory exercise: getting started with ndiskd.

If you are new to Windows kernel debugging, check out Ilias’s thorough tutorial.  You should follow that tutorial to get your kernel debugger attached to another computer.  While you can use either Windbg.exe or Kd.exe, I highly suggest using Windbg—in just a moment, you’ll see why Windbg is much easier than Kd.

When I start debugging network problems, my first step is always to double-check that the NDIS symbols are correctly loaded.  Use .reload /f ndis.sys to force the debugger to download the ndis.pdb symbol file.  Then use the !lmi ndis extension and look for the magic phrase “Symbols loaded successfully”.  If everything went according to plan, you should get output similar to this:

kd> .reload /f ndis.sys
kd> !lmi ndis
Loaded Module Info: [ndis]
         Module: ndis
   Base Address: fffff880014bf000
     Image Name: ndis.sys
   Machine Type: 34404 (X64)
     Time Stamp: 4a5bc184 Mon Jul 13 16:21:40 2009
           Size: f2000
       CheckSum: f0209
Characteristics: 22  perf
Debug Data Dirs: Type  Size     VA  Pointer
             CODEVIEW    21, 54920,   53f20 RSDS - GUID: {40D6C85A-C9F7-4887-A652-601839A1F56D}
               Age: 2, Pdb: ndis.pdb
                CLSID     4, 5491c,   53f1c [Data not mapped]
     Image Type: MEMORY   - Image read successfully from loaded memory.
    Symbol Type: PDB      - Symbols loaded successfully from symbol server.
                 c:\pubsym\cache\ndis.pdb\40D6C85AC9F74887A652601839A1F56D2\ndis.pdb
    Load Report: public symbols , not source indexed
                 c:\pubsym\cache\ndis.pdb\40D6C85AC9F74887A652601839A1F56D2\ndis.pdb

Now that your debugger is set up correctly, we can start using ndiskd.  The first command we’ll try is !ndiskd.help.

kd> !ndiskd.help

NDIS KD EXTENSIONS

    ndis               Show NDIS.sys build info
    help               This help and lots more
    miniport           Show miniports  (this is a good starting place)
    protocol           Show protocol drivers
    mopen              Show open bindings between miniport and protocol
    filter             Show light-weight filters
    nbl                Show information about an NET_BUFFER_LIST
    oid                Show pending OID Requests
                        → Show more extensions

If you are using Windbg.exe (as opposed to Kd.exe), you probably immediately noticed the clickable hyperlinks that allow you to drill down into more detail.  The hyperlinks are (in my opinion!) a major time-saver, since they save me the effort of typing and they save memorizing a bunch of the ndiskd syntax.  In fact, with windbg, you can exercise all the functionality of !ndiskd just by following links from the output of !ndiskd.help.  That’s a good reason to prefer windbg!

The help message offers smart advice: !ndiskd.miniport is indeed a good starting place.  After double-checking the symbols, !ndiskd.miniport is almost always the next command I use.  You can read ndiskd’s built-in help by clicking on the word “miniport” in Windbg (or by running !ndiskd.help miniport).

After reading the built-in help, we’re getting anxious to try it out.  Let’s take a look at what it shows on my computer:

kd> !ndiskd.miniport
    MiniDriver         Miniport            Name                                _
    fffffa800acf4640   fffffa800ad051a0    WAN Miniport (SSTP)
    fffffa800acf0530   fffffa800ad031a0    WAN Miniport (PPTP)
    fffffa800acec0a0   fffffa800ad011a0    WAN Miniport (PPPOE)
    fffffa800ace8640   fffffa800acff1a0    WAN Miniport (IPv6)
    fffffa800ace8640   fffffa800acfd1a0    WAN Miniport (IP)
    fffffa800ace8640   fffffa800acb71a0    WAN Miniport (Network Monitor)
    fffffa800acd76e0   fffffa800acb41a0    WAN Miniport (L2TP)
    fffffa800acc76e0   fffffa800acfb1a0    MAC Bridge Miniport
    fffffa800acabb90   fffffa800acac1a0    WAN Miniport (IKEv2)
    fffffa800ac8f020   fffffa800ac911a0    Microsoft Virtual Machine Bus Network Adapter
    fffffa800ac57020   fffffa800ac731a0    Teredo Tunneling Pseudo-Interface
    fffffa800ac57020   fffffa800ac711a0    Microsoft ISATAP Adapter #6
    fffffa800ac57020   fffffa800ac6f1a0    Microsoft ISATAP Adapter #5
    fffffa800ac57020   fffffa800ac681a0    Microsoft ISATAP Adapter #2
    fffffa800ac57020   fffffa800ac5d1a0    Microsoft ISATAP Adapter
    fffffa800ac57020   fffffa800ac5b1a0    Microsoft 6to4 Adapter #2
    fffffa800ac57020   fffffa800ac581a0    Microsoft 6to4 Adapter

Because we ran !ndiskd.miniport without any parameters, it prints a table of all the active miniport adapters in the system.  The first column contains the NDIS handle of the Miniport Driver (what we imaginatively call the MiniDriver), the second column contains the NDIS handle of the Miniport Adapter instance (what we call the Miniport), and the third column is the instance name.

What’s the difference between a MiniDriver and a Miniport?  Find out the answer here.  As an example, you can see that all the instances of “Microsoft ISATAP Adapter” have the same MiniDriver, but correspond to different Miniport instances.  That means that one driver (tunnel.sys, in this case) has created multiple miniport instances.

Most of the time, I would continue debugging by clicking on the Miniport instance in question (2nd column).  But it looks like we’ve already used up all our time this week.  In a future laboratory, we will discuss the !ndiskd.miniport command in more detail.  However, you don’t have to wait for us before you start exploring—get out Windbg and try the hyperlinks for yourself!  If you want a challenge, see if you can use the hyperlinks to set a breakpoint on your miniport's MiniportSendNetBufferLists handler and catch each packet before it is transmitted.