addr2line中的行号错误 我试图在C++程序中找到回溯中的调用的精确代码。现在我正在使用这些行(来自backtrace的手册页)来获取跟踪: void *bt_buffer[1000]; char **bt_strings; int bt_nptrs = backtrace(bt_buffer, 1000); bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);

addr2line中的行号错误 我试图在C++程序中找到回溯中的调用的精确代码。现在我正在使用这些行(来自backtrace的手册页)来获取跟踪: void *bt_buffer[1000]; char **bt_strings; int bt_nptrs = backtrace(bt_buffer, 1000); bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);,c++,c,callstack,backtrace,binutils,C++,C,Callstack,Backtrace,Binutils,在bt_字符串中,我找到了形式的行 ./prog() [0x402e42] 现在,我获取地址(十六进制字符串)并将其提供给addr2line。这有时会导致明显错误的行号。互联网搜索让我想到了这一点,它表明 readelf -wl ./prog 指示行的实际位置,或者更确切地说,符号移动到当前行的行数 编辑:当我使用-g-O0编译时会发生这种情况,也就是说,没有进行优化。编译器是gcc4.6.3是否还有另一个编译器标志我遗漏了 我的问题如下:我需要将其自动化。我需要我的程序创建回溯(完成),提

在bt_字符串中,我找到了形式的行

./prog() [0x402e42]
现在,我获取地址(十六进制字符串)并将其提供给addr2line。这有时会导致明显错误的行号。互联网搜索让我想到了这一点,它表明

readelf -wl ./prog
指示行的实际位置,或者更确切地说,符号移动到当前行的行数

编辑:当我使用
-g-O0
编译时会发生这种情况,也就是说,没有进行优化。编译器是
gcc4.6.3
是否还有另一个编译器标志我遗漏了

我的问题如下:我需要将其自动化。我需要我的程序创建回溯(完成),提取文件(完成)和行号(失败)

我当然可以调用
readelf
并解析输出,但这并不真正合适,因为每个符号的输出都不同,具体取决于发生了什么。有时,符号的地址在一行中,而有关行偏移的信息在下一行中

总而言之:

是否有一种优雅的方法可以在运行时从程序内部获取回溯中函数调用的准确行号?

编辑:示例代码:

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <execinfo.h>
#include <iostream>
#include <stdlib.h>

void show_backtrace()
{
  // get current address
  void* p = __builtin_return_address(0);
  std::cout << std::hex << p << std::endl;

  // get callee addresses
  p = __builtin_return_address(1);
  std::cout << std::hex << p << std::endl;

  p = __builtin_return_address(2);
  std::cout << std::hex << p << std::endl;
}

void show_backtrace2()
{
  void *array[10];
  size_t size;
  char **strings;
  int i;

  size = backtrace (array, 10);
  strings = backtrace_symbols ((void *const *)array, size);

  for (i = 0; i < size; i++)
    {
      std::cout << strings[i] << std::endl;
    }

  free (strings);
}

void show_backtrace3 (void)
{
  char name[256];
  unw_cursor_t cursor; unw_context_t uc;
  unw_word_t ip, sp, offp;

  unw_getcontext (&uc);
  unw_init_local (&cursor, &uc);

  while (unw_step(&cursor) > 0)
    {
      char file[256];
      int line = 0;

      name[0] = '\0';
      unw_get_proc_name (&cursor, name, 256, &offp);
      unw_get_reg (&cursor, UNW_REG_IP, &ip);
      unw_get_reg (&cursor, UNW_REG_SP, &sp);

      std::cout << std:: hex << name << " ip = " << (long) ip 
                << " , sp = " << (long) sp << std::endl;
    }
}

void dummy_function2()
{
  show_backtrace();
  show_backtrace2();
  show_backtrace3();
}

void dummy_function1()
{ 
  dummy_function2 (); 
} // line 73

int main(int argc, char **argv)
{
  dummy_function1 ();
  return 0;
}
输出:

