addr2line 通过读取二进制文件中的 dwarf 调试信息(如 .debug_line 段)将内存地址解析为源码行号,需用 -g 编译且未 strip;调用时应使用 popen 执行 addr2line -f -c -e ./app 0xaddr,并配合 backtrace 获取栈帧地址。

addr2line 为什么能解析内存地址到源码行号
它靠的是二进制文件里保留的调试信息(.debug_line 等 DWARF 段),不是靠运行时符号表。所以你的可执行文件必须用 -g 编译,且没被 strip 过。如果看到 ?? 或空输出,八成是调试信息丢了——检查 file your_program 输出里有没有 debug 字样,或者用 readelf -S your_program | grep debug 确认段存在。
如何在 C++ 程序里调用 addr2line 解析泄漏地址
别自己手写 ELF 解析,直接走系统命令最稳。关键点在于:地址要转成十六进制(带 0x 前缀)、指定可执行文件路径、加 -f -C -e 参数。注意 addr2line 默认读 stdin,但程序里更适合用 popen 构造完整命令行。
-
addr2line -f -C -e ./myapp 0x40123a是典型调用格式,-C启用 C++ 符号反解(demangle),-f输出函数名 - 地址必须是运行时捕获的虚拟地址(比如
malloc返回值),且和./myapp的加载基址对齐——如果你用了 ASLR,得先用/proc/self/maps算偏移,或编译时加-no-pie -fPIE关闭 - 输出是两行(函数名 + 文件:行号),用
fgets分两次读,中间可能有换行或空行,要跳过空白行
泄漏地址从哪来?别直接用 malloc 返回值
malloc 返回的是堆内存地址,但泄漏检测真正关心的是「谁申请了它」,也就是调用栈的返回地址(return address)。所以得在 malloc hook 里用 backtrace 获取栈帧,再取 backtrace[1](跳过 hook 函数自身)传给 addr2line。
- 用
execinfo.h的backtrace+backtrace_symbols只能拿到符号名,不带行号;要精确到行,必须走addr2line - 注意栈帧地址是调用指令的下一条地址(即
call指令后的rip),addr2line能自动往前找所属行,不用手动减 1 - 如果程序用了
LD_PRELOADhook,确保addr2line查的是原始可执行文件,不是libc或其他 so
常见失败现象和绕过方法
最常遇到的是 addr2line: 'xxx': No such file 或输出全 ??。这不是代码问题,而是环境链路断了。
立即学习“C++免费学习笔记(深入)”;
- 路径写错:
-e后必须是**当前进程实际加载的可执行文件路径**,不是编译路径;建议用/proc/self/exe读符号链接再realpath - 地址无效:栈帧地址被优化掉(加
-O0或-fno-omit-frame-pointer)、或函数内联了(加__attribute__((noinline))标记分配函数) - 权限问题:
addr2line在容器或 chroot 里可能找不到,可提前把二进制和调试文件 cp 到安全路径,或改用llvm-symbolizer(需安装llvm)
真正麻烦的是跨平台和 release 构建——调试信息体积大,上线通常要剥离。所以这个方案只适合开发/测试阶段快速定位,别指望它进生产监控。








