你需要了解的 JIT Debugging

如果你还不清楚什么是转储文件,不知道什么时候需要转储文件,请参考转储文件系列文章的第一篇 —— 转储文件知多少。

前言

我在 你需要知道的 N 种抓取 dump 的工具 的工具 这篇文章里,向大家介绍了几款可以抓取转储文件的工具及其简单用法。不知道大家是否还记得,以管理员权限运行 procdump -i 可以注册 procdump 为事后调试器。大家是否了解其实现原理?今天让我们一起揭开其神秘面纱。

约定

JIT DebuggerJust In Time DebuggerJIT 调试器Postmortem Debugger事后调试器,指的是同一个概念 —— 事后调试器。如果把 Debugger 换成 Debugging,表示事后调试。我有时候会说 JIT 调试器,有时候会说事后调试器,希望大家不要被我混乱的用词搞晕。

原理探究

运行 process monitor,开启监视。然后以管理员权限执行 procdump.exe -i,成功后,停止监视。为了方便大家,我特意录制了整个过程,感兴趣的小伙伴可以点开看看,不过我建议你亲自动手实战一番,毕竟 纸上来的终觉浅, 绝知此事要躬行

探究 procdump 安装为 JIT 调试器的过程

如果你没看视频,可以直接参考我过滤后的结果截图(保留ResultSuccess注册表 事件,排除非注册表相关事件):

我用黄色和红色高亮了 procdump 操作的注册表项。你能从图中得出什么结论呢?

  • procdump 会同时写 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebugHKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug 注册表项。

    相信有开发经验的小伙伴儿知道,在64 位系统下,部分注册表项有两套:一套是供 64 位进程使用的(黄色高亮部分),一套是供 32 位进程使用的(红色高亮部分,带 Wow6432Node)。

  • 如果 AeDebug下的 Auto 子项和 Debugger 子项有值,procdump 会先备份,再修改。(执行 procdump -u 的时候会恢复系统原有设置)

  • AutoDebugger 的数据类型都是 REG_SZ。(虽然我们看到 Auto 的值是 1

  • 我猜,32 位进程崩溃的时候,会使用带 Wow6432Node 的注册表项,64 位进程崩溃的时候,会使用不带 Wow6432Node 的注册表项。真的是这样吗?你知道怎么验证吗?相信聪明的你一定能想出验证办法。

其实,以上结论在 procdump -i 的输出结果中已经给出提示了(除了备份操作)。注意看下图中的黄色和红色高亮的部分。

procdump-i

温馨提示:

某些杀毒软件可能会对此注册表项有保护,如果设置失败,请检查是否是杀毒软件导致的。

至此,我们知道 procdump 是通过设置 AeDebug下的 AutoDebugger 子项实现的 JIT Debugging。那么这两项都有什么用呢?

AeDebug 探究

使用 google 搜索 AeDebug,搜到了微软的官方说明[1] ,有兴趣的小伙伴一定要读一读,有很多有价值的信息。

  • 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 保存的转储文件的时候,应该可以看到如下提示。

procdump 在转储文件中添加的注释

我们可以根据提示,输入.jdinfo 0x1afd59e0000 来查看异常来源及上下文信息。

jdinfo 结果

说明:

在运行 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 选项需要同时传递,缺一不可。

排除进程

如果我们真的不想让某些进程出现未处理异常的时候中断到 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[2] 看到这样一句话:

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 的话,表示仅对当前用户有效,其它用户不受影响,修改的是 HKCUHKEY_CURRENT_USER)下对应的注册表项。如果为 TRUE 的话,表示对所有用户都生效,修改的是 HKLMHKEY_LOCAL_MACHINE)下对应的注册表项,为 TRUE 的时候,需要有管理员权限。

注意:

如果你手动调用代码操作注册表的话,务必注意 64 位系统下的注册表重定向问题。相信一定有小伙伴儿和我一样踩过这个坑。

JIT 调试的运作机制

整个运作机制,在张银奎张老师的《软件调试》(第一版)第 12 章:未处理异常和 JIT 调试 中做了非常非常详细的介绍。我就不摘录了,感兴趣的小伙伴一定要好好多读几遍。

AeDebug 中的 Ae 是什么意思?

AeDebug中的 Debug 很好理解,就是调试的意思。那 Ae 代表什么意义呢?有人说 AeDebugAuto Exception Debug 的缩写,听上去挺有道理的。偶然的机会,google 到了 Ramond Chen写的一篇文章 —— What does the “Ae” stand for in AeDebug?[3]。根据他的说法,Ae 表示 Application Error 的意思。我把原文截取如下,方便大家阅读。

Raymond-Chen-explain-AE

知道 AeDebug 是什么单词的缩写有助于帮助大家记忆,但没必要纠结。

