How to get BACKTRACE (function number + line number) in Solaris?

I made some C code that would happily send a full return line with the function name and line number to the log file.

This was done using a mixture of backtrace, backtrace_symbols and dladdr and ADDR2LINE on LINUX. Also using "execinfo.h" on Linux ....

So essentially the following:

Backtrace: Line Layout:

signalErrorHandler /home/lynton/Desktop/TestThreadLeak/TestThreadLeak/./main.c:211 ?? ??:0 *__GI_raise /build/buildd/eglibc-2.12.1/signal/../nptl/sysdeps/unix/sysv/linux/raise.c:64 *__GI_abort /build/buildd/eglibc-2.12.1/stdlib/abort.c:94 __libc_message /build/buildd/eglibc-2.12.1/libio/../sysdeps/unix/sysv/linux/libc_fatal.c:168 malloc_printerr /build/buildd/eglibc-2.12.1/malloc/malloc.c:6283 *__GI___libc_free /build/buildd/eglibc-2.12.1/malloc/malloc.c:3739 threadMainLoop /home/lynton/Desktop/TestThreadLeak/TestThreadLeak/./main.c:260 start_thread /build/buildd/eglibc-2.12.1/nptl/pthread_create.c:304 ?? /build/buildd/eglibc-2.12.1/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:114 

Now that I have taken the code in Solaris, I see that it is not supported; - (

I tried using pstack on Solaris and getting something like:

 15871: ./exit_test ----------------- lwp# 1 / thread# 1 -------------------- ffffffff7efdaf48 lwp_wait (2, ffffffff7ffffb9c) ffffffff7efd34ac _thrp_join (2, 0, 0, 1, 0, ffffffff7ffffb9c) + 38 00000001000012f0 main (1, ffffffff7ffffd28, ffffffff7ffffd38, 100101f68, 100000000, ffffffff7f500200) + 204 0000000100000ba4 _start (0, 0, 0, 0, 0, 0) + 7c ----------------- lwp# 2 / thread# 2 -------------------- ffffffff7efdb210 waitid (0, 3e01, ffffffff7eaf8c30, 3) ffffffff7efc9cbc waitpid (3e01, ffffffff7eaf8eb0, 0, 0, ffffffff7f100300, 0) + 64 ffffffff7efbcc08 system (ffffffff7eaf9ff0, 1ad8, 1800, 0, ffffffff7f13c000, ffffffff7eaf8f18) + 394 0000000100000fec signalErrorHandler (b, 0, ffffffff7eafbba0, 40000000, 0, 0) + 2bc ffffffff7efd6fdc __sighndlr (b, 0, ffffffff7eafbba0, 100000d30, 0, 0) + c ffffffff7efcab70 call_user_handler (ffffffff7f500a00, ffffffff7f500a00, ffffffff7eafbba0, 12, 0, 0) + 3e0 ffffffff7efcad7c sigacthandler (0, 0, ffffffff7eafbba0, ffffffff7f500a00, 0, ffffffff7f13c000) + 68 --- called from signal handler with signal 0 (SIGEXIT) --- ffffffff7ee0052c memcpy (ffffffff7ffffd28, 1fc000, 0, 0, 100001040, 0) + 30 ffffffff7efd6eb0 _lwp_start (0, 0, 0, 0, 0, 0) 

How can I use the above somehow for the SOFTWARE to get the LINE NUMBERS and function names? I see something about a "walkcontext" or a "walkstack" .... does anyone have sample code for me to get line numbers, etc.?

Also, I used ADDR2LINE on Linux and it works fine ... can anyone tell me how to use it on Solaris from DUMP above? I can not make it work, - (

Any advice would be much appreciated

thanks

Linton

+4
source share
1 answer

To begin with, C may not be the best way to do this in 2011 (depending on your larger goals). Look at another question: MIPS binary analysis: is there a Python library for parsing binary data? that are referenced (for example) by pydevtools .

However, the following is an example using gaddr2line (since Solaris addr2line ).

This short program simply calls the foo() function, which in turn calls pstack(1) (on line 9 via system(3C) ). On exit from the program, pstack(1) tells us that the address in the foo() function when calling system() is 0x00010724. Finally, running gaddr2line(1) at this address tells us that this matches line 9 of foo.c , and we got a full circle.

 /tmp $ cat -n foo.c 1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 6 int foo() { 7 char buf[64]; 8 snprintf(buf, 64, "/bin/pstack %i", getpid()); 9 return system(buf); 10 } 11 12 int main(int argc, char *argv[]) { 13 return foo(); 14 } 15 /tmp $ gcc -g -o foo foo.c /tmp $ /tmp $ ./foo 15954: ./foo ff2cd4d8 waitid (0, 3e53, ffbff668, 3) ff2bce94 waitpid (3e53, ffbff7bc, 0, 0, ffbff814, ff390140) + 60 ff2afe20 system (ffbff910, ff339bd0, 20000, 1, ff3303d8, ffbff814) + 2ec 00010724 foo (209b8, 1c00, ff335900, 4, ff392a00, ff2b6d6c) + 38 00010748 main (1, ffbffa34, ffbffa3c, 209dc, ff3900c0, 0) + c 00010584 _start (0, 0, 0, 0, 0, 0) + 5c /tmp $ /tmp $ gaddr2line -e foo 00010724 /tmp/foo.c:9 /tmp $ 

Following this, here is a brief example of using walkcontext(3C) to traverse a stack. To get information about the debug number, you will need to request the appropriate sections of the ELF binary (?), Using (for example) libdwarf in walker() , but this should get you started.

 /tmp $ cat -n bar.c 1 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <ucontext.h> 6 #include <dlfcn.h> 7 8 int walker(uintptr_t pc, int sig, void *usrarg) { 9 10 Dl_info dlip; 11 12 if(dladdr((void *)pc, &dlip)) { 13 (void)printf(" %08lx %s %s\n", pc, dlip.dli_fname, dlip.dli_sname); 14 return 0; 15 } else { 16 perror("dladdr()"); 17 return -1; 18 } 19 20 } 21 22 int bar() { 23 24 char buf[64]; 25 snprintf(buf, 64, "/bin/pstack %i", getpid()); 26 system(buf); 27 28 (void)printf("\nprintstack()\n"); 29 printstack(0); 30 31 ucontext_t ucp; 32 if(getcontext(&ucp)) { 33 perror("\ngetcontext()"); 34 return -1; 35 } else { 36 (void)printf("\nwalkcontext()\n"); 37 return walkcontext(&ucp, &walker, NULL); 38 } 39 40 } 41 42 int main(int argc, char *argv[]) { 43 return bar(); 44 } 45 /tmp $ gcc -g -o bar bar.c /tmp $ /tmp $ ./bar 16486: ./bar ff2cd4d8 waitid (0, 4067, ffbff4b8, 3) ff2bce94 waitpid (4067, ffbff60c, 0, 0, ffbff664, ff390140) + 60 ff2afe20 system (ffbff928, ff339bd0, 20000, 1, ff3303d8, ffbff664) + 2ec 000108b8 bar (20c70, 1c00, ff335900, 4, ff392a00, ff2b6d6c) + 38 00010968 main (1, ffbffa4c, ffbffa54, 20c94, ff3900c0, 0) + c 00010698 _start (0, 0, 0, 0, 0, 0) + 5c printstack() /tmp/bar:bar+0x54 /tmp/bar:main+0xc /tmp/bar:_start+0x5c walkcontext() 00010968 /tmp/bar main 00010698 /tmp/bar _start 
+3
source

All Articles