簡體   English   中英

如何使用atos/addr2line/llvm-symbolizer/lldb圖像查找--address獲取與lldb相同的行號

[英]how to get line numbers same as lldb using atos/addr2line/llvm-symbolizer/lldb image lookup --address

我想以編程方式將回溯堆棧地址(例如從 backtrace_symbols/libunwind 獲得)轉換為 file:line:column。 我在 OSX 上,但懷疑這有什么不同。

所有這些都為調用 fun1() 提供了錯誤的行號(第 11 行):

  • 阿托斯
  • 地址線
  • llvm-符號化器
  • lldb image lookup --address使用 lldb 在 bt 中的 pc 地址

lldb bt本身給出正確的文件:行:列,(第 7 行),如下所示。

我如何以編程方式獲取正確的堆棧地址,以便在使用 atos/addr2line/llvm-symbolizer/image lookup --address 時,它會解析為正確的行號? lldb bt做對了,所以一定有辦法做到。 需要注意的是,如果我使用backtrace_symbolslibunwind (相減info.dli_saddr調用后dladdr ),我結束了同一個地址0x0000000100000f74如圖LLDB BT是指向錯誤的行數11

注意:在 .lldbinit 中,如果我添加settings set frame-format frame start-addr:${line.start-addr}\\n它將顯示正確的地址(即解析為 0x0000000100000f6f 而不是 0x0000000100000f74,它將解析為正確的第 7 行)。 但是,如何以編程方式從 ac 程序生成 start-addr 而不調用產生對lldb -p $pid調用(調用 lldb 有其他問題,例如與 llvm-symbolizer 相比的開銷,實際上即使使用-batch也可以永遠掛起) .

clang -g -o /tmp/z04 test_D20191123T162239.c

test_D20191123T162239.c:

void fun1(){
}

void fun1_aux(){
  int a = 0;

  fun1(); // line 7

  mylabel:
    if(1){
      a++; // line 11
    }
}

int main(int argc, char *argv[]) {
  fun1_aux();
  return 0;
}
lldb /tmp/z04
(lldb) target create "/tmp/z04"
Current executable set to '/tmp/z04' (x86_64).
(lldb) b fun1
Breakpoint 1: where = z04`fun1 + 4 at test_D20191123T162239.c:2:1, address = 0x0000000100000f54
(lldb) r
Process 7258 launched: '/tmp/z04' (x86_64)
Process 7258 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100000f54 z04 fun1 + 4 at  test_D20191123T162239.c:2:1
   1    void fun1(){
-> 2    }
   3
   4    void fun1_aux(){
   5      int a = 0;
   6
   7      fun1();
Target 0: (z04) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000100000f54 z04 fun1 + 4 at  test_D20191123T162239.c:2:1
    frame #1: 0x0000000100000f74 z04 fun1_aux + 20 at  test_D20191123T162239.c:7:3
    frame #2: 0x0000000100000fab z04 main(argc=1, argv=0x00007ffeefbfb748) + 27 at  test_D20191123T162239.c:16:3
    frame #3: 0x00007fff71c182e5 libdyld.dylib start + 1
    frame #4: 0x00007fff71c182e5 libdyld.dylib start + 1
(lldb)


(lldb) image lookup --address 0x0000000100000f74
      Address: z04[0x0000000100000f74] (z04.__TEXT.__text + 36)
      Summary: z04`fun1_aux + 20 at test_D20191123T162239.c:11:8
echo 0x0000000100000f74 | llvm-symbolizer -obj=/tmp/z04
fun1_aux
test_D20191123T162239.c:11:8
atos -o /tmp/z04 0x0000000100000f74
fun1_aux (in z04) (test_D20191123T162239.c:11)

同樣使用addr2line

如果您查看fun1_aux的反匯編會更容易理解——您會看到一條 CALLQ 指令到fun1 ,然后是類似mov %rax, $rbp-16或類似內容的指令,即a++行的第一條指令。 當您調用fun1返回地址是當fun1退出時將執行的指令、 mov %rax, $rbp-16或其他任何指令。

這不是大多數人對計算機工作的直觀看法——他們希望查看第 1 幀fun1_aux並看到“當前 pc 值”是 CALLQ,因為調用正在執行 但是當然,那是不正確的,調用指令已經完成,保存的pc將指向下一條指令。

在這種情況下,下一條指令是下一條源代碼行的一部分,因此有點令人困惑。 更好的是,如果您有一個函數調用像abort()這樣的“noreturn”函數——函數中的最后一條指令將是 CALLQ,如果您查看返回地址指令,它可能指向下一個函數

因此,當 lldb 對幀 #0 上方的堆棧幀進行符號化時,它知道使用saved_pc - 1進行符號查找以將地址移回 CALLQ 指令。 這不是一個有效的地址,所以它永遠不應該向你顯示saved_pc - 1 ,但它應該基於它進行符號/文件和行查找。

通過執行相同的操作,您可以為手動符號化獲得相同的效果。 一個需要注意的是,如果你有一個異步中斷( _sigtramp在MacOS),上述框架_sigtramp不應該其保存的PC值遞減。 當接收到信號時,您可能正在執行函數的第一條指令,並且遞減它會使您進入前一個函數,這會非常混亂。

暫無
暫無

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

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