来自addr2line的行号错误 [英] Wrong line numbers from addr2line

查看:103
本文介绍了来自addr2line的行号错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试在C ++程序的回溯中找到调用的确切行.现在,我正在使用这些行(来自backtrace的手册页)来获取跟踪:

I try to find the exact line of a call in the backtrace in C++ program. Right now I am using these lines (from the man page of backtrace) to get the trace:

  void *bt_buffer[1000];
  char **bt_strings;
  int bt_nptrs = backtrace(bt_buffer, 1000);
  bt_strings = backtrace_symbols(bt_buffer, bt_nptrs);

在bt_strings中,我找到格式为

In bt_strings I find lines of the form

./prog() [0x402e42]

现在,我获取地址(十六进制字符串)并将其提供给addr2line.有时,这显然会导致错误的行号.互联网搜索将我引到以下帖子中,显示为

Now I take the address (the hex string) and feed it to addr2line. That sometimes results in apparently wrong line numbers. Internet search led me to this post, in which it is shown that

readelf -wl ./prog

表示行确实的位置,或者表示该符号已移动到当前行的行数.

indicates where the line really is, or rather how many lines the symbol has moved to the current line.

编辑:当我使用 -g -O0 进行编译时,即在没有优化的情况下进行编译,就会发生这种情况.编译器是 gcc 4.6.3 ,还有其他我错过的编译器标志吗?

edit: This happens when I compile with -g -O0, i.e. explicetly without optimisations. The compiler is gcc 4.6.3 Is there another compiler flag that I miss?

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

My problem is the following: I need to automate this. I need my program to create a backtrace (done), extract the file (done) and the line number (fail).

我当然可以调用 readelf 并解析输出,但这并不十分合适,因为根据发生的确切情况,符号之间的输出有所不同.有时符号的地址在一行中,而有关行偏移的信息则在下一行中...

I could of course call readelf and parse the output, but that's not really suitable, as the output differs from symbol to symbol depending on what exactly happened. Sometimes The address of a symbol is in one line and the information about the line offset in the next line...

总结:

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

示例代码:

#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;
}

编译并运行:

g++ test_unwind.cc -g -O0 -lunwind  && ./a.out

输出:

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产量

testing e.g. 0x400ef0 with addr2line yields

/path/to/code/test_unwind.cc:73

这是正确的文件,但行号错误.在现实生活中的应用中,行号可以相差很多行,向前和向后.

which is the correct file, but wrong line number. In real life applications the line number can differ by many lines, forward and backward.

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

edit: compiling with -S shows that the relevant part is:

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

addr2line 显示的内容和返回地址类似,如 call 之后的行中所示.我想获得"entry"行,即之前显示的内容!

What is displayed by addr2line and alike is the return address, as shown in the line after the call. I would like to get the "entry" line, i.e. what is shown before!

推荐答案

您一定可以!我知道一个使用 libunwind 的示例实现.请参阅此博客文章: http://blog.bigpixel.ro/使用gcc/

You sure can do! I know of an example implementation which uses libunwind. See this blog post: http://blog.bigpixel.ro/stack-unwinding-stack-trace-with-gcc/

这要归结为这段代码(从文章中照搬过来):

It comes down to this piece of code (literally copied from the article):

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);
    }
}

这篇关于来自addr2line的行号错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