WinDbg

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.

Basic WinDbg Commands

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

Stack Trace Commands

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

Display Memory Commands

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

Breakpoint Memory Commands

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

Command

Description

bp

This is the basic breakpoint command, where the program is interrupted when execution reaches the specified location.

Here is the syntax for the bp command:

bp location options

There are several options. For example, the /1 option is useful for defining one-time breakpoints. This type of breakpoint is removed automatically after being hit. This is similar to the Run To Cursor command in Visual Studio.

ba

This command breaks on access to a memory address.

Here is the basic syntax for the ba command:

ba options size address

Options include which action to break on:

  • e – execute

  • r – read/write

  • w – write

  • i – input/output

The size element gives the width of the memory address.

bc

This command clears a breakpoint. You can clear multiple breakpoints in a space-delimited or comma-delimited list. Alternatively, specify a range with a hyphen.

bl

This command lists the set breakpoints.

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

Step Commands

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.

Step buttons on the WinDbg toolbar

Figure 16-2. Step buttons on the WinDbg toolbar

WinDbg Directives

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:

  • .dump /ma filename.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.228.78