backtrace function give set of backtrace how to map it with function name/file name/line number?
for ex:-
backtrace() returned 8 addresses
./libtst.so(myfunc5+0x2b) [0xb7767767]
./libtst.so(fun4+0x4a) [0xb7767831]
./libtst.so(fun3+0x48) [0xb776787f]
./libtst.so(fun2+0x35) [0xb77678ba]
./libtst.so(fun1+0x35) [0xb77678f5]
./a.out() [0x80485b9]
/lib/libc.so.6(__libc_start_main+0xe5) [0xb75e9be5]
./a.out() [0x80484f1]
From the above stack how can I get the file name and line number? I did following things, but no luck. Correct me if I am wrong :)
for ex:-
./libtst.so(fun2+0x35) [0xb77dc887]
0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result)
result is no way related to function in nm output.
I used addr2line command:-
addr2line -f -e libtst.so 0xb77dc887
??
??:0
So, how can I resolve either at runtime or post runtime? Thanks in advance...
nm:-
00000574 T _init
00000680 t __do_global_dtors_aux
00000700 t frame_dummy
00000737 t __i686.get_pc_thunk.bx
0000073c T myfunc5
000007e7 T fun4
00000837 T fun3
00000885 T fun2
000008c0 T fun1
00000900 t __do_global_ctors_aux
00000938 T _fini
000009b4 r __FRAME_END__
00001efc d __CTOR_LIST__
00001f00 d __CTOR_END__
00001f04 d __DTOR_LIST__
00001f08 d __DTOR_END__
00001f0c d __JCR_END__
00001f0c d __JCR_LIST__
00001f10 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
00002030 d __dso_handle
00002034 A __bss_start
00002034 A _edata
00002034 b completed.5773
00002038 b dtor_idx.5775
0000203c B funptr
00002040 A _end
U backtrace@@GLIBC_2.1
U backtrace_symbols@@GLIBC_2.1
U free@@GLIBC_2.0
U __isoc99_scanf@@GLIBC_2.7
U perror@@GLIBC_2.0
U printf@@GLIBC_2.0
U puts@@GLIBC_2.0
w __cxa_finalize@@GLIBC_2.1.3
w __gmon_start__
w _Jv_RegisterClasses
pmap:-
START SIZE RSS PSS DIRTY SWAP PERM MAPPING
08048000 4K 4K 4K 0K 0K r-xp /home/test/libtofun/a.out
08049000 4K 4K 4K 4K 0K r--p /home/test/libtofun/a.out
0804a000 4K 4K 4K 4K 0K rw-p /home/test/libtofun/a.out
...
b7767000 4K 4K 4K 0K 0K r-xp /home/test/libtofun/libtst.so
b7768000 4K 4K 4K 4K 0K r--p /home/test/libtofun/libtst.so
b7769000 4K 4K 4K 4K 0K rw-p /home/test/libtofun/libtst.so
....
Total: 1688K 376K 82K 72K 0K
128K writable-private, 1560K readonly-private, 0K shared, and 376K referenced
libtst.c:-
void myfunc5(void){
int j, nptrs;
#define SIZE 100
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
}
for (j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
void fun4(){
char ip;
char *fun = "fun4\0";
printf("Fun name %s\n",fun);
scanf("%c",&ip);
myfunc5();
}
void fun3(){
char *fun = "fun3\0";
printf("Fun name %s\n",fun);
funptr = fun4;
funptr();
}
void fun2(){
char *fun = "fun2\0";
printf("Fun name %s\n",fun);
fun3();
}
void fun1(){
char *fun = "fun1\0";
printf("Fun name %s\n",fun);
fun2();
}
main.c:-
int main(){
char ip;
funptr = &fun1;
scanf("%c",&ip);
funptr();
return 0;
}
Let me know if need more information...
Try giving the offset to addr2line, along with the section name. Like this:
addr2line -j .text -e libtst.so 0x26887
Edit: By the way, if it wasn't clear, the 0x26887
comes from what you provided:
0xb77dc887(fun2 addr+offset)-0xb77b6000 (lib starting addr) = 0x26887 (result)
I've had a look at files backtrace.c
and backtracesyms.c
files in glibc source code (git://sourceware.org/git/glibc.git, commit 2482ae433a4249495859343ae1fba408300f2c2e).
Assuming I haven't misread/misunderstood things: backtrace() itself looks like it will only give you symbol addresses as they are at runtime, which I think means you need the library load address as it was from pmap or similar. However, backtrace_symbols() recalculates things so that the addresses are relative to the shared library ELF, and not the process at runtime, which is really convenient. It means you don't need information from pmap.
So, if you've compiled with -g (or with -rdynamic), then you're in luck. You should be able to do the following:
$ # get the address in the ELF so using objdump or nm
$ nm libtst.so | grep myfunc
0000073c T myfunc5
$ # get the (hex) address after adding the offset
$ # from the start of the symbol (as provided by backtrace_syms())
$ python -c 'print hex(0x0000073c+0x2b)'
0x767
$ # use addr2line to get the line information, assuming any is available
addr2line -e libtst.so 0x767
Or, using gdb:
$ gdb libtst.so
(gdb) info address myfunc
Symbol "myfunc" is at 0x073c in a file compiled without debugging. # (Faked output)
(gdb) info line *(0x073c+0x2b)
Line 27 of "foo.cpp" starts at address 0x767 <myfunc()+21> and ends at 0x769 <something>. # (Faked output)
Also, if you've stripped the library, but stashed off debug symbols for later use, then you'll likely only have ELF offsets printed out by backtrace_syms() and no symbol names (so not quite the case in the original question): In this instance, using gdb is arguably more convenient than using other command line tools. Assuming you've done this, you'll need to invoke gdb like so (for example):
$ gdb -s debug/libtst.debug -e libtst.so
And then go through a similar sequence as above, using 'info line' and 'info address' depending on whether you only have ELF symbol offsets, or symbol names plus offsets.
objdump -x --disassemble -l <objfile>
This should dump, among other things, each compiled instruction of machine code with the line of the C file it came from.
At runtime with eu-addr2line
(automatically finds the libraries and calculates offsets):
//-------------------------------------
#include <sys/types.h>
#include <unistd.h>
int i;
#define SIZE 100
void *buffer[100];
int nptrs = backtrace(buffer, SIZE);
for (i = 1; i < nptrs; ++i) {
char syscom[1024];
syscom[0] = '\0';
snprintf(syscom, 1024, "eu-addr2line '%p' --pid=%d > /dev/stderr\n", buffer[i], getpid());
if (system(syscom) != 0)
fprintf(stderr, "eu-addr2line failed\n");
}
Stick a --debuginfo-path=...
option if your debug files are somewhere else (matched by the build-id, etc.).
eu-addr2line
is in the elfutils
package of your distribution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With