问题
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.
回答1:
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) info symbol 0x4005BDC
回答2:
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
- 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
addr2line usage
Following is the message from 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
Example.
Take the helloworld
as an example.
#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.
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
.
Following is output of 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:
- Only code segment generated with
-g
flag (which means the segment have debug information) could successfully generate filename and linenumber information. - Not all offsets of a function body compiled with
-g
flag will successfully output filename and linenumber. The offset0x40054b
is the last instruction afterret
instruction of themain
function, but we could not get the information.
回答3:
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.
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.
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:
addr2line -e a.out -j .text 0xbdc
And see if that gets you your line number.
回答4:
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
.)
Other times when addr2line
will fail is if you're including a library that has no debug information.
回答5:
Try adding the -f
option to show the function names :
addr2line -f -e a.out 0x4005BDC
来源:https://stackoverflow.com/questions/7648642/how-to-use-the-addr2line-command-in-linux