GDB JIT 编译接口集成
GDB JIT 编译接口集成允许 V8 向 GDB 提供 V8 运行时生成的原生代码的符号和调试信息。
当 GDB JIT 编译接口被禁用时,GDB 中的典型回溯包含标记为 ??
的帧。这些帧对应于动态生成的代码。
#8 0x08281674 in v8::internal::Runtime_SetProperty (args=...) at src/runtime.cc:3758
#9 0xf5cae28e in ?? ()
#10 0xf5cc3a0a in ?? ()
#11 0xf5cc38f4 in ?? ()
#12 0xf5cbef19 in ?? ()
#13 0xf5cb09a2 in ?? ()
#14 0x0809e0a5 in v8::internal::Invoke (construct=false, func=..., receiver=..., argc=0, args=0x0,
has_pending_exception=0xffffd46f) at src/execution.cc:97
但是,启用 GDB JIT 编译接口允许 GDB 生成更具信息量的堆栈跟踪。
#6 0x082857fc in v8::internal::Runtime_SetProperty (args=...) at src/runtime.cc:3758
#7 0xf5cae28e in ?? ()
#8 0xf5cc3a0a in loop () at test.js:6
#9 0xf5cc38f4 in test.js () at test.js:13
#10 0xf5cbef19 in ?? ()
#11 0xf5cb09a2 in ?? ()
#12 0x0809e1f9 in v8::internal::Invoke (construct=false, func=..., receiver=..., argc=0, args=0x0,
has_pending_exception=0xffffd44f) at src/execution.cc:97
GDB 未知的帧对应于没有源信息的原生代码。有关更多详细信息,请参阅 已知限制。
GDB JIT 编译接口在 GDB 文档中指定:https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html
先决条件 #
- V8 v3.0.9 或更高版本
- GDB 7.0 或更高版本
- Linux 操作系统
- 具有 Intel 兼容架构 (ia32 或 x64) 的 CPU
启用 GDB JIT 编译接口 #
GDB JIT 编译接口目前默认情况下不包含在编译中,并且在运行时被禁用。要启用它:
- 使用定义了
ENABLE_GDB_JIT_INTERFACE
的编译 V8 库。如果您使用 scons 构建 V8,请使用gdbjit=on
运行它。 - 启动 V8 时传递
--gdbjit
标志。
要检查您是否已正确启用 GDB JIT 集成,请尝试在 __jit_debug_register_code
上设置断点。此函数被调用以通知 GDB 有关新的代码对象。
已知限制 #
JIT 接口的 GDB 端目前(截至 GDB 7.2)无法有效地处理代码对象的注册。每次后续注册都需要更多时间:注册了 500 个对象后,每次后续注册都需要超过 50 毫秒,注册了 1000 个代码对象后,需要超过 300 毫秒。这个问题已被 报告给 GDB 开发人员,但目前还没有解决方案。为了减轻 GDB 的压力,GDB JIT 集成的当前实现以两种模式运行:默认模式和完整模式(由
--gdbjit-full
标志启用)。在默认模式下,V8 仅通知 GDB 有关附加了源信息的代码对象(这通常包括所有用户脚本)。在完整模式下,通知 GDB 有关所有生成的代码对象(存根、IC、跳板)。在 x64 上,GDB 无法在没有
.eh_frame
部分的情况下正确地展开堆栈 (问题 1053)GDB 未收到有关从快照反序列化的代码的通知 (问题 1054)
仅支持 Intel 兼容 CPU 上的 Linux 操作系统。对于不同的操作系统,应该生成不同的 ELF 头文件,或者应该使用完全不同的对象格式。
启用 GDB JIT 接口会禁用压缩 GC。这样做是为了减轻 GDB 的压力,因为注销和注册每个移动的代码对象会产生相当大的开销。
GDB JIT 集成仅提供近似的源信息。它不提供有关局部变量、函数参数、堆栈布局等的任何信息。它不启用单步执行 JavaScript 代码或在给定行上设置断点。但是,可以根据函数名称在函数上设置断点。