【发布时间】:2011-11-30 17:01:22
【问题描述】:
我正在尝试在 Unix 中使用 addr2line 命令,但每次它给出的输出都与 ??:0 相同。我以 addr2line -e a.out 0x4005BDC 的身份发出命令。我在使用valgrind 工具运行这个 a.out 可执行文件以查找内存泄漏时得到了这个地址。我还使用-g 选项编译了源代码。
【问题讨论】:
标签: c linux valgrind addr2line
我正在尝试在 Unix 中使用 addr2line 命令,但每次它给出的输出都与 ??:0 相同。我以 addr2line -e a.out 0x4005BDC 的身份发出命令。我在使用valgrind 工具运行这个 a.out 可执行文件以查找内存泄漏时得到了这个地址。我还使用-g 选项编译了源代码。
【问题讨论】:
标签: c linux valgrind addr2line
您也可以使用 gdb 代替 addr2line 来检查内存地址。在 gdb 中加载可执行文件并打印存储在该地址处的符号名称。 16 Examining the Symbol Table.
(gdb) info symbol 0x4005BDC
【讨论】:
您需要为 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
看看这是否能让你得到你的行号。
【讨论】:
这正是您使用它的方式。但是,您拥有的地址可能与源代码中的某些内容不直接对应。
例如:
$ 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
0x400534 在我的例子中是main 的地址。 0x400408 也是a.out 中的有效函数地址,但它是由 GCC 生成/导入的一段代码,没有调试信息。 (在本例中为__libc_csu_init。您可以使用readelf -a your_exe 查看可执行文件的布局。)
addr2line 会失败的其他情况是,如果您包含没有调试信息的库。
【讨论】:
尝试添加-f 选项以显示函数名称:
addr2line -f -e a.out 0x4005BDC
【讨论】: