你需要了解的JIT Debugging
如果你还不清楚什么是转储文件,不知道什么时候需要转储文件,请参考转储文件系列文章的第一篇 —— 转储文件知多少。
前言
我在 你需要知道的 N 种抓取 dump 的工具 这篇文章里,向大家介绍了几款可以抓取转储文件的工具及其简单用法。不知道大家是否还记得,以管理员权限运行 procdump -i
可以注册 procdump
为事后调试器。大家是否了解其实现原理?今天让我们一起揭开其神秘面纱。
约定
JIT Debugger
, Just In Time Debugger
,JIT 调试器
, Postmortem Debugger
,事后调试器
,指的是同一个概念 —— 事后调试器。如果把 Debugger
换成 Debugging
,表示事后调试。我有时候会说 JIT 调试器
,有时候会说事后调试器
,希望大家不要被我混乱的用词搞晕。
原理探究
运行 process monitor
,开启监视。然后以管理员权限执行 procdump.exe -i
,成功后,停止监视。为了方便大家,我特意录制了整个过程,感兴趣的小伙伴可以点开看看,不过我建议你亲自动手实战一番,毕竟 纸上来的终觉浅, 绝知此事要躬行
。
如果你没看视频,可以直接参考我过滤后的结果截图(保留Result
是 Success
的 注册表
写
事件,排除非注册表相关事件):
我用黄色和红色高亮了 procdump
操作的注册表项。你能从图中得出什么结论呢?
procdump
会同时写HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
和HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug
注册表项。相信有开发经验的小伙伴儿知道,在
64
位系统下,部分注册表项有两套:一套是供64
位进程使用的(黄色高亮部分),一套是供32
位进程使用的(红色高亮部分,带Wow6432Node
)。如果
AeDebug
下的Auto
子项和Debugger
子项有值,procdump
会先备份,再修改。(执行procdump -u
的时候会恢复系统原有设置)Auto
和Debugger
的数据类型都是REG_SZ
。(虽然我们看到Auto
的值是1
)我猜,
32
位进程崩溃的时候,会使用带Wow6432Node
的注册表项,64
位进程崩溃的时候,会使用不带Wow6432Node
的注册表项。真的是这样吗?你知道怎么验证吗?相信聪明的你一定能想出验证办法。
其实,以上结论在 procdump -i
的输出结果中已经给出提示了(除了备份操作)。注意看下图中的黄色和红色高亮的部分。
{% note warn %}
温馨提示:
某些杀毒软件可能会对此注册表项有保护,如果设置失败,请检查是否是杀毒软件导致的。
{% endnote %}
至此,我们知道 procdump
是通过设置 AeDebug
下的 Auto
和 Debugger
子项实现的 JIT Debugging
。那么这两项都有什么用呢?
AeDebug 探究
使用 google
搜索 AeDebug
,搜到了微软的官方说明 ,有兴趣的小伙伴一定要读一读,有很多有价值的信息。
Auto
项:指定是否向用户显示错误提示框,如果值为"0"
,则显示提示框。为"1"
则不显示提示框,直接附加注册的事后调试器到目标进程中。Debugger
项:指定事后调试器的路径,及传递给事后调试器的参数。我们发现procdump -i
设置的参数是-accepteula -j "E:\dumps" %ld %ld %p
。其中:-accepteula
表示接受用户协议。-j
表示参数中有指向JIT_DEBUG_INFO
的指针(父进程传递了%p
对应的内容)。"E:\dumps"
表示转储文件保存的路径(如果运行procdump -i
的时候,没有指定转储文件的保存路径,默认会取当前路径 )。- 第一个
%ld
表示目标进程的进程ID
。 - 第二个
%ld
表示事件句柄。这个事件句柄是WER
复制到事后调试器中的。如果事后调试器激活该事件(通过SetEvent()
)后,WER
将继续目标进程的执行,而无需等待事后调试器终止。如果事后调试器在没有激活该事件的情况下终止,WER
将继续收集关于目标进程的信息。 %p
指向目标进程空间中的JIT_DEBUG_INFO
结构指针。包含了异常的来源和与异常相关的上下文信息。
如果转储文件中保存了 JIT_DEBUG_INFO
,使用 windbg
调试时,可以通过 .jdinfo address
来查看异常发生时的信息。例如,使用 windbg
打开 procdump
保存的转储文件的时候,应该可以看到如下提示。
我们可以根据提示,输入.jdinfo 0x1afd59e0000
来查看异常来源及上下文信息。
{% note info %}
说明:
在运行 procdump -i
的时候,如果没有指定转储选项,会默认使用 -mm
选项。该选项只包含 Process, Thread, Module, Handle and Address Space info.
信息,不会包含 %p
对应的内存数据。如果我们在调试 使用 -mm
选项保存的转储文件的时候执行 .jdinfo address
,会得到如下错误:
Unable to process JIT_DEBUG_INFO, Win32 error 0n30
我们可以简单的通过指定 -ma
或 -mp
来生成包含内存数据的转储文件,这样我们在调试器里执行 .jdinfo address
的时候就不会报错了。
据我观察,对于 procdump
来说 -j
和 %p
选项需要同时传递,缺一不可。
{% endnote %}
排除进程
如果我们真的不想让某些进程出现未处理异常的时候中断到 JIT
调试器中,有没有办法呢?从 vista
开始,我们可以显示排除某些进程,不让这些进程在出现未处理异常的时候中断到 JIT
调试器中。对应的注册表项如下:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\AutoExclusionList
下面是我机器上的该注册表项的值:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\AutoExclusionList]
"DWM.exe"=dword:00000001
"demo.exe"=dword:00000001
上面的 demo.exe
是我为了测试手动添加的,而 DWM.exe
是系统添加的。windows
为什么要默认把 DWM.exe
添加到排除列表呢?我也不太清楚,不过我在 Excluding an Application from Automatic Debugging 看到这样一句话:
By default, the Desktop Window Manager (Dwm.exe) is excluded from automatic debugging because otherwise a system deadlock can occur if Dwm.exe stops responding (the user cannot see the interface displayed by the debugger because Dwm.exe isn't responding, and Dwm.exe cannot terminate because it is held by the debugger).
我想这就是 DWM.exe
会被排除的原因吧。
如果想通过代码的形式实现,除了直接操作注册表外,还可以通过 WerAddExcludedApplication()
来实现,对应的,可以通过 WerRemoveExcludedApplication()
来删除 。这两个函数的原型摘录如下:
HRESULT WerAddExcludedApplication(
PCWSTR pwzExeName,
BOOL bAllUsers
);
HRESULT WerRemoveExcludedApplication(
PCWSTR pwzExeName,
BOOL bAllUsers
);
第一个参数 pwzExeName
表示要排除的程序,不要带路径,只传递程序名称即可。比如,demo.exe
。
第二个参数 bAllUsers
如果是 FALSE
的话,表示仅对当前用户有效,其它用户不受影响,修改的是 HKCU
(HKEY_CURRENT_USER
)下对应的注册表项。如果为 TRUE
的话,表示对所有用户都生效,修改的是 HKLM
(HKEY_LOCAL_MACHINE
)下对应的注册表项,为 TRUE
的时候,需要有管理员权限。
{% note info %}
注意:
如果你手动调用代码操作注册表的话,务必注意 64
位系统下的注册表重定向问题。相信一定有小伙伴儿和我一样踩过这个坑。
{% endnote %}
JIT调试的运作机制
整个运作机制,在张银奎张老师的《软件调试》(第一版)第 12 章:未处理异常和 JIT 调试 中做了非常非常详细的介绍。我就不摘录了,感兴趣的小伙伴一定要好好多读几遍。
AeDebug 中的 Ae 是什么意思?
AeDebug
中的 Debug
很好理解,就是调试的意思。那 Ae
代表什么意义呢?有人说 AeDebug
是 Auto Exception Debug
的缩写,听上去挺有道理的。偶然的机会,google
到了 Ramond Chen
写的一篇文章 —— What does the “Ae” stand for in AeDebug?。根据他的说法,Ae
表示 Application Error
的意思。我把原文截取如下,方便大家阅读。
不论 AeDebug
是什么的缩写,大家知道这个注册表项的意义就足够了,没必要过于纠结。否则,就真成了孔乙己了。
总结
一般情况下,修改
HKLM
下的子键需要管理员权限。注册为
JIT
调试器,需要管理员权限,因为需要写HKLM
下的子键。procdump
可以通过-i
选项注册为事后调试器,另外windbg
也可以通过-I
选项注册为事后调试器。AeDebug
注册表项是JIT
调试的关键,该注册项在64
位系统下有对32
位进程和64
位进程分别有对应的注册表项。其中,带Wow6432Node
的注册表项是给32
位目标进程使用的。64
位系统下,除了AeDebug
有两套,还有很多其它注册表项也有两套。如果确实不希望自己的进程在出现未处理异常时中断到
JIT
调试器中,可以设置注册表进行排除(Vista
及之后的操作系统才支持)。
参考资料
你需要了解的JIT Debugging的更多相关文章
- JIT Debug Info 简介
原总结debug调试dump转储文件JITprocdumpJIT Debugging 前言 在上一篇介绍 JIT Debugging 的文章 -- 你需要了解的JIT Debugging 中,我们了解 ...
- 迁移Reporting Services的方法与WMI错误
今天上午,接到一个任务:迁移SQL SERVER 2005的报表服务到另外一台SQL SERVER 2008服务器,结果等我备份了两边服务器的ReportServer,ReportServerTemp ...
- 【解决方法】System.IO.FileNotFoundException
错误日志 See the end of this message for details on invoking just-in-time (JIT) debugging instead of thi ...
- Open Live Writer
最近突然发现我的CSDN博客里面的很多内容都被删除了,虽然我没有用CSDN写博了,不过还是想到可能我现在用的博客园写博,如果有些内容敏感的话会不会也会被删除文章或者关掉我的博客.心里满是担心,于是想说 ...
- VS2008,System.Runtime.InteropServices.COMException (0x800401F3): Invalid class string (Exception from HRESULT: 0x800401F3 (CO_E_CLASSSTRING))
在VS2008环境中编译调试运行不报错,但在发布的exe文件运行就报错 System.Runtime.InteropServices.COMException (0x800401F3): Invali ...
- BPF+XDP比较全的资料都在这里
Dive into BPF: a list of reading material Sep 1, 2016 • Quentin Monnet◀Table of contents What is BPF ...
- gdb help all 帮助信息
Command class: aliases ni -- Step one instruction rc -- Continue program being debugged but run it i ...
- JVM参数(二)参数分类和即时(JIT)编译器诊断
在这个系列的第二部分,我来介绍一下HotSpot JVM提供的不同类别的参数.我同样会讨论一些关于JIT编译器诊断的有趣参数. JVM 参数分类 HotSpot JVM 提供了三类参数.第一类包括了标 ...
- .Net 揭密--JIT怎样运行你的代码
方法调用: 第一部分 (普通调用) 译者:我们都知道.NET托管代码如C#.VB.NET写成的代码,都是先被编译成中间语言(IL,Intermediate Language,在运行时,再由即时编译器( ...
随机推荐
- 109-PHP类成员初始化值
<?php class mao{ //定义猫类 public $age=0; //定义多个属性并初始化 public $weight=50; public $color='white'; } $ ...
- HDU 4862 JUMP 最小费用最大流
2014 多校的B题,由于我不怎么搞图论,当时碰到这个题目,我怎么想都没往网络流方面弄,不过网络流真的是个好东西,对于状态多变,无法用动规或者数据结构来很好表示的时候,非常有用 这个题目要求每个点一定 ...
- nosql的介绍以及和关系型数据库的区别
一直对非关系型数据库和关系型数据库的了解感觉不太深入,在网上收集了一些关于sql和nosql的区别和优缺点分享给大家. Nosql介绍 Nosql的全称是Not Only Sql,这个概念早起就有人提 ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-facetime-video
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- Spring 事件(2)- 自定义事件
Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...
- java基础源码 (3)--Annotation(注解)
借鉴博客地址:https://www.cnblogs.com/skywang12345/p/3344137.html /** * The common interface extended by al ...
- super方法
继承 __init__是python中的构造函数,用于属性的初始化. 如果在子类中定义了构造函数,python默认不会调用父类的构造函数,父类里的属性就不会集成到子类. super 用于调用父类(超类 ...
- mybatis基础CURD的学习
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...
- 执行 composer update 命令的时候报 Your requirements could not be resolved to an installable set of packages. 错误
Your requirements could not be resolved to an installable set of packages. 以上原因:不匹配composer.json要求的版 ...
- c++ auto_ptr笔记
1.auto_ptr 不可以使用指针惯用的赋值初始化方式,只能直接初始化. 示例: char *p = 'A';//error auto_ptr<char>ptr = new char ...