通过数组获取调用栈; 一般获取的是内存地址;
dladdr
获取地址信息, 计算可执行文件中的偏移地址;有的没有实现backtrace
但是大多都支持unwind
; 利用unwind
实现类似;
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
略
gdb
void show() {
while(1);
}
int main() {
show();
}
执行输出
ch@ch-ubuntu:~/ch/cfile/test$ gcc test.c -g
ch@ch-ubuntu:~/ch/cfile/test$ ./a.out &
[2] 42592
ch@ch-ubuntu:~/ch/cfile/test$ sudo gdb -q -ex "bt" -ex "q" -p 42592 <<< "Y"
Attaching to process 42592
Reading symbols from /home/ch/ch/cfile/test/a.out...
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/.build-id/d1/704d25fbbb72fa95d517b883131828c0883fe9.debug...
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/29/2e105c0bb3ee8e8f5b917f8af764373d206659.debug...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x0000558c38dab132 in show () at test.c:2
2 while(1);
#0 0x0000558c38dab132 in show () at test.c:2
#1 0x0000558c38dab146 in main () at test.c:5
A debugging session is active.
Inferior 1 [process 42592] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
Detaching from program: /home/ch/ch/cfile/test/a.out, process 42592
[Inferior 1 (process 42592) detached]
backtrace
获取#include <execinfo.h>
void show()
{
void * s[30] = {0};
backtrace(s,30);
return;
}
void cool()
{
show();
}
int main()
{
cool();
}
gdb
查看
ch@ch-ubuntu:~/ch/cfile/test$ gdb ./a.out -q
Reading symbols from ./a.out...
(gdb) b 6
Breakpoint 1 at 0x11b2: file test.c, line 6.
(gdb) list 6
1 #include <execinfo.h>
2 void show()
3 {
4 void * s[30] = {0};
5 backtrace(s,30);
6 return;
7 }
8
9 void cool()
10 {
(gdb) r
Starting program: /home/ch/ch/cfile/test/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, show () at test.c:6
6 return;
(gdb) x /3xg s
0x7fffffffdf70: 0x00005555555551b2 0x00005555555551db
0x7fffffffdf80: 0x00005555555551f0
(gdb) bt
#0 show () at test.c:6
#1 0x00005555555551db in cool () at test.c:11
#2 0x00005555555551f0 in main () at test.c:16
(gdb) p show
$1 = {void ()} 0x555555555169 <show>
addr2line解析
ch@ch-ubuntu:~/ch/cfile/test$ addr2line -fapCe a.out 0x11b2 0x11db 11f0
0x00000000000011b2: show at /home/ch/ch/cfile/test/test.c:6
0x00000000000011db: cool at /home/ch/ch/cfile/test/test.c:12
0x00000000000011f0: main at /home/ch/ch/cfile/test/test.c:16
#define _GNU_SOURCE
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
void show()
{
void * s[30] = {0};
int n = backtrace(s,30);
int i;
Dl_info info;
for(i = 0 ; i < n; i++)
{
// 获取提供地址信息, 地址没有对应symbol, dli_saddr可能会为0;
// 这里直接用输入地址作为比较;
dladdr(s[i],&info);
printf("%p %p %p\n", info.dli_fbase, s[i], (void*)((char*)s[i] - (char*)info.dli_fbase));
}
}
void cool()
{
show();
}
int main() {
cool();
}
执行和解析
ch@ch-ubuntu:~/ch/cfile/test$ ./a.out
0x56344a851000 0x56344a8521f2 0x11f2
0x56344a851000 0x56344a8522b3 0x12b3
0x56344a851000 0x56344a8522c8 0x12c8
0x7f56fcc00000 0x7f56fcc23510 0x23510
0x7f56fcc00000 0x7f56fcc235c9 0x235c9
0x56344a851000 0x56344a8520e5 0x10e5
ch@ch-ubuntu:~/ch/cfile/test$ addr2line -fapCe a.out 0x11f2 0x12b3 0x12c8 0x23510 0x235c9 0x10e5
0x00000000000011f2: show at /home/ch/ch/cfile/test/test.c:8
0x00000000000012b3: cool at /home/ch/ch/cfile/test/test.c:21
0x00000000000012c8: main at /home/ch/ch/cfile/test/test.c:24
0x0000000000023510: ?? ??:0
0x00000000000235c9: ?? ??:0
0x00000000000010e5: _start at ??:?
android,docker
等参考链接 https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace
#define _GNU_SOURCE
#include <dlfcn.h>
#include <unwind.h>
typedef unsigned int uint;
struct BacktraceState
{
void** current;
void** end;
};
static _Unwind_Reason_Code unwind_backtrace(struct _Unwind_Context* context, void* arg)
{
struct BacktraceState* state = (struct BacktraceState*)(arg);
_Unwind_Word pc = _Unwind_GetIP(context);
if (pc) {
if (state->current == state->end) {
return _URC_END_OF_STACK;
} else {
*state->current++ = (void*)(pc);
}
}
return _URC_NO_REASON;
}
uint backtrace(void** buffer, uint max)
{
struct BacktraceState state = {buffer, buffer + max};
_Unwind_Backtrace(unwind_backtrace, &state);
return state.current - buffer;
}
void backtrace2offset(void** buffer, uint buffer_len) {
int i = 0;
Dl_info info;
for(i = 0; i < buffer_len; i++) {
dladdr(buffer[i],&info);
buffer[i] = (void*)((char*)buffer[i] - (char*)info.dli_fbase);
}
}
#include<stdio.h>
#include<string.h>
void show() {
void *s[30] = {0}, *offset[30]={0};
int n = backtrace(s, sizeof(s)/sizeof(*s));
memcpy(offset, s, sizeof(offset));
backtrace2offset(offset, n);
int i = 0;
for(; i<n ; i++) printf("%p ", offset[i]);
printf("\n");
}
int main() {
show();
}
执行输出
ch@ch-ubuntu:~/ch/cfile/test$ gcc test.c -g
ch@ch-ubuntu:~/ch/cfile/test$ ./a.out
0x12ad 0x13df 0x15f1 0x23510 0x235c9 0x1125
ch@ch-ubuntu:~/ch/cfile/test$ addr2line -fapCe a.out 0x12ad 0x13df 0x15f1 0x23510 0x235c9 0x1125
0x00000000000012ad: backtrace at /home/ch/ch/cfile/test/test.c:32
0x00000000000013df: show at /home/ch/ch/cfile/test/test.c:48
0x00000000000015f1: main at /home/ch/ch/cfile/test/test.c:57
0x0000000000023510: ?? ??:0
0x00000000000235c9: ?? ??:0
0x0000000000001125: _start at ??:?
struct BacktraceState
,头尾指针的数组.存放 void*
类型数据的指针数组._Unwind_Reason_Code
回调函数返回值.struct _Unwind_Context* context
回调函数第一参数.void* arg
用户用于存放数据的结构体,任意类型.unwindCallback
自定义的回调函数,传入堆栈信息 content
,和用户的容器指针._Unwind_GetIP
获取栈指针._Unwind_Backtrace
实际函数,回调和容器.