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

发布于 2024-11-16 07:23:54 字数 2466 浏览 3 评论 0原文

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

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

所以本质上如下:

Backtrace: Line Locations:

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 中使用它吗?我无法让它工作;-(

任何建议都会非常有用感谢

林顿

I have done some code in C that happily send the full backtrace with function name and line number to a log file.

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

So essentially the following:

Backtrace: Line Locations:

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 to Solaris I see it is not supported ;-(

I have tried the pstack approach on Solaris and get 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 to PROGRAMATICALLY get the LINE NUMBERS and function names as well? I have see something about "walkcontext" or "walkstack"....does anyone have any sample code for me to get line numbers etc?

Also, I have used ADDR2LINE on Linux and it works great.....can someone tell me how to use it on Solaris from the DUMP above? I cannot get it to work ;-(

Any advise will be hugely appreciated

Thanks

Lynton

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

咿呀咿呀哟 2024-11-23 07:23:54

我首先要说的是,在 2011 年,C 可能不是实现这一目标的最佳方法(取决于您的更大目标是什么)。查看另一个问题:分析 MIPS 二进制文件:是否有用于解析二进制数据的 Python 库? 其中引用(例如)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) 遍历堆栈的简短示例。但是,要获取调试行号信息,您需要使用(例如) libdwarf 但这应该可以帮助您入门。

/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

I'll start out by saying that C might not be the best way to do this in 2011 (depending on what your larger aims are). Check out this other question: Analizing MIPS binaries: is there a Python library for parsing binary data? which references (eg) pydevtools.

That said, please find below an example using gaddr2line (which is how Solaris spells addr2line).

This short program just calls function foo(), which in turn calls pstack(1) (on line 9, via system(3C)). In the output from the program, pstack(1) tells us that the address in function foo() when system() is invoked is 0x00010724. Finally, running gaddr2line(1) on that address tells us that this corresponds to line 9 of foo.c, and we have come 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 on from that, here is a short example of using walkcontext(3C) to walk the stack. To get debug line number information however you will need to query the appropriate sections of the ELF(?) binary using (eg) libdwarf in the walker() function 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文