[英]gdb doesn't show source-level debug info for JITted code made by LLVM's MCJIT
我正在嘗試提高我們正在編寫的 JIT 的可調試性。
JIT 是一種跟蹤 JIT,它使用 LLVM 在運行時使用 ExecutionEngine 接口發出代碼(據我所知,它是 MCJIT 的變體,而不是更新的 ORC 東西)。
我們使用 LLVM 的 C++ API 在內存中生成一個 LLVM 模塊,然后最終制作這樣的執行引擎:
auto MPtr = std::unique_ptr<Module>(M);
string ErrStr;
ExecutionEngine *EE =
EngineBuilder(std::move(MPtr))
.setEngineKind(EngineKind::JIT)
.setMemoryManager(std::unique_ptr<MCJITMemoryManager>(memman))
.setErrorStr(&ErrStr)
.create();
if (EE == nullptr)
errx(EXIT_FAILURE, "Couldn't compile trace: %s", ErrStr.c_str());
...
EE->finalizeObject();
...
// Then later on when we want to execute this code, we call to
// EE->getFunctionAddress(TraceName), where tracename is a function inside
// the module we've just compiled.
(系統這部分的完整代碼在這里)
以這種方式執行代碼對我們來說工作正常。
但是,在調試 gdb 中的 JITted 代碼時,源級調試信息不起作用。
我在 LLVM 文檔(以及gdb 文檔中的此頁面)中找到了這個頁面,它描述了 MCJIT 在運行時編譯代碼時如何在調用 function __jit_debug_register_code()
之前將 DWARF 調試信息放入 memory 緩沖區。 據我了解,當附加 gdb 時,它會在幕后在此符號上放置一個斷點,並為新的 JIT 代碼加載調試信息。
聽起來很完美。 讓我們試試看。 這是一些 JIT 代碼的 IR:
define i8 @__yk_compiled_trace_0(ptr nocapture %0, ptr %1, i64 %2, ptr %3, ptr %4) local_unnamed_addr {
%6 = load ptr, ptr %0, align 8, !dbg !21
%7 = getelementptr %YkCtrlPointVars, ptr %0, i64 0, i32 1, !dbg !21
%8 = load ptr, ptr %7, align 8, !dbg !21
%9 = getelementptr %YkCtrlPointVars, ptr %0, i64 0, i32 2, !dbg !21
%10 = load ptr, ptr %9, align 8, !dbg !21
...
}
...
!5 = !DIFile(filename: "c/noopts.c", directory: "/home/vext01/research/yk/tests", checksumkind: CSK_MD5, checksum: "21402bb47784fb6db5e1a02382e9c053")
...
!21 = !DILocation(line: 46, column: 5, scope: !22)
!22 = distinct !DILexicalBlock(scope: !23, file: !5, line: 45, column: 17)
...
在這里我們可以看到前幾行附加了指向noopts.c
第 46 行的調試元數據。這是我希望在指令指針位於與這些 IR 行對應的機器代碼上時在 gdb 中顯示的信息。
我已經通過在__jit_debug_register_code()
上放置我自己的斷點來驗證 LLVM 正在做正確的事情:
$ YKD_SERIALISE_COMPILATION=1 gdb /tmp/.tmpcaG9yl/noopts
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
...
(gdb) b __jit_debug_register_code
Function "__jit_debug_register_code" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (__jit_debug_register_code) pending.
(gdb) run
Starting program: /tmp/.tmpcaG9yl/noopts
DW_FORM_rnglistx index pointing outside of .debug_rnglists offset array [in module /home/vext01/research/yk/tests/../ykcapi/scripts/../../target/debug/deps/libykcapi.so]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff4555700 (LWP 11177)]
[Thread 0x7ffff4555700 (LWP 11177) exited]
Thread 1 "noopts" hit Breakpoint 1, 0x00007ffff5c8d690 in __jit_debug_register_code.localalias () from /home/vext01/research/yk/tests/../ykcapi/scripts/../../target/debug/deps/libykcapi.so
(gdb)
偉大的。 所以現在讓我們在 JITted 代碼的開頭放置一個斷點並切換到split
布局:
(gdb) b __yk_compiled_trace_0
Breakpoint 2 at 0x7ffff4fe8004
(gdb) c
Continuing.
Thread 1 "noopts" hit Breakpoint 2, 0x00007ffff4fe8004 in __yk_compiled_trace_0 ()
(gdb) la split
gdb不顯示出處信息。 我的問題是為什么?
我的一個理論是 function prolog 沒有任何與之關聯的調試信息,也許如果我繼續編寫稍后的代碼,一些源代碼可能會顯示。 但是,我已經跨過整個 JITted function 並且沒有顯示任何 PC 值的源代碼級信息。
(幾周前我正在使用 LLVM 的主要分支)
編輯@Andrew 的建議(謝謝):
(我不得不更新到 gdb-12.1 以獲得main info jit
的東西。還要注意舊的 gdb 不會接受“on”來打開一個選項,而是需要“1”)
啟用這些選項后,這就是我所看到的:
(gdb) set debug jit on
(gdb) b __yk_compiled_trace_0
Function "__yk_compiled_trace_0" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (__yk_compiled_trace_0) pending.
(gdb) run
Starting program: /tmp/.tmpcaG9yl/noopts
[jit] jit_inferior_init: called
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[jit] jit_breakpoint_re_set_internal: breakpoint_addr = 0x7ffff5c8d690
...
[jit] jit_read_descriptor: descriptor_addr = 0x7ffff7f789f0
[jit] jit_register_code: symfile_addr = 0x3c8820, symfile_size = 2776
[jit] jit_bfd_try_read_symtab: symfile_addr = 0x3c8820, symfile_size = 2776
[jit] jit_breakpoint_re_set_internal: breakpoint_addr = 0x7ffff5c8d690
(gdb) maint info jit
jit_code_entry address symfile address symfile size
0x00000000003e8270 0x00000000003c8820 2776
我認為這表明 gdb 攔截新代碼並在進一步的新 JIT 代碼到達時重新設置它的內部斷點。
我仍然不確定為什么 gdb 中沒有顯示源代碼級調試信息。今天我將閱讀 gdb 源代碼,看看是否可以收集任何見解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.