WinDbg 入门 (用户模式)
Page.0 内容提要
1.使用WinDbg直接启动notepad.exe
2.启动自己的应用程序并附加WinDbg
3.命令摘要
Page.1 使用WinDbg直接启动notepad.exe
1.导航到安装目录启动WinDbg.exe
汉化的exe为:ha_windbg.exe
2. 菜单:“文件”-“打开可执行文件”
选择:C:\Windows\System32\notepad.exe
启动后见上图。
ModLoad: 说明了加载的模块DLL
3.添加符号搜索路径(.PDB文件路径)
菜单:“文件”->“符号文件路径”->浏览,即可添加搜索路径PDB所在路径
e.g: srv*;c:\windows\system32;
另:不需要指定cpp路径,PDB文件直接记录了cpp文件
3.1显示符号路径:PDB路径 (命令 .sympath)
命令: .sympath
下面显示了当前的PDB路径
0:000 >.sympath
************* Path validation summary **************
Response Time (ms) Location
Deferred srv*
OK c:\windows\system32
3.2 重新加载PDB符号信息 (命令 .reload)
0:000 >.reload
//此处应该显示各模块
4 查看notepad.exe模块的符号 (命令 x)
0:000 >x notepad!*
//此处会显示在notepad中的所有符号
//数量特别多-很慢
4.1搜索符号,通配符 (命令 x 模块!函数名)
0:000 >x notepad!wWin*
//显示适配函数
// 函数地址 函数=命名空间::函数名()
// 函数地址 类函数: 命名空间::类::函数名()
00007ff6`6e76b0a0 notepad!wWinMain (wWinMain)
00007ff6`6e783db0 notepad!wWinMainCRTStartup (wWinMainCRTStartup)
5 断点 (命令 bu)
5.1 新增断点 (命令 bu 模块!函数名)
0:000 >bu notepad!wWinMain
//如果有重名的 可以使用函数地址
// bu notepad!06cb22ea
//这里的函数地址可以从 x命令里面看
5.2 列出所有断点 (命令 bl)
0:000 >bl
//列出断点位置
6 继续运行 (命令 g)
g == F5
0:000 >g
7 列出模块 (命令 lm)
0:000 >lm
start end module name
00007ff6`6e760000 00007ff6`6e798000 notepad (pdb symbols) C:\ProgramData\Dbg\sym\notepad.pdb\BC04D9A431EDE299D4625AD6201C8A4A1\notepad.pdb
00007ff8`066a0000 00007ff8`067ab000 gdi32full (deferred)
00007ff8`067b0000 00007ff8`068b0000 ucrtbase (deferred)
00007ff8`06a10000 00007ff8`06aad000 msvcp_win (deferred)
00007ff8`06ab0000 00007ff8`06ad2000 win32u (deferred)
00007ff8`06b40000 00007ff8`06e08000 KERNELBASE (deferred)
00007ff8`07220000 00007ff8`072dd000 KERNEL32 (deferred)
7.1 带有通配符的列出模块 (命令 lm m note*)
0:000 >lm m note*
start end module name
00007ff6`6e760000 00007ff6`6e798000 notepad (pdb symbols) C:\ProgramData\Dbg\sym\notepad.pdb\BC04D9A431EDE299D4625AD6201C8A4A1\notepad.pdb
注意:可以加载pdb文件的路径也已经列出
8 查看堆栈跟踪 (命令 k)
k的使用场景
Column 1 | Column 2 | Column 2 | Column 2 |
---|---|---|---|
lm | 列出模块 | notepad 的名字 “notepad” | |
x | 查出函数名 | x notepad!run_cmd* | |
bu | 加断点 | bu notepad!run_cmd | 也可以用函数地址 |
bl | 列出所有断点 | bl |
0:000 >k
00 000000c8`2647f708 00007ff6`6e783d36 notepad!wWinMain
01 000000c8`2647f710 00007ff8`07237034 notepad!__scrt_common_main_seh+0x106
02 000000c8`2647f750 00007ff8`08e02651 KERNEL32!BaseThreadInitThunk+0x14
03 000000c8`2647f780 00000000`00000000 ntdll!RtlUserThreadStart+0x21
从上到下 = 函数调用从近到远
8.1继续下一步 命令:g
8.2中断: 菜单:文件->中断
9 解析命令行开头 0:000
0:011 >k
//处理器:线程>k
//0处理器
//011线程
10 查看线程
10.1查看所有线程(命令 ~) 切换线程 (命令 ~2s)
0:000>~
0 Id: 5500.34d8 Suspend: 1 Teb: 000000c8`262c4000 Unfrozen
1 Id: 5500.3960 Suspend: 1 Teb: 000000c8`262c6000 Unfrozen
2 Id: 5500.5d68 Suspend: 1 Teb: 000000c8`262c8000 Unfrozen
0:000>~2s
0:002>k
解析:
0:000 在0处理器 0线程
- 命令列出所有线程,共计3个
~2s切换到线程2 注意命令行变为0:002
输入k 得到调用堆栈
11 分离进程 命令 qd
0:000>qd
Page.2 自己调试的流程
1.打开ha_windbg.exe
2.启动自己的程序
- 没有命令行,
1.1 使用菜单:文件->打开可执行文件 - 带有命令行,
2.1 使用菜单:文件->附加到进程
2.2 到“任务管理器”->“详细信息”页面查找PID
3.设置符号路径
使用菜单:文件->符号文件路径
4.重新加载pdb (命令.reload)
5.列出模块名字,精准确定名称 命令:lm
搜索时使用 lm m sp*
6.列出模块中的函数 符号 命令:x
序号 | 条件 | 操作 |
---|---|---|
1 | 知道准确函数名时 | x 模块名!函数名 |
2 | 搜索函数名 | x 模块名!符号* x SpasTrussEx!NsBDJ::CBdjColumnListDock::CMD_Change* 带命名空间,带类名,带函数名 |
7.加断点 命令 bu 模块!函数名
也可以使用地址 bu 模块!地址
序号 | 操作 |
---|---|
1. | bu SpasTrussEx!NsBDJ::CBdjColumnListDock::CMD_Change 注意不带void参数 |
8.列出断点 命令bl
bl
0:007>
0 e 50991900 0001(0001) 0: *** SpasTrussEx!NsBDJ::CBdjColumnListDock::CMD_Change
9.继续调试 命令g
10.分析问题!analyze -v
11.列出调用堆栈 k
12.退出调试
菜单:调试-停止调试
Page.3 命令摘要
1.命令
命令 | 功能 |
---|---|
.sympath | (设置符号路径) |
.reload | (重新加载模块) |
x | (检查符号) |
g | (转到) |
lm | (列出已加载的模块) |
k | 显示堆栈回溯) |
bu | (设置断点) |
bl | 断点列表 |
~ | 断点列表 |
~ns | 设置当前线程 |
!analyze -v | 分析问题 |
qd | 退出和分离 |
2.调试菜单
调试菜单:
继续
退出
暂停等调试命令