简体   繁体   English

如何在Linux中使用addr2line命令?

[英]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: 请检查:

  • 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. 这意味着您的偏移量不应该是虚拟内存地址,并且应该只是.text部分中的偏移量。 In the .text section means the address should point to an instruction in the binary .text部分中表示地址应指向二进制中的指令

addr2line usage addr2line用法

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 ,源文件名和文件中的行号

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.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: 我们可以从上面的输出中得出一些结论:

  1. Only code segment generated with -g flag (which means the segment have debug information) could successfully generate filename and linenumber information. 只有使用-g标志生成的代码段(这意味着该段具有调试信息)才能成功生成文件名和亚麻码信息。
  2. Not all offsets of a function body compiled with -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. 偏移量0x40054bmain函数的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. 在我的情况下, 0x400534main的地址。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM