[英]Wrong line numbers from 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);
在 bt_strings 中,我找到了以下形式的行
./prog() [0x402e42]
现在我获取地址(十六进制字符串)并将其提供给 addr2line。 这有时会导致明显错误的行号。 互联网搜索让我找到这篇文章,其中显示
readelf -wl ./prog
指示该行的实际位置,或者更确切地说,该符号已移动到当前行的行数。
编辑:当我使用-g -O0
编译时会发生这种情况,即明确地没有优化。 编译器是gcc 4.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;
}
编译运行:
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
使用 addr2line 收益率测试例如 0x400ef0
/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
等显示的是返回地址,如call
后的行所示。 我想获得“输入”行,即之前显示的内容!
你一定可以的! 我知道一个使用libunwind的示例实现。 请参阅此博客文章: http ://blog.bigpixel.ro/stack-unwinding-stack-trace-with-gcc/
归结为这段代码(从文章中字面复制):
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,但为 x86 添加 -1 或为 aarch32 添加 -8 以获得源代码行的实际地址。 后向 CPP 使用相同的想法。 https://github.com/bombela/backward-cpp/blob/master/backward.hpp (搜索 ip_before_instruction)。 我发现唯一不减去的时间是地址是崩溃发生的地方。 这是有道理的,因为在调用错误处理程序(例如为页面错误提供服务)之后,它可以恢复执行错误指令。
你有没有尝试过
__LINE__
它是一个预处理器符号,但你可以编译它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.