WinDbg is both a kernel-mode and user-mode debugger. It is pronounced Wind-bag, Win-d-b-g, or, more descriptively, Win-Debug. For many developers and support engineers, WinDbg is the center of the advanced debugging universe. It has been available for some time and has evolved to encompass an impressive assortment of commands. Learning WinDbg requires a small commitment of time, but it can help you solve even the most complex debugging problems.
The focus of this book is C# and managed code. For this reason, this book is not the ideal place to explore the depths of WinDbg. However, knowing some basic WinDbg commands is helpful even when debugging managed applications.
When WinDbg is started, you can attach the debugger to an existing application with command-line arguments. Doing this requires the process identifier (PID) of the target application. Tlist is a utility installed with Debugging Tools for Windows. This tool lists the process identifier of active processes.
The following is sample output from the Tlist utility. Applications are listed in execution sequence. The first column is the process identifier, the second column is the program, and the final column contains the title bar information or description, if available:
C:store>tlist 0 System Process 4 System 784 smss.exe 844 csrss.exe 872 winlogon.exe 916 services.exe 928 lsass.exe 936 KHALMNPR.exe KHALHPP_MainWindow 1052 gcasDtServ.exe GIANT AntiSpyware Data Service 1444 DVDRAMSV.exe 1488 inetinfo.exe 1524 mdm.exe 1748 sqlservr.exe 1828 nvsvc32.exe NVSVCPMMWindowClass 1440 wscntfy.exe 2380 iPodService.exe 2620 alg.exe 3384 iTunes.exe iTunes 3648 WINWORD.EXE MarshallChap14_0830 - Microsoft Word 2892 cmd.exe Visual Studio 2008 Command Prompt - tlist 2572 Store.exe Store 2696 tlist.exe
Use the PID from the Tlist command to attach to a process. WinDbg uses the –p command-line option to attach an application with identifier given PID:
windbg -p 2572
You also can attach to a running process simply with the application name. If more than one instance of the process is running, an error is reported and the attach fails:
windbg -pn store.exe
You can start WinDbg and then attach to an application. From the File menu, select the Attach To A Process command. Choose the target application from the list of available and active processes. Alternatively, you can start and debug an application. The Open Executable command on the File menu starts an application and immediately attaches the debugger. This is convenient if the application is not running already.
When using WinDbg, some essential commands are helpful. Most of the WinDbg commands are not case-sensitive—check the documentation for confirmation. Table 16-2 lists the basic commands in WinDbg.
Table 16-2. Basic WinDbg commands
Command | Description |
---|---|
g(o) | If in break mode, resumes execution of a debugged application. |
Ctrl+Break | Interrupts the running application. The application changes from running to break mode. |
q(uit) | Quits the WinDbg debugger. |
? | Displays help documentation. |
Now that the basic commands have been presented, we can discuss the more interesting commands.
Displaying the active threads and changing thread context is commonly useful. In WinDbg, the tilde (~) command is for thread management.
The command without parameters lists all the threads. The thread identifier, status, and address of the thread environment block are some of the information presented for each thread. The current thread is prefixed with a dot (.). The pound sign (#) prefixes the thread that raised an exception (if any) that interrupted the attached application.
The ~n command, where n is the thread number, displays information on the specified thread instead of all the threads.
The ~ns command changes the current thread and context. The WinDbg prompt is updated to reflect the current thread. Some commands, such as the stack trace command, display information based on the current thread. After selecting a different thread, the register values of that thread are displayed.
The following demonstration lists all the threads, displays information pertaining to Thread 2, and then sets Thread 3 as the current thread:
0:001> ~ 0 Id: a1c.9c0 Suspend: 1 Teb: 7ffde000 Unfrozen . 1 Id: a1c.804 Suspend: 1 Teb: 7ffdd000 Unfrozen 2 Id: a1c.ea0 Suspend: 1 Teb: 7ffdc000 Unfrozen 3 Id: a1c.de0 Suspend: 1 Teb: 7ffdb000 Unfrozen # 4 Id: a1c.c04 Suspend: 1 Teb: 7ffda000 Unfrozen 0:001> ~2 2 Id: a1c.ea0 Suspend: 1 Teb: 7ffdc000 Unfrozen Start: mscorwks!Thread::intermediateThreadProc (79ee80cf) Priority: 2 Priority class: 32 0:001> ~3s eax=4ec62ef0 ebx=0103fe7c ecx=0000d9c7 edx=7c90eb94 esi=00000000 edi=7ffdf000 eip=7c90eb94 esp=0103fe54 ebp=0103fef0 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 7c90eb94 c3 ret
The stack trace commands present views of the native call stack, which is invaluable when debugging. Even with managed code, viewing the unmanaged call stack can be informative. In WinDbg, variations of the k command display the call stack with different information or a different level of detail. A stack trace listing can be quite long. To minimize this problem, you can follow a stack trace command with a number, which limits the depth of the call stack.
Table 16-3 details the common stack trace commands.
Table 16-3. Stack trace commands
Command | Description |
---|---|
k | Lists the methods on the call stack. In addition, the pointer to the child frame and function return address of the calling method is listed. No parameters are displayed. |
kb | Lists the call stack with the first three arguments of each method. |
kP | Lists the call stack and all the parameters of each method. This command is case-sensitive. |
kn | Lists the call stack and the frame number for each method. You can use the frame information to move between frames on the call stack using the .frame directive. This is sometimes useful for such actions as viewing local variables that would be out of scope otherwise. |
The following command lists the call stack from a thread in the Store application. The kb command lists the first three arguments of each method:
0:003> kb ChildEBP RetAddr Args to Child 0103fe50 7c90e9ab 7c8094f2 00000002 0103fe7c ntdll!KiFastSystemCallRet 0103fe54 7c8094f2 00000002 0103fe7c 00000001 ntdll!ZwWaitForMultipleObjects+0xc 0103fef0 77d495f9 00000002 0103ff18 00000000 KERNEL32!WaitForMultipleObjectsEx+0x12c 0103ff4c 77d496a8 00000001 0103ffac ffffffff USER32!RealMsgWaitForMultipleObjectsEx+0x13e 0103ff68 4ec95846 00000001 0103ffac 00000000 USER32!MsgWaitForMultipleObjects+0x1f 0103ffb4 7c80b50b 00000000 00000000 0012e0d0 gdiplus!BackgroundThreadProc+0x59 0103ffec 00000000 4ec957ed 00000000 00000000 KERNEL32!BaseThreadStart+0x37
What if you want the stack trace of every thread? Each thread could be selected individually and then the k command issued for each one. However, that approach becomes tedious if there are more than a few threads. The solution is to use "~*". Commands prefixed with "~*" are applied to all threads of the application. This command lists the call stack for every thread:
~* k
Displaying raw memory is often useful when debugging. The d command is the basic display memory command. There are variants on the d command that format memory differently. Memory commands display rows and columns of data. Rows begin with a memory address. This is the starting address for the contiguous memory displayed on that row. The memory is organized in row order. By default, bytes are shown in two-byte columns. As an option, the final column is the text translation of the current row.
This is a typical display of memory:
0:003> d 0103fe50 0103fe50 cc 33 66 00 ab e9 90 7c-f2 94 80 7c 02 00 00 00 .3f....|...|.... 0103fe60 7c fe 03 01 01 00 00 00-00 00 00 00 00 00 00 00 |............... 0103fe70 00 00 00 00 02 00 00 00-00 00 00 00 94 06 00 00 ................ 0103fe80 8c 06 00 00 cc 99 99 00-cc 99 cc 00 cc 99 ff 00 ................ 0103fe90 cc cc 00 00 cc cc 33 00-cc cc 66 00 14 00 00 00 ......3...f..... 0103fea0 01 00 00 00 00 00 00 00-00 00 00 00 10 00 00 00 ................ 0103feb0 cc ff 66 00 cc ff 99 00-cc ff cc 00 00 b0 fd 7f ..f............. 0103fec0 00 c0 fd 7f ff 00 33 00-00 00 00 00 7c fe 03 01 ......3.....|...
Here is the general syntax of the display memory commands:
dL address1 address2
The second letter (L) of the display memory command indicates the specific command, such as dc, dd, and du, which is case-sensitive. The address1 parameter is the beginning address and address2 is the ending address. Memory is displayed from address1 to address2. Omit the ending address, and a default number of bytes are displayed. The default is set from the previous command. If neither the beginning nor the ending memory address is provided, memory is displayed from the current address.
Table 16-4 lists some of the commands that display memory.
Table 16-4. Common display memory commands
Command | Description |
---|---|
d | Repeats the previous display command. It defaults to the db command. |
da | Displays memory with ASCII text translation. |
db | Displays memory within a stated range. |
dc | Displays memory in four-byte columns. |
dd | Same as dc, but with no text translation. |
du | Displays memory with Unicode text translation. |
The following command displays memory in three columns of four-byte data. The /c option sets the number of columns:
0:003> dd /c 3 0103fe50 0103fe50 006633cc 7c90e9ab 7c8094f2 0103fe5c 00000002 0103fe7c 00000001 0103fe68 00000000 00000000 00000000 0103fe74 00000002 00000000 00000694 0103fe80 0000068c 009999cc 00cc99cc 0103fe8c 00ff99cc 0000cccc 0033cccc 0103fe98 0066cccc 00000014 00000001 0103fea4 00000000 00000000 00000010 0103feb0 0066ffcc 0099ffcc 00ccffcc 0103febc 7ffdb000 7ffdc000 003300ff 0103fec8 00000000 0103fe7c
In WinDbg, you can set a variety of breakpoints, such as memory address, source location, data, and event. The breakpoint commands are detailed in Table 16-5.
Table 16-5. Breakpoint commands
The following is a demonstration of the breakpoint command (bp). The sxe command is the set exception command. This command requests that the debugger interrupt on an exception or other event, which is similar to a breakpoint. In this example, the sxe command instructs the debugger to interrupt when the mscorwks module is loaded, which is where the CLR is found. For a compound statement in WinDbg, use a semicolon. In the following command, the sxe and g commands are combined into a compound statement.
The following command asks the debugger to break on a mscorwks module load event (the application then resumes):
0:000> sxe ld mscorwks;g
ModLoad: 77dd0000 77e6b000 C:WINDOWSsystem32ADVAPI32.dll
ModLoad: 77e70000 77f01000 C:WINDOWSsystem32RPCRT4.dll
ModLoad: 77f60000 77fd6000 C:WINDOWSsystem32SHLWAPI.dll
ModLoad: 77f10000 77f56000 C:WINDOWSsystem32GDI32.dll
ModLoad: 77d40000 77dd0000 C:WINDOWSsystem32USER32.dll
ModLoad: 77c10000 77c68000 C:WINDOWSsystem32msvcrt.dll
ModLoad: 76390000 763ad000 C:WINDOWSsystem32IMM32.DLL
ModLoad: 629c0000 629c9000 C:WINDOWSsystem32LPK.DLL
ModLoad: 74d90000 74dfb000 C:WINDOWSsystem32USP10.dll
ModLoad: 79e70000 7a3cf000 C:WINDOWSMicrosoft.NETFrameworkv2.0.50727mscorwks.dll
eax=00000000 ebx=00000000 ecx=009f0000 edx=7c90eb94 esi=00000000 edi=00000000
eip=7c90eb94 esp=0012f1c0 ebp=0012f2b4 iopl=0 nv up ei ng nz ac po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000296
ntdll!KiFastSystemCallRet:
7c90eb94 c3 ret
The following compound command sets a breakpoint on the ExecuteMainMethod method and then continues execution. You must have properly configured symbols for this command to work. (See the section "Symbols," later in this chapter, for more information.)
0:000> bp mscorwks!SystemDomain::ExecuteMainMethod;g
ModLoad: 78130000 781ca000 C:WINDOWSMicrosoft.NETFrameworkv2.0.50727MSVCR80.dll
ModLoad: 7c9c0000 7d1d4000 C:WINDOWSsystem32shell32.dll
ModLoad: 773d0000 774d2000 C:WINDOWSWinSxSx86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9comctl32.dll
ModLoad: 5d090000 5d127000 C:WINDOWSsystem32comctl32.dll
ModLoad: 60340000 60348000 C:WINDOWSMicrosoft.NETFrameworkv2.0.50727culture.dll
ModLoad: 790c0000 79baa000 C:WINDOWSassemblyNativeImages_v2.0.50727_32mscorlibcee6ddb471db1c489d9b4c39549861b5mscorlib.ni.dll
Breakpoint 0 hit
eax=0012ff38 ebx=00000002 ecx=00000000 edx=ffffffff esi=00000000 edi=00000000
eip=79efb428 esp=0012ff1c ebp=0012ff68 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
mscorwks!SystemDomain::ExecuteMainMethod:
79efb428 55 push ebp
After the breakpoint is hit, the kb command performs a stack trace, as shown here. You see ExecuteMainMethod is at the top of the call stack:
0:000> kb
ChildEBP RetAddr Args to Child
0012ff18 79efb3cb 00400000 00000000 b4ebfe93 mscorwks!SystemDomain::ExecuteMainMethod
0012ff68 79ef8bc8 00400000 b4ebfe4b 00080000 mscorwks!ExecuteEXE+0x59
0012ffb0 790122f6 00d9fa9c 79e70000 0012fff0 mscorwks!_CorExeMain+0x11b
0012ffc0 7c816d4f 00080000 00d9fa9c 7ffd8000 mscoree!_CorExeMain+0x2c
0012fff0 00000000 790122c2 00000000 78746341 KERNEL32!BaseProcessStart+0x23
After reaching a breakpoint, you can step through the application and watch variables, evaluate memory, inspect register values, or view the call stack. The WinDbg toolbar is the most convenient way to step through an application. If it is not visible, open the View menu and choose the Toolbar command to display the toolbar.
Figure 16-2 shows the Step buttons on the Debugging toolbar: from left to right, these are the Step In, Step Over, Step Out, and Run To Cursor buttons.
Standard commands in WinDbg affect or control the application being debugged. Commands such as kb (call stack), ~ (list threads), and da (display memory—ASCII) are standard commands and apply to the application being debugged. Conversely, WinDbg directives affect the debugger and not the debuggee. For example, the .load directive loads a debugging extension dynamic-link library (DLL). The .logopen directive opens a log file and records future commands and results to that log file.
There are several WinDbg directives. Table 16-6 lists some of the more common ones. Directives are prefixed with a dot (.).
Table 16-6. WinDbg directives
Command | Description |
---|---|
.load dllname | Loads a debugger extension DLL. Extension commands are exposed as exported functions from the DLL. Developers of managed code routinely load the SOS (SOS.dll) debugger extension. Commands from debugger extensions are prefixed with an exclamation point (!). |
.unload dllname | Unloads a debugger extension. |
.chain | Lists the debugger extensions that are presently loaded and available. |
.reload | Reloads symbols and usually is requested after the symbol path has been updated. Typically, symbols are retrieved as needed by the debugger. The /f option forces the immediate load of all symbols for a specific module or all modules. |
.logopen filename | Opens a log file. Future commands and results are written into the log file. |
.logclose | Closes the log file. |
.kill | Terminates the current debuggee and ends the debugging session. |
.frame n | Changes the current stack frame. Some information, such as local variables and register values, are affected by changing the current stack frame. |
.srcpath | Sets or displays the source code path. |
.dump options filename | Creates a dump, which is used for postmortem analysis. For managed dumps, this is the appropriate command. The following options—"m" and "a" are separate options—create a dump appropriate for SOS:
|
3.144.228.78