如何使用atos / addr2line / llvm-symbolizer / lldb图像查找--address获得与lldb相同的行号

问题描述 投票:0回答:1

我想以编程方式将回溯堆栈地址(例如从backtrace_symbols / libunwind获得)转换为file:line:column。我正在使用OSX,但怀疑是否会有所不同。

所有这些都给fun1()的调用提供了错误的行号(第11行):

  • atos
  • addr2line
  • llvm-符号
  • lldb image lookup --address使用bt中lldb的pc地址

lldb bt本身给出了正确的file:line:column,(第7行),如下所示。

我如何以编程方式获取正确的堆栈地址,以便在使用atos / addr2line / llvm-symbolizer / image查找--address时,它将解析为正确的行号? lldb bt正确执行此操作,因此必须有一种方法可以执行此操作。请注意,如果我使用backtrace_symbolslibunwind(在调用info.dli_saddr之后从dladdr减去),我将得到与lldb bt所示相同的地址0x0000000100000f74,该地址指向错误的行号11

注意:在.lldbinit中,如果我添加settings set frame-format frame start-addr:${line.start-addr}\n,它将显示正确的地址(即解析为0x0000000100000f6f而不是0x0000000100000f74,它将解析为正确的第7行)。但是,如何在不调用生成对lldb -p $pid的调用的情况下以编程方式从ac程序生成start-addr(调用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相同

lldb backtrace addr2line
1个回答
0
投票

[如果您查看fun1_aux的反汇编会更容易理解-您会看到fun1的CALLQ指令,后跟mov %rax, $rbp-16之类的内容,或者是a++的第一条指令]行。当您调用fun1时,返回地址是将在fun1退出,mov %rax, $rbp-16或其他任何内容时执行的指令。

这不是直观上大多数人如何看待计算机的工作方式-他们希望看一下第1帧fun1_aux,并将“当前pc值”看成CALLQ,因为调用是执行中 。但是,当然,这是不正确的,调用指令已完成,并且保存的pc将指向下一条指令。

在这种情况下,下一条指令是下一条源代码行的一部分,因此这会造成一些混乱。更好的是,如果您有一个调用诸如abort()之类的“ noreturn”函数的函数,则该函数中的最后一条指令将是CALLQ,并且如果您查看返回地址指令,它可能指向next功能

因此,当lldb在第0帧上方表示堆栈帧时,它知道使用saved_pc - 1进行符号查找,以将地址移回CALLQ指令。这不是一个有效的地址,因此它永远不要向您显示saved_pc - 1,但应基于该地址进行符号/文件和行查找。

通过执行相同的操作,您可以为手动符号获得相同的效果。一个警告是,如果您有一个异步中断(在macOS上为_sigtramp),则_sigtramp上方的帧不应减小其已保存的pc值。当接收到信号时,您可能正在执行一个函数的第一条指令,并将其递减将使您进入previous function,这将非常令人困惑。

© www.soinside.com 2019 - 2024. All rights reserved.