【问题标题】:How to get BACKTRACE (function + line number) on Solaris?如何在 Solaris 上获取 BACKTRACE(函数 + 行号)?
【发布时间】:2011-06-19 17:01:26
【问题描述】:

我用 C 语言编写了一些代码,很高兴地将带有函数名称和行号的完整回溯发送到日志文件。

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

基本上如下:

回溯:行位置:

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)

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

另外,我在 Linux 上使用过 ADDR2LINE,效果很好.....有人能告诉我如何从上面的 DUMP 中在 Solaris 上使用它吗?我无法让它工作;-(

任何建议将不胜感激

谢谢

林顿

【问题讨论】:

    标签: c solaris stack-trace traceback pstack


    【解决方案1】:

    我首先要说的是,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) 告诉我们,当调用 system() 时,函数 foo() 中的地址是 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
    

    【讨论】:

    • 感谢您的帮助,非常感谢 ;-)
    猜你喜欢
    • 1970-01-01
    • 2011-10-19
    • 2023-04-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多