如何在Linux中使用addr2line命令?

时间:2021-08-26 00:39:00

I am trying to use addr2line command in Unix but everytime it is giving the same output as ??:0. I am giving command as addr2line -e a.out 0x4005BDC . I got this address while running this a.out executable with valgrind tool to find the memory leakage. I also compiled the source code with -g option.

我正在尝试在Unix中使用addr2line命令,但是每次输出的输出都是一样的?我用addr2line - ea命令。0 x4005bdc。我在运行这个a时得到了这个地址。使用valgrind工具可执行文件查找内存泄漏。我还用-g选项编译了源代码。

5 个解决方案

#1


24  

You can also use gdb instead of addr2line to examine memory address. Load executable file in gdb and print the name of a symbol which is stored at the address. 16 Examining the Symbol Table.

您还可以使用gdb而不是addr2line来检查内存地址。在gdb中加载可执行文件并打印存储在该地址的符号的名称。检查符号表。

(gdb) info symbol 0x4005BDC 

#2


16  

Please check:

请检查:

  • Whether all the functions in your binary are compiled with -g, addr2line only support functions has debug information, that is compiled with -g
  • 无论二进制文件中的所有函数都是用-g编译的,addr2line支持函数都有调试信息,都是用-g编译的
  • Whether your offset is a valid offset. That means your offset should not be an virtual memory address, and should only be an offset in the .text section. In the .text section means the address should point to an instruction in the binary
  • 是否您的偏移是一个有效的偏移。这意味着您的偏移量不应该是一个虚拟内存地址,并且应该只是.text部分中的偏移量。在.text部分中,地址应该指向二进制中的一条指令

addr2line usage

Following is the message from man addr2line.

以下是来自man addr2line的消息。

addr2line - convert addresses into file names and line numbers.

将地址转换为文件名和行号。

The addresses should be the address in an executable or an offset in a section of a relocatable object.

地址应该是可执行文件中的地址或可重定位对象的部分中的偏移量。

The output is something like FILENAME:LINENO, the source file name, and the line number in the file

输出类似文件名:LINENO,源文件名,以及文件中的行号

Example.

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中的偏移信息。出文件。

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. main function comes from our helloworld code which has debug information since we compile the file with -g.

代码最左边的一列是二进制文件中的偏移量。__start函数来自标准的C库,它是在没有调试信息的情况下预编译的。主函数来自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` functionhello.c:21$ addr2line -e a.out 0x40054b -f #The last instruction of the `main` functionmain??:?

We could make some conclusions from the above output:

我们可以从上面的输出中得出一些结论:

  1. Only code segment generated with -g flag (which means the segment have debug information) could successfully generate filename and linenumber information.
  2. 只有用-g标志生成的代码段(这意味着段有调试信息)才能成功地生成文件名和linenumber信息。
  3. Not all offsets of a function body compiled with -g flag will successfully output filename and linenumber. The offset 0x40054b is the last instruction after ret instruction of the main function, but we could not get the information.
  4. 使用-g标志编译的函数体的所有偏移量都不会成功地输出文件名和linenumber。偏移后的0x40054b是主函数ret指令之后的最后一条指令,但是我们无法得到信息。

#3


15  

You need to specify an offset to addr2line, not a virtual address (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.

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

Given the VA 0x4005BDC by valgrind, find the base address of your process or library in memory. Do this by examining the /proc/<PID>/maps file while your program is running. 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.

根据valgrind生成的VA 0x4005BDC,在内存中找到进程或库的基本地址。在程序运行时检查/proc/ /maps文件。感兴趣的行是进程的文本段,它可以通过权限r-xp和程序或库的名称进行标识。

Let's say that the base VA is 0x0x4005000. Then you would find the difference between the valgrind supplied VA and the base VA: 0xbdc. Then, supply that to add2line:

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

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

And see if that gets you your line number.

看看这是不是你的行号。

#4


9  

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. 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. (In this case, __libc_csu_init. You can see the layout of your executable with readelf -a your_exe.)

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

Other times when addr2line will fail is if you're including a library that has no debug information.

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

#5


4  

Try adding the -f option to show the function names :

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

addr2line -f -e a.out 0x4005BDC

#1


24  

You can also use gdb instead of addr2line to examine memory address. Load executable file in gdb and print the name of a symbol which is stored at the address. 16 Examining the Symbol Table.

您还可以使用gdb而不是addr2line来检查内存地址。在gdb中加载可执行文件并打印存储在该地址的符号的名称。检查符号表。

(gdb) info symbol 0x4005BDC 

#2


16  

Please check:

请检查:

  • Whether all the functions in your binary are compiled with -g, addr2line only support functions has debug information, that is compiled with -g
  • 无论二进制文件中的所有函数都是用-g编译的,addr2line支持函数都有调试信息,都是用-g编译的
  • Whether your offset is a valid offset. That means your offset should not be an virtual memory address, and should only be an offset in the .text section. In the .text section means the address should point to an instruction in the binary
  • 是否您的偏移是一个有效的偏移。这意味着您的偏移量不应该是一个虚拟内存地址,并且应该只是.text部分中的偏移量。在.text部分中,地址应该指向二进制中的一条指令

addr2line usage

Following is the message from man addr2line.

以下是来自man addr2line的消息。

addr2line - convert addresses into file names and line numbers.

将地址转换为文件名和行号。

The addresses should be the address in an executable or an offset in a section of a relocatable object.

地址应该是可执行文件中的地址或可重定位对象的部分中的偏移量。

The output is something like FILENAME:LINENO, the source file name, and the line number in the file

输出类似文件名:LINENO,源文件名,以及文件中的行号

Example.

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中的偏移信息。出文件。

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. main function comes from our helloworld code which has debug information since we compile the file with -g.

代码最左边的一列是二进制文件中的偏移量。__start函数来自标准的C库,它是在没有调试信息的情况下预编译的。主函数来自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` functionhello.c:21$ addr2line -e a.out 0x40054b -f #The last instruction of the `main` functionmain??:?

We could make some conclusions from the above output:

我们可以从上面的输出中得出一些结论:

  1. Only code segment generated with -g flag (which means the segment have debug information) could successfully generate filename and linenumber information.
  2. 只有用-g标志生成的代码段(这意味着段有调试信息)才能成功地生成文件名和linenumber信息。
  3. Not all offsets of a function body compiled with -g flag will successfully output filename and linenumber. The offset 0x40054b is the last instruction after ret instruction of the main function, but we could not get the information.
  4. 使用-g标志编译的函数体的所有偏移量都不会成功地输出文件名和linenumber。偏移后的0x40054b是主函数ret指令之后的最后一条指令,但是我们无法得到信息。

#3


15  

You need to specify an offset to addr2line, not a virtual address (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.

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

Given the VA 0x4005BDC by valgrind, find the base address of your process or library in memory. Do this by examining the /proc/<PID>/maps file while your program is running. 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.

根据valgrind生成的VA 0x4005BDC,在内存中找到进程或库的基本地址。在程序运行时检查/proc/ /maps文件。感兴趣的行是进程的文本段,它可以通过权限r-xp和程序或库的名称进行标识。

Let's say that the base VA is 0x0x4005000. Then you would find the difference between the valgrind supplied VA and the base VA: 0xbdc. Then, supply that to add2line:

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

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

And see if that gets you your line number.

看看这是不是你的行号。

#4


9  

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. 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. (In this case, __libc_csu_init. You can see the layout of your executable with readelf -a your_exe.)

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

Other times when addr2line will fail is if you're including a library that has no debug information.

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

#5


4  

Try adding the -f option to show the function names :

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

addr2line -f -e a.out 0x4005BDC