WinDbg - A To Z
WinDbg - A To Z
WinDbg - A To Z
Everything you need to know about WinDbg. And nothing you dont.
By Robert Kuster
December 2007. All rights reserved. www.windbg.info
Why WinDbg?
Because WinDbg is: used by the Microsoft Windows product team to develop Windows much more powerful than the well-known Visual Studio debugger extensible through extension DLLs its debug engine is part of the Windows OS
Up from Windows XP dgbeng.dll and dbghelp.dll are installed in C:\Windows\System32.
2
www.windbg.info
WinDbg. From A to Z! is a quick start and introduction to WinDbg. After reading it you will have a good feeling about what WinDbg is and what it can do for you.
While many parts of WinDbg. From A to Z! are based on user-mode examples, you will benefit from it even if you are doing kernel-mode development. Note that the same debugging engine is running behind the scenes, no matter if you debug user-mode or kernel-mode code. Essentially the only visible difference for kernel-mode debugging is that you will end up using another set of extension commands.
3
www.windbg.info
4
www.windbg.info
dbgeng.dll
dbghelp.dll
5
www.windbg.info
Many c) and d) functions are duplicates (same declaration) also found and exported from imagehlp.dll. While many imaghlp functions are simply forwarded to dbghelp functions, a disassembly of some functions reveals that they are obviously build from the same sources (see disassembly on next slide). While some MS Tools prefer the usage of DbgHelp.dll, some tools like Visual Studio or Dependency Walker rely on imagehlp.dll or use both libraries.
6
www.windbg.info
7
www.windbg.info
ImageHlp Dependencies
8
www.windbg.info
Included in the operating system, starting with Windows XP Accessible through interfaces:
IDebugAdvanced, IDebugControl, IDebugSystemObjects, ...
Fact 1: WinDbg is really just a shell on top of a debugging engine. Fact 2: You can write new standalone tools on top of this engine.
9
www.windbg.info
DbgEng Dependencies
10
www.windbg.info
Debug Symbols
Executables are just sequences of raw bytes Symbols help the debugger to:
map raw addresses in the executable to source-code lines analyze internal layout and data of applications
Program Database
PDB Files
The newest Microsoft debug information format COFF and CodeView are considered deprecated. PDBs are stored in a file separately from the executable PDB format is not documented There are special APIs to work with it: DbgHelp.dll and MsDiaXY.dll
11
www.windbg.info
Description
Functions and variables visible across several compilation units (source files) Additional information needed for retrieving stack-frames when compiling with FPO optimization (frame pointer omission) All functions and variables including local variables, function parameters, .. Source file and line information Additional information for functions and variables. Variables: type (int, string, ..) Functions: number and type of parameters, calling convention, return value
linker: /pdbstripped
Public Symbols for MS modules (kernel32.dll, user32.dll, ..) are always stripped.
12
www.windbg.info
Compiler options: /Z7, /Zi, /ZI Linker options: /debug, /pdb, /pdbstripped
Point of interest for Static libraries: Use /Z7 to store the debug information in the resulting .LIB file.
13
www.windbg.info
Algorithm to search PDB files: 1. Try module (EXE or DLL) folder 2. Try name and path specified in the PE file (the NB10 or RSDS debug header) 3. Try environment variables: _NT_SYMBOL_PATH and _NT_ALT_SYMBOL_PATH
14
www.windbg.info
Call Stack
Without valid symbols
002df350 ntdll!DbgBreakPoint 002df43c TestApplication+0x127eb 002df544 TestApplication+0x12862 002df550 MFC80UD!AfxDlgProc+0x3e 002df57c USER32!InternalCallWinProc+0x28 002df5f8 USER32!UserCallDlgProcCheckWow+0x102 002df648 USER32!DefDlgProcWorker+0xb2 002df668 USER32!DefDlgProcW+0x29 002df694 USER32!InternalCallWinProc+0x28 002df70c USER32!UserCallWinProcCheckWow+0x16a 002df744 USER32!CallWindowProcAorW+0xab 002df764 USER32!CallWindowProcW+0x1b 002df788 MFC80UD!CWnd::DefWindowProcW+0x32 002df7a4 MFC80UD!CWnd::Default+0x3b 002df7c8 MFC80UD!CDialog::HandleInitDialog+0xd3 002df900 MFC80UD!CWnd::OnWndMsg+0x817 002df920 MFC80UD!CWnd::WindowProc+0x30 002df99c MFC80UD!AfxCallWndProc+0xee 002df9bc MFC80UD!AfxWndProc+0xa4 002df9f8 MFC80UD!AfxWndProcBase+0x59
15
www.windbg.info
Noninvasive attach:
OpenProcess is called no break-in thread is created we dont attach to the process as a debugger all threads of the target application are frozen we can change and examine memory we cannot set breakpoints we cannot step through the application we can exit or detach the debugger without killing the target application we can attach several noninvasive debuggers to a process (+ one invasive debugger)
useful if: the target application is being debugged by Visual Studio (or any other invasive debugger), we can still attach WinDBG as a noninvasive debugger in order to get additional information the target application is completely frozen and cannot launch the break-in thread necessary for a true attach
16
www.windbg.info
Exceptions
A system mechanism that isnt language specific.
Don't use try-catch-except for condition checking in time critical parts of your application.
For every exception the system creates an exception record, searches for frame based exception handlers (catch-except) through all stack frames in reverse order, and finally continues with program execution. This can result in performance degradation due to the execution of hundreds of instructions.
17
www.windbg.info
Exception Dispatching
1) 2)
The system first attempts to notify the process's debugger, if any If the process is not being debugged, or if the associated debugger does not handle the exception (WinDbg gN == Go with Exception Not Handled), the system attempts to locate a frame-based exception handler If no frame-based handler can be found, or no frame-based handler handles the exception, the UnhandledExceptionFilter makes a second attempt to notify the process's debugger. This is known as second-chance or last-chance notification. If the process is not being debugged, or if the associated debugger does not handle the exception, the postmortem debugger specified in AeDebug will be started.
3)
4)
18
www.windbg.info
19
www.windbg.info
Postmortem settings:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
Whatever program is specified in AeDebug is run. No validation is made that the program is actually a debugger!
20
www.windbg.info
21
www.windbg.info
WinDbg Commands
Regular commands
are used to debug processes Examples: k, lm, g
Meta or Dot-Commands
usually control the behavior of the debugger Examples: .sympath, .cls, .lastevent, .detach, .if
Extension Commands
implemented as exported functions in extension DLLs are a large part of what makes WinDbg such a powerful debugger there is a set of preinstalled extension DLLs: exts.dll, ntsdexts.dll, uext.dll, wow64exts.dll, kdexts.dll, .. we can write our own extension DLLs Examples: !analyze, !address, !handle, !peb
22
www.windbg.info
Main Extensions
!exts.help !Uext.help !Ntsdexts.help !Kdexts.help !logexts.help !clr10\sos.help !wow64exts.help .. General Extensions User-Mode Extensions (non-OS specific) User-Mode Extensions (OS specific) Kernel-Mode Extensions Logger Extensions Debugging Managed Code Wow64 Debugger Extensions
23
www.windbg.info
Symbols in WinDbg
_NT_SYMBOL_PATH environment variable must be set
Example for MS symbols: _NT_SYMBOL_PATH=srv*C:\Symbols\MsSymbols*http://msdl.microsoft.com/download/symbols; With this setting WinDbg will automatically download all needed symbols for MS components (i.e. kernel32) from the MS server.
Useful Commands:
.sympath get/set path for symbol search append XY directory to the searched symbol path instructs the debugger to display information about its search for symbols load symbols for kernel32.dll load symbols for all modules reloads symbol information examine and list all symbols in kernel32 list all symbols in kernel32 which contain *LoadLibrary* display all variables in ntdll
.sympath +XY
!sym noisy ld kernel32 ld * .reload x kernel32!* dt ntdll!*
x kernel32!*LoadLibrary*
24
www.windbg.info
Sources in WinDbg
_NT_SOURCE_PATH environment variable must be set
Example: _NT_SOURCE_PATH=C:\Sources
Useful Commands:
.srcpath .srcpath+ XY get/set path for source-file search append XY directory to the searched source path
Important: Be sure to set up the symbols and sources for WinDbg correctly. This is the first and most important step where people new to WinDbg often fail. Note that without symbols for MS components (kernel32.dll, ntdll.dll,.. ) many commands in the following sections will not work. 25
www.windbg.info
Every Windows process is represented by an executive process block (EPROCESS) in kernel-mode EPROCESS points to a number of related data structures; for example, each process has one or more threads represented by executive thread blocks (ETHREAD) EPROCESS points to a process environment block (PEB) in process address space ETHREAD points to a thread environment block (TEB) in process address space 26
www.windbg.info
FACT: Many WinDbg commands (lm, !dlls, !imgreloc, !tls, !gle) rely on the data retrieved from PEB and TEB.
27
www.windbg.info
28
www.windbg.info
Command
!peb dt nt!_PEB Addr lm lmD lm vm kernel32 !lmi kernel32 !dlls
Description
displays a formatted view of the information in the process environment block (PEB) full PEB dump list loaded and unloaded modules -||- (output in Debugger Markup Language) verbose output (including image and symbol information) for kernel32 similar implementation as an extension display list of loaded modules with loader specific information (entry point, load count) same as before for kernel32 only display relocation information display the headers for kernel32 29
www.windbg.info
Size TlsIndex
0x0005a000 0x00000000
0:001> lm vm msvcrt start end module name 77ba0000 77bfa000 msvcrt (deferred) Image path: C:\WINDOWS\system32\msvcrt.dll Image name: msvcrt.dll Timestamp: Fri Mar 25 03:33:02 2005 (4243785E) CheckSum: 0006288A ImageSize: 0005A000 File version: 7.0.3790.1830 Product version: 6.1.8638.1830 ... CompanyName: Microsoft Corporation ProductName: Microsoft Windows Operating System InternalName: msvcrt.dll OriginalFilename: msvcrt.dll ProductVersion: 7.0.3790.1830 FileVersion: 7.0.3790.1830 (srv03_sp1_rtm.050324-1447) FileDescription: Windows NT CRT DLL LegalCopyright: Microsoft Corporation. All rights reserved.
30
www.windbg.info
displays a formatted view of the information in the thread environment block (TEB) full TEB dump 31
www.windbg.info
Example - Threads
0:001> !runaway 7 User Mode Time Thread Time 0:d28 0 days 1:2b0 0 days Kernel Mode Time Thread Time 0:d28 0 days 1:2b0 0 days Elapsed Time Thread Time 0:d28 0 days 1:2b0 0 days
0:00:00.015 0:00:00.000
0:00:00.093 0:00:00.000
0:04:04.156 0:03:53.328
0:000> ~* . 0 Id: dac.d28 Suspend: 1 Teb: 7efdd000 Unfrozen Start: TestApp!ILT+1415(_wWinMainCRTStartup) (0041158c) Priority: 0 Priority class: 32 Affinity: 3 1 Id: dac.2b0 Suspend: 1 Teb: 7efda000 Unfrozen Start: 00000001 Priority: 0 Priority class: 32 Affinity: 3
0:000> !gle LastErrorValue: (Win32) 0 (0) - The operation completed successfully. LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0
32
www.windbg.info
2)
Be sure to check these menus. They are often hiding interesting features.
33
www.windbg.info
34
www.windbg.info
DML allows debugger output to include directives and extra non-display information in the form of tags Debugger user interfaces parse out the extra information to provide new behaviors DML is primarily intended to address the following issues:
Linking of related information Discoverability of debugger and extension functionality Enhancing output from the debugger and extensions
35
www.windbg.info
DML in WinDbg
Note that you can click on any link If you right-click on it, you can even start the command in a new window 36
www.windbg.info
From MSDN:
Each new thread receives its own stack space, consisting of both committed and reserved memory. By default, each thread uses 1 Mb of reserved memory, and one page of committed memory. The system will commit one page block from the reserved stack memory as needed. (see MSDN CreateThread > dwStackSize > "Thread Stack Size").
37
www.windbg.info
0:000> dt ntdll!_TEB DeallocationStack 7ffdf000 +0xe0c DeallocationStack : 0x00030000 0:000> !address esp AllocBase : SubRegionBase - SubRegionSize 00030000 : 0012c000 - 00004000 Type 00020000 MEM_PRIVATE Protect 00000004 PAGE_READWRITE State 00001000 MEM_COMMIT Usage RegionUsageStack Pid.Tid e34.e78
0:000> ? 00130000 - 0012c000 Evaluate expression: 16384 = 00004000 0:000> ? 00130000 - 00030000 Evaluate expression: 1048576 = 00100000
0x004000 0x100000
Our thread has 4 pages or 16KB of committed memory. Our thread has 256 pages or 1MB of reserved memory.
38
www.windbg.info
The ESP register points to the current stack location of a thread. If a program attempts to access an address within a guard page, the system raises a STATUS_GUARD_PAGE_VIOLATION (0x80000001) exception. A guard page provides a one-shot alarm for memory page access. If a stack grows until the end of reserved memory, a STATUS_STACK_OVERFLOW is raised.
39
www.windbg.info
0:000> dt ntdll!_TEB DeallocationStack 7ffdf000 +0xe0c DeallocationStack : 0x00030000 0:000> ? 00130000 - 0012c000 Evaluate expression: 16384 = 00004000 0x004000 0x100000 Our thread has 4 pages or 16KB of committed memory. Our thread has 256 pages or 1MB of reserved memory.
0:000> ? 00130000 - 00033000 Evaluate expression: 1036288 = 000fd000 0x0fd000 Now our thread has 253 pages of committed memory. The system will throw a stack-overflow exception if another page will be requested.
40
www.windbg.info
41
www.windbg.info
Example - UniqStack
0:000> !uniqstack Processing 2 threads, please wait . Id: dac.154c Suspend: 1 Teb: 7efdd000 Unfrozen Start: TestApp!ILT+1415(_wWinMainCRTStartup) (0041158c) Priority: 0 Priority class: 32 Affinity: 3 ChildEBP RetAddr 002df44c 00411eeb ntdll!DbgBreakPoint 002df52c 783c2100 TestApp!CMyDialog::OnBnClicked_ExecuteBreakPoint+0x2b [d:\TestApp\MyDialog.cpp @ 72] 002df570 783c2842 MFC80UD!_AfxDispatchCmdMsg+0xb0 002df5d4 7839d671 MFC80UD!CCmdTarget::OnCmdMsg+0x2e2 002df610 7836142d MFC80UD!CDialog::OnCmdMsg+0x21 ... 002dffb8 0041371d TestApp!__tmainCRTStartup+0x289 [f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 589] 002dffc0 7d4e992a TestApp!wWinMainCRTStartup+0xd [f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 414] 002dfff0 00000000 kernel32!BaseProcessStart+0x28 . Id: dac.127c Suspend: 1 Teb: 7efda000 Unfrozen Start: 00000001 Priority: 0 Priority class: 32 Affinity: 3 ChildEBP RetAddr 0242f550 7d626c3f ntdll!NtQueryAttributesFile+0x12 .. 0242ff08 7d62b958 ntdll!LdrpCallInitRoutine+0x14 0242ffbc 7d674613 ntdll!LdrShutdownThread+0xd2 0242ffc4 7d665017 ntdll!RtlExitUserThread+0xa 0242fff4 00000000 ntdll!DbgUiRemoteBreakin+0x41 Total threads: 2 1 0
42
www.windbg.info
44
www.windbg.info
45
www.windbg.info
_HEAP struct
Defined in ntdll.dll: dt ntdll!_HEAP For every HeapCreate there is a unique _HEAP You can use "!heap -p -all" to get addresses for all _HEAP structs in your process
_HEAP_ENTRY struct
Defined in ntdll.dll: dt ntdll!_HEAP_ENTRY For every HeapAlloc there is a unique _HEAP_ENTRY You can use "!heap -p -all" to get addresses for all heap entries in your process
46
www.windbg.info
_DPH_HEAP_ROOT struct
Defined in ntdll.dll: dt ntdll!_DPH_HEAP_ROOT For every HeapCreate there is a unique _DPH_HEAP_ROOT You can use "!heap -p -all" to get addresses for all heap roots in your process
Usually address of a _DPH_HEAP_ROOT = value of HeapHandle + 0x1000
_DPH_HEAP_BLOCK struct
Defined in ntdll.dll: dt ntdll!_DPH_HEAP_BLOCK For every HeapAlloc there is a unique _DPH_HEAP_BLOCK You can use "!heap -p -all" to get addresses for all heap blocks in your process
47
www.windbg.info
48
www.windbg.info
Restart your application and attach WinDbg From WinDbgs command line: !heap -p -a <UserAddr>
<UserAddr> = address of our allocation (returned by HeapAlloc, new, ..) Will dump the call-stack but without source information
dds <StackTrace>
<StackTrace> = value retrieved in previous step dds will dump the call-stack with source information included
49
www.windbg.info
VirtAddr 25f0000
VirtSize) a02000
50
www.windbg.info
Restart your application and attach WinDbg From WinDbgs command line: !heap -p h <HeapHandle>
<HeapHandle> = value returned by HeapCreate You can do a !heap -stat or !heap -p to get a list of heaps for you process and their handles
dds <CreateStackTrace>
<CreateStackTrace> = value retrieved in previous step dds will dump the call-stack with source information included
51
www.windbg.info
0:000> dt ntdll!_DPH_HEAP_ROOT CreateStackTrace 3001000 +0x08c CreateStackTrace : 0x0238e328 _RTL_TRACE_BLOCK 0:000> dds 0x0238e328 0238e328 abcdaaaa 0238e32c 00000001 0238e330 00000010 0238e334 00000000 0238e338 00000000 0238e33c 00000000 0238e340 00000000 0238e344 0238e348 0238e348 7c93a874 ntdll!RtlCreateHeap+0x41 0238e34c 7c812bff kernel32!HeapCreate+0x55 0238e350 0045b841 TestApp!CMyDlg::OnBnClicked_HeapCreate+0x31 [d:\development\sources\TestApp\MyDlg.cpp @ 345] 0238e354 0040b122 TestApp!_AfxDispatchCmdMsg+0x43 [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp @ 82] 0238e358 0040b32f TestApp!CCmdTarget::OnCmdMsg+0x118 [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\cmdtarg.cpp @ 381] 0238e35c 00408838 TestApp!CDialog::OnCmdMsg+0x1b [f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\dlgcore.cpp @ 85]
52
www.windbg.info
Enable stack traces and page heap for you application Restart your application and attach WinDbg From WinDbgs command line: !heap stat h 0
Will list down handle specific allocation statistics for every AllocSize. For every AllocSize the following is listed: AllocSize, #blocks, and TotalMem. Take the AllocSize with maximum TotalMem.
!heap -p -a <UserAddr>
<UserAddr> = address of our allocation (returned by HeapAlloc, new, ..) Will dump the call-stack but without source information. Check the Who called HeapAlloc? slide for how to proceed to get a call-stack with source information included.
53
www.windbg.info
( %) (percent of total busy bytes) (99.99) 0x101 * 1MB allocated. Looks like a good candidate for a memory leak. (0.00) (0.00)
0:001> !heap -flt s 100000 _DPH_HEAP_ROOT @ 151000 Freed and decommitted blocks DPH_HEAP_BLOCK : VirtAddr VirtSize Busy allocations DPH_HEAP_BLOCK : UserAddr UserSize 024f0698 : 13831000 00100000 024f0620 : 13721000 00100000 There should be 0x101 entries with
size 100000 output here. Lets take the first one with UserAddr=0x13831000
0:001> !heap -p -a 13831000 address 13831000 found in _DPH_HEAP_ROOT @ 151000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr 24f0698: 13831000 7c91b298 ntdll!RtlAllocateHeap+0x00000e64 0045b74e TestApp!CMyDlg ::OnBnClicked_DoMemoryLeak+0x0000003e 0040b122 TestApp!_AfxDispatchCmdMsg+0x00000043 0040b32f TestApp!CCmdTarget ::OnCmdMsg+0x00000118 00408838 TestApp!CDialog ::OnCmdMsg+0x0000001b
UserSize 100000 -
VirtAddr 13830000
VirtSize) 102000
54
www.windbg.info
Description displays a list of locked critical sections for the process display all critical sections for the process Displays one or more critical sections, or the entire critical section tree.
Options: -l == display only locked sections -s == causes each CSs initialization stack to be displayed -o == causes the owners stack to be displayed -t == display critical section tree EnterCntr, WaitCnt,
!avrf -cs
55
www.windbg.info
56
www.windbg.info
57
www.windbg.info
Example dt & dv
0:000> dt TestApp!CMyDialog +0x000 __VFN_table : Ptr32 =00400000 classCObject : CRuntimeClass =00400000 classCCmdTarget : CRuntimeClass =00400000 _commandEntries : [0] AFX_OLECMDMAP_ENTRY =00400000 commandMap : AFX_OLECMDMAP =00400000 _dispatchEntries : [0] AFX_DISPMAP_ENTRY .. +0x004 m_dwRef : Int4B +0x008 m_pOuterUnknown : Ptr32 IUnknown +0x00c m_xInnerUnknown : Uint4B +0x010 m_xDispatch : CCmdTarget::XDispatch +0x014 m_bResultExpected : Int4B +0x018 m_xConnPtContainer : CCmdTarget::XConnPtContainer +0x01c m_pModuleState : Ptr32 AFX_MODULE_STATE =00400000 classCWnd : CRuntimeClass +0x020 m_hWnd : Ptr32 HWND__ .. +0x064 m_lpDialogInit : Ptr32 Void +0x068 m_pParentWnd : Ptr32 CWnd +0x06c m_hWndTop : Ptr32 HWND__ +0x070 m_pOccDialogInfo : Ptr32 _AFX_OCC_DIALOG_INFO +0x074 m_hIcon : Ptr32 HICON__ +0x078 m_nn : Int4B 0:000> dv /t /i /V prv local 002df440 @ebp-0x08 class CMyDialog * this = 0x002dfe24 prv param 002df450 @ebp+0x08 int nn = 1
58
www.windbg.info
Pseudo-Registers in WinDbg
1)
Virtual registers provided by the debugger Begin with a dollar sign ($) Automatic pseudo-registers
are set by the debugger to certain useful values examples: $ra, $peb, $teb, ..
2)
User-defined pseudo-registers
there are twenty user-defined registers: $t0, $t1, $t2, .., $t19 integer variables that can be used to store intermediate data can additionally hold type-information r? assigns a typed result to an lvalue
r? $t0 = @peb->ProcessParameter
- Assigns a typed value to $t0
- $t0s type is remembered so it can be used in further expressions
?? @$t0->CommandLine
59
www.windbg.info
Automatic Pseudo-Registers
Command $ra $ip $exentry $retreg $csp $peb $teb $tpid $tid $ptrsize $pagesize
Description
Return address currently on the stack. Useful in execution commands, i.e.: g $ra The instruction pointer x86 = EIP, Itanium = IIP, x64 = RIP Entry point of the first executable of the current process Primary return value register X86 = EAX, Itanium = ret0, x64 = rax Call stack pointer X86 = ESP, Itanium = BSP, x64 = RSP Address of the process environment block (PEB) Address of the thread environment block (TEB) of current thread Process ID (PID) Thread ID (tID) Size of a pointer Number of bytes in one page of memory
See Pseudo-Registry Syntax in WinDbgs help.
60
www.windbg.info
Expressions in WinDbg
1)
MASM expressions
evaluated by the ? command each symbol is treated as an addresses (the numerical value of a symbol is the memory address of that symbol to get its value you must dereference it with poi)
source line expressions can be used (`myfile.c:43`) the at sign for register values is optional (eax or @eax are both fine) used in almost all examples in WinDbgs help the only expression syntax used prior to WinDbg version 4.0 of Debugging Tools
2)
C++ expressions
evaluated by the ?? command symbols are understood as appropriate data types source line expressions cannot be used the at sign for register values is required (eax will not work)
MASM operations are always byte based. C++ operations follow C++ type rules (including the scaling of pointer arithmetic). In both cases numerals are treated internally as ULON64 values.
61
www.windbg.info
C++:
The numerical value of a variable is its actual value Operators can be used only with corresponding data types A symbol that does not correspond to a C++ data type will result in a syntax error Data structures are treated as actual structures and must be used accordingly. They do not have numerical values. The value of a function name or any other entry point is the memory address, treated as a function pointer Numerals: the default is always decimal
Can be overridden by a prefix: 0x (hex), 0 (=zero- octal)
62
www.windbg.info
0:000> ? nLocalVar // get address (memory location) of nLocalVar Evaluate expression: 1243184 = 0012f830 0:000> ? Evaluate 0:000> ? Evaluate dwo(nLocalVar) // get value of nLocalVar - dereference it expression: 7 = 00000007 // (dwo = double-word, poi = pointer sized data) poi(nLocalVar) expression: 7 = 00000007
63
www.windbg.info
0:000> r eax = 4, ebx = 3 0:000> ? 0*(eax = ebx) + 1*(eax > ebx) + -1*(eax < ebx) Evaluate expression: 1 = 00000001 0:000> ?? 0*(int)(@eax == @ebx) int 1 + 1*(int)(@eax > @ebx) + -1*(int)(@eax < @ebx)
0:000> r eax = 3, ebx = 4 0:000> ? 0*(eax = ebx) + 1*(eax > ebx) + -1*(eax < ebx) Evaluate expression: -1 = ffffffff 0:000> ?? 0*(int)(@eax == @ebx) int -1 + 1*(int)(@eax > @ebx) + -1*(int)(@eax < @ebx)
64
www.windbg.info
wo, by
wo = low-order word from specified address by = low-order byte from specified address
Binary operators
Operator = (or ==), != <, >, <=, >= and (or &), xor (or ^), or (or |) +, -, *, / <<, >>, >>> Description
Equal to, not equal to Less than, greater than, less than or equal to, greater or equal to Bitwise AND, bitwise XOR, bitwise OR Addition, subtraction, multiplication, division Left shift, right shift, arithmetic right shift
65
www.windbg.info
Pattern = can be an alias or string constant but not a memory pointer (i.e. you cannot use a poi (address) directly with $spat. You must save the result into an alias first). Pattern may contain a variety of wildcard specifiers.
$vvalid(Address, Length)
1 0
66
www.windbg.info
Optimizations
To avoid unnecessary symbol lookup time: MASM:
The usage of @ for registers is recommended. Otherwise they may be interpreted as symbols.
C++:
Prefix for local symbols: $!MySymbol Prefix for global symbols: <moduleName>!MySymbol
67
www.windbg.info
0:000> ?? dlg.m_nn int 0 0:000> ?? $!dlg.m_nn int 0 0:000> ?? sizeof($!dlg.m_nn) unsigned int 0xac 0:000> ?? ((MyModule!CMyDlg*) 0x12f878)->m_nn int 0
0:000> ?? ((ntdll!_TEB*) 0x7ffdf000)->ClientId struct _CLIENT_ID +0x000 UniqueProcess : 0x000017d8 // +0x004 UniqueThread : 0x00000ea8 // 0:000> ?? @$teb->ClientId struct _CLIENT_ID +0x000 UniqueProcess +0x004 UniqueThread
PID TID
0:001> r? $t0 = @$peb->ProcessParameters // Note that type information is preserved 0:001> ?? @$t0->CommandLine // for user-defined pseudo registers struct _UNICODE_STRING ""D:\Development\Sources\CrashMe\release\CrashMe.exe" " +0x000 Length : 0x6a +0x002 MaximumLength : 0x6c +0x004 Buffer : 0x00020724 ""D:\Development\Sources\CrashMe\release\CrashMe.exe" "
68
www.windbg.info
myInt expression: 1243256 = 0012f878 dwo(myInt) expression: 1 = 00000001 myInt+4 expression: 1243260 = 0012f87c dwo(myInt+4) expression: 2 = 00000002
0:000> ?? (&myInt) int * 0x0012f878 0:000> ?? myInt int [2] 0x0012f878 1 0:000> ?? (&myInt+1) int * 0x0012f87c 0:000> ?? *(&myInt+1) int 2
69
www.windbg.info
All other commands and debugging information windows use the default expression evaluator You can use the .expr command to change the default evaluator
.expr .expr /q .expr /s c++ .expr /s masm show current evaluator show available evaluators set c++ as the default expression evaluator set masm as the default expression evaluator
70
www.windbg.info
71
www.windbg.info
// // // // //
------------------------------------------------------------------source-line expressions cannot be used in C++ expressions lets nest a MASM expression within a C++ expression store address of line 43 of myFile.cpp into nLocalVar -------------------------------------------------------------------
72
www.windbg.info
Aliases in WinDbg
1)
Strings that are automatically replaced with other character strings Consist of: alias name + alias equivalent User-named aliases
Set and named by the user (both are case-sensitive) Manipulate by: as or aS (Set Alias), ad (Delete Alias), al (List Aliases)
2)
Fixed-name aliases
Set by the user, named $u0, $u1, .. $u9 Set by the r (register) command + . (dot) before the u
Example: r $.u0 = dd esp+8; g
3)
Automatic aliases
Set and named by the debugger Are similar to automatic pseudo registers, except that they can be used with alias-related tokens such as ${ .. } (pseudo-registers cannot) Examples: $ntsym, $CurrentDumpFile, $CurrentDumpPath, ...
73
www.windbg.info
User-named aliases
By default a user-named alias must be separated from other characters. The first and last character of an alias name must either:
begin/end the line or be preceded/followed by a space, semicolon, or quotation mark
If a user-named alias is touching other text, it must be enclosed in ${ } (Alias interpreter) Can be used in the definition of a fixed-name alias
To use a user-named alias in the definition of another user-named alias, you need to prefix the as or aS command with a semicolon (else no alias replacement will occur on that line). Explanation: Any text entered into a line that begins with as, aS, ad, or al will not receive alias replacement. If you need aliases replaced in a line that begins with these characters, prefix it with a semicolon.
2)
Fixed-named aliases
Are automatically replaced if they are used adjacent to other text Can be used in the definition of any alias
74
www.windbg.info
Description
Set alias Set alias to the NULL-terminated ASCII string at Address Set alias to the NULL-terminated Unicode string at Address
Delete alias with Name Delete all aliases List user-named aliases ${Alias} is replaced by the alias equivalent, even if it is touching other text. If the alias is not defined, the ${Alias} is not replaced Same as above except that ${/f:Alias} is replaced with an empty string if the alias is not defined Evaluates to the alias name Evaluates: 1 = alias defined; 0 = alias not defined
75
www.windbg.info
Example - Aliases
0:001> as Short kernel32!CreateRemoteThread 0:001> uf Short 0:001> r $.u0 = kernel32!CreateRemoteThread 0:001> uf $u0 0:001> as DoInc r eax=eax+1; r ebx=ebx+1 0:001> DoInc 0:001> DoInc
// user-named alias
//
fixed-name alias
//
0:001> as two 2 0:001> r $.u1 = 1+ two // notice the empty space before two! 0:001> as two 6 0:001> ? $u1 Evaluate expression: 3 = 00000003
// ------------------------------------------------------------------// using a named alias within another named alias // -------------------------------------------------------------------
// //
xy1 = two + 1 xy2 = 2 + 1 (you must prefix as with a semicolon for a replacement to occur)
76
www.windbg.info
Consist of
debugger commands control flow tokens (.if, .for, .while, ..)
Variables
Use user-named aliases or fixed-name aliases as local variables Use pseudo-registers ($t0, ..) for numeric or typed variables
For comments use $$ [any text] A pair of braces {} is used to surround a block of statements
When each block is entered all aliases within a block are evaluated There must be a control flow token before the opening brace To create a block solely to evaluate aliases use the .block { .. } Use ${Alias} (alias interpreter) for user-named aliases that touch other text 77
www.windbg.info
Command .block .if, .else, .elseif .for, .while, .Break, .continue .foreach
Description
Performs no action. It is used solely to introduce a block. Note that you cannot simply use {} to create a block. Like the if, else or else if keyword in C Like the for, while, break or continue keyword in C Parses the output of debugger commands, a string or a text file. It then takes each item it finds and uses it as the input to a specified list of debugger commands.
78
www.windbg.info
79
www.windbg.info
$$ Get module list LIST_ENTRY in $t0. r? $t0 = &@$peb->Ldr->InLoadOrderModuleList $$ Iterate over all modules in list. .for (r? $t1 = *(ntdll!_LDR_DATA_TABLE_ENTRY**)@$t0; (@$t1 != 0) & (@$t1 != @$t0); r? $t1 = (ntdll!_LDR_DATA_TABLE_ENTRY*)@$t1->InLoadOrderLinks.Flink) { $$ Get base address in $Base. as /x ${/v:$Base} @@c++(@$t1->DllBase) $$ Get full name into $Mod. as /msu ${/v:$Mod} @@c++(&@$t1->FullDllName) .block { .echo ${$Mod} at ${$Base} } ad ${/v:$Base} ad ${/v:$Mod} }
80
www.windbg.info
81
www.windbg.info
break on access (read or write); monitor 4 bytes break on access (write); monitor 2 bytes
82
www.windbg.info
Useful if the same method is overloaded and thus present on several addresses
83
www.windbg.info
Right at a functions entry point the value found on the top of the stack contains the return address r eip = poi(@esp) Set EIP (instruction pointer) to the value found at offset 0x0
WinMain has 4x4 byte parameters = 0x10 bytes + 4 bytes for the return address = 0x14 r esp = @esp + 0x14 Add 0x14 to ESP, effectively unwinding the stack pointer
The first parameter to LoadLibrary (at address ESP + 4) is a string pointer to the DLL name in question. The MASM $spat operator will compare this pointer to a predefined string-wildcard, this is *MYDLL* in our example. Unfortunately $spat can accept aliases or constants, but no memory pointers. This is why we store our pointer in question to an alias (MyAlias) first. Our kernel32!LoadLibraryExW breakpoint will hit only if the pattern compared by $spat matches. Otherwise the application will continue executing.
84
www.windbg.info
85
www.windbg.info
Example - Exceptions
0:000> .lastevent Last event: dac.154c: Stack overflow - code c00000fd (first chance) debugger time: Wed Aug 29 16:04:15.367 2007 (GMT+2)
0:000> .exr -1 ExceptionAddress: 00413fb7 (TestApp!_chkstk+0x00000027) ExceptionCode: c00000fd (Stack overflow) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000000 Parameter[1]: 001e2000 0:000> !analyze v FAULTING_IP: TestApp!_chkstk+27 [F:\SP\vctools\crt_bld\SELF_X86\crt\src\intel\chkstk.asm @ 99] 00413fb7 8500 test dword ptr [eax],eax ...
86
www.windbg.info
Host computer (client) Run WinDbg.exe -premote tcp:server=TargetIP_or_Name,port=1025 Select Process on Target Computer File (Menu) Attach to Process that you would like to debug
87
www.windbg.info
Description Lists all debugging servers running on the specified network server. Detach from Process End dbgsrv.exe on remote computer. This command will kill the debugged process if you dont detach first. lists all processes running on the (remote) system
88
www.windbg.info
Monitoring Events
The debugger engine provides facilities for monitoring and responding to events in the target application Events are generally divided into: Exception events
Breakpoint, Access Violation, Stack Overflow, division-by-zero, etc. For a full list see: Specific Exceptions.
Non-exception events
Create Process, Create Thread, Load Module, Unload Module. For a full list see DEBUG_FILTER_XXX.
Handling or Continue status: Determines whether an exception event should be considered handled (gH) or not-handled (gN) in the target
90
www.windbg.info
Execution:
Enabled Disabled Output Ignore - first-chance break (sxe) - second-chance break (sxd) - message output on event (sxn) - ignore event (sxi)
Continue:
Handled - Consider event handled when execution resumes
91
www.windbg.info
Event Arguments
Some filters take arguments that restrict which events they match No arguments No restriction
Event
Create Process Exit Process Load Module Target Output Unload Module
Match criteria
The name of the created process must match the argument. The name of the exited process must match the argument. The name of the loaded module must match the argument. The debug output from the target must match the argument. The base address of the unloaded module must be the same as the argument.
String wildcard syntax
92
www.windbg.info
93
www.windbg.info
The OS reads these settings and adopts its functionality accordingly GFlags can be run from the command line or by using a dialog box We can also use !gflags in WinDbg to set or display the global flags With GFlags we can enable:
heap checking heap tagging Loader snaps Debugger for an Image (automatically attached each time an Image is started) Application verifier Etc.
94
www.windbg.info
GFlags Dialog
System Registry: System-wide settings that affect all processes running on Windows. They remain effective until you change them. Restart Windows to make the changes effective. Kernel Flags: Run-time settings that affect the entire system. They take effect immediately without rebooting, but they are lost if you shut down or restart the system. Image File: They affect instances of the specified program that start after the command completes. They are saved in the registry and remain effective until you change them.
95
www.windbg.info
96
www.windbg.info
Process Dumps
97
www.windbg.info
Application Verifier:
is a runtime verification tool for Windows applications is monitoring an application's interaction with the OS profiles and tracks:
Microsoft Win32 APIs (heap, handles, locks, threads, DLL load/unload, and more) Exceptions Kernel objects Registry File system
98
www.windbg.info
Application Verifier
Can freely be downloaded and installed from the MS website Additionally installs vrfcore.dll, vfbasics.dll, vfcompat.dll, and more into Windows\System32 Enables much more test options and full functionality of the !avrf extension
99
www.windbg.info
Note the source information included in the disassembly These are the only modules from Microsoft that Ive seen delivered with full symbol information In fact, WinDbg must use these symbols rather than the public ones from the server. Otherwise the !avrf extension will not work
.reload /f @"C:\Windows\System32\verifier.pdb
100
www.windbg.info
Displays the DLL load/unload log. Displays the exception log. Displays a list of global counters (WaitForSingleObject calls, CreateEvent calls, HeapAllocation calls, ..). Displays information about threads in the target process. For child threads, the stack size and the CreateThread flags specified by the parent are displayed as well. Displays a log of all terminated* and suspended threads.
* TerminateThread API
!avrf -trm
101
www.windbg.info
Example !avrf
// Right after our application executes: // HeapAlloc( 0x00140000, 8, dwBytes =0x00A00000 ) -->> 0x033D1000; 0:000> !avrf -hp 1 Verifier package version >= 3.00 Dumping last 1 entries from tracker @ 01690fd8 with 1291 valid entries ... -------------------------------------------------------------HeapAlloc: 33D1000 A00000 0 0 004019cf: TestApp!CMyDialog::OnBnClicked_HeapAlloc+0x4F 0041a0c1: TestApp!_AfxDispatchCmdMsg+0x3D 0041a2a6: TestApp!CCmdTarget::OnCmdMsg+0x10A 0041a76c: TestApp!CDialog::OnCmdMsg+0x1B 0041d05c: TestApp!CWnd::OnCommand+0x51 0041d92b: TestApp!CWnd::OnWndMsg+0x2F 0041b2eb: TestApp!CWnd::WindowProc+0x22 0:000> !avrf -threads =================================================== Thread ID = 0xDE4 Parent thread ID = 0xE3C Start address = 0x004a7d82: TestApp!ILT+11645(?ThreadProcYGKPAXZ) Parameter = 0x0061833c =================================================== Thread ID = 0xE3C Initial thread =================================================== Number of threads displayed: 0x2
102
www.windbg.info
103
www.windbg.info
Process Dumps
A Processs dump
is quite similar to a non-invasive attach represents a snapshot of a process at a given time varies in size, depending on what contents and information it includes
With a dump
we can examine memory as well as other internal structures of a process we cannot set breakpoints or step through the program execution
Dump a dump
we can always "shrink" a dump with more information to a dump with less information use the .dump command as you would with a live process
104
www.windbg.info
Types of Dumps
1) Kernel-mode dumps
Variants: Complete Memory Dump, Kernel Memory Dump, Small Memory Dump
3) Minidumps
.dump /m?? The modern dump format Fine-grained control about what is included in the dump (see MSDN: MINIDUMP_TYPE) Despite their names, the largest minidump file actually contains more information than a full usermode dump. For example, .dump /mf or .dump /ma creates a larger and more complete file than .dump /f
105
www.windbg.info
You can load the dump in question into WinDbg. WinDbg will call a minidump a "User Mini Dump File," and the old style crash dump will be called a "User Dump File." 106
www.windbg.info
only basic information: module information (signatures), thread and stack information
107
www.windbg.info
Yes
No
Yes
Yes
Yes No No No No No
Yes No No No No No1
1: Always creates a small Minidump --MiniDumpNormal -- with basic information only. It is usually less than 20KB in size. 2: Always creates a Minidump with Full Memory information. It is usually 20-200MB in size.
108
www.windbg.info
Your Homework
Read WinDbgs documentation
Memory leaks, handles, deadlocks, breakpoints with conditions, and more. Everything is explained there.
Learn assembly
It will greatly improve your debugging skills Besides WinDbg assembly will be your best friend when it comes to debugging situations
109
www.windbg.info
Questions? Suggestions?
??
110
www.windbg.info
You have a question about WinDbg? You are interested in a WinDbg lab or seminar? You think that something in WinDbg. From A to Z! could be improved? Or you would just like to say WOW, this presentation was really useful? Feel free to drop a line at: mailrkuster@windbg.info
The actual email address does not contain the word mail spam prevention.
References
WinDbgs Documentation, MSDN Common WinDbg Commands (Thematically Grouped)
http://software.rkuster.com/windbg/printcmd.htm