一、基础命令
说明 | 命令 | 用法 | 描述 |
帮助 | ? | ? ? 表达式 | 显示常规命令 计算表达式的值 |
.help | .help | 显示元命令(以 . 开头的命令) | |
.hh | .hh .hh bp | 打开windbg help文档 打开windbg help文档,并自动输入bp命令进行搜索 | |
版本 | version | 显示调试器和调试目标版本 | |
vercommand | 显示调试器启动时的命令行 | ||
vertarget | 显示调试目标系统信息 | ||
清空屏幕 | .cls | ||
查看异常信息 | .ecxr | 显示异常信息的上下文 | |
.lastevent | 显示最近一次发生的异常信息或事件 | ||
.exr -1 | 显示最近一次的异常记录 | ||
!analyze | !analyze -v !analyze -hang !analyze -f | 显示当前异常信息 分析线程栈,看是否有线程blocking其他线程 | |
寄存器 | r | 显示各寄存器的值 | |
时间 | .time | 显示system/process/kernel/user time | |
32位和64位切换 | !wow64exts.sw | 查看64位机器上生成的32位程序的dmp时,需要使用此命令转换一下模式 !wow64exts.help 可查看相关帮助信息 |
二、调试命令
命令 | 说明 | 示例 |
g | 继续执行 | |
gu | 执行到当前函数返回 step out | |
p | 单步调试 step over | |
t | step into | |
q | 结束调试会话/退出 | |
.restart | 重新启动调试目标 | |
.detch | 分离调试目标 | |
.attach | 附加到存在的进程,参数为16进制的PID | |
.create | 创建一个新的进程进行调试 | 例如调试cmd.exe .create cmd |
.dbgdbg | 启动另一个调试器来调试当前调试器 | |
.opendump | 打开dmp文件 | .opendump d:\dump\xxx.dmp |
三、模块信息
命令 | 说明 |
lm | 显示加载的模块信息,exe和dll等 |
lmvm 模块名 | 查看指定模块详细信息 |
四、调试符号
命令 | 说明 | 示例 |
ld | 加载模块的调试符号 | ld * |
ln | 搜索相邻符号(距离指定地址最近的符号) | ln 747ba8ee |
x | 显示匹配参数类型的符号 | x xxx.dll!yy*(显示xxx.dll中所有以yy开头的符号) |
.sympath | 设置符号文件路径 | .sympath h:\dump |
.symfix | 设置系统符号存放位置 | .symfix d:\pdb_path |
.reload | 重新加载某个模块 | .reload kernel32 |
五、线程
命令 | 说明 | 示例 |
~ | 显示所有线程信息 | |
~* [Command] ~. [Command] ~#[Command] | 为所有线程执行指定命令 为当前线程执行指定命令 为导致当前异常或调试事件的线程执行指定命令 | 查看所有线程的栈信息 ~* k |
~Number ~Number s | 显示序号为Number的线程 切换当前线程为序号Number的线程 | 显示3号线程: ~3 切换到3号线程: ~3 s |
~~[TID] | 线程ID为TID的线程 | |
~ Number n ~ Number m | SuspendThread 增加线程的挂起计数 ResumeThread 减少线程的挂起计数 | ~ 3 n ~3 m |
~ Number f ~ Number u | Freeze thread 冻结线程 Unfreeze thread 解冻线程 控制被调试的线程的冻结状态, 与上面两个命令类似(处于冻结状态时恢复目标执行时这个线程不会恢复执行,这个状态是调试器维护的一个状态,执行~ 线程号 n 增加挂起计数后,执行g运行时该线程也不会运行) | |
~ Number s | 在恢复执行命令g前加线程限定符,可以只恢复指定的线程执行(只对该线程调用ResumeThread使其恢复执行,其他线程仍处于挂起状态) | |
!runaway | 显示每个线程运行时间,可以方便找到消耗cpu时间长的线程 | |
.ttime | 显示线程时间(用户+内核模式) | |
!gle !gle all | 显示当前线程的上次错误值GetLastError 显示所有线程的上一个错误值 | |
!error | 解码并显示有关错误值的信息。指定以下错误代码之一: Win32 Winsock NTSTATUS NetAPI |
六、栈
命令 | 说明 |
k | 显示EBP,返回地址和源文件信息(如果有私有符号的话) |
kb | 显示EBP,返回地址,函数参数及源文件信息(如果有私有符号的话) |
k L | L选项表示不显示源文件信息,也可以用于其他命令比如 kb L, kv L或写为 kL,kbL,kvL |
kv | 在kb的基础上增加显示FPO(栈指针省略)信息和调用协议(调用协议仅支持On x86-based processors) |
kp kP | 根据私有符号文件中的函数原型信息自动显示参数信息 P为大写,表示每个参数占一行 |
kn | 在k命令的基础上,每行前显示栈帧的序号 |
kn f | f选项表示显示每两个相邻栈帧的内存距离,即栈帧基地址的差值 |
七、查看/修改/搜索内存数据
说明 | 命令 | 描述 | 示例 |
查看内存数据 命令格式: d{a|b|c|d|D|f|p|q|u|w|W} [Options] [Range] dy{b|d} [Options] [Range] d [Options] [Range] | da | ASCII字符 | Range指定要显示的内存范围,有如下几种表示方法: 起始地址+终止地址: 比如:dd 0012fd9c 0012fda8 起始地址+L/l+元素个数 比如:dd 0012fd9c L4 或 dd 0012fd9c l4 终止地址+L/l+负号+元素个数 比如:dd 0012fda8 L-4 或 dd 0012fda8 l-4 |
du | Unicode字符 | ||
dc | DWORD和ASCII码 | ||
dd | DWORD | ||
dD | 双精度浮点数 | ||
df | 单精度浮点数 | ||
dp | 指针 | ||
dq | 四字/8字节 | ||
dw | 一个字/2字节 | ||
查看局部变量 dv [Flags] [Pattern] | dv | 查看局部变量 | |
dv /i | 查看局部变量, 并显示符号的类型和参数类型. | ||
dv /t | 查看局部变量, 并显示每个局部变量的数据类型 | ||
dv /V | 查看局部变量, 并显示变量的存储位置 | ||
dv /V VariableName | 查看指定名称的变量 | ||
查看复合类型变量 | dt | Display Type的缩写. 当变量的类型为复合类型, 比如说结构体或者类, 那么dv命令只会显示变量的地址. dt命令可以将一块内存按照某个数据类型来解析, 其中的数据类型需要作为参数被传递给dt命令。 -b:递归显示所有子类型 -r :指定显示深度,-r0表示不显示子类型 -y:附加搜索选项,只显示某个匹配的字段 | |
编辑内存数据 | 按字符串方式编辑 命令格式:e{a|u|za|zu} Address "String" | 其中a和u分别代表不是以0结尾的ASCII和Unicode字符串,za和zu分别代表以0结尾的ASCII和Unicode字符串 | |
按数值方式编辑 命令格式:e{b|d|D|f|p|q|w} Address [Values] | Values指定新的值,如果命令中没有指定该值,则Windbg会以交互式方式让用户输入 | ||
搜索内存数据 | 指定范围搜索任何ANSII或UNICODE字符串 命令格式:s -[[Flags]] sa|su Range | [Flags]用来指定搜索选项: L/l+整数 指定字符串的最小长度 s 将搜索结果保存起来 r 在保存的结果中搜索 Range指定内存范围,写法与d命令的Range参数一样 | |
指定内存地址范围内搜索与指定对象相同类型的对象 命令格式:s -[[Flags]]v Range Object | 对象:指定对象的地址或指向对象的指针的地址 | ||
指定范围内搜索某一内容模式 命令格式:s -[[[Flags]Type]] Range Pattern | Type指定要搜索内容的数据类型,即决定匹配搜索内容的方式。取值可以为:b(字节),w(字),d(双字),q(四字),a(ASCII字符串),u(Unicode字符串)。如果不指定,默认为b。 Pattern指定要搜索的内容 | ||
在当前进程的所有模块中进行搜索 !for_each_module s-a @#Base @#End "xxx" | 在每个模块中搜索字符串" xxx" 其中@#Base和@#End是!for_each_module定义的别名,其他的还有:@#ModuleName(模块名称),@#SymbolFileName(符号文件名称),@#Size(模块大小),@#SymbolType(符号文件类型) |
八、设置断点
命令 | 说明 | 示例 |
bp | 设置断点 命令格式: bp[ID号] [Options] [Address [第几次命中断点时中断到调试器]] ["一组命令,用分号隔开"] Options选项可用的值: /1 断点被命中一次后自动删除,即一次命中断点 /p 只用于内核调试中,/p后跟一个EPROCESS结构的地址,即对指定的进程设置断点 /t 只用于内核调试中,/t后跟一个ETHREAD结构的地址,即对指定的线程设置断点 /c 和 /C 指定中断给用户的最大函数调用深度和最小函数调用深度 Address表达方式: 使用模块名加函数符号 直接使用内存地址 如果使用完全的调试符号,调试符号中包含源代码行信息,可以用: bp`模块名!XXX.cpp:行号` , 其中`为重音符号 对于C++的类方法,可以使用类名双冒号(::)或双下划线(__)来连接类名和方法名: bp MyClass::MyMethod 或 bp MyClass__MyMethod 或 bp @@(MyClass::MyMethod) | |
bu | 用于对尚未被加载模块中的代码设置断点 命令格式: bu[ID号] [Options] [Address [第几次命中断点时中断到调试器]] ["一组命令,用分号隔开"] | 对于调试动态加载模块的入口函数和初始化代码比较有用,比如对于即插即用设备的驱动程序 |
bm | 用于设置一批断点 命令格式:bm [Options] SymbolPattern [第几次命中断点时中断到调试器] ["一组命令,用分号隔开"] | bm命令要求目标模块的调试符号有类型信息,这通常需要私有符号文件,如果对公共符号文件的模块使用bm命令,会提示错误信息。解决这个问题的方法是使用 /a 开关,强制针对所有匹配的符号设置断点,无论是数据还是代码,建议只有在确信所有符号是函数时才使用。 |
ba | 设置读,写,执行断点 命令格式:ba[ID号] Access Size [Options] [Address [第几次命中断点时中断到调试器]] ["一组命令,用分号隔开"] | 其中Access指定触发断点的访问方式,Size指定访问的长度。 Access的取值如下: e 读取和执行指令时触发断点,即访问代码硬件断点 r 读取和写入数据时触发断点 w 写入数据时触发断点 i 执行I/O访问时触发断点 Size的取值如下: 对于访问代码硬件断点,它的值应该为1 对于x86系统,可以为1,2,4,分别表示1字节访问,字访问和双字访问 对于x64系统,可以为1,2,4, 8 对于安腾系统,可以为1 - 0x80000000间的任意2次方值 |
bl | 列出当前所有断点 | |
bc 断点号 | 删除断点 | 断点号可以使用*来通配所有断点,使用 - 来表示一个范围,或者使用逗号来指定多个断点号 |
bd 断点号 | 禁用断点 | |
be 断点号 | 启用断点 | |
sxe ld:[dll名称] | 加载某个DLL时下断点 | sxe ld:wininet:加载wininet时下断点 sxe ld:* / sxe ud:* :匹配所有DLL模块 |
sxe ud:[dll名称] | 卸载某个DLL时下断点 |