.NET 调试入门(三)常用的命令
windbg ANSI Command Tree 1.0
title {"Crash Dump Analysis Checklist"}
body
{"Crash Dump Analysis Checklist"}
{"General"}
{"Versions and locations"} {"version"}
{"Set longer stack trace"} {".kframes 100"}
{"Application crash or hang"}
{"Default analysis (crash)"} {"!analyze -v"}
{"Default analysis (hang)"} {"!analyze -v -hang"}
{"Switch to x86 architecture"} {".load wow64exts; .effmach x86"}
{"Critical sections (locked)"} {"!locks"}
{"Modules"} {"lmv"}
{"Threads (all)"} {"~*kv 250"}
{"Threads (unique)"} {"!uniqstack"}
{"Gflags"} {"!gflag"}
{"Time consumed by thread"} {"!runaway"}
{"PEB"} {"!peb"}
{"TEB"} {"!teb"}
{"Hooked functions (ntdll)"} {"!chkimg -lo 50 -d !ntdll -v"}
{"Hooked functions (kernel32)"} {"!chkimg -lo 50 -d !kernel32 -v"}
{"Hooked functions (user32)"} {"!chkimg -lo 50 -d !user32 -v"}
{"Hooked functions (ALL)"} {"!for_each_module !chkimg -lo 50 -d !${@#ModuleName} -v"}
{"Exception handlers"} {"!exchain"}
{"Computer name"} {"!envvar COMPUTERNAME"}
{"Stack of exception thread"} {"~#kv 250"}
{"Stack of current thread"} {"~.kv 250"}
{"Switch to thread"}
{"#0"} {"~0s"}
{"#1"} {"~1s"}
{"#2"} {"~2s"}
{"#3"} {"~3s"}
{"#4"} {"~4s"}
{"#5"} {"~5s"}
{"#6"} {"~6s"}
{"#7"} {"~7s"}
{"#8"} {"~8s"}
{"#9"} {"~9s"}
{"System hang"}
{"Default analysis"} {"!analyze -v -hang"}
{"ERESOURCE contention"} {"!locks"}
{"Processes and virtual memory"} {"!vm 4"}
{"Sorted pool consumption (paged)"} {"!poolused 4"}
{"Sorted pool consumption (nonpaged)"} {"!poolused 3"}
{"Waiting threads"} {"!stacks"}
{"Critical system queues"} {"!exqueue f"}
{"I/O"} {"!irpfind"}
{"The list of all thread stack traces"} {"!process 0 ff"}
{"Critical sections for current process"} {"!ntsdexts.locks"}
{"Sessions"} {"!session"}
{"Processes"} {"!process 0 0"}
{"Running threads"} {"!running"}
{"Ready threads"} {"!ready"}
{"DPC queues"} {"!dpcs"}
{"The list of APCs"} {"!apc"}
{"Internal queued spinlocks"} {"!qlocks"}
{"Computer name"} {"dS srv!srvcomputername"}
{"Switch to processor"}
{"#0"} {"~0s"}
{"#1"} {"~1s"}
{"#2"} {"~2s"}
{"#3"} {"~3s"}
{"#4"} {"~4s"}
{"#5"} {"~5s"}
{"#6"} {"~6s"}
{"#7"} {"~7s"}
{"BSOD"}
{"Default analysis"} {"!analyze -v"}
{"Processes and virtual memory"} {"!vm 4"}
{"Bugcheck callback data (prior to Windows XP SP1)"} {"!bugdump"}
{"Bugcheck secondary callback data"} {".enumtag"}
{"Computer name"} {"dS srv!srvcomputername"}
以上内容另存为.wl 文件就可以放到WinDbg安装目录中,就可以在Windbg命令行中输入.cmdtree **.wl 就可以打开该命令窗口了。
{".NET 常用命令"}
{"!threads 显示所有线程"} {"!threads"}
{"!eeheap -gc 查看托管堆的总信息"} {"!eeheap -gc"}
{"!dumpheap -min 200 -stat 获取占用堆内存的各对象的统计信息"} {"!dumpheap -min 200 -stat"}
{"!dumpheap -type Byte[] -min 200 看各Byte数组占用堆内存的详细信息"} {""}
{"!dumpheap 显示托管堆的信息"} {"!dumpheap"}
{"!gcroot <对象地址> 看对象引用关系"} {""}
{"!dumpobj(!do) <对象地址> 显示一个对象的内容"} {"!do"}
{"!dumparray 显示数组"} {"!dumparray"}
{"!syncblk 查看哪些线程拿到了锁"} {"!syncblk"}
{"!runaway 显示线程cpu时间"} {"!runaway"}
{"!threadpool 查看Cpu占用率"} {"!threadpool "}
{"!runaway 看线程的执行时间"} {"!runaway"}
{".time看进程运行了多长时间"} {".time"}
{"!~'*' s切换线程 ‘*’表示那个线程"} {""}
{"!clrstack 显示调用栈"} {"!clrstack "}
{"!dso 查看当前堆栈的所有对象"} {"!dso"}
{"!analyze -v 分析挂掉线程的详细情形,错误原因"} {"!analyze -v"}
{"~*e!clrstack 查看所有持有和等待锁的线程"} {"~*e!clrstack"}
{".NET 常用命令"}
{".load psscor2\amd64\psscor2.dll; load sos.dll"} {".load psscor2\amd64\psscor2.dll"}
{"!threads 显示所有线程"} {"!threads"}
{"!eeheap -gc 查看托管堆的总信息"} {"!eeheap -gc"}
{"!dumpheap -min 200 -stat 获取占用堆内存的各对象的统计信息"} {"!dumpheap -min 200 -stat"}
{"!dumpheap -type Byte[] -min 200 看各Byte数组占用堆内存的详细信息"} {""}
{"!dumpheap 显示托管堆的信息"} {"!dumpheap"}
{"!gcroot <对象地址> 看对象引用关系"} {""}
{"!dumpobj(!do) <对象地址> 显示一个对象的内容"} {"!do"}
{"!dumpvc <方法表地址> <值类型地址>; 导出值类型对象"}
{"!dumparray 显示数组"} {"!dumparray"}
{"!dumpdomain; 显示所有应用程序域"} {"!dumpdomain"}
{"!syncblk 查看哪些线程拿到了锁"} {"!syncblk"}
{"!runaway 显示线程cpu时间"} {"!runaway"}
{"!threadpool 查看Cpu占用率"} {"!threadpool "}
{"!runaway 看线程的执行时间"} {"!runaway"}
{".time看进程运行了多长时间"} {".time"}
{"!~'*' s切换线程 ‘*’表示那个线程"} {""}
{"!clrstack 显示调用栈"} {"!clrstack "}
{"!dso 查看当前堆栈的所有对象"} {"!dso"}
{"!analyze -v 分析挂掉线程的详细情形,错误原因"} {"!analyze -v"}
{"~*e!clrstack 查看所有持有和等待锁的线程"} {"~*e!clrstack"}
{"!eeversion 查看SOS版本"} {"!eeversion"}
!syncblk 查看同步块表的信息
dd 将内容转储出来(用于查看内存的内容)。
"dd 值类型数组地址,其结构为:{方法表地址}{数组维度} {数组的内容}" 注:在64位win7系统中,方法表、数组维度的地址的循序是反的,如:f953edc8 000007fe,00000005 00000000 真实的结果是:000007fef9141fb8,0000000000000005
"dd 引用类型数组地址,其结构为:{方法表地址}{数组维度}{数组元素的方法表}{数组的内容},在64位win7系统中,地址顺序同样是反的。
du 会把转储出来的内容视为Unicode字符
da 会把转储出来的内容视为ACSII字符
dw 会把转储出来的内容视为字(Word)
db 会把转储出来的内容视为字节值和ACSII字符
dq 会把转储出来的内容视为四字(quad Word)值
dds <代码地址> 查看这个地址是什么函数,显示函数名
lmvm <加载的DLL名,如clr、mscorwks> 显示加载DLL的详细信息
kb 用于输出异常的调用栈
!pe <地址>:得到改异常的详细描述,如异常消息等(注:改地址怎么来,1,通过调用kb得到异常的调用栈。2,找到调用栈的“mscorwks!RaiseTheExceptionInternalOnly”异常节点,取他的第一个地址如:
“000007fe`f9e52460 : 00000000`0268aa30 00000000`00000000 00000000`00000000 00000000`00000001 : mscorwks!RaiseTheExceptionInternalOnly+0x2ff”
异常地址就是:“0268aa30”
)
~*kn:显示进程中所有线程的回溯,包含栈帧的编号。
!PrintException <异常地址>
000007fe`fa822460 : 00000000`0269c330 00000000`00000000 00000000`00000000 00000000`00000001 : mscorwks!RaiseTheExceptionInternalOnly+0x2ff
异常地址要看RaiseTheExceptionInternalOnly,这个异常地址就为0269c330
!Threads 可以显示所有托管线程的信息,并能显示出各线程的最后一个异常。包括异常地址
!threads -live 显示处于活跃状态的线程
!threads -special:输出进程中所有“特殊的”线程,如,垃圾回收线程,调试器线程,线程池定时线程
!u <代码地址> 反汇编
!U <代码地址> 反汇编并带有托管代码
!ip2md <代码地址>:将托管代码地址转换为一种方法描述符
SOSEX命令:
!bpsc 推荐用 !mbp <.CS 文件名> <行号> "设置断点"
!bpmd <执行的EXE或DLL> <方法名> 在某个方法中设置断点
!mbm 在IL代码中设置断点
!mbl 显示所有设置断点列表
!mbc 从列表中清除指定断点,或清除所有断点
!mbd 禁用列表中指定断点,或禁用所有断点
!mbe 启用列表中的指定断点,或启用所有断点
!mx <查询字符串> :快速找出相应的元数据,如,类型名、方法名
!mln <地址>:可以识别出该地址上内容相关的托管代码
!mk:显示托管、非托管代码的栈帧外,还能显示栈帧的编号
!mdv <栈帧编号> 显示栈帧的局部变量
!mdv -w:显示所有调用栈 的参数和局部变量。
!mdt <地址> (显示包括[typename|paramname|localname|mt|addr]) :他可以显示托管代码的局部变量,全局变量,或某个数据类型的信息
!mdt <地址> -r 递归显示所有嵌套对象的MDT,并输出相应的值
!dlk :找到那些线程可能发生死锁的过程的详细信息
!gcgen <托管堆上的对象地址> :显示该对象所属的代
!dumpgen <第*代>:显示参考中第*代有那些对象
!strings [-g|-m|-n|-x]:搜索托管堆上的任意字符串
!strings -m:<查询字符串> 可以用通配符*
-g:在指定代中搜索
-n:字符串的最小长度
-x:字符串的最大长度
------------------------------------------------------
bp <地址>:在非托管代码中设置断点.
!dumpmt -md <地址> 得到指定方法表的描述符(就是该类有那些方法)
lm 用来加载完程序的其它模块(相当DLL)
ln<地址> 查看该地址能否被解析为代码
.load sosex_64\sosex.dll
.load psscor2\amd64\psscor2.dll
.loadby sos.dll mscorwks
.dump 生成dump文件
.dump /ma <文件路径>
ntsd.exe -p <进程ID> 调试一个在运行的进程
ntsd.exe -g <调试程序路径> -g表示不希望调试器在初始启用时停止程序的执行。
ntsd.exe -G <调试程序路径> -G每当调试目标准备退出时,调试器也将停止执行。
ntsd.exe -z <dump文件>:调试一个dump文件
类型句柄指向的是某个类型的方法表
--------------------------------------------------
.sympath <符号文件路径>
.symfix 将符号路径自动设置为Microsoft公用的符号服务器。 加载符号
.reload 找到进程地址空间所有已加载的模块,并尝试找出各模块相关的符号文件。
Ctrl+C 中断执行
g 恢复执行
p(step)和t(trace) 单步调试
pc 重复执行所有指令
pt 会一直执行指令,直到遇到一个ret指令
ta <address>:执行到address指定的地址,并且将包含被调用函数的单步执行显示出来。
tc:执行到下一个call指令,并且将包含被调用函数的单步执行显示出来。
tt:执行到下一个ret指定, 并且将包含被调用函数的单步执行显示出来。
r 将寄存器转储出来 ->esp、rsp:保存的是当前栈指针
k[参数]:显示非托管调用栈信息
kn:显示非托管代码调用栈信息
!ClrStack :显示托管代码调用栈信息
!clrstack -l 显示局部变量信息
!clrstack -p 显示参数信息
!clrstack -a 合并显示局部变量和参数信息
!dumpstack: 同时显示托管代码、非托管代码调用栈信息
!dumpstack -ee:只显示托管代码的调用栈信息
!eestack:显示所有托管线程的调用栈
q:结束调度会话并终止调试目标。
qd(quit and detach):结束调试会话,但让调试目标继续运行。
.loadby <DLL名字> <模块名字>
sxe ld <加载的DLL mscorwkds.dll>:当加载完该DLL后,调试器停止等待用户加载其它DLL
sxe clr 告诉调试器在所有托管异常上都停止执行
.cordll:在事后调试可能出现mscorwks.dll与mscordacwks.dll的版本不匹配造成不正确调试,可以使用此命令。
.cordll -lp <mscordacwks.dll 的路径>:-lp 是用于指定mscordacwks.dll的新路径。
.cordll -u <mscordacwks.dll 的路径>:-lp 是用于卸载mscordacwks.dll。
!name2ee <模块名字> <类型或方法名> 检查函数是否已经被JIT编译器编译,找出类型、方法的描述符
!do: dump出引用类型的值。
!do -nofields 只显示内容不会显字符串类型中的各个域
!da(!DumpArray)[-start <数组那个索引开始>] [-length<显示数组多少个元素>] [-details] [-nofields] 数据地址
[-details] 显示数组的详细信息,包括具体值。
[-nofields] 只显示内容不会显字符串类型中的各个域
dump 出栈上的对象:
!DumpStackObjects [-verify] [top stack [bottom stack]]
-verify 表示对每天托管对象进行一次验证过程
!dumpheap:dump堆中的所有对象
!dumpheap -type <类型,包括命名空间> :dump堆中的指定对象
!dumpheap -mt <方法表地址> :dump堆中的指定对象
!dumpheap -min <最小内存大小> :dump堆中大于指定内存的对象
!dumpheap -startAtLowerBound <开始地址> 显示该地址块中有那些对象。
!dumpheap -thinlock:查看堆上所有瘦锁对象
!dumpheap -stat 统计堆中各对象的个数,类型于sql中的group by
!ObjSize <对象的地址> 找到对象的大小
!eeversion 显示.net 版本和SOS版本信息
!eeheap -gc: 查看托管堆的总信息,包括各代的起始地址
!FinalizeQueue:查看进程中可以终结的对象
!syncblk:它将输出某个线程中所有对象的同步块,查看哪些线程拿到了锁
如何找出某个对象的同步块索引?
对象指针指向的是类型句柄域,然后才是实际的对象数据,类型句柄前的4个字节同样是内存布局的一部分,其中包含了对象的对象头。
如何得到对象头的索引?
通过dd将对象的地址(指针)减去4个字节即可
对象头的位掩码如果是“0x08000000”表示一个正在处理一个同步块索引
C:\Users\ADMINI~1\AppData\Local\Temp\MyTools (2).DMP
C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
C:\Windows\System32\mscoree.dll
出处: http://www.cnblogs.com/jiguixin
我的新浪微博: http://weibo.com/jiguixin
本文版权归【吉桂昕】和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。