简体   繁体   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

I want to programmatically convert backtrace stack addresses (eg obtained from backtrace_symbols/libunwind) to file:line:column.我想以编程方式将回溯堆栈地址(例如从 backtrace_symbols/libunwind 获得)转换为 file:line:column。 I'm on OSX but doubt this makes a difference.我在 OSX 上,但怀疑这有什么不同。

All of these give wrong line number (line 11) for the call to fun1():所有这些都为调用 fun1() 提供了错误的行号(第 11 行):

  • atos阿托斯
  • addr2line地址线
  • llvm-symbolizer llvm-符号化器
  • lldb image lookup --address using lldb's pc addresses in bt lldb image lookup --address使用 lldb 在 bt 中的 pc 地址

lldb bt itself gives correct file:line:column, (line 7) as shown below. lldb bt本身给出正确的文件:行:列,(第 7 行),如下所示。

How do I programmatically get the correct stack address such that, when using atos/addr2line/llvm-symbolizer/image lookup --address, it would resolve to the correct line number?我如何以编程方式获取正确的堆栈地址,以便在使用 atos/addr2line/llvm-symbolizer/image lookup --address 时,它会解析为正确的行号? lldb bt is doing it correctly, so there must be a way to do it. lldb bt做对了,所以一定有办法做到。 Note that if I use backtrace_symbols or libunwind (subtracted from info.dli_saddr after calling dladdr ), I'd end up with the same address 0x0000000100000f74 as shown in lldb bt that points to the wrong line number 11需要注意的是,如果我使用backtrace_symbolslibunwind (相减info.dli_saddr调用后dladdr ),我结束了同一个地址0x0000000100000f74如图LLDB BT是指向错误的行数11

Note: in .lldbinit, if I add settings set frame-format frame start-addr:${line.start-addr}\\n it will show the correct address (ie resolve to 0x0000000100000f6f instead of 0x0000000100000f74, which will resolve to the correct line 7).注意:在 .lldbinit 中,如果我添加settings set frame-format frame start-addr:${line.start-addr}\\n它将显示正确的地址(即解析为 0x0000000100000f6f 而不是 0x0000000100000f74,它将解析为正确的第 7 行)。 However, how do I programmatically generate start-addr from ac program without calling spawning a call to lldb -p $pid (calling lldb has other issues, eg overhead compared to llvm-symbolizer, and in fact can hang forever even with -batch ).但是,如何以编程方式从 ac 程序生成 start-addr 而不调用产生对lldb -p $pid调用(调用 lldb 有其他问题,例如与 llvm-symbolizer 相比的开销,实际上即使使用-batch也可以永远挂起) .

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

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)

likewise with addr2line同样使用addr2line

It's easier to understand if you look at the disassembly for fun1_aux -- you'll see a CALLQ instruction to fun1 , followed by something like a mov %rax, $rbp-16 or something like that, the first instruction of your a++ line.如果您查看fun1_aux的反汇编会更容易理解——您会看到一条 CALLQ 指令到fun1 ,然后是类似mov %rax, $rbp-16或类似内容的指令,即a++行的第一条指令。 When you have called fun1 , the return address is the instruction that will be executed when fun1 exits, the mov %rax, $rbp-16 or whatever.当您调用fun1返回地址是当fun1退出时将执行的指令、 mov %rax, $rbp-16或其他任何指令。

This isn't intuitively how most people think of the computer working -- they expect to look at frame 1, fun1_aux , and see the "current pc value" be the CALLQ, because the call is executing .这不是大多数人对计算机工作的直观看法——他们希望查看第 1 帧fun1_aux并看到“当前 pc 值”是 CALLQ,因为调用正在执行 But of course, that's not correct, the call instruction has completed, and the saved pc is going to point to the next instruction.但是当然,那是不正确的,调用指令已经完成,保存的pc将指向下一条指令。

In cases like this, the next instruction is part of the next source line, so it's a little extra confusing.在这种情况下,下一条指令是下一条源代码行的一部分,因此有点令人困惑。 Even better is if you have a function that calls a "noreturn" function like abort() -- the final instruction in the function will be a CALLQ, and if you look at the return address instruction, it may point to the next function .更好的是,如果您有一个函数调用像abort()这样的“noreturn”函数——函数中的最后一条指令将是 CALLQ,如果您查看返回地址指令,它可能指向下一个函数

So when lldb is symbolicating stack frames above frame #0, it knows to do a symbol lookup with saved_pc - 1 to move the address back into the CALLQ instruction.因此,当 lldb 对帧 #0 上方的堆栈帧进行符号化时,它知道使用saved_pc - 1进行符号查找以将地址移回 CALLQ 指令。 That's not a valid address, so it should never show you saved_pc - 1 , but it should do symbol / file & line lookups based on it.这不是一个有效的地址,所以它永远不应该向你显示saved_pc - 1 ,但它应该基于它进行符号/文件和行查找。

You can get the same effect for your manual symbolication by doing the same thing.通过执行相同的操作,您可以为手动符号化获得相同的效果。 The one caveat is if you have an asynchronous interrupt ( _sigtramp on macOS), the frame above _sigtramp should not have its saved pc value decremented.一个需要注意的是,如果你有一个异步中断( _sigtramp在MacOS),上述框架_sigtramp不应该其保存的PC值递减。 You could be executing the first instruction of a function when the signal is received, and decrementing it would put you in the previous function which would be very confusing.当接收到信号时,您可能正在执行函数的第一条指令,并且递减它会使您进入前一个函数,这会非常混乱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM