Windbg Tutorials

The debugger is always a very helpful tool for a developer. In this post I'll present windbg. This tool works both as a user-mode debugger (in order to debug user applications) and as a kernel-mode debugger (in order to debug windows drivers). It's not as fancy and heavy as the Visual Studio debugger, however it has the advantage that it's really small and extensible using debugger extension dlls. Besides, since SoftIce has been discontinued, currently windbg is the only windows kernel-mode debugger available (The Visual Studio debugger is only a user-mode debugger. Also, kd is just a non-graphical frontend to the same core functions that windbg supplies).

STEP 1: Installation

The first step for somebody interested in windows debugging is to download windgb from this link. The default installation path is "C:\program files\Debugging Tools for Windows". In order to use windbg you need to execute the file C:\program files\Debugging Tools for Windows\windbg.exe

STEP 2: Setting the symbol file path

After executing windgb, you need to set the path to the symbol files. This path points to the directories with the pdb files of your drivers. You can have different directories by seperating them with a semicolon (;). You also need to point to the corresponding pdb files of all the windows components, if you want the call stacks that you'll see to include the functions from the components that are developed by Microsoft. The problem in this case is that the windows pdb files change between service packs, hotfixes, etc. Fortunately, Microsoft has configured a symbol server, which can be used to download the needed files on-demand. This means that you just set the symbol  path to the symbol server and windbg downloads only the pdb files that it needs. As it is mentioned here, in order to do this, you need to add an entry to the windbg source path that's equal to:

SRV*DownstreamStore*http://msdl.microsoft.com/download/symbols

In the above line, http://msdl.microsoft.com/download/symbols is the symbol server (so you don't need to modify this), and DownstreamStore is the path, where you want the pdb files to be downloaded. This needs to be substituted by a local directory, e.g. c:\symbols, so the complete entry would be

SRV*c:\symbols*http://msdl.microsoft.com/download/symbols

Finally, as I said above, if you have additional pdb files for the drivers that you are developing in directories c:\drivers1, c:\drivers1\misc and d:\drivers2, the complete symbol path would be:

 SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols;c:\\drivers1;c:\\drivers1\\misc;d:\\drivers2

In order to set this line, you need to open windbg, go to "File", then click at "Symbol File Path" and paste the line in the textarea. Also, as it can be seen from the above example, the directories in the path aren't recursive, so if you have pdb files both in c:\drivers1 and c:\drivers1\misc, then you need to include both of them, since the format doesn't imply the latter.

If you want to observe the process of symbol matching, you can enable verbose symbol matching by executing the command

!sym noisy 

Afterwards, you can force windbg to reload the symbols by typing

.reload /f

and look at the output, in order to identify possible problems.

STEP 3: Setting the source file path

After setting the symbol file path, you might want to set the source file path, which points to your driver source files. This way you'll be able to do source level debugging instead of assembly-level debugging. In order to do that, you need to go to "File" and then "Source File Path".

STEP 4: Find a good command reference list

The next step is to find a good list of windbg commands. Actually, windbg supports a huge list of commands and there are many lists that you'll find in the internet. I am using the one that I found in this website. Until you get familiar with the list, it might be helpful to print it and keep it next to you while debugging. Fortunately, after playing for a while with windbg, you'll be able to remember the most common ones and learn where to find information about the rest.

STEP 5: Configuring the working environment

One important feature for debugging is the usage of breakpoints, which stop the normal flow of execution. So, if you set a breakpoint, while debugging an application, then the application will stop executing, when it hits it. This way you'll be able to debug. However, if you wanted to set a breakpoint in the windows kernel and the kernel hit the breakpoint, then the whole system would freeze, because kernel controls (among other stuff) process management, thread switching, etc. Therefore, even though it's possible to perform restricted kernel debugging (no breakpoints and some other limitations) using windbg with only one computer (by going to "File", "Kernel Debug", "Local"), the true power of kernel debugging can be seen, if you have 2 computer.

So, let's say that you have "Computer1", which is the machine that has the drivers that you want to debug, and "Computer2", which is the computer that will be running windbg. First of all, you need to connect these two computers using a serial cable or a USB cable or Firewire (IEEE 1394). After that, you need to go to Computer2, start windbg, go to "File", "Kernel Debug" and select COM or USB or 1394 from the top tab according to the connection that you have chosen. You need to fill the corresponding tabs (e.g. for COM you need to specify the baud rate, which would most probably be 115200 and the COM port, which would be COM1 or COM2). After that you press "ok" and windbg will wait, until you configure "Computer1" to go into debug mode.

