Search notes:

windbg.exe

Windows GUI symbolic debugger
windbg.exe is the GUI version of CDB/NTSD and KD/NTKD.
The debugger can be started anywhere by entering the command WinDbgX.

Commands

.sympath srv*
.reload
x notepad!*

Loading symbols

Listing modules lm shows that most modules don't yet have the symbols:
0:000> lm
00007ff9`232b0000 00007ff9`233b0000   ucrtbase   (deferred)             
00007ff9`233b0000 00007ff9`233d2000   win32u     (deferred)             
00007ff9`233e0000 00007ff9`2347d000   msvcp_win   (deferred)             
00007ff9`23770000 00007ff9`23a39000   KERNELBASE   (deferred)             
00007ff9`23ac0000 00007ff9`23bcb000   gdi32full   (deferred)             
00007ff9`23bd0000 00007ff9`23c8d000   KERNEL32   (deferred)             
00007ff9`242b0000 00007ff9`24450000   USER32     (deferred)             
00007ff9`25a40000 00007ff9`25a6a000   GDI32      (pdb symbols)          C:\ProgramData\Dbg\sym\gdi32.pdb\26374D0C904F7078CBA564E8FCA58EE71\gdi32.pdb
00007ff9`25b70000 00007ff9`25d66000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\ntdll.pdb\432F2B8588C52E47219EE25E35F653491\ntdll.pdb
So, let's refresh at least USER32 and KERNEL32:
0:000> ld USER32
Symbols loaded for USER32
0:000> ld KERNEL32
Symbols loaded for KERNEL32
Executing lm again now shows that USER32 and KERNEL32 have their symbols updated:
O:OOO> lm
00007ff9`232b0000 00007ff9`233b0000   ucrtbase   (deferred)             
00007ff9`233b0000 00007ff9`233d2000   win32u     (deferred)             
00007ff9`233e0000 00007ff9`2347d000   msvcp_win   (deferred)             
00007ff9`23770000 00007ff9`23a39000   KERNELBASE   (deferred)             
00007ff9`23ac0000 00007ff9`23bcb000   gdi32full   (deferred)             
00007ff9`23bd0000 00007ff9`23c8d000   KERNEL32   (pdb symbols)          C:\ProgramData\Dbg\sym\kernel32.pdb\789BD698F50E4D3F96DDF36A5D4BAD6E1\kernel32.pdb
00007ff9`242b0000 00007ff9`24450000   USER32     (pdb symbols)          C:\ProgramData\Dbg\sym\user32.pdb\EF56DB6F9CC97AD4E21FDF7B2A0A0FEA1\user32.pdb
00007ff9`25a40000 00007ff9`25a6a000   GDI32      (pdb symbols)          C:\ProgramData\Dbg\sym\gdi32.pdb\26374D0C904F7078CBA564E8FCA58EE71\gdi32.pdb
00007ff9`25b70000 00007ff9`25d66000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\ntdll.pdb\432F2B8588C52E47219EE25E35F653491\ntdll.pdb

Expressions

When a command expects a value, the value can be specified using an expression. The expression can contain names of registers and addressed in the module!function+byte format:
bp EIP+1
u ntdll!CsrSetPriorityClass+0x41
dd ebp+4

Numerical expressions

By default, numerical are interpreted as hexadecimally formatted. In order to specify, the numbers can be prefixed with 0x (explicitly hexadecimal), 0n (base 10), 0t (octal) 0y (binary).
The default base can be changed with n.
The .formats command displays a number in various formats:
0:000> .formats 0n4096
Evaluate expression:
  Hex:     00000000`00001000
  Decimal: 4096
  Octal:   0000000000000000010000
  Binary:  00000000 00000000 00000000 00000000 00000000 00000000 00010000 00000000
  Chars:   ........
  Time:    Thu Jan  1 02:08:16 1970
  Float:   low 5.73972e-042 high 0
  Double:  2.02369e-320
«Mathematical» expressions are calculated using the question mark:
0:000> ? FF+1
Evaluate expression: 256 = 00000000`00000100
The double-questionmark (??) allows to evaluate a C++ expression.
.expr specifies the default expression evaluator:
.expr /s masm 
.expr /s c++ 
.expr /q displays the list of possible expression types.

?

The question mark evaluates a MASM expression.
An interesting feature are source line expressions: prog.c:42.

??

When evaluating C++ expressions, register names need to be prefixed with an @
The default base for numerals is 10.

