首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Libunwind值不适用于addr2line

Libunwind值不适用于addr2line
EN

Stack Overflow用户
提问于 2018-03-03 10:26:21
回答 2查看 1.2K关注 0票数 2

我正试图跟随链接中的一个示例:https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/

然而,我遇到了一些问题。我有一段代码,类似于这样,它使用libunwind打印反向跟踪信息:

test.cpp

代码语言:javascript
复制
#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;
}

运行此代码将产生类似于这样的输出,即程序计数器值:(function_name+0xoffset)

代码语言:javascript
复制
$ 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)

正如上面的链接所提到的,函数名左侧的程序计数器值可以输入到addr2line,以获得文件名和行号信息。然而,每当我试图这样做的时候(如。(关于foo函数):

代码语言:javascript
复制
$ addr2line 56154da9c9c3 -e libunwind_backtrace
??:0

在查看objdump文件之后,我发现函数foo有一个调试条目:

代码语言:javascript
复制
$ 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
...

当我在addrline中输入DW_at_low_pc的值时,它设法生成正确的输出。

代码语言:javascript
复制
addr2line 0x9c6 -e libunwind_backtrace
/root/Desktop/test.cpp:36
  1. 首先,为什么libunwind返回的PC值与DW_AT_low_pc不同?
  2. 看起来libunwind为PC返回了一个不正确的值,但是如果是这样,那么libunwind如何才能获得函数名呢?
  3. 给出从libunwind获得的PC值,我是否可以使用addr2line或其他命令行工具获得文件名和文件号?

谢谢你的阅读,我知道这是个很长的问题。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-01-18 11:28:04

libunwind擅长从调用堆栈中获取地址,但它所做的并不比这更多。当不涉及重新定位时,addr2line工作得很好,但是ASLR使重新定位更加常见。

现在,正确的工具是伊恩·兰斯·泰勒( Ian Lance Taylor )。它提供了合并在一个库中的libunwind和addr2line的功能。

票数 1
EN

Stack Overflow用户

发布于 2018-03-07 17:28:35

  1. DW_AT_low_pc是与该函数相关联(在本例中)的first指令的重新定位的地址。查看堆栈跟踪中的地址,您的可执行文件似乎已在0x56154da9c000加载,而foo()开始于0x56154da9c9ba,即0x56154da9c000 + 0x9ba。程序计数器是0x56154da9c9c3,正如libunwind所建议的,它是0x56154da9c9ba + 0x9
  2. 我还没有看过libunwind,但是值得指出的是,address->函数名映射并不需要矮小;一般来说,ELF符号表就足够了(而且导航速度要快得多)。
  3. 我建议尝试未重新定位的程序计数器,即0x9c3。
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49083152

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档