Linux下打印栈回溯代码异常,addr2line输出全为?? ??:0求助
问题描述
我尝试在代码触发异常后打印栈回溯信息,获取回溯的代码如下:
constexpr size_t MAX_STACK_FRAMES{ 64 }; static void* stack_traces[MAX_STACK_FRAMES]; void posix_print_stack_trace() { int i, trace_size = 0; char** messages = (char**)NULL; char buffer[1024]{}; // buffer for error message trace_size = backtrace(stack_traces, MAX_STACK_FRAMES); messages = backtrace_symbols(stack_traces, trace_size); /* skip the first couple stack frames (as they are this function and our handler) and also skip the last frame as it's (always?) junk. */ // for (i = 3; i < (trace_size - 1); ++i) // we'll use this for now so you can see what's going on for (i = 0; i < trace_size; ++i) { if (addr2line(global_program_name, stack_traces[i]) != 0)
我通过调用addr2line命令的addr2line函数尝试格式化回溯信息,代码如下:
/* have addr2line map the address to the relevant line in the code */ #ifdef __APPLE__ /* apple does things differently... */ sprintf(addr2line_cmd, "atos -o %.256s %p", program_name, addr); #else sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr); #endif
但得到的输出全为:
?? ??:0 ?? ??:0 ?? ??:0 ?? ??:0 ?? ??:0 ?? ??:0 ?? ??:0
我确定问题出在addr2line的调用方式上,若需调整传入的地址,请问该如何操作?
解决方案
- 修正地址输出格式
%p输出的是带0x前缀的地址,而addr2line/atos需要的是纯十六进制数字(无前缀)。将地址转换为无符号长整型,用%lx格式输出:
#ifdef __APPLE__ sprintf(addr2line_cmd, "atos -o %.256s %lx", program_name, (unsigned long)addr); #else sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %lx", program_name, (unsigned long)addr); #endif
抵消ASLR的地址偏移
系统开启ASLR时,backtrace返回的是虚拟地址,需要减去程序的加载基址才能得到正确的偏移地址:- Linux下读取
/proc/self/maps获取基址:
调用时使用unsigned long get_base_address() { FILE* maps = fopen("/proc/self/maps", "r"); char line[256]; unsigned long base = 0; if (maps) { if (fgets(line, sizeof(line), maps)) { sscanf(line, "%lx-", &base); } fclose(maps); } return base; }(unsigned long)addr - get_base_address()作为传入addr2line的地址。 - macOS下通过dyld接口获取基址:
#include <mach-o/dyld.h> unsigned long get_base_address() { return _dyld_get_image_vmaddr_slide(0); }
- Linux下读取
确保编译时保留调试符号
编译必须添加-g参数保留调试信息,Release版本可搭配-Og(保留调试信息的优化编译),避免符号被剥离导致addr2line无法解析。验证程序路径的正确性
确认program_name是程序的绝对路径,可通过以下方式获取:- Linux:
realpath("/proc/self/exe", NULL) - macOS:
_NSGetExecutablePath接口获取绝对路径
- Linux:
内容的提问来源于stack exchange,提问作者David Partridge
相关产品推荐
相关产品推荐

