如何手工抓取dump文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何手工抓取dump文件相关的知识,希望对你有一定的参考价值。

在生产环境下进行故障诊断时,为了不终止正在运行的服务或应用程序,有两种方式可以对正在运行的服务或应用程序的进程进行分析和调试。
首先一种比较直观简洁的方式就是用WinDbg等调试器直接attach到需要调试的进程,调试完毕之后再detach即可。但是这种方式有个缺点就是执行debugger命令时必须先break这个进程,执行完debug命令之后又得赶紧F5让他继续运行,因为被你break住的时候意味着整个进程也已经被你挂起。另外也经常会由于First Chance Excetpion而自动break,你得时刻留意避免长时间break整个进程。所以这样的调试方式对时间是个很大的考验,往往没有充裕的时间来做仔细分析。
另一种方式则是在出现问题的时候,比如CPU持续长时间100%,内存突然暴涨等非正常情况下,通过对服务进程snapshot抓取一个dump文件,完成dump之后先deatch,让进程继续运行。然后用windbg等工具来分析这个抓取到的dump文件。
那么如何在不终止进程的情况下抓取dump文件呢?Debugging Tools for Windows里提供了一个非常好的工具,adplus.vbs。从名字可以看出,实际上是一个vb脚本,只是对cdb调试器作的一个包装脚本。
其路径与Debugging Tools for Windows的安装路径相同,使用的方法也很简单,如下所示:
adplus.vbs -hang -p 1234 -o d:/dump
其中-hang指明使用hang模式,亦即在进程运行过程中附加上去snapshot抓取一个dump文件,完成之后detach。与之对应的是-crash崩溃模式,用户先启动adplus,然后由它启动要监控的程序,在出现异常崩溃时自动生成dump文件,或者通过Ctrl-C人为发出抓取指令。但是-crash模式在抓取完成之后,被监控的进程就必须终止。因此我们在这里只选用-hang模式。
-p是要调试的进程ID,比如ASP.NET应用线程池,在Win2003下就是w3wp.exe
-o 指定要output的dump文件路径。
另外,与adplus类似的,有个UserDump工具,但是抓取用户模式的进程,而adplus则是内核模式和用户模式两者皆可。
而总所周至的Dr. Waston,则会在进程崩溃之后的自动时候抓取dump文件,一样可以用于windbg等调试器来事后分析程序崩溃时的状态。
====================
0:000> !dumpheap -stat
No export dumpheap found
======解决方法:
.load clr20/sos.dll,你要先执行的。sos.dll在默认的c:/windows/microsoft.net/framework/v2.....下面,你复制到c:/program files/debugging tools for windows下面的clr20目录下面(clr20是你手工创建的)
=======================

在.NET下开发时,最基本的调试方法就是使用Visual Studio的单步调试。但是对于一些特殊情况,特别是涉及到CLR内部的时候使用这种方式就达不到目的了。
如果要查看运行时内存使用情况,IL代码,CLR信息等可以使用以下两种方式:
1、使用VS2005 + sos.dll
2、使用Windbg + sos.dll
第二种方式功能更加强大,下面我就通过实际操作展示一下怎么使用这种方法得到运行时ArrayList内部的值。
有人可能会说:我直接用Visual Studio的单步调试岂不是更快?当然,这个只是一个演示,通过这个演示是为以后的高级调试打下基础

在操作之前,先熟悉一下基本知识:
A、使用VS2005 + sos.dll调试
1、需要在项目->属性->调试-〉启用非托管代码调试
2、打开调试-〉窗口-〉即时
3、在即时窗口中输入 !load sos 加载调试模块
4、输入其它调试语句

B、使用Windbg + sos.dll
1、去微软的网站下载最新的Windbg
2、打开Windbg在File-〉Symbol File Path ...窗口中输入 srv*c:/symbols*http://msdl.microsoft.com/download/symbols
3、运行需要调试的程序,然后在Windbg中File-〉Attach to Process中选择刚才运行的程序
4、在出现的Command窗口中就可以输入调试语句
5、常用调试语句:
lm //查看加载了哪些模块
.load C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/sos.dll //加载调试模块
ld TestClass //加载调试符号
!name2ee TestClass.exe TestClass.Program.test //显示test方法相关的地址
!dumpmt -md 00976d48 //得到类的成员函数详细信息
!dumpil 00973028 // 显示这个方法被编译器编译之后的IL代码
!dumpheap -stat //该命令显示程序中所有对象的统计信息,显示的大小是对象本身的大小,不包括对象里面值的大小
!dumpheap -mt 790fcb30 //该命令显示MethodTable 790fcb30的详细信息
!gcroot 012919b8 //来显示一个实例的所属关系
!dumpobj(do) 012a3904 //显示一个对象的具体内容,看对象里面有什么,值是什么
!ObjSize 012a1ba4 //对象实际在内存中的大小
!eeheap -gc //查看托管堆的情况(包括大小)
!DumpArray //查看数组信息
下面就来看看具体的调试步骤:
1、我们的测试代码

namespace TestClass

class Program

[STAThread]
static void Main(string[] args)

ArrayList list = new ArrayList();
list.Add("aaaa");
list.Add("bbbb");
Console.ReadLine();


很简单,就是一个ArrayList

运行这个程序(开始执行,不调试),然后进入Windbg,Attach到这个进程

2、查看所有堆栈信息
0:004> !dumpheap -stat
MT Count TotalSize Class Name
7910062c 1 12 System.Security.Permissions.SecurityPermission
7918e284 1 16 System.IO.TextReader+SyncTextReader
79102d10 1 20 Microsoft.Win32.SafeHandles.SafeFileMappingHandle
79102cb4 1 20 Microsoft.Win32.SafeHandles.SafeViewOfFileHandle
79101d30 1 20 System.Text.InternalEncoderBestFitFallback
79100a7c 1 20 Microsoft.Win32.SafeHandles.SafeFileHandle
79105cd4 1 24 System.Collections.ArrayList
......
7912ad90 11 9036 System.Object[]
790fcb30 2083 131492 System.String
Total 2202 objects
除了我们的ArrayList外,还有很多其它的系统信息,先不用管它

3、查看我们的ArrayList的信息
0:004> !dumpheap -mt 79105cd4
Address MT Size
012a1b88 79105cd4 24
total 1 objects
Statistics:
MT Count TotalSize Class Name
79105cd4 1 24 System.Collections.ArrayList
Total 1 objects

4、查看对应地址内部实际的值
0:004> !do 012a1b88
Name: System.Collections.ArrayList
MethodTable: 79105cd4
EEClass: 79105c28
Size: 24(0x18) bytes
(C:/WINDOWS/assembly/GAC_32/mscorlib/2.0.0.0__b77a5c561934e089/mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
7912ad90 40008df 4 System.Object[] 0 instance 012a1bb0 _items
791018e0 40008e0 c System.Int32 1 instance 2 _size
791018e0 40008e1 10 System.Int32 1 instance 2 _version
790fc35c 40008e2 8 System.Object 0 instance 00000000 _syncRoot
7912ad90 40008e3 1c0 System.Object[] 0 shared static emptyArray
>> Domain:Value 00149c58:012a1ba0 <<
可以看到ArrayList的大小为2,具体的值保存在地址012a1bb0中,是一个System.Object[]类型的数组

5、查看数组信息
0:004> !DumpArray 012a1bb0
Name: System.Object[]
MethodTable: 7912ad90
EEClass: 7912b304
Size: 32(0x20) bytes
Array: Rank 1, Number of elements 4, Type CLASS
Element Methodtable: 790fc35c
[0] 012a1b50
[1] 012a1b6c
[2] null
[3] null

6、查看数组内对象的值
0:004> !do 012a1b50
Name: System.String
MethodTable: 790fcb30
EEClass: 790fca90
Size: 26(0x1a) bytes
(C:/WINDOWS/assembly/GAC_32/mscorlib/2.0.0.0__b77a5c561934e089/mscorlib.dll)
String: aaaa
Fields:
MT Field Offset Type VT Attr Value Name
791018e0 4000096 4 System.Int32 1 instance 5 m_arrayLength
791018e0 4000097 8 System.Int32 1 instance 4 m_stringLength
790fe534 4000098 c System.Char 1 instance 61 m_firstChar
790fcb30 4000099 10 System.String 0 shared static Empty
>> Domain:Value 00149c58:790d81bc <<
7912b1d8 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 00149c58:012a16f0 <<
====================
windbg使用小总结
【抓dump】
1、一般抓法
adplus -hang -p 3230 -quiet 抓3230 pid进程,hang模式,相当于把那个进程暂停住,取内存快照
adplus -crash -pn w3wp -quiet 抓w3wp进程,crash模式,当那个进程崩溃结束的时候自动抓取当时的内存
adplus -hang -iis -quiet 抓IIS相关进程,包括其上host的web应用,以及iis自身
2、抓window服务
http://support.microsoft.com/kb/824344/zh-cn
3、远程抓
http://blog.joycode.com/tingwang/archive/2006/08/11/79763.aspx
4、抓蓝屏和死机的dump
电脑无故重启或者蓝屏会在C:/WINDOWS/Minidump/下保存一个minidump,但是这个minidump可用的命令很少,一般只打!analyze –v看到是哪个进程引起的,还有相关的驱动模块就基本定位问题了。
5、IIS回收的时候抓
http://blog.yesky.com/blog/omakey/archive/2006/12/17/1618015.html
6、计划任务抓
比如一个进程起来后不知道它什么时候会意外崩溃,可以在计划任务里用crash里抓,当那个进程意外终止的时候,cdb可以直接附加上去,抓取当时的dump,如果要抓一些会自动重启的进程,而且要抓每次重启前的dump,可以参考附录里一节。
【常用命令】
1、先path C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727,把.net路径设置为path环境变量,一遍在windbg里可以直接.load sos,而不必.load C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/sos.dll
2、ld demo,加载你程序的pdb文件,调试.net程序一般要把kernel32和mscorwks的符号加载上,关于这两个东西大家可以查资料,尤其是后者有哪些函数可以多了解一些。
3、在windbg的file/symbol file path对话框里输入以下文字,以便自动加载和下载符号
C:/WINDOWS/Symbols;d:/Program Files/Microsoft Visual Studio 8/SDK/v2.0/symbols;.sympath SRV*d:/localsymbols*http://msdl.microsoft.com/download/symbols
其中有windows、.net2.0和自动从网上下载的调试符号,注意根据自己的情况适当修改目录
【调试死锁】
1、!syncblk,查看哪些线程拿到了锁
2、~67e!clrstack 跳到某个拿到锁的线程看它正在干什么操作,迟迟不肯释放锁
3、!runaway 查看这个占有锁的线程运行了多长时间。
4、~*e!clrstack查看所有线程的托管堆栈,看看哪些是正在等待锁的,比如hang在System.Threading.Monitor.Enter(System.Object)
5、~136s选择该线程,显示如下
0:000> ~136s eax=00005763 ebx=08deeb5c ecx=03eff0d4 edx=5570ab69 esi=08deeb5c edi=7ffd6000 eip=7c95ed54 esp=08deeb10 ebp=08deebb8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCallRet: 7c95ed54 c3 ret
找到ecx寄存器的值,复制后ctrl+f,向上查找,会找到!syncblk的地方,如下
0:000> !syncblk Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner 1906 03ee4be4 5 1 03ee8f88 22c8 67 185e2ef0 System.Object 5390 052ca39c 3 1 05292b30 1dd4 49 1060d3ac System.Object 9372 0530702c 15 1 0012d3a8 1aa8 80 185e7704 System.Object 11428 03eff0d4 35 1 053b8fa8 169c 120 166acd98 System.Object 15278 0531c6b4 61 1 06bc1430 26d8 86 1a5bea88 System.Object
可以看到136线程等待的锁被120号线程占着不放(格式有点乱,凑合看),
6、有时候通过ecx寄存器找锁不是很确定,可以用~* kb来把所有线程堆栈打出来,然后根据!syncblk出来的同步快的值去搜索大概有多少个线程在等那个锁。因为同样是等待锁,可等的状态不一样,有的在Q里,有的锁已经升级,有的去尝试去拿锁了,所以不一定当时ecx寄存器指向那块内存,具体如何找到某个正在等待锁的线程等待的锁的内存地址,以及它正等待的这个锁被哪个线程拿着,我还没琢磨出规律来,但一般情况下,如果有其它同步对象的话,更难查。.net里用我上面说的几步就能查出锁的问题了。

【内存泄漏】
1、!dumpheap -stat看看哪些对象个数最多,占内存最大,
2、找到某个格式比较多的对象,可以看它的方法表,然后用!dumpheap -mt 66398fa4去随机找几个对象的地址
3、用!do 1e5a22bc命令去查看几个对象的状态,属性的值等,看看正常不正常
4、用!gcroot -nostacks 1e5a22bc去查看几个对象的根正常不正常,如果有些对象的根不是自己预先设计的那样,很可能被自己没想到的对象强引用了,所以GC无法回收它,就泄漏了。
【CPU百分百】
主要用几个计数器和!runaway命令,具体见以下链接
http://www.cnblogs.com/onlytianc ... 7/06/03/769307.html
【线程池耗尽】
!threadpool 能看到完成端口,线程池工作线程和timer回调各占线程池的情况。
【其它】
1、!eestack -short -ee查看所有重要(获取锁的,托管的,停止并允许回收的)线程的dumpstack,差不多相当于~*e!dumpstack
2、.time 可以看到进程跑了多少时间
3、!dso 查看当前线程里有哪些对象,分析内存泄漏问题也许会用到
参考技术A 通常在CDialog::OnInitDialog中调用,用于将对话框定位到应用程序主窗口的中央。在缺省情况下,这个函数将子窗口定位到它们的父窗口的中央,而将弹出窗口定位到拥有者的中央。如果弹出窗口没有拥有者,它将被定位到屏幕中央。如果要使窗口根据不是父窗口也不是拥有者的窗口来定位,则可以将pAlternateOwner参数可以被设为一个有效的窗口。如果要强迫相对于屏幕定位,则应在pAlternateOwner参数中传递CWnd::GetDesktopWindow返回的值。

WinDbg抓取程序报错dump文件的方法

转自:http://www.cnblogs.com/jinjiangongzuoshi/p/4268467.html


程序崩溃的两种主要现象:

a. 程序在运行中的时候,突然弹出错误窗口,然后点错误窗口的确定时,程序直接关闭

例如: “应用程序错误” “C++错误之类的窗口” “程序无响应” “假死”等

此种崩溃特点:程序已异常,在你未点出错窗口的确定或其他按,所有错误信息都还保留在PC的内存中,可以直接抓取Dump文件。当然,如果你知道

怎么样操作可以让程序崩溃,也可以用守株待兔的抓取方法抓Dump文件。

b.程序在运行中的时候,窗口和进程突然消失,没有任何错误窗体

典型的现象:程序自动关闭 或者玩游戏时,游戏界面自动消息等。

此种崩溃的特点:程序是自动崩溃的,当程序崩溃后,所有错误信息就都消息了,如果你要抓取这种崩溃的Dump,就必须先设置好抓取环境,否则是无

法抓取Dump文件的。

 

以上是两种最常见的程序崩溃现象,下面分享利用Windbug工具抓取dump文件的方法。

a. 抓取方法一

此方法特点:

1. 必须指定要抓取的进程或PID,同时程序必须已经在运行,否则无法抓dump.

2.必须在出现问题之前,先布置好抓取环境。

3.正常关闭进程也会出现DUMP文件,因此需要确定抓到的Dump是在程序崩溃时生成的。

 

step1: 下载需要使用的工具

windbg: 此工具是抓取dump的主角。

step2: 设置Windbg抓取环境

先运行可能存在问题的程序,例如:IE,如果不先运行程序,则无法抓Dump。

然后将下载的Windbg解压到任意盘符,例如C盘,使用下面的参数抓取Dump。

C:\\WinDbg\\adplus.vbs -crash -pn ieexplore.exe -o d:

运行此命令后,WinDbg会跳出黑色窗口,用于监控进程的运行状况,注意不要关闭这个窗口,否则Dump就抓不到了。

WinDbg参数说明:

-crash: 当程序挂掉的一刹那抓取Dump,这个参数只能抓到程序报错时的信息,如果程序不报错,则无法抓到Dump。

-hang: 当开启WinDbg之后就开始抓取Dump,主要用于抓取程序异常,但程序未崩溃的情况,例如进程的CPU使用率100%。

-pn:进程的PID或进程名,如果是进程名,会区分大小写。

-o: Dump输出路径.

step3:收集Dump文件

当程序崩溃后,Dump文件会保存在指定的输出路径内,例子中的Dump保存路径是D盘,然后打包Dump文件,提交给软件官方。

 

b.抓取方法二

此方法特点:

1. 无需指定要抓取的进程或PID,也不要求设置环境时必须存在进程,只要任意程序崩溃后都可以抓到Dump。

2. 必须在出现问题之前,先布置好抓取环境。

3.程序正常关闭时,比如点X时,不会生成Dump,只有程序崩溃时才会生成。

step1:下载需要使用的工具

step2:设置WinDbg抓取环境

将下载的工具解压到任意盘符,比如C盘,使用下面的参数抓取Dump:

C:\\WinDbg\\Windbg.exe -I

运行此参数时,Windbg会弹出一个提示,点确定后Windbg界面会消失,此时代表环境已经设置好,现在就需要你想方设法让程序崩溃,比如IE崩溃。

WinDbg参数说明:

-I: 将WinDbg作为默认的调试工具,注意I必须为大写,小写无效。

Step3:收集Dump文件

在程序崩溃时,WibDbg窗口再次弹出来时,使用以下命令保存Dump文件。

.dump -ma d:\\test.dmp

当开始保存Dump文件时,左下角的状态信息会变成*Busy*,表示WinDbg正在工作,Dump保存完成后会出现"Dump successfully written"这个提示,接

下来就等Dump保存好,然后把Dump文件打包提交软件官方。

 

c.抓取方法三

此方法特点:

可以在程序报错后,直接抓取Dump文件,不需要额外设置,适用于突然发现报错,且不确定能否复现问题时抓取Dump,这是一个非常重要的抓取方法,

强烈建议大家记住。

step1:下载需要使用的工具

ProcessExplorer:此工具用于定位报错窗口的进程ID

step2:使用ProcessExplorer定位报错窗口的进程PID

step3:运行WinDbg,抓取Dump文件

运行Windbg后,依次点”File" --> "Attack to a Process" ,在弹出的界面中,找到刚才捕捉到的PID,然后点OK.

点OK完成后,你就会看到可以抓取的Dump界面了,再用dump保存参数保存dump即可。

.dump -ma d:\\test.dmp

WinDbg参数说明:

-m: 却省选项,生成标准的minidump,转储文件通常较小,便于在网络上通过邮件或其它方式传输。这种文件的信息量较少,只包含系统信息、加载的模块DLL信息,

进程信息和线程信息。

-ma:带有尽量多选项的minidump(包括完整的内存内容、句柄、未加载的模块等等),文件较大,但如果条件允许(本机调试,局域网环境),推荐用这个。

-mFhutwd: 带有数据段,非共享的读、写内存页和其他有用的信息的minidump,包含了通过minidump能够得到的最多的信息。是一种折中方案。

技术改变世界! --狂诗绝剑

以上是关于如何手工抓取dump文件的主要内容,如果未能解决你的问题,请参考以下文章

如何抓取windows的dump?抓取dump

如何抓取分析Thread Dump

你需要知道的 N 种抓取 dump 的工具

在进程崩溃的时候自动抓取一个DUMP文件

抓取win32程序崩溃dump文件的几种方法

抓取win32程序崩溃dump文件的几种方法