forked from danielwaterworth/Raphters
-
Notifications
You must be signed in to change notification settings - Fork 7
/
backtrace.c
92 lines (73 loc) · 1.79 KB
/
backtrace.c
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
#define _GNU_SOURCE
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <dlfcn.h>
#include <time.h>
#include <fcgi_stdio.h>
#include "backtrace.h"
volatile static int caught_fatal = 0;
static unw_context_t resume_ctx;
static void (*segfault_callback)() = 0;
void addr2line(void *p, char *c) {
Dl_info dli = { 0 };
(void)dladdr(p, &dli);
ptrdiff_t offset = p - (dli.dli_saddr ?: dli.dli_fbase);
if (dli.dli_fname) {
sprintf(c, "%s(%s+0x%lx)[%p]",
dli.dli_fname, dli.dli_sname ?: "", offset, p);
} else {
sprintf(c, "[%p]", p);
}
}
void show_backtrace(FILE *f) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
char buffer[1024];
unw_step(&cursor);
for(;;) {
int end = (unw_step(&cursor) > 0);
unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (!end || !ip)
break;
addr2line((void*)ip, buffer);
fprintf(f, "%s\n", buffer);
}
}
void on_segfault(int signal, siginfo_t *si, void *arg) {
if (segfault_callback) {
segfault_callback();
}
caught_fatal = si->si_code == SI_USER || si->si_code == SI_TKILL;
if (caught_fatal) return;
unw_cursor_t resume_cursor;
unw_init_local(&resume_cursor, &resume_ctx);
unw_resume(&resume_cursor);
}
int install_segfault_handler(void (*cb)()) {
segfault_callback = cb;
struct sigaction sa = { 0 };
sa.sa_sigaction = &on_segfault;
sa.sa_flags = SA_SIGINFO;
int rc;
if (rc = sigaction(SIGSEGV, &sa, NULL))
return rc;
if (rc = sigaction(SIGBUS, &sa, NULL))
return rc;
if (rc = sigaction(SIGABRT, &sa, NULL))
return rc;
if (rc = sigaction(SIGUSR1, &sa, NULL))
return rc;
unw_getcontext(&resume_ctx);
if (caught_fatal) {
// here we go!!!
void _start(void);
_start();
}
return 0;
}