簡體   English   中英

gdb 不顯示由 LLVM 的 MCJIT 生成的 JITted 代碼的源代碼級調試信息

[英]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 不顯示源級信息

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 源代碼,看看是否可以收集任何見解。

我可以提供部分答案。

我們將所有 JIT 代碼放入其中的 function 沒有dbg! 元數據,這會導致 gdb 不顯示任何源級信息。

我通過從第一個 JITted 指令復制子程序元數據使它有點工作。 我能夠跨過 JITted 跟蹤並在源窗格更新中看到 C 代碼。

顯示來源

還要注意 JITted 代碼現在如何識別為主要代碼。 這是由於我復制元數據的方式不對。

(現在我們面臨的另一個問題是,當 LLVM 遇到帶有dbg!的指令時,它會因斷言失敗而崩潰!對於不同的子程序。這是由於我們跟蹤 JIT 的工作方式,通過在運行時內聯指令。但那是我認為這個 SO 問題的 scope)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM