56

我正在尝试在 Unix 中使用 addr2line 命令,但每次它都给出与 ??:0 相同的输出。我正在发出命令addr2line -e a.out 0x4005BDC。我在使用valgrind查找内存泄漏的工具运行此 a.out 可执行文件时得到了此地址。-g我还用选项编译了源代码。

4

4 回答 4

36

您也可以使用 gdb 代替 addr2line 来检查内存地址。在 gdb 中加载可执行文件并打印存储在该地址处的符号名称。16 检查符号表

(gdb) info symbol 0x4005BDC 
于 2011-10-04T13:45:13.747 回答
24

您需要指定 addr2line 的偏移量,而不是虚拟地址 (VA)。大概如果您关闭了地址空间随机化,您可以使用完整的 VA,但在大多数现代操作系统中,地址空间是随机的以用于新进程。

给定 valgrind 的 VA 0x4005BDC,在内存中找到进程或库的基地址。/proc/<PID>/maps通过在程序运行时检查文件来做到这一点。感兴趣的行是text您的进程段,可通过权限r-xp和程序或库的名称来识别。

假设基础 VA 是0x0x4005000。然后你会发现 valgrind 提供的 VA 和基本 VA: 之间的区别0xbdc。然后,将其提供给 add2line:

addr2line -e a.out -j .text 0xbdc

看看这是否能让你得到你的行号。

于 2011-10-04T15:35:49.620 回答
13

这正是你使用它的方式。但是,您拥有的地址可能与源代码中的某些内容不直接对应。

例如:

$ cat t.c
#include <stdio.h>
int main()
{
    printf("hello\n");
    return 0;
}
$ gcc -g t.c
$ addr2line -e a.out 0x400534
/tmp/t.c:3
$ addr2line -e a.out 0x400550
??:0

0x400534main我的地址。0x400408也是 中的有效函数地址a.out,但它是由 GCC 生成/导入的一段代码,没有调试信息。(在这种情况下,__libc_csu_init您可以使用 . 查看可执行文件的布局readelf -a your_exe。)

其他时候addr2line会失败的情况是,如果您包含一个没有调试信息的库。

于 2011-10-04T13:40:21.423 回答
12

尝试添加-f选项以显示函数名称:

addr2line -f -e a.out 0x4005BDC
于 2015-04-24T14:59:14.933 回答