目录
1、Windbg调试器介绍
2、Windbg版本说明
3、Windbg命令汇总
VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931 在使用Windbg分析问题的过程中,会频繁地使用到多个Windbg命令去查看相关信息去辅助分析问题。因此,我们要掌握一些常用的Windbg调试命令,可能在部分场景下还需要去查阅一些不常用的命令。本文将列出大部分Windbg调试命令,供大家参考与查阅。
Windbg是微软推出的一款Windows平台强大的用户态/内核态调试工具,可以静态分析dump文件,也可以动态调试目标进程。
对于静态分析,则需要软件本身能捕获到发生的异常并生成dump文件。对于动态调试,可以将Windbg附加到已经运行的进程上进行调试,也可以用Windbg启动目标程序。点击Windbg菜单栏的File,在弹出的菜单中即可找到打开程序和附加到进程的入口,如下:
什么时候需要用到Windbg的动态调试呢?一般以下几个场景中会用到:
1)软件运行过程中发生的崩溃或者闪退,软件的异常捕获模块没有捕获到,此时可以尝试将Windbg附加到目标进程上调试运行,即Windbg挂在目标进程上,和目标进程一起跑。一旦软件中发生异常,Windbg会第一时间感知到并中断下来。
2)软件运行过程中发生异常,软件的异常捕获模块捕获到了,但在生成dump文件时产生二次崩溃,导致dump文件生成失败,此时也可以尝试将Windbg挂在上去。
3)Visual Studio调试过程中产生了异常并中断下来,但Visual Studio看不到函数调用堆栈或者看不到有效的函数调用堆栈,此时可以尝试用Windbg启动目标程序调试运行,Windbg捕捉到异常后会中断下来,可能可以查看到详细的函数调用堆栈。这个场景我们遇到好几次了,比如软件中发生Stack Overflow线程栈溢出,如果在Visual Studio调试的过程中遇到,Visual Studio会直接退出调试状态,也就没机会看到异常发生的函数调用堆栈了。此时可以直接用Windbg启动目标程序,复现异常,Windbg捕获到异常后是能看到详细的函数调用堆栈的。
无论是静态分析dump文件还是动态调试,都需要使用Windbg命令去查看信息,通过查看的信息去分析问题。
我们这边常用的Windbg版本主要有两个版本,一个是免安装的绿色版Windbg6,一个是安装版的Windbg10。建议大家使用较新的Windbg10,因为在Windbg10中不用再输入复杂的命令,都做成了超链接的方式,只要点击超链接就可以查看了,比如下图:
函数调用堆栈中的左侧序号,可以点击展开对应的函数,可以查看函数中局部变量的值以及所在类的this指针的信息,正如截图下方显示的那样。点击图中this超链接,可以查看函数所在C++对象的成员变量的值。
这些超链接在老版本的Windbg6中是需要手动输入的,有些命令还是比较长比较复杂的。当然一些简单常用的命令还是需要手动输入的,比如.ecxr、kn、lm、.reload等。
关于Windbg的版本及如何安装,可以参考我之前写的文章:
Windbg调试工具介绍https://blog.csdn.net/chenlycly/article/details/125505992
下面列出Windbg的大部分命令,以方便大家可以在需要的时候来查阅想用的命令!
## 重要说明
(1)windbg命令分为标准命令,元命令和扩展命令。
标准命令提供最基本的调试功能,不区分大小写。如:bp g dt dv k 等。
元命令提供标准命令没有提供的功能,也内建在调试引擎中,以 . 开头。如 .sympath .reload 等。
扩展命令用于扩展某一方面的调试功能,实现在动态加载的扩展模块中,以 ! 开头。如 !analyze等。
(2)进入调试状态时,直接回车可重复执行上一条命令;按上下方向键可以浏览和选择以前输入过的命令
(3) 神奇的Tab键,进行命令补全;ESC清除当前命令输入框中的文本。
(4)上图红色框中的“0:000”。其中,0为当前调试会话的进程号;000为调试会话的线程号。
(5)当命令提示符显示*BUSY*时,即使命令输入框可以输入命令,但输入的命令不会立即被执行,要等windbg空闲时才能执行。可使用Ctrl + Break来终止一个长时间未完成的命令。
(6)一次可以执行多条命令,命令间用分号 ; 分隔 【如:bp main; bp `view.cpp:120`】,一次打2个断点。
## 启动调试
windbg -I // 将windbg设置成默认调试器
windbg "notepad.exe" arguments // 使用windbg启动调试notepad.exe
windbg -p 4200 // 将windbg附加到一个正在运行的pid为4200的进程上
windbg -pn "notepad.exe" // 将windbg附加到一个正在运行的名为notepad.exe的进程上
windbg –z "c:\mydumpfile.dmp" // 调试mydumpfile.dmp文件
.opendump "c:\mydumpfile.dmp" // 调试mydumpfile.dmp文件
.attach 0n4220 // 4220为十进制pid,使用该命令附加调试时,必须先存在一个调试会话
.detach // 分离调试
.restart // 重启并调试
.kill // 强制结束当前调试
q // 结束当前调试会话,回到基础工作空间,并结束调试进程
qd // 结束当前调试会话,回到基础工作空间,但不结束调试进程
## 获取帮助
? // 打印出所有标准命令
.help // 打印出所有元命令
.hh // 打开windbg的chm帮助文件
.hh bp // 打开windbg的chm帮助文件bp命令介绍页
command /? // 打印命令command具体参数用法
## 注释符
* // 注释整行
$$ // 注释(遇到分号结束)
## 配置调试环境
注:如果被调试的模块(无论移动到本机的何处)是用本机代码编译产生的,都不需要进行符号和源代码的路径设置
.sympath // 查看当前符号查找路径
.sympath c:\symbols // 将符号查找路径设为:c:\symbols
.sympath+ c:\symbols // 将c:\symbols添加到符号查找路径集合中
.symfix // 将符号查找路径设为:SRV*WinDbg安装目录\Sym*http://msdl.microsoft.com/download/symbols
.symfix f:\symbols // 将符号查找路径设为:SRV*f:\symbols*http://msdl.microsoft.com/download/symbols
.symfix+ f:\symbols // 将SRV*f:\symbols*http://msdl.microsoft.com/download/symbols添加到符号查找路径集合中
.srcpath // 查看当前源文件查找路径
.srcpath f:\src // 将源文件查找路径设为:f:\src 注:必须勾选上菜单“Debug”-“Source Mode”;另外pdb须与exe、dll等执行模块匹配上
.srcpath+ f:\src // 将f:\src添加到源文件查找路径集合中
.exepath // 查看可执行文件查找路径
.exepath f:\bin // 将可执行文件查找路径设为:f:\bin
.exepath+ f:\bin // 将f:\bin添加到可执行文件查找路径集合中
## 系统信息
vertarget // os信息
!cpuid // cpu信息
## wow64模式
【x64版windbg调试win32程序】
.effmach // 查看当前调试mode:x86、x64等
.load wow64exts // [!load wow64exts] 加载wow64exts.dll模块 注:!sw就是wow64exts中的命令
.unload wow64exts // [!unload wow64exts] 卸载wow64exts.dll模块
!sw // [!wow64exts.sw] 在多个mode:x86、x64上进行循环切换 注:如果win32程序在x64的mode下,会看到地址是64位的
!k // [!wow64exts.k] 打印32位、64位堆栈
!k 5 // [!wow64exts.k 5] 打印32位、64位堆栈,栈帧个数为5
!info // [!wow64exts.info] 输出wow64相关的PEB、TEB和TLS基本信息
!r // [!wow64exts.r] 输出处理器当前上下文信息
!r dumpTest!main // [!wow64exts.r dumpTest!main] 输出main函数地址的上下文信息
## 符号加载与查看
除了使用ld和.reload命令直接加载符号文件,某些使用符号的命令也可以触发调试器来加载符号,如:栈回溯命令(k*)和反汇编命令(u)等。
值得说明的是,windbg缺省使用的是懒惰式符号加载策略,当它收到模块加载事件时,它通常是不会加载符号的,符号状态显示为deferred(延迟加载)。
.symopt // 显示当前所有符号选项
.symopt+ flags // 添加符号选项
.symopt- flags // 删除符号选项
!sym noisy // 激活详细符号加载(noisy symbol loading)显示
!sym quiet // 禁止详细符号加载显示
ld * // 为所有模块加载符号
ld kernel32 // 加载kernel32.dll的符号
.reload // 为所有已加载模块载入符号信息
.reload /i // 重新加载不匹配符号的模块【dmp文件没有对应的pdb时使用】
.reload /i TGame.exe // 重新加载不匹配符号的TGame.exe
.reload /f /v // f:强制立即模式(不允许延迟载入) v:详细模式
.reload /f @"c:\windows\System32\verifier.dll"// 为指定模块加载符号信息
.reload /f TGame.exe // 为TGame.exe加载符号信息
.reload /u TGame.exe // 卸载TGame.exe及其载符号信息
.chain // 显示已经加载进来的模块
x *! // 列出所有模块对应的符号信息
lm // 列出所有模块(加载和未加载)对应的符号信息
lmv // 列出所有模块(加载和未加载)对应的符号信息
lmvm ntdll // 查看ntdll.dll的详细信息(注意exe、dll等都不要带后缀名)
x ConsoleTest!* // 列出ConsoleTest模块中的所有符号
x ConsoleTest!add* // 列出ConsoleTest模块中的所有add开头的符号
x /t /v ConsoleTest!* // 带数据类型、符号类型和大小信息,列出ConsoleTest模块中的所有符号
x kernel32!*LoadLib* // 列出kernel32模块中所有含LoadLib字样的符号
## 进程
| // 列出调试进程
|* // 列出调试进程
|N // 参看序数为N的调试进程
|Ns // 切换序数为N的进程为当前调试进程
## 线程
~ // 列出线程
~* // 所有线程
~* k // 所有线程堆栈信息
~* r // 所有线程寄存器信息
~. // 查看当前线程
~0s // 查看主线程
~# // 查看导致当前事件或异常的线程
~N // 查看序数为N的线程
~~[n] // 查看线程ID为n的线程
~Ns // 切换序数为N的线程为当前调试线程
~N f // 冻结序数为N的线程
~N u // 解冻序数为N的线程
~N n // Suspend序数为N的线程
~N m // Resume序数为N的线程
~* e !gle // 显示所有线程最后的一个错误信息 e后可以为任意windbg命令
.ttime // 查看当前线程时间信息
!runaway //显示当前进程的所有线程时间信息
## 断点
bl // 列出所有断点
bc * // 清除所有断点
bc 1 // 清除1号断点
bc 1 2 5 // 清除1号、2号、5号断点
be * // 启用所有断点
be 1 // 启用1号断点
be 1 2 5 // 启用1号、2号、5号断点
bd * // 禁用所有断点
bd 1 // 禁用1号断点
bd 1 2 5 // 禁用1号、2号、5号断点
bp 7c801b00 // 在7c801b00地址处放置一个断点
bp `ConsoleTest.cpp:36` // 在ConsoleTest.cpp的36行处放置一个断点
bp main // 在main函数的起始处放置一个断点
bp CSecondLoader::CSecondLoader // 在CSecondLoader的构造函数处放置一个断点
bp TestCommon! CTest::add // 在TestCommon.dll的Test.cpp文件的CTest::add()函数起始处放置一个断点
bp `ConsoleTest.cpp:40` ".if (poi(pVar)>5) {}; {g}" // ".if (Condition) {Optional Commands}; {g}" 条件断点 pVar指针指向的值>5,执行空语句(;),断住 否则继续执行
bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) ' '; 'g'"// "j (Condition) 'Optional Commands'; 'g'" j为条件表示式:条件断点 pVar指针指向的值>5,执行空语句(;),断住 否则继续执行
注:Condition表达式语法默认的是MASM表达式语法。使用复杂C++表达式时我们需要用@@c++()将表达式包围住;如:"j @@c++(*pVar>5) ' '; 'g'"
x表示的一个地址
hi(x) 高16 bits
low(x) 低16 bits
by(x) 返回第一个byte
wo(x) 返回第一个word
dwo(x) 返回第一个dword
qwo(x) 返回第一个4 word(Quad-word)
poi(x) 返回第一个指针所指向的值
bp `ConsoleTest.cpp:40` "j @eax = 0xa3 ''; 'g'"// j为条件表示式:条件断点 寄存器eax的值为0xa3时断住
bp kernel32!CreateFileA // 在系统API的CreateFileA函数处放置一个断点
bp kernel32!CreateFileA ".echo;.printf\"CreateFileA(%ma,%p,%p), ret=\",poi(esp+4),dwo(esp+8),dwo(esp+c);gu;.printf\"%N\",eax;.echo;g" // 不断住进程情况下,打印所有的CreateFileA调用
bp advapi32!RegOpenKeyExA ".echo;.printf\"RegOpenKeyExW(%p,\\\"%ma\\\",%N,%N,%p) returned: \", dwo(esp+4), poi(esp+8), dwo(esp+c), dwo(esp+10), dwo(esp+14);gu;.printf\"%N\",eax;.echo;g" // 不断住进程情况下,打印所有的RegOpenKeyExA调用(打开注册表键值)
注意:有些函数Symbol Name与导出函数名可能不一致,例如SetWindowPos,这时可以用Dependency查看相应的导出函数地址(Entry Point列):0x00018E5E,然后在windbg菜单“Debug”—〉“Modules...”对话框中获得user32.dll模块起始地址0x77d10000,在两个值相加后的绝对地址处直接设置断点:bp 77d28E5E;也可以通过x user32!*命令列出全部Symbols列表,查找77d28E5E,找到SetWindowPos对应的Symbol Name为“NtUserSetWindowPos”,然后通过符号设置断点:bp user32!NtUserSetWindowPos。通过符号设置断点的好处是当dll代码改变时,不需要修改,windbg会根据符号来自动匹配函数地址。
bu // 保存断点,其用法和bp一样
bm add_* // 匹配add_开头的函数,并在这些函数起始处都打上断点
ba w4 0x0483dfe0 // 当对0483dfe0地址写操作时停下,前面要带上0x,否则会报错
// ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
## 调试执行控制
g // Go(F5)
gH // 执行gH命令强制让调试器返回已经处理了这个异常。【Go with Exception Handled】
// 系统收到这个回复后会停止分发异常(因为调试器声称已经处理了异常),恢复调试目标继续执行,
// 但由于异常条件仍在,所以还会产生异常,于是再次分发,WinDBG再次中断到命令模式。
gN // 【Go with Exception Not Handled】
// 执行gN命令强制让调试器返回没有处理了这个异常,那么系统会进一步分发该异常,
// 如果没有其他调试器也不处理,最后系统会弹出程序终止对话框。
gu // 执行到当前函数完成时停下 【Go Up】
Ctrl+Break // 暂停正在运行的程序
p // 单步执行(F10) 【Step】
p 2 // 2为步进数目
pc // 执行到下一个函数调用处停下 【Step to Next Call】
pa 7c801b0b // 执行到7c801b0b地址处停下 【Step to Adress】
t // Step into(F11) 【Trace】
tc // 执行到下一个进入点处停下 【Trace to Next Call】
ta 7c801b12 // 执行到7c801b12地址处停下 【Trace to Adress】
## 查看句柄
!handle // 查看所有句柄的ID
!handle 000007f8 1 // 查看ID为000007f8的句柄的类型
!handle 000007f8 4 // 查看ID为000007f8的句柄的名称
!handle 0 5 // 查看所有句柄的类型和名称
## 查看变量
=== 0n(十进制) 0x(十六进制) 0t(8进制) 0y(2进制) 可以使用n [8|10|16]命令来修改数值进制表示方式(输入n可查看当前进制,默认为16进制)===
-- VC6.0的Link选项需要将/pdbtype:sept改为/pdbtype:con, 否则生成的pdb文件中将不包含如自定义结构体,类等信息
dt nRet // 查看局部变量nRet的类型与值(函数参数变量请用dv命令)
dt myApp!g_app // 表示显示myApp进程里全局变量g_app的内存布局(注:vc6见上述说明)
dt WindbgTest!CTest // 查看模块WindbgTest的CTest的内存布局(注:vc6见上述说明)
dt WindbgTest!CTest 0x0041f8d4 // 将0x0041f8d4地址处内容按照模块WindbgTest的CTest的内存布局来解析(注:vc6见上述说明)
Windbg默认会用寄存器ECX里面的值作为this指针地址,其实这样是有时候是错误的。
有些C++编译器在做代码优化之后会把 this指针放在其他寄存器里面,比如ESI。
所以在调试的时候还需要读一下汇编代码来确定this 在哪个寄存器里面。
比如我们看到 MOV EAX, dword ptr [ESI + 0x48h](获取当前对象内存偏移为0x48h处的4字节成员变量),就可以判断ESI 是this 指针。
这时可以通过如下命令打印this的内存结构:dt -b 模块名!类名 @esi
dt this // 查看this指针的类型及成员变量(注:vc6见上述说明)
dt -b this // 查看this指针的类型及成员变量,如果某一成员变量为结构体,则把其结构成员也一一打印出来
dt _PEB @$PEB // 查看PEB(process's environment block)内存结构
?? this->m_nPen // 查看成员变量的值(注:vc6见上述说明)
?? this // 查看this指针中的成员变量(注:vc6见上述说明)
? nCount // 显示局部变量nCount的地址(前面4198608为10进制表示地址,004010d0为16进制表示地址) 形如:Evaluate expression: 4198608 = 004010d0
? HeapTest!CTest::Add // 显示HeapTest模块中CTest类中的Add函数地址
dv // 显示当前函数内所有局部变量,函数参数的值
dv n* // 显示当前函数内n开头的所有局部变量,函数参数的值
dv nCount // 查看局部变量nCount的值
dv a // 查看函数参数变量a的值
dv /t /i /V /a|/n|/z
更加详细地显示当前函数内所有局部变量,函数参数信息
i = type (local, global, parameter)
t = data type
V = memory address or register location
-----------------------
a = sort by Addr, n = sort by name, z = sort by size
x // 用法和dv命令一致,显示当前函数内所有局部变量,函数参数的地址与值
## 调用堆栈
k // 显示当前调用堆栈
kn // 带栈编号显示当前调用堆栈
kb // 打印出前3个函数参数的当前调用堆栈
02a9ffec 00000000 01e511f9 0174c570 00000000 kernel32!BaseThreadStart+0x37
----------------------------------------------
kernel32!BaseThreadStart+0x37 当前函数kernel32!BaseThreadStart执行的指令地址。
01e511f9 0174c570 00000000 参数相关的数值【从左到右 -- 参数1 参数2:offset为sizeof(参数1) 参数3:offset为sizeof(参数1)+sizeof(参数2) ...】。注:如果是成员函数,this指针通过ecx或其他寄存器来传递
02a9ffec 00000000是 ebp 和 上层函数返回地址。======================================================
Windows 7 Ultimate Service Pack 1 [Build 6.1.7601]
CPU: Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
《Game》 20.15.1112 6EF76A43E6B1DD58907F3E066506E918
----------------------------------------
Type: EXCEPTION_ACCESS_VIOLATION//非法地址访问异常
Error: Read address 0x00074685//读取0x00074685地址出错(该地址对应的内存页,进程无读取权限)
Address: 64DCAF68//崩溃发生的指令地址CallStack:
//0x64D90000为模块MSVCR90.dll的基地址,3AF68为崩溃指令在模块中的偏移值,(0492B5D0,00074685,0000000C,00462482)为参数信息
0x64D90000[3AF68] MSVCR90.dll: (0492B5D0,00074685,0000000C,00462482)
0X00400000[11158A] tgame.exe: (0492B5D0,00074685,00000000,00000000)
kb 5 // 只显示最上的5层调用堆栈
kv // 在kb的基础上增加了函数调用约定等信息
kp // 显示每一层函数调用的完整参数,包括参数类型、名字、取值(必须是完整符号的情况下,private symbols);注意:若程序被优化,这些值不一定对
kd // 打印堆栈的地址
.frame // 显示当前栈帧
.frame n // 设置编号n的栈帧为当前栈帧(n为16进制数)
.frame /r n // 设置编号n的栈帧为当前栈帧(n为16进制数) 并显示寄存器变量
!uniqstack // 显示所有线程的调用堆栈
## 查看汇编
u . // 反汇编当前ip寄存器地址的后8条指令
u $ip // 反汇编当前ip寄存器地址的后8条指令
ub . // 反汇编当前ip寄存器地址的前8条指令
ub $ip // 反汇编当前ip寄存器地址的前8条指令
u main+0x29 L30 // 反汇编main+0x29地址的后30条指令
u // 反编译下8条指令
uf CTest::add // 反汇编CTest类的add函数
uf /c main // 反汇编main函数,通过/c可以查看main函数中的函数调用(call)都有哪些
ub 000c135d L20 // 查看地址为000c135d指令前的20条指令内容
## 寄存器
r // 显示所有寄存器信息及发生core所在的指令
r eax, edx // 显示eax,edx寄存器信息
r eax=5, edx=6 // 对寄存器eax赋值为5,edx赋值为6
## 内存
!address 7ffd8000 // 查看7ffd8000地址处内存页属性
dd /c 5 7c801e02 // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)【默认显示128字节长度的内容】
dd /c 5 7c801e02 L8 // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)【显示8个dword】
da /c 100 7c80ff03 // 从7c80ff03内存处开始显示Ascii字符串(宽度为:100)
du /c 100 7c8022f5 // 从7c8022f5内存处开始显示Unicode字符串(宽度为:100)
/*****************************************
d[a| u| b| w| W| d| c| q| f| D] [/c 列数] [地址]
a = ascii chars
u = Unicode chars
b = byte + ascii
w = word (2b)
W = word (2b) + ascii
d = dword (4b)
c = dword (4b) + ascii
q = qword (8b)
f = floating point (single precision - 4b)
D = floating point (double precision - 8b)*****************************************/
dyb /c 3 7c801e02 // 从7c801e02内存处开始,显示byte及二进制(宽度为:3)
/*****************************************
dy[b | d] .. // b = binary+byte d = binary+dword
*****************************************/
s -w 522e0000 L0x100 0x1212 0x2212 0x1234 // 表示在起始地址522e0000之后的0x100个单位内搜索0x1212 0x2212 0x1234系列的起始地址
s -u 522e0000 527d1000 "web" //表示在522e0000 和527d1000之间搜索Unicode 字符串”web”
ea 0x445634 "abc" // 表示在0x445634地址写入Ascii字符串abc, 不包含结束符0
eza 0x445634 "abc" // 表示在0x445634地址写入Ascii字符串abc, 包含结束符0
eu 0x445634 "abc" // 表示在0x445634地址写入Unicode字符串abc, 不包含结束符0
ezu 0x445634 "abc" // 表示在0x445634地址写入Unicode字符串abc, 包含结束符0
ed nCounter 80 // 将变量nCounter的值修改为80(注:80为10进制还是16进制,还是其他,取决于当前进制)
## 查看堆(Heap)
!heap -s // 显示进程堆的个数(每一项是一个堆,也就是_HEAP结构指针,对应的API是HeapCreate)
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
00140000 50000062 1024 12 12 1 1 1 0 0 L
00240000 50001062 64 24 24 15 1 1 0 0 L
00250000 50008060 64 12 12 10 1 1 0 0
00380000 50001063 64 12 12 4 2 1 0 bad
-----------------------------------------------------------------------------
dt _HEAP 00140000 // 选取一个堆的地址,打印该堆的内存结构
ntdll!_HEAP
+0x000 Entry : _HEAP_ENTRY
+0x008 Signature : 0xeeffeeff
+0x00c Flags : 0x50000062
+0x010 ForceFlags : 0x40000060
+0x014 VirtualMemoryThreshold : 0xfe00
+0x018 SegmentReserve : 0x100000
+0x01c SegmentCommit : 0x2000
+0x020 DeCommitFreeBlockThreshold : 0x200
+0x024 DeCommitTotalFreeThreshold : 0x2000
+0x028 TotalFreeSize : 0xaf
+0x02c MaximumAllocationSize : 0x7ffdefff
+0x030 ProcessHeapsListIndex : 1
+0x032 HeaderValidateLength : 0x608
+0x034 HeaderValidateCopy : (null)
+0x038 NextAvailableTagIndex : 0
+0x03a MaximumTagIndex : 0
+0x03c TagEntries : (null)
+0x040 UCRSegments : (null)
+0x044 UnusedUnCommittedRanges : 0x00140598 _HEAP_UNCOMMMTTED_RANGE
+0x048 AlignRound : 0x17
+0x04c AlignMask : 0xfffffff8
+0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0x140050 - 0x140050 ]
+0x058 Segments : [64] 0x00140640 _HEAP_SEGMENT
+0x158 u : __unnamed
+0x168 u2 : __unnamed
+0x16a AllocatorBackTraceIndex : 0
+0x16c NonDedicatedListLength : 1
+0x170 LargeBlocksIndex : (null)
+0x174 PseudoTagEntries : (null)
+0x178 FreeLists : [128] _LIST_ENTRY [ 0x142a90 - 0x142a90 ]
+0x578 LockVariable : 0x00140608 _HEAP_LOCK
+0x57c CommitRoutine : (null)
+0x580 FrontEndHeap : 0x00140688 Void
+0x584 FrontHeapLockCount : 0
+0x586 FrontEndHeapType : 0x1 ''
+0x587 LastSegmentIndex : 0 ''
!heap -a 00140000 // 选取一个堆的地址,打印该堆的信息,比上面打印内存命令更详细直观
Index Address Name Debugging options enabled
1: 00140000
Segment at 00140000 to 00240000 (00003000 bytes committed)
Flags: 50000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 000000af
Max. Allocation Size: 7ffdefff
Lock Variable at: 00140608
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 00140050
UCR FreeList: 00140598
FreeList Usage: 00000000 00000000 00000000 00000000
FreeList[ 00 ] at 00140178: 00142a90 . 00142a90
00142a88: 00050 . 00578 [14] - free
Segment00 at 00140640:
Flags: 00000000
Base: 00140000
First Entry: 00140680
Last Entry: 00240000
Total Pages: 00000100
Total UnCommit: 000000fd
Largest UnCommit:000fd000
UnCommitted Ranges: (1)
00143000: 000fd000Heap entries for Segment00 in Heap 00140000
00140000: 00000 . 00640 [01] - busy (640)
00140640: 00640 . 00040 [01] - busy (40)
00140680: 00040 . 01818 [07] - busy (1800), tail fill - unable to read heap entry extra at 00141e90
00141e98: 01818 . 00040 [07] - busy (22), tail fill - unable to read heap entry extra at 00141ed0
00141ed8: 00040 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00141f20
00141f28: 00050 . 002f0 [07] - busy (2d8), tail fill - unable to read heap entry extra at 00142210
00142218: 002f0 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142540
00142548: 00330 . 00330 [07] - busy (314), tail fill - unable to read heap entry extra at 00142870
00142878: 00330 . 00040 [07] - busy (24), tail fill - unable to read heap entry extra at 001428b0
001428b8: 00040 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 001428d8
001428e0: 00028 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142930
00142938: 00058 . 00058 [07] - busy (40), tail fill - unable to read heap entry extra at 00142988
00142990: 00058 . 00060 [07] - busy (44), tail fill - unable to read heap entry extra at 001429e8
001429f0: 00060 . 00020 [07] - busy (1), tail fill - unable to read heap entry extra at 00142a08
00142a10: 00020 . 00028 [07] - busy (10), tail fill - unable to read heap entry extra at 00142a30
00142a38: 00028 . 00050 [07] - busy (36), tail fill - unable to read heap entry extra at 00142a80
00142a88: 00050 . 00578 [14] free fill
00143000: 000fd000 - uncommitted bytes.
## 虚拟内存
!vadump // 查看虚拟内存布局
## 设置事件发生时windbg行为
sx // 显示windbg遇到每个异常和事件时的行为
sxr // 将所有异常和事件过滤器的状态重设为默认值
sxe ld // 当加载模块时,立即中断(Break)到调试器中(第一次处理机会)
sxe ud // 当卸载模块时,windbg不会在第一次处理机会时中断(虽然会显示信息)。如果其他错误处理器没有处理掉该异常,执行会停止下来并中断(Break)到windbg中(第二次处理机会)
sxn et // 当线程退出时,windbg会打印出一条消息
sxi ct // 当线程创建时,windbg不中断也不打印消息
## dump输出
.dump /ma "d:\mydmpfile.dmp" // 将当前调试进程输出Dump文件
## 其他元命令
.tlist // 显示所有进程
.cls // 清除屏幕
.logopen c:\1.log // 将command内容输出到c:\1.log文件中
## 其他扩展命令
!analyze -v // 详细显示当前异常信息
!peb // 格式化输出PEB信息(process's environment block)
PEB at 7efde000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: No
ImageBaseAddress: 00f20000
Ldr 76fa0200
Ldr.Initialized: Yes
Ldr.InInitializationOrderModuleList: 003a4d78 . 003e4a00
Ldr.InLoadOrderModuleList: 003a4ce8 . 003e49f0
Ldr.InMemoryOrderModuleList: 003a4cf0 . 003e49f8
Base TimeStamp Module
f20000 54772f74 Nov 27 22:04:36 2014 C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe
76ea0000 5684255b Dec 31 02:41:31 2015 C:\windows\SysWOW64\ntdll.dll
74790000 568425ff Dec 31 02:44:15 2015 C:\windows\syswow64\kernel32.dll
75b00000 56842600 Dec 31 02:44:16 2015 C:\windows\syswow64\KERNELBASE.dll
... ...
71d40000 55a5cad6 Jul 15 10:52:06 2015 C:\windows\System32\msxml6.dll
71d20000 4a5bdb38 Jul 14 09:11:20 2009 C:\windows\System32\bcrypt.dll
71ce0000 5600ce51 Sep 22 11:43:13 2015 C:\windows\SysWOW64\bcryptprimitives.dll
SubSystemData: 00000000
ProcessHeap: 003a0000
ProcessParameters: 003a2188
CurrentDirectory: 'C:\windows\system32\'
WindowTitle: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe"'
ImageFile: 'C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe'
CommandLine: '"C:\Program Files (x86)\Citrix\ICA Client\wfcrun32.exe" -Embedding'
DllPath: 'C:\Program Files (x86)\Citrix\ICA Client;C:\windows\system32;C:\windows\system;C:\windows;
Environment: 003a07f0
=::=::\
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\kekec\AppData\Roaming
CommonProgramFiles=C:\Program Files (x86)\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=KEKEC-PC1
ComSpec=C:\windows\system32\cmd.exe
DXSDK_DIR=D:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\kekec
include=D:\Program Files (x86)\Microsoft Visual Studio\VC98\atl\include;D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\include;
lib=D:\Program Files (x86)\Microsoft Visual Studio\VC98\mfc\lib;D:\Program Files (x86)\Microsoft Visual Studio\VC98\lib
LOCALAPPDATA=C:\Users\kekec\AppData\Local
LOGONSERVER=\\GM-HEIJI
MSDevDir=D:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
Path=C:\ProgramData\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_ARCHITEW6432=AMD64
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=3c03
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files (x86)
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PSModulePath=C:\windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\windows
TEMP=C:\Users\kekec\AppData\Local\Temp
TMP=C:\Users\kekec\AppData\Local\Temp
USERDNSDOMAIN=TENCENT.COM
USERDOMAIN=TENCENT
USERNAME=kekec
USERPROFILE=C:\Users\kekec
VS120COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\
VS80COMNTOOLS=D:\Program Files (x86)\Microsoft Visual Studio 8\Common7\Tools\
VS90COMNTOOLS=d:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
windir=C:\windows
!gle // 打印当前线程最近的错误信息LastError
!gle -all // 打印所有线程的最近的错误信息
!error 897// 显示错误码为897的详细描述信息
## 帮助
查看某条命令的详细说明,可以查看windbg自带的帮助文档,可以在windbg命令行输入:.hh + 命令名。也可以点击Windbg菜单栏中的Help->Index,打开chm格式的帮助文档,如下所示:
在左边的输入框中输入要查看的命令,会模糊匹配到相关的命令。双击要查看的命令,右边就会显示该命令的详细说明页面。