事儿"/>
windbg调试的那些事儿
这两天一直在查一个qt程序的异常崩溃,把多年不用的windbg拾起来真实不容易,记得之前用的时候,敲命令熟悉的不行,而且那个symbols也是轻松就下载下来了,想故技重施吧,命令忘记的都差不多了,汗。
先来熟悉一下creator的环境,配置cdb调试环境,需要工具->选项->构建和运行->Debuggers->中配置,自动检测到CDB
然后路径,分别标注Name和Path到安装目录下的cdb.exe即可。
然后在工具->选项->调试器->概要中源码路径映射中点击添加QT源码...回自动添加QT源码,CDB Paths中添加QT符号表的路径,而在源码中添加源码路径。这样就可以调试到QT的源码了。
随后回忆一下这个windows的符号表的添加方法,这里我没有添加成功,没有下载下来。
设置添加系统环境变量_NT_SYMBOL_PATH 的值为:srv*c:\symbols*
我从网上查了一个帖子是这样的,然后.reload之后就可以把符号表下载到c:\symbols目录了。
接下来看一下windbg常用的命令吧
windbg的命令依据一定的语法规则和字母简写来表示特定的指令。
通配符的语法规则:
i 一个星号(*) 表示零个或多个字符
ii 问号(?)表示任何单个字符
iii 方括号[]半酣一系列字符表示列表中的任何单个字符,在列表中一个字符进行匹配。
iv 数字符号(#)表示另个或多个前面的字符
iiv 加号(+)表示一个或多个前面的字符
如果必须指定文本的数学符号(#),(?),([]) ,(*), (+),必须添加一个反斜杠(\)的前面字符。
挡在表达式中使用寄存器时,应添加at符号(@)之前注册,在登录这将告知调试器以下文本是寄存器的名称。
尤其是使用的是C++语法,at符号始终是必须的。
R(寄存器)命令是此规则的例外。调试器始终将其第一个参数解释为寄存器,如没有为第二个参数命令时,它根据默认
表达式语法进行解释
0:000> r eax = @ebx
每个线程都具有其自己的注册值。 这些值存储在 CPU 寄存器时线程正在执行并在内存中执行另一个线程时。
在用户模式下,任何对寄存器的引用被解释为与当前线程相关联的寄存器。
在内核模式下,任何对寄存器的引用被解释为与当前寄存器上下文关联的寄存器。 可以设置寄存器上下文以匹配特定线程、 上下文记录或捕获帧。 指定注册上下文,并且不能更改它们的值,可以显示仅最重要的注册。
许多调试器命令作为其参数具有线程标识符。波形符(~)出现在之前的线程描述符
~. 当前线程
~# 导致当前异常或调试事件的线程
~* 此进程中的所有线程
~数量 其索引的线程数
~~[TID] 线程ID是在线程TID
~[表达式] 线程的线程ID是到整数数值表达式解析
线程在创建时分配索引,当调试开始时,当前线程时导致出现异常或调试事件(或活动线程时调试器附加到进程)。线程保持当前线程,直到指定一个使用的新~s(设置当前线程)命令或使用进程和线程窗口的windbg中。另注意,线程标识符通常显示为命令前缀。并非所有通配符使用线程标识符的所有命令中提供。
许多调试器命令都将进程标识符作为其参数。 竖线(|)出现在进程标识符之前
|. 当前进程
|# 导致当前异常或调试事件的进程
|* 所有进程
|号 序号为number的进程
|~ [PID] 进程ID为PID的进程
$< , $>< , $$< , $$>< ,$$>a< 运行脚本命令
?显示所有命令和运算符的列表
? Expression 问好命令的计算结果并显示表达式的值
# [Pattern] [Address [ L Size ]] 搜索指定模式中的反汇编代码
|| System 打印指定的系统或当前正在调试的所有系统的状态
||System s
|| s 设置或显示当前的系统数
| Process 显示指定进程的状态或当前正在调试你的所有进程
|Process s
| s 设置或显示当前进程数目
~ Thread 显示当前进程中的指定线程或所有线程的状态
~Thread e CommandString 目标进程中执行一个或多个命令在特定线程或所有线程
~Thread f 冻结给定的线程,使其停止,并等待直到它是未冻结
~Thread u 取消冻结指定的线程
~Thread n 挂起线程
~Thread m 回复指定的线程执行
~Thread s
~ s 设置或显示当前的线程数
bc Breakpoints 永久删除以前从系统中设置断点
bd Breakpoints 命令禁用,但不会删除,之前设置断点
be Breakpoints 还原之前已禁用的一个或多个断点
[~Thread] bp[ID] [Options] [Address [Passes]] ["CommandString"]
[~Thread] bu[ID] [Options] [Address [Passes]] ["CommandString"]
[~Thread] bm [Options] SymbolPattern [Passes] ["CommandString"] 设置一个或多个软件断点
br OldID NewID [OldID2 NewID2 ...] 对一个或多个断点进行重新编号
bs ID ["CommandString"] 更改时遇到指定的断点执行的命令
c Range Address 将保存在两个内存方面的值进行比较
d{a|b|c|d|D|f|p|q|u|w|W} [Options] [Range]
dy{b|d} [Options] [Range]
d [Options] [Range] 显示给定范围中的内存内容
ddp [Options] [Range]
dqp [Options] [Range]
dpp [Options] [Range]
dda [Options] [Range]
dqa [Options] [Range]
dpa [Options] [Range]
ddu [Options] [Range]
dqu [Options] [Range]
dpu [Options] [Range] 显示在指定位置的指针,取消引用该指针,然后在结果中显示的内存中各种格式的位置
d{s|S} [/c Width] [Address] 显示一个字符串
dt [-DisplayOpts] [-SearchOpts] [module!]Name [[-SearchOpts] Field] [Address] [-l List]
dt [-DisplayOpts] Address [-l List]
dt -h 显示有关局部变量,全部变量或数据类型的信息。
e{b|d|D|f|p|q|w} Address [Values]
e{a|u|za|zu} Address "String"
e Address [Values] 输入到内存中指定的值
f Range Pattern
fp [MemoryType] PhysicalRange Pattern 填充指定的内存范围
[~Thread] g[a] [= StartAddress] [BreakAddress ... [; BreakCommands]] 开始执行给定的进程或线程
gc 继续执行从条件断点命中断点所用的方式像提供
[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] [FrameCount]
[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] = BasePtr [FrameCount]
[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] = BasePtr StackPtr InstructionPtr
[~Thread] kd [WordCount] 显示以及相关的信息,在给定的线程的堆栈帧...
ld ModuleName [/f FileName] 加载指定的模块的符号和更新模块的所有信息
lm Options [a Address] [m Pattern | M Pattern] 显示指定的加载的模块,包括状态和模块的路径
ln Address
ln /D Address 显示的符号处或符进的给定的地址
ls [.] [first] [, count]
lsa [.] address [, first [, count]] 显示一系列的当前源文件中的行和提升当前的源行号
m Range Address 将内存中的内容从一个位置复制到另一个
[~Thread] p[r] [= StartAddress] [Count] ["Command"] 执行单个指令或源行,并有选择性的显示所有寄存器和标志的生成值
当子例程调用或中断发生,又被称为单步执行
[~Thread] pa [r] [= StartAddress] StopAddress ["Command"] 执行程序,直到指定的地址,显示每个步骤
[~Thread] pc [r] [= StartAddress] [Count] 执行程序,直到达到调用指令
[~Thread] ph [r] [= StartAddress] [Count] 执行程序,直到分支指令的任何类型,包括条件或无条件分支,调用
[~Thread] pt [r] [= StartAddress] [Count] ["Command"] 执行程序,直到达到返回指令
[~Thread] r[M Mask|F|X|?] [ Register[:[Num]Type] [= [Value]] ]
r. 显示或修改寄存器,浮点寄存器,标志,伪寄存器和固定名称的别名
s [-[[Flags]Type]] Range Pattern
s -[[Flags]]v Range Object
s -[[Flags]]sa Range
s -[[Flags]]su Range 通过内存以查找特定字节模式的索引
sx
sx{e|d|i|n} [-c "Cmd1"] [-c2 "Cmd2"] [-h] {Exception|Event|*}
sx- [-c "Cmd1"] [-c2 "Cmd2"] {Exception|Event|*}
sxr 控制调试器在要调试的应用程序中发生异常或发生某些事件时所执行的操作
[~Thread] t [r] [= StartAddress] [Count] ["Command"] 执行单个指令或源行,并有选择性的显示所有寄存器和标志的生成值
tb [r] [= StartAddress] [Count] 跟踪到下一个分支
元命令
.attach [-premote RemoteOptions] AttachOptions PID 附加到进程
.call [/v] Function( Arguments )
.call /s Prototype Function( Arguments )
.call /c
.call /C 调用函数
.create [-premote RemoteOptions] [-f] CommandLine 创建一个新的目标进程
.detach [ /h | /n ] 结束调试会话
.load DLLName
!DLLName.load
.loadby DLLName ModuleName 将新的扩展dll加载到调试器中
.open [-m Address] FileName
.open -a Address 打开源文件
.process [/i] [/p [/r]] [/P] [Process] 设置哪个进程用于处理上下文
.push
.push /r
.push /r /q 保存在调试器的当前状态
.reload [Options] [Module[=Address[,Size[,Timestamp]]]]
.reload -? 删除指定模块的所有符号信息,并根据需要重新加载这些符号
.remote session 启动Remote.exe Server,启用到当前调试会话的远程连接
.symfix[+] [LocalSymbolCache] 自动设置符号路径以指向Microsoft符号存储区
.symopt+ Flags
.symopt- Flags
.symopt 设置和显示符号选项
.sympath[+] [Path [; ...]] 设置或更改符号路径
.thread [/p [/r] ] [/P] [/w] [Thread] 指定线程将用于寄存器上下文
常用扩展命令
!address Address
!address -summary
!address [-f:F1,F2,...] {[-o:{csv | tsv | 1}] | [-c:"Command"]}
!address -? | -help 地址扩展吓死你hi目标进程或目标计算机使用的内存有关的信息
!analyze [-v] [-f | -hang] [-D BucketID]
!analyze -c [-load KnownIssuesFile | -unload | -help ] 显示有关当前异常或错误检查的信息
!chksym Module [Symbol] 测试针对符号文件的模块的有效性
!handle [Handle [UMFlags [TypeName]]]
!handle -? 显示有关句柄的信息
!heap [HeapOptions] [ValidationOptions] [Heap]
!heap -b [{alloc|realloc|free} [Tag]] [Heap | BreakAddress]
!heap -B {alloc|realloc|free} [Heap | BreakAddress]
!heap -l
!heap -s [SummaryOptions] [StatHeapAddress]
!heap -i HeapAddress
!heap -x [-v] Address
!heap -p [PageHeapOptions]
!heap -srch [Size] Pattern
!heap -flt FilterOptions
!heap -stat [-h Handle [-grp GroupBy [MaxDisplay]]]
!heap [-p] -?
!heap -triage [Handle | Address] 显示堆使用情况信息,控制堆管理器中的断点,检测泄露的堆块,搜索堆块。
!list -t [Module!]Type.Field -x "Commands" [-a "Arguments"] [Options] StartAddress
!list " -t [Module!]Type.Field -x \"Commands\" [-a \"Arguments\"] [Options] StartAddress "
!list -h 扩展指定的调试器命令重复执行
以上只是列出了一部分的命令,相信应付一般的软件调试已经足够。至于深入学习的话,还是要亲自操刀测试咯。
至于QT的调试窗口的话,左列的菜单中定向到调试这一项,就会在下方弹出调试窗口,然后点击调试窗口顶部右上角Views文字,就会显示一些断点,模块,寄存器,堆栈,线程等子窗口,可以看到一些调试信息,结合输出日志信息,可以进行本地的异常调试咯。
更多推荐
windbg调试的那些事儿
发布评论