Display data

dv displays local variables. dv /i classifies them into categories, dv /V shows addresses and offsets for the relevant base frame register, dv /t shows type information.
dd rdx L1, dd rdx L2, …

poi

poi(addr) dereferences an address (pointer).
For example, if the rdx register stores a pointer to char* (as for example for the argv parameter in main), the value of this string (argv[0]) can be displayed with da poi(rdx).
In C++ expression evaluation, this expression would be equivalent to ?? *(char**) @rdx.
The value of the argv[1] is displayed with da poi(rdx+8), the value of argv[2] with da poi(rdx+10) etc.

Breakpoints

Breakpoints can be set with bu, bp and bm.
bp converts the given expression into an address and are not saved in the workspace.
bu stays asssociated with the symbolic value.
A breakpoint can be set on the entry point for an executable with code bp $exentry or bp @$exentry (which at least for console applications seems to be something like conhost!wWinMainCRTStartup)
Another interesting breakpoint seems to be conhost!wWinMain
Breakpoints that have been set are shown with bl:
0:000> bu prog_64!main
0:000> bl
     0 e Disable Clear  00007ff9`25c40670     0001 (0001)  0:**** ntdll!LdrpDoDebuggerBreak+0x30
     1 e Disable Clear  00007ff6`34b47280     0001 (0001)  0:**** prog_64!main
The breakpoint at ntdll!LdrpDoDebuggerBreak+0x30 seems to be set by default.
A breakpoint can be disabled with bd and cleared with bc:
bd 1
bc 1

Scriptproviders

0:000> .scriptproviders
Available Script Providers:
    NatVis (extension '.NatVis')
    JavaScript (extension '.js')

NatVis

There are three default NatVis extensions:
dx @$cursession
dx @$curthread
dx @$cursession

dx @$curthread.Registers
dx @$curthread.Registers.User

Others

.exepath sets or displays the executable file search path.
p executes a single instruction or a source line», pt goes to next ret, gu (go up) finished the current function
d… displays memory, dd… displays referenced memory
kv displays stack backtrace.
dt nt!_KPROCESS and dt nt!_EPROCESS
dt ntdll!*IMAGE_*, dt ntdll!_IMAGE_NT_HEADERS64 etc

Simple debugging session

Show specific symbols in a module

Show symbols in the notepad module that contain main:
0:000> x notepad!*main*
00007ff6`3d17ac68 notepad!__mainCRTStartup (void)
00007ff6`3d17b8e3 notepad!__mainCRTStartup$filt$0 (void)
00007ff6`3d17cf68 notepad!_imp___getmainargs = <no type information>
00007ff6`3d164238 notepad!WinMain (<no parameter info>)
00007ff6`3d17ac50 notepad!WinMainCRTStartup (<no parameter info>)

Put a breakpoint on WinMain

bu notepad!WinMain

Show breakpoints

bl

run debuggee

g

Show loaded modules

lm

View stack trace

k

Run again

g

Break into running applcation

Menu Debug -> Break or keyboard shortcut ctrl+break.

Set another breakpoint

bu ntdll!ZwWriteFile

Start running again

g

Wait for breakpoint

Go to notepad and save the document. The breakpoint will be hit.

Quit debugging and detach from application

qd

Symbol related

Set or append to the symbol file path
symset  p:\ath\to\a\dir
symset+ p:\ath\to\another\dir
Set the symbol path to the Microsoft symbol store.
.symfix
The following command turns on symbol loading diagnostics to trouble shoot symbol file related issues
!sym noisy

Thread related

Show all threads in process

~

Look at stack trace of another thread

~0s
k

Some keyboard shortcuts

ctrl+e opens an executable for debugging.

Attaching to a running process

In order to attach WinDbg to a running process, it process id (which uniquely identifies a process) must be known.
In an already running WinDbg application, the Keyboard shortcut <F6> or the menu File -> Attach to a process can be used to attach to a process.
On the command line, a new WinDbg instance can be started like so
windbg -p  <pid>
windbg -pn <pid>

WinDbg Preview

WinDbg Preview uses the same debugging engine (dbgeng.dll) as Windbg. However, it comes with more modern visuals, a scripting environment and a few more improvements.
The Preview can be downloaded from https://aka.ms/WinDbgPreview

See also

WinDbgX.exe seems to be WinDbg Preview.
Debugging Windows applications

Index