-
backtrace
-
简介
- 有的系统没有实现
backtrace
这个函数. - 常见的就有
linux
还有一些docker
的库.
- 有的系统没有实现
-
判断是否支持
backtrace
#include<stdio.h> #include<dlfcn.h> int main() { void * bt = dlsym(NULL,"backtrace"); if(NULL != bt) { printf("support\n"); } else { printf("not support\n"); } return 0; }
-
输出
[root@localhost bt_support]# gcc test.c -ldl -g [root@localhost bt_support]# ./a.out support
-
-
堆栈
-
说明
- 查看某一个时刻,函数调用栈.
- 在 崩溃 的时候输出,可以精确的查看在什么地方出的问题.
-
常见工具
pstack -p pid
查看正在执行的进程某一时刻的堆栈.gdb
.
-
案例
(gdb) bt #0 show () at test.c:3 #1 0x0000000000400501 in cool () at test.c:7 #2 0x0000000000400511 in main () at test.c:12
-
注意
- 必须要有调试信息.
- 否则结果是
??:00
这类无意义数据.
-
-
获取堆栈
-
说明
- 堆栈一般是代码地址.
- 也可能是共享库的映射地址.
-
获取地址
#include <execinfo.h> void show() { void * s[30] = {0}; backtrace(s,30); return; } void cool() { show(); } int main() { cool(); }
输出
(gdb) bt #0 show () at test.c:6 #1 0x0000000000400587 in cool () at test.c:11 #2 0x0000000000400597 in main () at test.c:16 (gdb) x /3xg s 0x7fffffffe320: 0x0000000000400576 0x0000000000400587 0x7fffffffe330: 0x0000000000400597 (gdb) p show $2 = {void ()} 0x40053d <show>
backtrace
获取到的地址和gdb bt
指令获取到的一样.
addr2line
[root@localhost bt_support]# addr2line -fap 0x0000000000400576 0x0000000000400587 0x0000000000400597 0x0000000000400576: show at /root/cfile/bt_support/test.c:6 0x0000000000400587: cool at /root/cfile/bt_support/test.c:12 0x0000000000400597: main at /root/cfile/bt_support/test.c:17
- 得到的结果基本相同.
-
-
动态库
-
获取堆栈
test.c
#define _GNU_SOURCE #include <dlfcn.h> #include <execinfo.h> void show() { void * s[30] = {0}; int n = backtrace(s,30); int i; Dl_info info; for(i = 0 ; i < n; i++) { dladdr(s[i],&info); i+=0; } return; } void cool() { show(); }
main.c
extern void cool(); int main() { cool(); }
编译
gcc -fPIC -shared -o test.so test.c -g gcc ./test.so main.c -g -ldl
调试输出
(gdb) p info $1 = {dli_fname = 0x7ffff7ff9640 "./test.so", dli_fbase = 0x7ffff7bd9000, dli_sname = 0x7ffff7bd942d "show", dli_saddr = 0x7ffff7bd9785 <show>} (gdb) printf "%x\n",info.dli_saddr - info.dli_fbase 785 (gdb) !addr2line -e ./test.so 806 /root/cfile/bt_support/test.c:21 (gdb) bt #0 show () at test.c:10 #1 0x00007ffff7bd9806 in cool () at test.c:20 #2 0x000000000040063b in main () at main.c:4
addr
信息需要借助dladdr
.获取某个地址的信息.
-
-
实现
backtrace
-
参考链接
-
应用场景
- 有的会没有这个函数,比如
android,docker
.
- 有的会没有这个函数,比如
-
堆栈
#include <unwind.h> struct BacktraceState { void** current; void** end; }; static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = static_cast<BacktraceState*>(arg); uintptr_t pc = _Unwind_GetIP(context); if (pc) { if (state->current == state->end) { return _URC_END_OF_STACK; } else { *state->current++ = reinterpret_cast<void*>(pc); } } return _URC_NO_REASON; } } size_t captureBacktrace(void** buffer, size_t max) { BacktraceState state = {buffer, buffer + max}; _Unwind_Backtrace(unwindCallback, &state); return state.current - buffer; }
struct BacktraceState
,头尾指针的数组.存放void*
类型数据的指针数组._Unwind_Reason_Code
回调函数返回值.struct _Unwind_Context* context
回调函数第一参数.void* arg
用户用于存放数据的结构体,任意类型.unwindCallback
自定义的回调函数,传入堆栈信息content
,和用户的容器指针._Unwind_GetIP
获取栈指针._Unwind_Backtrace
实际函数,回调和容器.
-
pipeline
-
-
backtrace
实现-
原型
-
实现
#include<stdio.h> #include <unwind.h> struct BacktraceState { void** start; void** current; void** end; }; static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = (BacktraceState*)(arg); _Unwind_Ptr pc = _Unwind_GetIP(context); if (pc) { if (state->current == state->end) { return _URC_END_OF_STACK; } if(NULL != state->start) { *state->current = (void*)(pc); } state->current++; } return _URC_NO_REASON; } int Backtrace(void** buffer, int size) { BacktraceState state = {buffer, buffer, buffer + size}; _Unwind_Backtrace(unwindCallback, &state); return state.current - state.start; } int main() { void * s[10] = {NULL}; Backtrace(s,10); return 0; }
- 编译
gcc -g backtrace_demo.c
-
-
backtrace + addr2line
-
说明
- 将地址转成可读.
-
案例
#include<stdio.h> #include<unwind.h> typedef struct BacktraceState { void** start; void** current; void** end; } BacktraceState; static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = (BacktraceState*)(arg); _Unwind_Ptr pc = _Unwind_GetIP(context); if (pc) { if (state->current == state->end) { return _URC_END_OF_STACK; } if(NULL != state->start) { *state->current = (void*)(pc); } state->current++; } return _URC_NO_REASON; } int Backtrace(void** buffer, int size) { BacktraceState state = {buffer, buffer, buffer + size}; _Unwind_Backtrace(unwindCallback, &state); return state.current - state.start; } int show() { void * s[10] = {NULL}; int i = 0 , n = Backtrace(s,10); for( i = 0 ; i < n ;i ++) { printf("%p\n",s[i]); } return 0; } int main() { show(); return 0; }
编译
gcc backtrace_demo.c -g -o demo.out ./demo.out | addr2line -fapCe ./demo.out
-
-
最终版本
-
简介
- 利用
Backtrace
获取堆栈,再通过dladdr
辨别是否为可执行文件代码. - 最后通过
addr2line
将结果输出.
- 利用
-
案例
#define _GNU_SOURCE #include<stdio.h> #include <unistd.h> #include<stdlib.h> #include<unwind.h> #include<dlfcn.h> typedef struct BacktraceState { void** start; void** current; void** end; } BacktraceState; static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) { BacktraceState* state = (BacktraceState*)(arg); _Unwind_Ptr pc = _Unwind_GetIP(context); if (pc) { if (state->current == state->end) { return _URC_END_OF_STACK; } if(NULL != state->start) { *state->current = (void*)(pc); } state->current++; } return _URC_NO_REASON; } int Backtrace(void** buffer, int size) { BacktraceState state = {buffer, buffer, buffer + size}; _Unwind_Backtrace(unwindCallback, &state); return state.current - state.start; } void * main_base; extern int main(); void __attribute__((constructor)) ms() { Dl_info info; dladdr(main,&info); main_base = info.dli_fbase; } int show() { void * s[10] = {NULL}; int i = 0 , n = Backtrace(s,10); for( i = 0 ; i < n ;i ++) { char buf[100]={0}; Dl_info info; if(dladdr(s[i],&info)) { sprintf(buf,"addr2line -fpia -e %s %p",info.dli_fname,info.dli_fbase == main_base ? (unsigned long)s[i] : s[i] - info.dli_fbase); } //printf("%s %p\n",buf,s[i]); system(buf); } printf("\n"); return 0; } int cool() { show(); return 0; }
test.c
extern int cool(); int main() { cool(); return 0; }
-
编译
gcc -fPIC backtrace_demo.c -shared -o backtrace_demo.so -ldl -g gcc ./backtrace_demo.so test.c -ldl -g
-
输出
[root@localhost chap01]# ./a.out 0x0000000000000ab0: Backtrace at xxxxxx/backtrace_demo.c:31 0x0000000000000b2f: show at xxxxxx/backtrace_demo.c:46 0x0000000000000c1a: cool at xxxxxx/backtrace_demo.c:64 0x000000000040063b: main at xxxxxx/test.c:5 0x0000000000022555: __libc_start_main at /usr/src/debug/glibc-2.17-c758a686/csu/../csu/libc-start.c:300 0x0000000000400569: _start at ??:?
-
anddoird 实现backtrace
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.