总结

  • 一般情况下,修改 HKLM 下的注册表项需要管理员权限。

  • 注册为 JIT 调试器,需要管理员权限,因为需要写 HKLM 下的子键。

  • procdump 可以通过 -i 选项注册为事后调试器,另外 windbg也可以通过 -I 选项注册为事后调试器。

  • AeDebug 注册表项是 JIT 调试的关键,该注册项在 64 位系统下有对 32 位进程和 64 位进程分别有对应的注册表项。其中,带 Wow6432Node 的注册表项是给 32 位目标进程使用的。

  • 64位系统下,除了AeDebug有两套,还有很多其它注册表项也有两套。

  • 如果确实不希望自己的进程在出现未处理异常时中断到 JIT 调试器中,可以设置注册表进行排除(Vista 及之后的操作系统才支持)。

参考资料

  • 《windows sysinternals 实战指南》

  • 《软件调试》(第一版)

  • Microsoft Document : Enabling Postmortem Debugging[4]

  • Raymond-Chen : What does the “Ae” stand for in AeDebug?[5]

  • Configuring Automatic Debugging[6]

  • WerAddExcludedApplication[7]

  • WerRemoveExcludedApplication[8]

References:

[1]

微软的官方说明: https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-postmortem-debugging

[2]

Excluding an Application from Automatic Debugging: https://docs.microsoft.com/en-us/windows/win32/debug/configuring-automatic-debugging#excluding-an-application-from-automatic-debugging

[3]

What does the “Ae” stand for in AeDebug?: https://devblogs.microsoft.com/oldnewthing/20181017-00/?p=99995

[4]

Microsoft Document : Enabling Postmortem Debugging: https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/enabling-postmortem-debugging

[5]

Raymond-Chen : What does the “Ae” stand for in AeDebug?: https://devblogs.microsoft.com/oldnewthing/20181017-00/?p=99995

[6]

Configuring Automatic Debugging: https://docs.microsoft.com/en-us/windows/win32/debug/configuring-automatic-debugging#configuring-automatic-debugging-for-application-crashes

[7]

WerAddExcludedApplication: https://docs.microsoft.com/en-us/windows/win32/api/werapi/nf-werapi-weraddexcludedapplication

[8]

WerRemoveExcludedApplication: https://docs.microsoft.com/en-us/windows/win32/api/werapi/nf-werapi-werremoveexcludedapplication

猜你喜欢:

转储文件系列:

转储文件知多少

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

你生成的转储文件有问题吗?

调试系列:

调试实战——你知道怎么使用DebugView查看调试信息吗?

调试实战——程序CPU占用率飙升,你知道如何快速定位吗?

调试实战——崩溃在ComFriendlyWaitMtaThreadProc

调试实战——使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs

调试实战——调试PInvoke导致的内存破坏

调试实战——调试excel启动时死锁

调试实战——调试DLL卸载时的死锁

调试实战——调试TerminateThread导致的死锁

排错系列:

排错实战——VS清空最近打开的工程记录

排错实战——拯救加载调试符号失败的IDA

排错实战——你知道拖动窗口时只显示虚框怎么设置吗?

排错实战——解决Tekla通过.tsep安装插件失败的问题

排错实战——使用process explorer替换任务管理器

排错实战——通过对比分析sysinternals事件修复程序功能异常

欢迎留言交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超越“迁移”的思考:应用程序该如何被Kubernetes接管?

传统虚拟机(VM)的可扩展性差强人意,但Kubernetes可以快速,无缝地扩展正在运行的服务。Kubernetes将容器、集群以及广泛的抽象配置方法引入桌面,用于提升部署和变更管理体验,从而使人们对Kubernetes关注更多…

C++string容器-字符串拼接

string字符串拼接 功能描述&#xff1a; 实现在字符串末尾拼接字符串 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>//string字符串拼接 void test01() {string str1 "我";str1 "爱…

如何运用领域驱动设计 - 存储库

概述在上一篇文章<如何运用领域驱动设计 - 聚合>中&#xff0c;我们已经了解过领域驱动设计中一个很核心的对象-聚合。在现实场景中&#xff0c;我们往往需要将聚合持久化到某个地方&#xff0c;或者是从某个地方创建出聚合。此时就会使得领域对象与我们的基础架构产生紧…

C++string容器-字符串查找和替换

string查找和替换 功能描述&#xff1a; 查找&#xff1a;查找指定字符串是否存在 替换&#xff1a;在指定的位置替换字符串 函数原型&#xff1a; rfind 和find 的区别&#xff1a; rfind从右往左查找 find从左往右查找 查找案列代码如下&#xff1a; #include <iostrea…

如何运用领域驱动设计 - 工作单元

概述在上一篇 《如何运用领域驱动设计 - 存储库》 的文章中&#xff0c;我们讲述了有关仓储的概念和使用规范。仓储为聚合提供了持久化到本地的功能&#xff0c;但是在持久化的过程中&#xff0c;有时一个聚合根中的各个领域对象会分散到不同的数据库表里面&#xff1b;又或者是…

C++string容器-字符串比较

string字符串比较 功能描述: 字符串之间的比较 比较方式&#xff1a; 通常用来比较两个字符串是否相等 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring> //string字符串比较void test01() {string…

国产自主研发编程语言火了,同行十二年,不知Python是木兰?

1月17号有媒体称&#xff0c;一款面向智能物联网和编程教育的号称自主研发语言横空出世&#xff0c;名为【Mulan 】。消息一出&#xff0c;引起了众多争议。但有知乎网友发现&#xff0c;下载的程序包解包后——是个 Python&#xff1f;何为木兰&#xff1f;1月17号&#xff0c…

