-
-
[原创]WinDbg Dump 分析完整指南
-
发表于: 4天前 394
-
问题背景
在使用 WinDbg 分析 dump 文件时,很多人只准备了:
- ✅ Dump 文件 (.dmp)
- ✅ PDB 符号文件
但会发现调用栈信息不完整,无法查看详细的代码和变量信息。
解决方案
要获得完整的调用栈和调试信息,需要准备:
- ✅ Dump 文件 (.dmp)
- ✅ PDB 符号文件 (.pdb)
- ✅ 可执行文件 (exe)
- ✅ 所有依赖的 DLL 文件
为什么需要 EXE 和依赖文件?
| 文件类型 | 作用 | 缺失后的影响 |
|---|---|---|
| PDB | 符号信息、函数名、变量名 | 只能看到地址,无法看到函数名 |
| EXE | 主程序二进制代码 | 无法反汇编主程序代码,堆栈显示不完整 |
| DLL | 依赖库的二进制代码 | 依赖库的调用栈显示为地址,无法看到详细信息 |
完整操作步骤
1. 准备文件
将以下文件放在同一个目录(例如:D:\Crash_Analysis):
D:\Crash_Analysis\ ├── crash.dmp # Dump 文件 ├── YourApp.exe # 主程序 ├── YourApp.pdb # 主程序符号 ├── Module1.dll # 依赖 DLL ├── Module1.pdb # DLL 符号 ├── Module2.dll # 其他依赖 ├── Module2.pdb └── ...
提示:确保 exe/dll 和对应的 pdb 文件版本完全匹配(时间戳一致)。
2. 打开 WinDbg Preview
- 启动 WinDbg Preview
- File → Open dump file
- 选择你的
.dmp文件
3. 配置路径(关键步骤)
在底部的命令窗口(Command window)输入以下命令:
.sympath srv*c:\symbols*1e9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7$3c8D9i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6r3!0%4L8X3I4G2j5h3c8Q4x3V1k6K6P5h3#2T1L8$3I4K6 .sympath+ D:\Crash_Analysis .exepath D:\Crash_Analysis .reload /f
命令说明:
.sympath- 设置符号路径(包含微软符号服务器 + 本地路径).sympath+- 添加额外的符号路径.exepath- 设置可执行文件路径(包括 exe 和 dll).reload /f- 强制重新加载所有符号
4. 自动分析崩溃
!analyze -v
这个命令会:
- 自动分析崩溃原因
- 显示崩溃线程的完整调用栈
- 显示异常信息和错误代码
- 给出可能的原因分析
5. 验证符号加载状态
lm vm YourApp lm vm Module1
查看输出,确认:
- ✅ Symbol status: Symbols loaded
- ✅ Symbol file: 显示正确的 pdb 路径
- ✅ Image path: 显示正确的 exe/dll 路径
- ✅ Timestamp: 时间戳匹配
正常输出示例:
Module name: YourApp Image path: D:\Crash_Analysis\YourApp.exe Symbol file: D:\Crash_Analysis\YourApp.pdb Symbol status: Symbols loaded successfully Timestamp: Thu Dec 12 15:30:22 2024
异常输出(需要修复):
Module name: YourApp Symbol status: Symbols not found Symbol file: *** ERROR: Symbol file could not be found.
常用分析命令
查看调用栈
k # 简单调用栈 kb # 带参数的调用栈 kp # 带完整参数类型的调用栈 kpn # 带帧编号和完整参数(推荐) ~*k # 所有线程的调用栈
切换线程
~ # 列出所有线程 ~5s # 切换到线程 5 ~5k # 查看线程 5 的调用栈
查看变量
dv # 显示当前函数的局部变量 dv /V # 显示变量的详细信息(地址、类型) dt 变量名 # 显示变量的完整结构
查看内存
dd 地址 # 以 DWORD 格式显示内存 dq 地址 # 以 QWORD 格式显示(64位) da 地址 # 以 ASCII 字符串显示 du 地址 # 以 Unicode 字符串显示
反汇编代码
u @rip # 反汇编当前指令位置(64位) u @eip # 反汇编当前指令位置(32位) ub 地址 # 向前反汇编 uf 函数名 # 反汇编整个函数
查看寄存器
r # 显示所有寄存器 r rax # 显示特定寄存器
完整分析工作流示例
# 1. 配置路径 .sympath srv*c:\symbols*5a7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7$3c8D9i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6r3!0%4L8X3I4G2j5h3c8Q4x3V1k6K6P5h3#2T1L8$3I4K6 .sympath+ D:\Crash_Analysis .exepath D:\Crash_Analysis .reload /f # 2. 自动分析 !analyze -v # 3. 查看所有线程 ~*k # 4. 查看崩溃线程详细信息(假设是线程 5) ~5s kpn # 5. 查看崩溃点的代码 u @rip # 6. 查看局部变量 dv /V # 7. 查看特定对象(假设有个指针变量 pObject) dt pObject dt 0x000001234567890 MyClass # 8. 查看模块加载信息 lmv
常见问题排查
问题 1:调用栈显示不完整,只有地址
原因:缺少 exe 或 dll 文件
解决:
# 查看哪些模块缺少符号 lm # 找到 "no symbols" 的模块,将对应的 exe/dll 和 pdb 放入路径 .exepath+ 新路径 .reload /f
问题 2:符号加载失败
原因:pdb 和 exe/dll 版本不匹配
解决:
- 确保使用的 exe/dll 和 pdb 是同一次编译生成的
- 检查文件的时间戳是否一致
- 使用
lm vm 模块名查看详细错误信息
问题 3:看不到源代码
解决:
# 设置源代码路径 .srcpath D:\Project\Source .srcfix
问题 4:第三方库没有符号
解决:
# 添加微软符号服务器(自动下载系统 DLL 的符号) .sympath+ srv*c:\symbols*95fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7$3c8D9i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6r3!0%4L8X3I4G2j5h3c8Q4x3V1k6K6P5h3#2T1L8$3I4K6 .reload /f
对比:有无 EXE 的差异
只有 PDB 时
0:000> k # Child-SP RetAddr Call Site 00 00000012`3456789a 00007ff8`12345678 YourApp+0x1234 01 00000012`345678b0 00007ff8`87654321 YourApp+0x5678 02 00000012`345678c0 00007ff8`11223344 Module1+0xabcd
只能看到模块名和偏移量,无法看到函数名
有 PDB + EXE + DLL 时
0:000> kpn # Child-SP RetAddr Call Site 00 00000012`3456789a 00007ff8`12345678 YourApp!CrashFunction(int param1 = 42, void* ptr = 0x0000000000000000) 01 00000012`345678b0 00007ff8`87654321 YourApp!MainLoop(void) + 0x123 02 00000012`345678c0 00007ff8`11223344 Module1!ProcessData(const std::string& data = "test") + 0x45
完整的函数名、参数信息,可以直接定位问题
保存工作区
如果经常分析同一个项目的 dump,可以保存配置:
# 保存当前工作区 .writemem workspace.dmp 开始地址 结束地址
或者创建一个批处理脚本 analyze.txt:
.sympath srv*c:\symbols*27cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7$3c8D9i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6r3!0%4L8X3I4G2j5h3c8Q4x3V1k6K6P5h3#2T1L8$3I4K6 .sympath+ D:\Crash_Analysis .exepath D:\Crash_Analysis .reload /f !analyze -v
使用时:
$$>a< analyze.txt
最佳实践建议
✅ 始终保存完整的崩溃现场
- Dump 文件
- 对应版本的 exe、dll
- 对应版本的 pdb 文件
- 最好建立版本号对应的文件夹
✅ 使用版本控制
Crash_v1.2.3\ ├── crash_20241212.dmp ├── YourApp.exe ├── YourApp.pdb └── 所有依赖 dll 和 pdb
✅ 记录时间戳
- 记录崩溃发生的时间
- 记录使用的程序版本
- 记录操作系统版本
✅ 配置符号服务器
- 始终包含微软符号服务器
- 可以自动下载系统 DLL 的符号
- 避免因系统库符号缺失导致分析不完整
✅ 使用
!analyze -v作为起点- 这是最快的自动分析方法
- 会给出很多有用的提示
- 然后根据提示深入分析
总结
完整的 WinDbg dump 分析需要:
- Dump 文件:崩溃时的内存快照
- PDB 文件:符号信息(函数名、变量名)
- EXE/DLL 文件:二进制代码(用于反汇编和完整堆栈)
三者缺一不可,才能获得最完整的调试信息!
提示:本文档适用于 WinDbg Preview。如果使用 WinDbg Classic,界面略有不同但命令完全相同。
赞赏记录
参与人
雪币
留言
时间
马来
为你点赞!
3小时前
mb_kbmkpcnd
谢谢你的细致分析,受益匪浅!
1天前
gegon
感谢你分享这么好的资源!
2天前
mb_wpitiize
谢谢你的细致分析,受益匪浅!
3天前
tmflxw
你的帖子非常有用,感谢分享!
3天前
赞赏
他的文章
- [原创]WinDbg Dump 分析完整指南 395
- [原创]无调试符号的崩溃分析:从汇编到结构体推断 456
- [原创]为什么我选择windbg而不是visual studio? 3199
- 重新认识线程sleep 1688
- [原创]CPU爆高,程序卡顿分析 3339
赞赏
雪币:
留言: