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

在如下的情况下需要使用这样的技巧: 1. 生产环境上出问题, 我们需要抓取dump文件, 在线下去debug. 2. 正在运行一大堆测试, 当其中一个崩溃的时候, 不希望在运行时干扰整个测试动作, 仅需要收集一些测试信息. 3. 问题在连接到debugger后无法重现. 简单来说, 就是你希望在对环境影响最小的前提下, 抓取尽可能多的信息. 为了满足这种需求, 最好的方式是配置 just-in-time (JIT) debugger , 让它在进程崩溃的任何时候能够: 启动, 抓取dump, 退出. JIT debugger的基本思想是:当一个进程崩溃的时候,加载debugger, attach debugger到进程上, 以便我们弄清楚为什么会崩溃. 有注册表键值可以提供这项基本的功能, 针对托管的, 非托管的都有. 如果你的应用程序是用托管代码编写的, 你也许会问, "我的应用程序是托管代码, 为什么我要关心native code?" 即使是给你最基本的托管代码应用程序都会运行native code, 如果你的需求是收集任何crash的数据, 你将需要为这两种类型的代码设置注册表键值. 在CLR第四版中, 已经定义了带有native code的托管JIT debugger. 然而, 这个修改并不影响我这里的指导, 这里, V2 V4都适用. 我如何配置debugger? ===================== 1. 下载并安装最新的“Debugging Tools for Windows.” a. 如果你是在运行64-bit OS, 你将会需要32-Bit and 64-bit 两个版本. b. 你在机器上既可以安装整个的工具集(这很快, 安装很小), 或者你可以在一台机器上安装, 然后从安装路径拷贝"cdb.exe"到任何目标机器上. 注意, 下面的sample.reg文件假设你安装32位debugger到c:/debuggers/x86/下, 64位debugger到c:/debuggers/x64/ 下 2. 创建或配置下面的注册表键和值(如果你使用的是64位版的windows, 你还需要在Wow6432节点下配置这些值) a. 键: HKLM/Software/Microsoft/Windows NT/Current Version/AeDebug: i. 值: "Debugger" 1. 类型: String 2. 值数据: -pv -p %ld -c “.dump /u /ma ;.kill;qd" ii. 值: “Auto” 1. 类型: String 2. 值数据: "1" b. 键: HKLM/Software/Microsoft/.NETFramework i. 值: “DbgManagedDebugger" 1. 类型: String 2. 值数据: -pv -p %ld -c ".dump /u /ma ;.kill;qd" ii. 值: "DbgJITDebugLaunchSetting" 1. 类型: DWORD(32-bit) 2. 值数据: 2 注意: 你应该根据合适的debugger的位数, 比如说, 你想要OS/CLR为64位进程崩溃加载64位的debugger, 32位的进程崩溃加载32为的debugger. 请确保你的debugger的路径是被正确地设置了的. 下面的sample.reg文件会配置机器上的cdb.exe为自动加载, 并在每个进程崩溃的时候生成一个crash dump文件. 注意文件中的关于debugger路径和dump文件存放路径的假设. Windows Registry Editor Version 5.00 ;This reg file installs just-in-time debuggers to capture a dump of all process ;crashes for the machine. ; ;Assumes 32-bit debugger is cdb.exe and is installed to c:/debuggers/x86/. ;Assumes 64-bit debugger is cdb.exe and is installed to c:/debuggers/x64/. ; ;Assumes crash dumps can be written to c:/crash_dumps/. ;Make sure all users have write access to this directory. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework] "DbgManagedDebugger"="/"c://debuggers//x64//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "DbgJITDebugLaunchSetting"=dword:00000002 [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug] "Debugger"="/"c://debuggers//x64//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "Auto"="1" ;The following keys are only used on 64-bit versions of Windows (note Wow6432Node). ;They can be safely created with no side-effects on 32-bit versions of Windows. ;Alternatively, you can delete the remainder of this file if you’re running a ;32-bit version of Windows. [HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows NT/CurrentVersion/AeDebug] "Debugger"="/"c://debuggers//x86//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "Auto"="1" [HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework] "DbgManagedDebugger"="/"c://debuggers//x86//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "DbgJITDebugLaunchSetting"=dword:00000002 这些键值有什么作用? ===================== “Debugger” 和“DbgManagedDebugger” 的值数据基本上就是在进程崩溃的时候运行的命令行(printf格式的字符串). OS 或者 CLR 用实际值替代掉其中的格式指示符, 然后使用当前用户的崩溃进程的上下文来运行命令. 比如说, 会用崩溃的process id去替换掉 "%ld". 在命令行中, 我指定了: 加载cdb.exel, 也就是debugger 很显然, 你必须为debugger指定正确的路径 “-pv %ld” : 非侵入性地(仅仅是把线程暂停)挂接到崩溃的进程上(操作系统或CLR会实质上地帮你添写PID) “.dump /u /ma ”: 拿下完整的内存dump, 使用一个独一无二的名字(使用日期, 时间, 和进程ID来扩展名称), 把它保存到指定的路径 路径和文件名可以是任何你想指定的形式. 因为debugger是在崩溃的进程的上下文中加载的, 所以你要确保你指定的路径是任何用户都有权限写入的 “.kill”: 干掉目标进程, 因为你已经得到了你需要的数据. “qd”: 离开debugger “Auto” 和“DbgJITDebugLaunchSetting”的值设定了何时加载debugger的策略规则(policy). 正如我上面写道的, 我们希望尽快地得到数据, 并继续, 所以我们不希望用户干预的介入. 比如说, 在一个服务器上, 可能不会有人登录并点击什么OK按钮. 我描述的配置会自动地为机器上的所有进程加载注册了的debugger, 而不会弹出框来让你选择(参考Enabling JIT-attach Debugging, 其中有关于弹这个框的更多信息). 注意, 当这些配置存在了之后, 机器上运行的所有进程在崩溃的时候都会自动地加载起debugger, 从而不会让你有机会去在"Windows Error Reporting"里呈交这个crash. 我不在乎一台机器上的绝大多数的进程, 我可以只抓取某一个进程的crash dump么? ==================== 这个问题的答案取决于你OS的版本, 还有CLR的版本. 下面是规则: 对于native code来说: 你的OS必须是Vista/Server 2008 或者更高. 对于managed code来说: 你的CLR的版本必须是V4(或者更高) 下面是如何配置的方法: 1. 如同上面的2.a.i 和2.b.i一样, 配置debugger键值. (AeDebug/Debugger 和.NETFramework/DbgManagedDebugger) 2. 确保AeDebug/Auto 和.NETFramework/DbgJITDebugLaunchSetting 已经被配置为自动加载(再一次强调, 参考Enabling JIT-attach Debugging 来查找更多信息). a. 或者你可以删除它们Or you can delete them. 3. 创建如下的注册表键值对Create the following registry keys and values: a. HKLM/Software/Microsoft/Windows/Windows Error Reporting/DebugApplications i. 值: (e.g. “myapp.exe”) 1. 类型: DWORD (32-bit) 2. 值数据: 1 b. 为每一个你希望debugger自动加载的应用程序重复这个操作. 如果你更喜欢个人的控制, 你可以配置HKCU中的DebugApplications 键值对. 当这些配置生效的时候, debugger会仅为你指定的进程加载起来, 而其他进程所使用的会是普通的错误处理方式(比如说, 最默认的配置下, 会弹出一个框, 让你提交这个错误到微软去.) 下面的例子中的sample.reg文件, 会配置cdb.exe为自动加载的, 但仅仅是为HelloWorld.exe. 你可以替代HelloWorld.exe为你想要抓取dump的进程. Windows Registry Editor Version 5.00 ;This reg file installs just-in-time debuggers to capture a dump of only the ;processes listed under the [DebugApplications] key, below. ; ;Assumes 32-bit debugger is cdb.exe and is installed to c:/debuggers/x86/. ;Assumes 64-bit debugger is cdb.exe and is installed to c:/debuggers/x64/. ; ;Assumes crash dumps can be written to c:/crash_dumps/. ;Make sure all users have write access to this directory. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework] "DbgManagedDebugger"="/"c://debuggers//x64//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "DbgJITDebugLaunchSetting"=dword:00000000 [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug] "Debugger"="/"c://debuggers//x64//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "Auto"="0" ;The following keys are only used on 64-bit versions of Windows (note Wow6432Node). ;They can be safely created with no side-effects on 32-bit versions of Windows. ;Alternatively, you can delete the remainder of this file if you’re running a ;32-bit version of Windows. [HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Windows NT/CurrentVersion/AeDebug] "Debugger"="/"c://debuggers//x86//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "Auto"="0" [HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework] "DbgManagedDebugger"="/"c://debuggers//x86//cdb.exe/" -pv -p %ld -c /".dump /u /ma c://crash_dumps//crash.dmp;.kill;qd/"" "DbgJITDebugLaunchSetting"=dword:00000000 ;For each application you want the debugger to be auto-launched, add a row below ;similar to “HelloWorld.exe"=dword:00000001 but replacing HelloWorld.exe with ;your application .exe name. [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/Windows Error Reporting/DebugApplications] "HelloWorld.exe"=dword:00000001 除了抓dump, 我还可以做更多的事情么? ========================= 关于Windows Debugger是的命令行开关的更多的信息, 可以在Debugging Tools fow Windows中包括的文档中找到. 你并没有被限制仅仅抓取dump, 你还可以执行很多debugger的自动化操作呢. 嗯, 那么究竟是什么导致了问题发生? ======================== 现在, 你已经有了dump文件, 是时候来弄清楚为什么应用程序崩溃了. 对于那些已经熟悉了dump debugging的读者, 到这里你就拉出WinDBG + SOS(托管debugging的扩展组件), 并深入研究了. 但是请等一下! 如果你的应用程序运行在CLR V4上(.Net Framework 4.0), 你可以在Visual Studio 2010中进行debug了. 我们的目标是在VS2010中, debug dump像live debug一样的体验(如同走到了断点). 针对如何debug托管代码的crash, 搜索"managed dump debugging"会返回不少结果. 一个很好的初学者去处是Tess Ferrandez’s blog (一个微软的技术支持大牛). 她有不少关于这个话题的精彩文章, 包括dump debugging in VS 2010, 还有一些实验, 手把手的文章. Automatically Capturing a Dump When a Process Crashes http://blogs.msdn.com/clrteam/archive/2009/10/15/automatically-capturing-a-dump-when-a-process-crashes.aspx Enabling JIT-attach Debugging http://msdn.microsoft.com/en-us/library/2ac5yxx6(VS.80).aspx

你可能感兴趣的:(在进程崩溃的时候自动抓取一个DUMP文件)