我在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上面使用它吗?我无法让它发挥作用; - (
任何建议都将受到高度赞赏
由于
林顿
答案 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