4.4.2 Creating Custom Extensions

You can create your own debugging commands by writing an extension DLL. You might want to write a command, for example, to dump a complex data structure.

To run a command called foo, which is an exported function from mydll.dll, enter the following at the WinDbg command prompt:

!mydll.foo [args]
 

WinDbg will load mydll.dll, call the entry point foo, and pass args to foo. Once WinDbg has loaded mydll.dll, you can run an extension command contained in it by using just the command's name:

!foo [args]
 

You can explicitly load an extension DLL with either of the following commands:

!mydll.foo
!load mydll.dll
 

There can be as many as 32 extension DLLs loaded, including the default extension DLL.

When you run !foo, WinDbg looks for foo in the current extension DLL, which is the last one loaded or the one that you specify with

!default mydll
 

If it does not find foo in the current extension DLL, WinDbg searches through the loaded extension DLLs, in the order that they were loaded, and runs the first instance of foo that it finds.

You can unload the current extension DLL with the following command:

!unload
 

The DDK provides source code for a few simple debugger extension samples in the src\krnldbg\kdexts directory of the DDK tree.

The following are requirements for a user-defined DLL:

  1. Extension command names must be lowercase.

  2. You must export a function named WinDbgExtensionDllInit (refer to the source for dbgexts.c, below). When WinDbg loads an extension DLL, it first calls WinDbgExtensionDllInit and passes it the following arguments:

    Pointer to an extension API structure

    This structure contains the callbacks to functions that you can use to do standard operations. For example, to print a string you can use dprintf(“string”). Include the header file wdbgexts.h in your extension source and use the #define function definitions from that file. The file wdbgexts.h also defines the parameters to the functions.

    Save the pointer in a global variable named ExtensionApis.

    Major version

    This indicates whether the target system is running a checked build of Windows NT (0x0c) or a free build (0x0f).

    Minor version

    This is the Windows NT build number of the target system (for example, 1381).

  3. You must export a function called ExtensionApiVersion. WinDbg calls this function and expects back a pointer to API_VERSION. The version number of your extension DLL must match the version number of WinDbg. If the numbers don't match, WinDbg will not load the extension DLL.

  4. You can optionally export a function called CheckVersion. WinDbg calls this function every time you use your DLL. Use it to verify that the version of your DLL matches the target system. To disable version checking, issue the !noversion command at the WinDbg prompt.

  5. Use the DECLARE_API macro defined in wdbgexts.h to declare your command functions. The basic format is:

    DECLARE_API(foo)
    {
    code for foo
    }

 

WinDbg does a try/except around a call to an extension DLL. Even though they won't crash WinDbg, bugs in your code can still cause it not to work properly, and you will have to quit and restart WinDbg.