C++string容器-字符存取

string中单个字符存取方式有两种 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>//string 字符存取 void test01() {string str "hello";cout << "str " << str << endl;for (int i…

有了容器为什么kubernetes还需要Pod?

简介容器并不是软件开发的银弹&#xff0c;没有任何一种技术能解决软件开发中的所有问题当我们采用容器化技术的时候&#xff0c;摒弃了传统的物理机或者虚拟机的部署方式&#xff0c;以一种更加轻快&#xff0c;便捷的方式来部署我们的应用。到容器化的进阶&#xff0c;再加上…

C++string容器-插入和删除

string插入和删除 功能描述&#xff1a; 对string字符串进行插入和删除字符操作 函数原型&#xff1a; #include <iostream> using namespace std; #include <cstring>//字符串 插入和删除 void test01() {string str "hello";str.insert(1, "…

.NET绘制旋转太极图

前言我之前发了一篇《 用.NET写“算命”程序》的文章&#xff0c;但有人纷纷提出了质疑&#xff0c;认为没有“科学”&#xff08; mi xin&#xff09;依据????。所谓“太极生两仪&#xff0c;两仪生四象&#xff0c;四象生八卦&#xff0c;八卦定吉凶&#xff0c;吉凶生大…

.NET CORE(C#) WPF 抽屉式菜单

.NET CORE(C#) WPF 抽屉式菜单阅读导航本文背景代码实现本文参考源码1. 本文背景使用简单动画实现抽屉式菜单2. 代码实现使用 .NET CORE 3.1 创建名为 “AnimatedColorfulMenu” 的WPF模板项目&#xff0c;添加1个Nuget库&#xff1a;MaterialDesignThemes&#xff0c;版本为最…

C++string容器-子串获取

string子串 功能描述&#xff1a; 从字符串中获取想要的子串 函数原型&#xff1a; 代码如下&#xff1a; #include <iostream> using namespace std; #include <cstring>//string求子串void test01() {string str "abcdef";string subStr str.sub…

我的 .NET Core 博客性能优化经验补充

点击上方蓝字关注“汪宇杰博客”导语去年年底我写了一篇《我的 .NET Core 博客性能优化经验总结》&#xff0c;但后来还发现有一处遗漏需要补充。我们一起来看看~牺牲空间换时间我们知道软件设计只有高手才能做到又小又快&#xff0c;像我这种普通程序员通常只有两种方案&#…

使用 OAS(OpenAPI标准)来描述 Web API

无论哪种类型的Web API, 都可能需要给其他开发者使用. 所以API的开发者体验是很重要的. API的开发者体验, 简写为 API DX (Developer Experience). 它包含很多东西, 例如如何使用API, 文档, 技术支持等等, 但是最重要的还是API的设计. 如果 API 设计的不好, 那么使用该API构建的…

dedemodule.class.php,DEDECMS5.7模块/模块管理列表显示空白问题解决方法

DEDECMS5.7模块/模块管理列表显示空白(站长基地配图)今天站长基地升级至dedecms最新版本&#xff0c;进入后台意外的发现&#xff0c;模块/模块管理一片空白&#xff0c;但有没有及时备份&#xff0c;于是赶紧去网上找寻解决办法&#xff0c;经过整理&#xff0c;大致有以下几种…

dotNET Core 中怎样操作AD(续1)

在之前的文章《dotNET Core 中怎样操作 AD&#xff1f;》中主要以AD的数据同步到数据库的场景来描述了在 dotNetCore 中怎样操作AD&#xff0c;本文将继续介绍一些在 dotNetCore 中操作 AD 的其他常用操作。环境dotNET Core&#xff1a;3.0Novell.Directory.Ldap.NETStandard2_…

【Magicodes.IE 2.0.0-beta1版本发布】已支持数据表格、列筛选器和Sheet拆分

为了更好的完善Magicodes.IE&#xff0c;春节期间我们会进行一次大的重构。由于精力有限&#xff0c;急缺文档和翻译&#xff08;将文档翻译为英文文档&#xff09;支持&#xff0c;诚邀各位加入。同时在功能方便也做了相关规划&#xff0c;有兴趣的朋友可以参与提交PR。https:…

Mbp,一个用于学习.net core的开发框架

Mbp(https://github.com/mbpframework/Mbp)是一个.net core 3的企业级web开发框架,是我个人用于学习.net core而发起的一个开源项目.这个借鉴了国外优秀开源项目abp vnext,及国内优秀开源框架Osharp的一些思想和实现.欢迎各路开发爱好者加入这个项目,一起学习,一起玩耍,共同成长…

什么?原来C#还有这两个关键字

系列介绍简介【五分钟的dotnet】是一个利用您的碎片化时间来学习和丰富.net知识的博文系列。它所包含了.net体系中可能会涉及到的方方面面&#xff0c;比如C#的小细节&#xff0c;AspnetCore&#xff0c;微服务中的.net知识等等。场景您可以在下班坐地铁的时候&#xff0c;拿出…