如何在Solaris上获取BACKTRACE(函数+行号)?

时间:2011-06-19 17:01:27

标签: c solaris stack-trace traceback pstack

我在C中完成了一些代码,它们很高兴地将带有函数名和行号的完整回溯发送到日志文件中。

这是在LINUX上使用backtrace,backtrace_symbols和dladdr以及ADDR2LINE的混合完成的。在Linux上也使用“execinfo.h”....

基本上如下:

Backtrace:行位置:

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

既然我已将代码带到Solaris,我发现它不受支持; - (

我在Solaris上尝试过pstack方法并得到类似的结果:

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)

如何以某种方式使用以上方式以编程方式获取LINE NUMBERS和函数名称?我看到了一些关于“walkcontext”或“walkstack”的内容....有没有人有任何示例代码可供我获取行号等?

另外,我在Linux上使用了ADDR2LINE并且效果很好.....有人能告诉我如何在SUMP上面使用它吗?我无法让它发挥作用; - (

任何建议都将受到高度赞赏

由于

林顿

1 个答案:

答案 0 :(得分:3)

我首先要说C可能不是2011年最好的方法(取决于你的更大目标)。查看另一个问题:Analizing MIPS binaries: is there a Python library for parsing binary data?引用(例如)pydevtools

那就是说,请在下面找一个使用gaddr2line的例子(这就是Solaris拼写addr2line的方式)。

这个简短的程序只调用函数foo(),然后调用pstack(1)(第9行,通过system(3C))。在程序的输出中,pstack(1)告诉我们调用foo()时函数system()中的地址是0x00010724。最后,在该地址上运行gaddr2line(1)告诉我们这对应于foo.c的第9行,我们已经完整了。

/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 $ 

接下来,这是一个使用walkcontext(3C)来处理堆栈的简短示例。要获取调试行号信息,您需要在walker()函数中使用(例如)libdwarf查询ELF(?)二进制文件的相应部分,但这应该可以帮助您入门。

/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