Skip to content

Commit 1c84613

Browse files
author
root
committed
backtrace test
1 parent 38bff3b commit 1c84613

5 files changed

Lines changed: 207 additions & 0 deletions

File tree

tools/backtrace/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
用于打印调用栈,示例在examples中
2+
3+
学习于
4+
5+
> https://blog.csdn.net/nanfeibuyi/article/details/81203021
6+
>
7+
> https://blog.csdn.net/littlefang/article/details/17654419
8+
9+
代码有小部分改动。
10+
11+
编译时注意 加上
12+
13+
-fno-omit-frame-pointer
14+

tools/backtrace/examples/Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
all:test main
2+
3+
test:lib.c lib.h
4+
gcc -g lib.c -fPIC -shared -o libtest.so
5+
6+
main:main.c
7+
gcc -g main.c -L./ -ltest -o main
8+
9+
.PHONY:clean
10+
clean:
11+
rm -rf main *.o *.so

tools/backtrace/examples/lib.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <execinfo.h>
5+
#include <unistd.h>
6+
7+
#include "lib.h"
8+
9+
10+
void exec_shell(char *cmd, char *buf, int buf_size)
11+
{
12+
FILE *fp = NULL;
13+
fp = popen(cmd, "r");
14+
if(fp == NULL) {
15+
return;
16+
}
17+
18+
while(fgets(buf, buf_size, fp) != NULL);
19+
20+
pclose(fp);
21+
return ;
22+
}
23+
24+
int get_backtrace_string(void* bt,char* buff,int buff_size)
25+
{
26+
char cmd[128] = {0};
27+
char property[256]={0};
28+
char not_care1[128]={0},not_care2[128]={0},not_care3[128]={0};
29+
char library_path[256]={0};
30+
char exe_path[256],function_name[256];
31+
char maps_line[1024]={0};
32+
void* offset_start,*offset_end;
33+
int maps_column_num=0, n;
34+
FILE* fd_maps=NULL;
35+
fd_maps=fopen("/proc/self/maps","r");
36+
unsigned long exe_symbol_offset=0;
37+
char unknow_position[12] ="??:?\n";
38+
unsigned char unknow_position_len = strlen(unknow_position);
39+
if(fd_maps==NULL)
40+
{
41+
return -1;
42+
}
43+
while(NULL!=fgets(maps_line,sizeof(maps_line),fd_maps))
44+
{
45+
maps_column_num=sscanf(maps_line,"%p-%p\t%s\t%s\t%s\t%s\t%s"
46+
,&offset_start
47+
,&offset_end
48+
,property
49+
,not_care1
50+
,not_care2
51+
,not_care3
52+
,library_path);
53+
54+
if(maps_column_num==7&&bt>=offset_start&&bt<=offset_end)
55+
{
56+
//printf("=== get in bt: %p, maps_line: %s\n", bt, maps_line);
57+
break;
58+
}
59+
60+
}
61+
fclose(fd_maps);
62+
n = readlink("/proc/self/exe", exe_path, sizeof(exe_path));
63+
exe_path[n] = 0;
64+
if(0==strcmp(exe_path,library_path))
65+
{
66+
exe_symbol_offset=(unsigned long)bt;
67+
}
68+
else
69+
{
70+
exe_symbol_offset=(char*)bt-(char*)offset_start;
71+
}
72+
snprintf(cmd,sizeof(cmd),"addr2line -Cfp -e %s 0x%lx",library_path,exe_symbol_offset);
73+
//printf("cmd: %s\n", cmd);
74+
exec_shell(cmd, buff, buff_size);
75+
//printf("buff: %s\n", buff);
76+
if(0==memcmp(&buff[strlen(buff) - unknow_position_len],unknow_position, unknow_position_len))
77+
{
78+
snprintf(cmd,sizeof(cmd),"addr2line -Cifp -e %s 0x%lx",library_path,exe_symbol_offset);
79+
//printf("cmd1: %s\n", cmd);
80+
exec_shell(cmd, function_name, sizeof(function_name));
81+
function_name[strlen(function_name)-1]='\0';
82+
snprintf(buff,buff_size,"%s(%s+0x%lx)\n",library_path,function_name,exe_symbol_offset);
83+
}
84+
return 0;
85+
}
86+
87+
88+
/*
89+
如果使用my_backtrace
90+
如果源代码编译时使用了-O1或-O2优化选项,可执行代码会把ebp/rbp/rsp寄存器当作普通寄存器使用,导致backtrace失败。
91+
为了防止这种情况发生,可以在编译时使用-O2 -fno-omit-frame-pointer 或-Og 来避免优化中使用上述寄存器。
92+
系统自带的backtrace函数是通过读取操作系统的一个全局信息区,在多线程并发调用时,会造成严重的锁冲突
93+
*/
94+
#define STACKCALL __attribute__((regparm(1),noinline))
95+
void ** STACKCALL getEBP(void){
96+
void **ebp=NULL;
97+
__asm__ __volatile__("mov %%rbp, %0;\n\t"
98+
:"=m"(ebp) /* 输出 */
99+
: /* 输入 */
100+
:"memory"); /* 不受影响的寄存器 */
101+
return (void **)(*ebp);
102+
}
103+
int my_backtrace(void **buffer,int size){
104+
105+
int frame=0;
106+
void ** ebp;
107+
void **ret=NULL;
108+
unsigned long long func_frame_distance=0;
109+
if(buffer!=NULL && size >0)
110+
{
111+
ebp=getEBP();
112+
func_frame_distance=(unsigned long long)(*ebp) - (unsigned long long)ebp;
113+
while(ebp&& frame<size
114+
&&(func_frame_distance< (1ULL<<24))//assume function ebp more than 16M
115+
&&(func_frame_distance>0))
116+
{
117+
ret=ebp+1;
118+
buffer[frame++]=*ret;
119+
ebp=(void**)(*ebp);
120+
func_frame_distance=(unsigned long long)(*ebp) - (unsigned long long)ebp;
121+
}
122+
}
123+
return frame;
124+
}
125+
126+
127+
128+
#define BACKTRACE_SIZE 30
129+
void bt_show()
130+
{
131+
int i;
132+
void *array[BACKTRACE_SIZE];
133+
char buf[2048] = {0};
134+
135+
#if 1
136+
//用get_backtrace_string
137+
//backtrace or my_backtrace
138+
int stack_num = backtrace(array, BACKTRACE_SIZE);
139+
for(i = 0; i < stack_num; i++) {
140+
get_backtrace_string(array[i], buf, 2048);
141+
printf(" [%02d] %s\n", i, buf);
142+
}
143+
#else
144+
//用系统的backtrace_symbols,需要释放
145+
//backtrace or my_backtrace
146+
int stack_num = backtrace(array, BACKTRACE_SIZE);
147+
printf("stack_num: %d\n", stack_num);
148+
char **stacktrace = backtrace_symbols(array, stack_num);
149+
if(stacktrace == NULL){
150+
return;
151+
}
152+
for(i = 0; i < stack_num; i++) {
153+
printf(" [%02d] %s\n", i, stacktrace[i]);
154+
}
155+
free(stacktrace);
156+
#endif
157+
}
158+
159+
void hello()
160+
{
161+
printf("hello world\n");
162+
test_inline();
163+
}

tools/backtrace/examples/lib.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef _LIB_H_
2+
#define _LIB_H_
3+
4+
void hello();
5+
6+
void bt_show();
7+
static inline void test_inline()
8+
{
9+
bt_show();
10+
}
11+
12+
#endif

tools/backtrace/examples/main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "lib.h"
2+
3+
4+
void main()
5+
{
6+
hello();
7+
}

0 commit comments

Comments
 (0)