0x400edb
0x400ef0
0x400f06
./a.out() [0x400cfb]
./a.out() [0x400ee0]
./a.out() [0x400ef0]
./a.out() [0x400f06]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f2f044ae76d]
./a.out() [0x400b79]
_Z15dummy_function2v ip = 400ee5 , sp = 7fffdb564580
_Z15dummy_function1v ip = 400ef0 , sp = 7fffdb564590
main ip = 400f06 , sp = 7fffdb5645a0
__libc_start_main ip = 7f2f044ae76d , sp = 7fffdb5645c0
_start ip = 400b79 , sp = 7fffdb564680
测试例如0x400ef0和addr2line产量

/path/to/code/test_unwind.cc:73
哪一个是正确的文件,但行号错误。在实际应用中,行号可以前后相差很多行

编辑:使用
-S
编译显示相关部分为:

.LCFI34:
  .cfi_def_cfa_register 6
  .loc 2 72 0
  call  _Z15dummy_function2v
  .loc 2 73 0
  popq  %rbp

通过
addr2line
和类似方式显示的是返回地址,如
呼叫后的行所示。我想获得“入口”行,即之前显示的内容

你当然可以!我知道有一个示例实现使用。请参阅此博客帖子:

归结起来就是这段代码(字面上是从文章中复制的):

你试过了吗

__LINE__

它是一个预处理器符号,但您可以在中编译它。

这是因为在大多数体系结构上,程序计数器。您仍然可以使用addr2line,但是为x86添加-1或为aarch32添加-8以获取源代码行的实际地址。反向CPP使用相同的想法。(在ip_指令之前搜索ip_)。我发现唯一不减法的时间是如果地址是发生车祸的地方。这是有意义的,因为在调用错误处理程序(例如,为页面错误提供服务)后,它可能会继续执行错误指令。

在未进行优化的情况下编译时,它是否出错?请尝试
gdb
对可执行文件进行错误处理,并使用
l*0x
。它是否给出了正确的地址,或者它是否也给出了与
addr2line
相同的地址?可能是一个愚蠢的注释,但是。。第73行不是实际的回信地址吗?即通话结束后返回到哪里?换句话说,被推送到堆栈的地址?您是否也尝试过使用汇编输出
-S
对其进行编译,以查看哪个汇编代码对应于哪一行?这帮我解决了一个类似的问题(在Windows中)。在这里我也需要这个,我在这个问题上绊倒了。我只需要不时手动使用它,但在将地址输入addr2line之前,通过从地址中减去1得到了很好的结果,这似乎使它符合调用指令。你有没有想到一个解决方案,也许你也想在这里发布呢?我很高兴一到办公室就尝试一下!我试过了,发现在
getFileAndLine
中,他们也使用
popen
调用
addr2line
。libunwind很有趣(+1),但具有与backtrace类似的功能。结果是相同的偏移行号。在你的问题中,你说你是用
-g
编译的,也许你应该改用
-ggdb
?谢谢你的提示。我尝试使用所有可用的调试符号标志,结果都是一样的。我也考虑过
\uuuuu文件\uuuuuuu
\uuuuuu行\uuuuuu
,但我想从调用
foo()
的函数中获取
foo()
的信息。我无法改变
foo()
的调用方式。总结得很好!谢谢
void show_backtrace (void)
{
    char name[256];
    unw_cursor_t cursor; unw_context_t uc;
    unw_word_t ip, sp, offp;

    unw_getcontext(&uc);
    unw_init_local(&cursor, &uc);

    while (unw_step(&cursor) > 0)
    {
        char file[256];
        int line = 0;

        name[0] = '\0';
        unw_get_proc_name(&cursor, name, 256, &offp);
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_reg(&cursor, UNW_REG_SP, &sp);

        //printf ("%s ip = %lx, sp = %lx\n", name, (long) ip, (long) sp);
        getFileAndLine((long)ip, file, 256, &line);
        printf("%s in file %s line %d\n", name, file, line);
    }
}
__LINE__