JIT Debug Info 简介

简介: JIT Debug Info 简介

前言

在上一篇介绍 JIT Debugging 的文章 —— 你需要了解的JIT Debugging 中,我们了解到 procdump 设置为 JIT调试器的时候,在设置的参数中,有一个叫 %p 的参数(需要和 -j 一起使用),指向了 JIT_DEBUG_INFO。今天简单介绍一下 JIT_DEBUG_INFO

JIT_DEBUG_INFO 结构

JIT_DEBUG_INFO 的定义如下:

typedef struct _JIT_DEBUG_INFO {
    DWORD dwSize;
    DWORD dwProcessorArchitecture;
    DWORD dwThreadID;
    DWORD dwReserved0;
    ULONG64 lpExceptionAddress;
    ULONG64 lpExceptionRecord;
    ULONG64 lpContextRecord;
} JIT_DEBUG_INFO, *LPJIT_DEBUG_INFO;

我们可以在 windbg 中,使用 dt JIT_DEBUG_INFO 来查看 JIT_DEBUG_INFO 的数据结构,如下:

0:000> dt JIT_DEBUG_INFO
demo!JIT_DEBUG_INFO
   +0x000 dwSize           : Uint4B
   +0x004 dwProcessorArchitecture : Uint4B
   +0x008 dwThreadID       : Uint4B
   +0x00c dwReserved0      : Uint4B
   +0x010 lpExceptionAddress : Uint8B
   +0x018 lpExceptionRecord : Uint8B
   +0x020 lpContextRecord  : Uint8B

如何使用?

如果转储文件保存的时候,已经保存了 JIT_DEBUG_INFO 信息,我们可以直接在 windbg 中执行 .jdinfo address

有什么用?

为什么 procdump 要保存 JIT_DEBUG_INFO 呢?我们可以从 .jdinfo 的帮助文档里得到答案!截取如下:

jdinfo 介绍 —— 截自 msdn

简略翻译一下(感谢 google 翻译 的大力支持):

.jdinfo 命令使用从 Windows Vista 开始引入的 AeDebug 注册表信息。 相关注册表项的更多信息,请参考 Enabling Postmortem Debugging.jdinfo 命令使用系统为 AeDebug 设置的 JIT_DEBUG_INFO 的地址,并设置上下文为崩溃时的上下文。

您可以在 AeDebug 中使用 .jdinfo 命令而不是 -g 将调试器设置为 AeDebug 状态,而无需执行。

这么做是有好处的,因为在通常情况下,当用户态进程发生异常时,将按顺序发生如下事件:

  1. 操作系统中断目标进程的执行。
  2. 启动事后调试器。
  3. 调试器附加到目标进程。
  4. 调试器发出 “Go” 命令。(此命令由 AeDebug 项中的 -g 触发。)
  5. 目标进程尝试继续运行,可能会也可能不会遇到相同的异常。
  6. 目标进程遇到异常后,中断到调试器。

上述事件的发生可能会导致一些问题:

  • 异常并非总能重复,可能是因为重新运行时,瞬态条件(注:导致异常的条件)已不复存在了。
  • 可能会发生另一个事件,例如另一个异常。 没有办法知道它与原始事件是否是同一个。
  • 附加调试器到目标进程需要在目标进程中注入新线程。如果目标进程中有线程正在持有程序加载锁,则新注入的线程很可能阻塞。 注入新线程可能会严重干扰整个处理过程。

如果在 AeDebug 项中使用 -c .jdinfo 而不是 -g,则目标进程不会执行(注:上面提到的第 4, 5, 6 步不会发生)。 而是使用变量 %pJIT_DEBUG_INFO 结构中获取异常信息。

总结

  • 上述的 1 ~ 6 步,对我们理解整个 JIT Debugging 流程非常有帮助。让我们更加明白,在通过 JIT Debugging 生成转储的时候,保存 JIT_DEBUG_INFO 是非常重要的。

  • windbg 中可以使用 .jdinfo 命令设置上下文为异常发生时的上下文,然后就可以使用 k 系列命令查看异常发生时的调用栈了。

参考资料

相关文章
|
1月前
|
运维 NoSQL 安全
debug学习
debug学习
126 65
【错误记录】Tinker 热修复示例运行报错 ( Execution failed for task ‘:app:tinkerProcessD‘ . tinkerId is not set!!! )
【错误记录】Tinker 热修复示例运行报错 ( Execution failed for task ‘:app:tinkerProcessD‘ . tinkerId is not set!!! )
294 0
【错误记录】Tinker 热修复示例运行报错 ( Execution failed for task ‘:app:tinkerProcessD‘ . tinkerId is not set!!! )
|
5月前
|
算法 编译器 程序员
深入理解C++编译模式:了解Debug和Release的区别
深入理解C++编译模式:了解Debug和Release的区别
905 3
|
5月前
|
Python
IDA3.12版本的python,依旧报错IDAPython: error executing init.py.No module named ‘impRefer to the message win
IDA3.12版本的python,依旧报错IDAPython: error executing init.py.No module named ‘impRefer to the message win
|
11月前
|
编译器 Go 开发工具
JetBrains GoLand 以debug运行Go程序时出现could not launch process: decoding dwarf section info at offset 0x0: too short报错之保姆级别解决方案
JetBrains GoLand 以debug运行Go程序时出现could not launch process: decoding dwarf section info at offset 0x0: too short报错之保姆级别解决方案
241 0
|
Swift
Swift Debug 和 Release 中 print() 函数调试切换
Swift Debug 和 Release 中 print() 函数调试切换
66 0
|
XML 敏捷开发 JSON
log4go源码分析(一)
log4go源码分析(一)
|
测试技术 Go
Go 源码解读|如何用好 errors 库的 errors.Is() 与 errors.As() 方法
写作这篇文章的原因是我在写单元测试的时候,有时会调用 Go 的 errors 库中 errors.Is() 和 errors.As() 方法,借此做一个分析总结。
290 0
Go 源码解读|如何用好 errors 库的 errors.Is() 与 errors.As() 方法
C# Debug Trace调试类用法
    Debug和Trace都是调试类。     Debug类的方法只有DEBUG版中生效,而Trace的方法可以在DEBUG/RELEASE版本中生效。 一、Debug类 Debug类的控制台输出及断言Assert用法。
1740 0
|
程序员 Go 开发工具
解决Go升级到1.14后无法Debug
解决Go升级到1.14后无法Debug
447 0
解决Go升级到1.14后无法Debug