Skip to content

Commit 48c460b

Browse files
committed
first commit
0 parents  commit 48c460b

File tree

7 files changed

+538
-0
lines changed

7 files changed

+538
-0
lines changed

.gitignore

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Prerequisites
2+
*.d
3+
4+
# Object files
5+
*.o
6+
*.ko
7+
*.obj
8+
*.elf
9+
10+
# Linker output
11+
*.ilk
12+
*.map
13+
*.exp
14+
15+
# Precompiled Headers
16+
*.gch
17+
*.pch
18+
19+
# Libraries
20+
*.lib
21+
*.a
22+
*.la
23+
*.lo
24+
25+
# Shared objects (inc. Windows DLLs)
26+
*.dll
27+
*.so
28+
*.so.*
29+
*.dylib
30+
31+
# Executables
32+
example
33+
*.exe
34+
*.out
35+
*.app
36+
*.i*86
37+
*.x86_64
38+
*.hex
39+
40+
# Debug files
41+
*.dSYM/
42+
*.su
43+
*.idb
44+
*.pdb
45+
46+
# Kernel Module Compile Results
47+
*.mod*
48+
*.cmd
49+
.tmp_versions/
50+
modules.order
51+
Module.symvers
52+
Mkfile.old
53+
dkms.conf
54+

Makefile

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# tool macros
2+
CC := cc
3+
CCFLAGS := -g -Wall
4+
LIBS := -lbfd
5+
CCOBJFLAGS := $(CCFLAGS) -c
6+
7+
8+
# compile macros
9+
TARGET := example
10+
SRC_PATH := .
11+
OBJ_PATH := .
12+
13+
14+
# src files & obj files
15+
SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/*,.c*)))
16+
OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
17+
18+
19+
# clean files list
20+
CLEAN_LIST := $(TARGET) $(OBJ)
21+
22+
23+
# default rule
24+
default: all
25+
26+
27+
# non-phony targets
28+
$(TARGET): $(OBJ)
29+
$(CC) $(CCFLAGS) -o $@ $(OBJ) $(LIBS)
30+
31+
$(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*
32+
$(CC) $(CCOBJFLAGS) -o $@ $<
33+
34+
35+
# phony rules
36+
.PHONY: all
37+
all: $(TARGET)
38+
39+
.PHONY: clean
40+
clean:
41+
@echo CLEAN $(CLEAN_LIST)
42+
@rm -f $(CLEAN_LIST)
43+

example.c

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <stdio.h>
2+
#include "stacktrace.h"
3+
4+
5+
static void bar()
6+
{
7+
char *p = 0;
8+
*p = 'a';
9+
}
10+
11+
12+
static void foo()
13+
{
14+
bar();
15+
}
16+
17+
18+
int main()
19+
{
20+
init_stacktrace();
21+
22+
foo();
23+
24+
return 0;
25+
}
26+

stacktrace.c

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#define _GNU_SOURCE
2+
#include <execinfo.h>
3+
#include <assert.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
#include <limits.h>
8+
#include <signal.h>
9+
#include <unistd.h>
10+
11+
#include "symbol_table.h"
12+
13+
14+
// The max number of levels in the stack trace
15+
#define STACK_TRACE_MAX_LEVELS 100
16+
#define BUFFER_LENGTH 4096
17+
18+
19+
typedef void (*signal_handler_t)(int signo, siginfo_t *info, void *ctx);
20+
21+
static void register_crash_handlers();
22+
static int backtrace_symbol_write(int fd, const char *text, void *addr);
23+
24+
25+
// store process full path.
26+
static char program_path[PATH_MAX];
27+
// the current program binary symbol table.
28+
static symbol_table_t symtab;
29+
30+
31+
// initialize stacktrace library.
32+
int init_stacktrace()
33+
{
34+
int n;
35+
36+
n = readlink("/proc/self/exe", program_path, PATH_MAX);
37+
if (n < 0 || n >= PATH_MAX) {
38+
return -1;
39+
}
40+
41+
program_path[n] = '\0';
42+
43+
if (symbol_table_build(program_path, &symtab) != 0) {
44+
return -2;
45+
}
46+
47+
register_crash_handlers();
48+
49+
return 0;
50+
}
51+
52+
53+
static void
54+
stack_trace_dump()
55+
{
56+
int i, btl;
57+
char **strings;
58+
void *stack[STACK_TRACE_MAX_LEVELS + 1];
59+
const char *msg = " - STACK TRACE: \n";
60+
61+
if (write(STDERR_FILENO, program_path, strlen(program_path)) == -1) {
62+
return;
63+
}
64+
65+
if (write(STDERR_FILENO, msg, strlen(msg)) == -1) {
66+
return;
67+
}
68+
69+
memset(stack, 0, sizeof(stack));
70+
71+
if ((btl = backtrace(stack, STACK_TRACE_MAX_LEVELS)) > 2) {
72+
strings = backtrace_symbols(stack, btl);
73+
if (strings != NULL) {
74+
for (i = 2; i < btl; i++) {
75+
backtrace_symbol_write(STDERR_FILENO, strings[i], stack[i]);
76+
}
77+
78+
free(strings);
79+
80+
} else {
81+
backtrace_symbols_fd(stack + 2, btl - 2, STDERR_FILENO);
82+
}
83+
}
84+
}
85+
86+
87+
// Reset a signal handler to the default handler.
88+
static void
89+
signal_reset_default(int signo)
90+
{
91+
struct sigaction act;
92+
93+
act.sa_handler = SIG_DFL;
94+
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
95+
sigemptyset(&(act.sa_mask));
96+
97+
assert(sigaction(signo, &act, NULL) == 0);
98+
}
99+
100+
101+
static void
102+
signal_crash_handler(int signo, siginfo_t *siginfo, void *data)
103+
{
104+
stack_trace_dump();
105+
106+
signal_reset_default(signo);
107+
// throw signal to default handler.
108+
raise(signo);
109+
}
110+
111+
112+
static void
113+
set_signal(int signo, signal_handler_t handler)
114+
{
115+
struct sigaction act;
116+
117+
act.sa_handler = NULL;
118+
act.sa_sigaction = handler;
119+
act.sa_flags = SA_SIGINFO;
120+
sigemptyset(&(act.sa_mask));
121+
122+
assert(sigaction(signo, &act, NULL) == 0);
123+
}
124+
125+
126+
static void
127+
register_crash_handlers()
128+
{
129+
set_signal(SIGBUS, signal_crash_handler);
130+
set_signal(SIGSEGV, signal_crash_handler);
131+
set_signal(SIGILL, signal_crash_handler);
132+
set_signal(SIGTRAP, signal_crash_handler);
133+
set_signal(SIGFPE, signal_crash_handler);
134+
set_signal(SIGABRT, signal_crash_handler);
135+
}
136+
137+
138+
static int
139+
backtrace_symbol_format(char *buf, size_t len, const char *prefix, frame_record_t fr)
140+
{
141+
int n;
142+
char *p = buf;
143+
144+
// file name
145+
if (fr.filename != NULL) {
146+
n = snprintf(p, len, "%s %s", prefix, fr.filename);
147+
148+
} else {
149+
n = snprintf(p, len, "%s ??", prefix);
150+
}
151+
152+
p += n;
153+
len -= n;
154+
155+
// function name
156+
if (fr.functionname != NULL && *fr.functionname != '\0') {
157+
n = snprintf(p, len, " %s()", fr.functionname);
158+
159+
} else {
160+
n = snprintf(p, len, " ??");
161+
}
162+
163+
p += n;
164+
len -= n;
165+
166+
// line
167+
if (fr.line != 0) {
168+
n = snprintf(p, len, ":%u", fr.line);
169+
170+
p += n;
171+
len -= n;
172+
}
173+
174+
// discriminator
175+
if (fr.discriminator != 0) {
176+
n = snprintf(p, len, " (discriminator %u)\n", fr.discriminator);
177+
178+
} else {
179+
n = snprintf(p, len, "\n");
180+
}
181+
182+
p += n;
183+
len -= n;
184+
185+
return p - buf;
186+
}
187+
188+
189+
static int
190+
backtrace_symbol_write(int fd, const char *text, void *addr)
191+
{
192+
frame_record_t fr;
193+
int n;
194+
char buf[BUFFER_LENGTH + 1];
195+
196+
if (symbol_table_find(&symtab, addr, &fr)) {
197+
n = backtrace_symbol_format(buf, BUFFER_LENGTH, text, fr);
198+
199+
} else {
200+
n = snprintf(buf, BUFFER_LENGTH, "%s\n", text);
201+
}
202+
203+
buf[n] = '\0';
204+
205+
if (write(fd, buf, strlen(buf)) == -1) {
206+
return -1;
207+
}
208+
209+
return 0;
210+
}
211+

stacktrace.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef __STACKTRACE_H__
2+
#define __STACKTRACE_H__
3+
4+
5+
/*
6+
* Initialize stack trace library.
7+
* DESCRIPTION
8+
* call init_stacktrace register crash signal handler.
9+
* if process crash, this library outputs the stack calls to stderr.
10+
*
11+
* RETURN VALUE
12+
* - On success, init_stacktrace return 0.
13+
* - On error, -1 is returned.
14+
*/
15+
int init_stacktrace();
16+
17+
18+
#endif /* __STACKTRACE_H__ */

0 commit comments

Comments
 (0)