1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
| $ cat trace.h
#ifndef TRACE_H_
#define TRACE_H_
#include <stdio.h>
void DebugInfo(FILE *out, const void *ip);
void __attribute__((noinline)) PrintStackTrace(FILE *out, int skip);
void FuncC(void);
void FuncB(void);
void FuncA(void);
#endif
$ cat trace.cpp
#define UNW_LOCAL_ONLY
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <libunwind.h>
#include <elfutils/libdwfl.h>
static void DebugInfo(FILE *out, const void *ip) {
char *debuginfo_path = NULL;
Dwfl_Callbacks callbacks;
callbacks.find_elf = dwfl_linux_proc_find_elf;
callbacks.find_debuginfo = dwfl_standard_find_debuginfo;
callbacks.debuginfo_path = &debuginfo_path;
Dwfl *dwfl = dwfl_begin(&callbacks);
assert(dwfl != NULL);
assert(dwfl_linux_proc_report(dwfl, getpid()) == 0);
assert(dwfl_report_end (dwfl, NULL, NULL) == 0);
Dwarf_Addr addr = (uintptr_t)ip;
Dwfl_Module *module = dwfl_addrmodule(dwfl, addr);
const char *function_name = dwfl_module_addrname(module, addr);
// 调用c++file命令还原函数名称
char cmd[1024];
snprintf(cmd, sizeof(cmd), "c++filt %s", function_name);
FILE *fp = popen(cmd, "r");
char result[1024];
fgets(result, sizeof(result), fp);
result[strlen(result) - 1] = '\0';
fprintf(out, "%s(", result);
pclose(fp);
Dwfl_Line *line = dwfl_getsrc(dwfl, addr);
if (line != NULL) {
int nline;
Dwarf_Addr addr;
const char *filename = dwfl_lineinfo(line, &addr, &nline, NULL, NULL, NULL);
fprintf(out, "%s:%d", strrchr(filename, '/') + 1, nline);
} else {
fprintf(out, "%p", ip);
}
}
static void __attribute__((noinline)) PrintStackTrace(FILE *out, int skip) {
unw_context_t uc;
unw_getcontext(&uc);
unw_cursor_t cursor;
unw_init_local(&cursor, &uc);
while (unw_step(&cursor) > 0) {
unw_word_t ip;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_word_t offset;
char name[32];
assert(unw_get_proc_name(&cursor, name, sizeof(name), &offset) == 0);
if (skip <= 0) {
fprintf(out, "\tat ");
DebugInfo(out, (void*)(ip - 4));
fprintf(out, ")\n");
}
if (strcmp(name, "main") == 0) {
break;
}
skip--;
}
}
void FuncC(void) {
PrintStackTrace(stdout, 0);
}
void FuncB(void) {
FuncC();
}
void FuncA(void) {
FuncB();
}
$ cat main.cpp
#include "trace.h"
int main() {
FuncA();
return 0;
}
$ cat makefile
CC = g++
CXXFLAGS = -ggdb3 -Wall
INCLUDE = -I./
LIB = -L./ -ltrace
TARGET = test_trace
all : $(TARGET)
$(TARGET) : main.o libtrace.so
$(CC) $(INCLUDE) main.o -o $(TARGET) $(LIB)
main.o : main.cpp
$(CC) $(CXXFLAGS) main.cpp -c
libtrace.so: trace.cpp trace.h
$(CC) -fPIC -shared $(INCLUDE) $(CXXFLAGS) trace.cpp -o libtrace.so -ldw -lunwind
clean :
rm -f *.o
rm -f libtrace.so
rm -f $(TARGET)
# 编译
$ make
g++ -ggdb3 -Wall main.cpp -c
g++ -fPIC -shared -I./ -ggdb3 -Wall trace.cpp -o libtrace.so -ldw -lunwind
g++ -I./ main.o -o test_trace -L./ -ltrace
# 运行
./test_trace
at FuncC()(trace.cpp:76)
at FuncB()(trace.cpp:80)
at FuncA()(trace.cpp:84)
at main(main.cpp:4)
|