[英]How to use the addr2line command in Linux?
I am trying to use addr2line command in Unix but everytime it is giving the same output as ??:0. 我试图在Unix中使用addr2line命令,但每次它提供与??:0相同的输出。 I am giving command as
addr2line -e a.out 0x4005BDC
. 我将命令作为
addr2line -e a.out 0x4005BDC
。 I got this address while running this a.out executable with valgrind
tool to find the memory leakage. 我用
valgrind
工具运行这个a.out可执行文件时得到了这个地址,以找到内存泄漏。 I also compiled the source code with -g
option. 我还用
-g
选项编译了源代码。
You can also use gdb instead of addr2line to examine memory address. 您也可以使用gdb而不是addr2line来检查内存地址。 Load executable file in gdb and print the name of a symbol which is stored at the address.
在gdb中加载可执行文件并打印存储在该地址的符号名称。 16 Examining the Symbol Table .
16检查符号表 。
(gdb) info symbol 0x4005BDC
Please check: 请检查:
-g
, addr2line
only support functions has debug information, that is compiled with -g
-g
编译的, addr2line
只支持函数有调试信息,用-g
编译 .text
section. .text
部分中的偏移量。 In the .text
section means the address should point to an instruction in the binary .text
部分中表示地址应指向二进制中的指令 Following is the message from man addr2line
. 以下是来自
man addr2line
的消息。
addr2line - convert addresses into file names and line numbers.
addr2line - 将地址转换为文件名和行号。
The addresses
should be the address in an executable or an offset in a section of a relocatable object. addresses
应该是可执行文件中的地址或可重定位目标文件的一部分中的偏移量。
The output is something like FILENAME:LINENO
, the source file name, and the line number in the file 输出类似于
FILENAME:LINENO
,源文件名和文件中的行号
Take the helloworld
as an example. 以
helloworld
为例。
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
After compile it with gcc -g hello.c
, we could firstly use objdump
to get an idea about the offset information in the generated a.out
file. 在使用
gcc -g hello.c
编译之后,我们首先可以使用objdump
来了解生成的a.out
文件中的偏移信息。
Following is part of the dumped dis-assembly: 以下是倾销拆卸的一部分:
Disassembly of section .text:
0000000000400440 <_start>:
400440: 31 ed xor %ebp,%ebp
400442: 49 89 d1 mov %rdx,%r9
400445: 5e pop %rsi
400446: 48 89 e2 mov %rsp,%rdx
400449: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40044d: 50 push %rax
40044e: 54 push %rsp
40044f: 49 c7 c0 c0 05 40 00 mov $0x4005c0,%r8
400456: 48 c7 c1 50 05 40 00 mov $0x400550,%rcx
40045d: 48 c7 c7 36 05 40 00 mov $0x400536,%rdi
400464: e8 b7 ff ff ff callq 400420 <__libc_start_main@plt>
400469: f4 hlt
40046a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
...
0000000000400536 <main>:
#include <stdio.h>
int main()
{
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
printf("hello\n");
40053a: bf d4 05 40 00 mov $0x4005d4,%edi
40053f: e8 cc fe ff ff callq 400410 <puts@plt>
return 0;
400544: b8 00 00 00 00 mov $0x0,%eax
}
400549: 5d pop %rbp
40054a: c3 retq
40054b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
The most left column of the code is the offset in the binary file. 代码的最左列是二进制文件中的偏移量。
__start
function comes from the standard C library and is precompiled without debug information. __start
函数来自标准C库,并且在没有调试信息的情况下进行预编译。 main
function comes from our helloworld code which has debug information since we compile the file with -g
. main
函数来自我们的helloworld代码,它具有调试信息,因为我们用-g
编译文件。
Following is output of addr2line
: 以下是
addr2line
输出:
$ addr2line -e a.out 0x400442 #offset in the `__start` function
??:?
$ addr2line -e a.out 0x400536 #offset in the `main` function
hello.c:21
$ addr2line -e a.out 0x40054b -f #The last instruction of the `main` function
main
??:?
We could make some conclusions from the above output: 我们可以从上面的输出中得出一些结论:
-g
flag (which means the segment have debug information) could successfully generate filename and linenumber information. -g
标志生成的代码段(这意味着该段具有调试信息)才能成功生成文件名和亚麻码信息。 -g
flag will successfully output filename and linenumber. -g
标志编译的函数体的所有偏移都将成功输出文件名和亚麻布。 The offset 0x40054b
is the last instruction after ret
instruction of the main
function, but we could not get the information. 0x40054b
是main
函数的ret
指令之后的最后一条指令,但是我们无法获取信息。 You need to specify an offset to addr2line, not a virtual address (VA). 您需要为addr2line指定偏移量 ,而不是虚拟地址(VA)。 Presumably if you had address space randomization turned off, you could use a full VA, but in most modern OSes, address spaces are randomized for a new process.
假设您关闭了地址空间随机化,您可以使用完整的VA,但在大多数现代操作系统中,地址空间随机化以用于新进程。
Given the VA 0x4005BDC
by valgrind, find the base address of your process or library in memory. 给定valgrind的VA
0x4005BDC
,在内存中找到进程或库的基址。 Do this by examining the /proc/<PID>/maps
file while your program is running. 通过在程序运行时检查
/proc/<PID>/maps
文件来执行此操作。 The line of interest is the text
segment of your process, which is identifiable by the permissions r-xp
and the name of your program or library. 感兴趣的行是您的流程的
text
段,可以通过权限r-xp
和您的程序或库的名称来识别。
Let's say that the base VA is 0x0x4005000
. 假设基础VA是
0x0x4005000
。 Then you would find the difference between the valgrind supplied VA and the base VA: 0xbdc
. 然后你会发现valgrind提供的VA和基础VA之间的区别:
0xbdc
。 Then, supply that to add2line: 然后,将其提供给add2line:
addr2line -e a.out -j .text 0xbdc
And see if that gets you your line number. 并查看是否能获得您的行号。
That's exactly how you use it. 这正是你如何使用它。 There is a possibility that the address you have does not correspond to something directly in your source code though.
但是,您所拥有的地址可能与源代码中的某些内容不对应。
For example: 例如:
$ 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
is the address of main
in my case. 在我的情况下,
0x400534
是main
的地址。 0x400408
is also a valid function address in a.out
, but it's a piece of code generated/imported by GCC, that has no debug info. 0x400408
也是a.out
的有效函数地址,但它是由GCC生成/导入的一段代码,没有调试信息。 (In this case, __libc_csu_init
. You can see the layout of your executable with readelf -a your_exe
.) (在这种情况下,
__libc_csu_init
。您可以使用readelf -a your_exe
查看可执行文件的布局。)
Other times when addr2line
will fail is if you're including a library that has no debug information. 有时
addr2line
失败的情况是你包含一个没有调试信息的库。
尝试添加-f
选项以显示函数名称:
addr2line -f -e a.out 0x4005BDC
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.