简体   繁体   English

Libunwind PC 值不适用于 addr2line

[英]Libunwind PC value not working with addr2line

I am trying to follow along with an example from the link: https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/我正在尝试按照链接中的示例进行操作: https ://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/

However I have run into a few issues.但是我遇到了一些问题。 I have a piece of code like so that uses libunwind to print backtrace information:我有一段这样的代码,它使用 libunwind 来打印回溯信息:

test.cpp测试.cpp

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>

// Call this function to get a backtrace.
void backtrace() {
  unw_cursor_t cursor;
  unw_context_t context;

  // Initialize cursor to current frame for local unwinding.
  unw_getcontext(&context);
  unw_init_local(&cursor, &context);

  // Unwind frames one by one, going up the frame stack.
  while (unw_step(&cursor) > 0) {
    unw_word_t offset, pc;
    unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (pc == 0) {
      break;
    }
    printf("0x%lx:", pc);

    char sym[256];
    if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
      printf(" (%s+0x%lx)\n", sym, offset);
    } else {
      printf(" -- error: unable to obtain symbol name for this frame\n");
    }
  }
}

void foo() {
  backtrace(); // <-------- backtrace here!
}

void bar() {
  foo();
}

int main(int argc, char **argv) {
  bar();

  return 0;
}

Running this code produces output like so ie the program counter value: (function_name+0xoffset)运行此代码会产生类似这样的输出,即程序计数器值:(function_name+0xoffset)

$ gcc -o libunwind_backtrace -Wall -g test.cpp -lunwind
$ LD_LIBRARY_PATH=/usr/local/lib ./libunwind_backtrace
0x56154da9c9c3: (_Z3foov+0x9)
0x56154da9c9cf: (_Z3barv+0x9)
0x56154da9c9e6: (main+0x14)
0x7facd1cc82e1: (__libc_start_main+0xf1)
0x56154da9c7da: (_start+0x2a)

As mentioned in the link above the program counter value to the left of the function name can be fed to addr2line to obtain file name and line number information.如上面链接中所述,可以将函数名称左侧的程序计数器值提供给 addr2line 以获取文件名和行号信息。 However whenever I try to do so (eg. for the function foo):但是,每当我尝试这样做时(例如,对于函数 foo):

$ addr2line 56154da9c9c3 -e libunwind_backtrace
??:0

After looking at the objdump file I have found that function foo has a debug entry:查看 objdump 文件后,我发现函数 foo 有一个调试条目:

$ objdump --dwarf=info libunwind_backtrace
...
<1><723>: Abbrev Number: 27 (DW_TAG_subprogram)
   <724>   DW_AT_external    : 1
   <724>   DW_AT_name        : foo
   <728>   DW_AT_decl_file   : 1
   <729>   DW_AT_decl_line   : 32
   <72a>   DW_AT_linkage_name: (indirect string, offset: 0x1cb): _Z3foov
   <72e>   DW_AT_low_pc      : 0x9ba
   <736>   DW_AT_high_pc     : 0xc
   <73e>   DW_AT_frame_base  : 1 byte block: 9c     (DW_OP_call_frame_cfa)
   <740>   DW_AT_GNU_all_tail_call_sites: 1
...

and when I enter the value for DW_at_low_pc into addrline it manages to produce the correct output.当我将 DW_at_low_pc 的值输入到 addrline 时,它设法产生了正确的输出。

addr2line 0x9c6 -e libunwind_backtrace
/root/Desktop/test.cpp:36
  1. Firstly why does the PC value returned by libunwind differ from that of the DW_AT_low_pc?首先,为什么 libunwind 返回的 PC 值与 DW_AT_low_pc 的不同?

  2. It seems like libunwind is returning an incorrect value for the PC but if this is the case then how is libunwind able to obtain the function names?似乎 libunwind 为 PC 返回了不正确的值,但如果是这种情况,那么 libunwind 如何获取函数名称?

  3. Is there any way given the PC value from libunwind that I can obtain the file name and file number using addr2line or some other command line tool?有什么方法可以从 libunwind 给出 PC 值,我可以使用 addr2line 或其他一些命令行工具获取文件名和文件号?

Thank you for reading, I know its a kinda long question.感谢您的阅读,我知道这是一个很长的问题。

  1. DW_AT_low_pc is the relocated address of the first instruction associated with (in this case) the function. DW_AT_low_pc是与函数(在本例中)关联的第一条指令的重定位地址。 Looking at the addresses in your stack trace, it seems that your executable has been loaded at 0x56154da9c000 and that foo() begins at 0x56154da9c9ba , ie 0x56154da9c000 + 0x9ba .查看堆栈跟踪中的地址,您的可执行文件似乎已加载到0x56154da9c000并且foo()0x56154da9c9ba开始,即0x56154da9c000 + 0x9ba The program counter is 0x56154da9c9c3 which, as libunwind suggests, is 0x56154da9c9ba + 0x9 .程序计数器是0x56154da9c9c3 ,正如 libunwind 所暗示的那样,它是0x56154da9c9ba + 0x9

  2. I haven't looked at libunwind but it's worth pointing out that address->function name mapping doesn't require DWARF;我没有看过 libunwind,但值得指出的是地址-> 函数名称映射不需要 DWARF; in general, the ELF symbol table will suffice (and is much faster to navigate).一般来说,ELF 符号表就足够了(而且导航起来要快得多)。

  3. I suggest trying the unrelocated program counter, ie 0x9c3.我建议尝试未重定位的程序计数器,即 0x9c3。

libunwind is good at fetching addresses from the call stack, but it does not do much more than this. libunwind 擅长从调用堆栈中获取地址,但除此之外它所做的并不多。 addr2line works well when no relocation is involved, but ASLR as made relocations much more common. addr2line 在不涉及重定位时运行良好,但 ASLR 使重定位变得更加普遍。

Nowadays, the right tool is libbacktrace by Ian Lance Taylor .如今,正确的工具是Ian Lance Taylor 的 libbacktrace It provides the functionality of both libunwind and addr2line combined in a single library.它提供了将 libunwind 和 addr2line 组合在一个库中的功能。

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

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