The configuration for "Computer1" depends on its Operating System. So, if you are running any Windows version prior to Windows Vista, you need to open the file "C:\boot.ini" with an editor (it's a hidden system file, so you might need to configure your system to show the system files). The file might look something like this:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect

What you need to do is either add "/debug /debugport=COM1 /baudrate=115200" after the end of the last line, in order to make it equal to

"multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect /debug /debugport=COM1 /baudrate=115200"

(but you need to keep in might that this way your system will always start in debug mode) or create a second entry by modifying boot.ini to look like:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional Debug Mode" /fastdetect /debug /debugport=COM1 /baudrate=115200

(so, when you boot the system, you'll see a menu and you'll be able to select whether you want to start in debug mode or not). All the above applies for serial debugging (which is the most popular method).

On the other hand, if you are using Windows Vista (or later), you have to use bcdedit. You need to open a command prompt as an Administrator (using runas) and execute bcdedit. The format of the command is:

bcdedit /dbgsettings DebugType [debugport: Port ] [baudrate: Baud ]

So, for serial debugging (using COM1 at 115200bps) it is:

bcdedit /dbgsettings serial debugport:1 baudrate:115200

For 1394 (using channel 32) it is:

bcdedit /dbgsettings 1394 CHANNEL:32

For USB (using "debugging" as the target name) it is:

bcdedit /dbgsettings USB targetname:debugging

After that, you need to enable debugging by typing:

bcdedit /debug on

In order to disable it later, you can type:

bcdedit /debug off

If you want more information about bcdedit's debug options, you can look at the following OSR article

After that you need to restart the computer and if everything was configured correctly, you will see Computer1 stop during boot, and Computer2's windbg will print a message saying that the connection was established.

STEP 6: Becoming familiar with windbg

After that, it's time to start playing with windbg. Since there are many online tutorials that cover this part, I won't try to reinvent the wheel by writing an additional one, but I would like to provide some pointers. Keep in mind that most of the tutorials in the internet don't require a second computer, so you can just use local kernel debugging, in case you don't have a second computer.

I think that one of the best tutorial to start with (both because it is very clear to understand and because it explains some terms in more depth than others) is the one that is supplied with windbg. It is located in the directory, where you installed windbg, and it is called kernel_debugging_tutorial.doc. This file explains both fundamental and more advanced debugging techniques by examining the sample driver IoCtl, which can be found at the WDK. If you don't have the WDK, then you can use any other driver, for which you have the source code, since the concepts are similar. This tutorial needs two computers, however even if you have only one, it would be useful to go through it and look at the commands and the different methods.

A couple more introductory tutorials are the codeproject Windbg tutorial  and Mike Taulty's tutorial. Both include a list of common commands, but the second one also goes step-by-step through a debug session (windbg is used as a user-mode debugger). Another list of common windbg commads can be found here,

After that, you can proceed to some more advanced debugging concepts by looking at the debuging tutorials in codeproject and most specifically:

Debug Tutorial Part 1: Beginning Debugging Using CDB and NTSD
Debug Tutorial Part 2: The Stack
Debug Tutorial Part 3: The Heap
Debug Tutorial Part 4: Writing WINDBG Extensions
Debug Tutorial Part 5: Handle Leaks
Debug Tutorial Part 6: Navigating The Kernel Debugger
Debug Tutorial Part 7: Locks and Synchronization Objects

A very good list of tutorials, which includes most of the above ones and some additional ones can be found here. In addition, for those, who prefer watching videos than reading tutorials, Mike Taulty has a list of debugging videos here. Both these blogs provide useful debugging information.

In addition, the 2 blogs below cover more advanced debugging topics:

Another very useful source of information is windbg's help file. Its filename is debugger.chm and is installed in the same directory as windbg's executable. It is an easy-to-read file, even though it might seem overwhelming in the beginning.

Finally, for additional information, you can look at OSR's windbg list (you need to register for free) and at the microsoft.public.windbg newsgroup.