[英]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 行):
image lookup --address
使用 lldb 在 bt 中的 pc 地址 lldb bt
本身給出正確的文件:行:列,(第 7 行),如下所示。
我如何以編程方式獲取正確的堆棧地址,以便在使用 atos/addr2line/llvm-symbolizer/image lookup --address 時,它會解析為正確的行號? lldb bt
做對了,所以一定有辦法做到。 需要注意的是,如果我使用backtrace_symbols
或libunwind
(相減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.