Skip to content

Commit 92bcfbb

Browse files
committed
Get a stack trace on Mac OS X as well.
1 parent f25ac8b commit 92bcfbb

1 file changed

Lines changed: 81 additions & 21 deletions

File tree

src/segfault-handler.cpp

Lines changed: 81 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
#include <fcntl.h>
77
#include <sys/types.h>
88
#include <sys/stat.h>
9-
#include <assert.h>
109
#include <stdarg.h>
1110
#include <node.h>
12-
#include <time.h>
1311
#include <node_buffer.h>
1412
#include <node_object_wrap.h>
1513
#include <v8-debug.h>
14+
15+
#ifdef __APPLE__
16+
#define UNW_LOCAL_ONLY
17+
#include <libunwind.h>
18+
#endif
19+
1620
using namespace v8;
1721
using namespace node;
1822

@@ -21,30 +25,86 @@ using namespace node;
2125
static Persistent<Function> callback;
2226
static bool handlersSet = false;
2327

24-
static void segfault_handler(int sig, siginfo_t *si, void *unused) {
25-
void *array[32]; // Array to store backtrace symbols
26-
size_t size; // To store the size of the stack backtrace
27-
char sbuff[128];
28-
int n; // chars written to buffer
29-
int pid;
28+
static void emptyCallback(siginfo_t *si) {
29+
Local<Array> argStack = Local<Array>::New(Array::New(0));
30+
Local<Value> argv[3] = {argStack, Local<Value>::New(Number::New(si->si_signo)), Local<Value>::New(Number::New((unsigned long long)si->si_addr))};
31+
callback->Call(Context::GetCurrent()->Global(), 3, argv);
32+
}
3033

31-
pid = getpid();
34+
static void segfaultHandler(int sig, siginfo_t *si, void *unused) {
35+
char buffer[1024 * 10];
3236

33-
n = snprintf(sbuff, sizeof(sbuff), "PID %d received SIGSEGV/SIGBUS (%i) for address: 0x%lx\n", pid, si->si_signo, (long)si->si_addr);
34-
write(STDERR_FD, sbuff, n);
37+
int pid = getpid();
3538

36-
size = backtrace(array, 32);
37-
backtrace_symbols_fd(array, size, STDERR_FD);
39+
snprintf(buffer, sizeof(buffer), "PID %d received SIGSEGV/SIGBUS (%i) for address: 0x%llx\n", pid, si->si_signo, (unsigned long long)si->si_addr);
40+
write(STDERR_FD, buffer, strlen(buffer));
3841

3942
if (!callback.IsEmpty()) {
40-
char **stack = backtrace_symbols(array, size);
41-
Local<Array> argStack = Local<Array>::New(Array::New(size));
42-
for (size_t i = 0; i < size; i++) {
43-
argStack->Set(i, String::New(stack[i]));
43+
void *stack[32];
44+
size_t stackSize;
45+
46+
stackSize = backtrace(stack, 32);
47+
48+
if (stackSize > 0) {
49+
char **stackSymbols = backtrace_symbols(stack, stackSize);
50+
Local<Array> argStack = Local<Array>::New(Array::New(stackSize));
51+
for (size_t i = 0; i < stackSize; i++) {
52+
argStack->Set(i, String::New(stackSymbols[i]));
53+
}
54+
free(stackSymbols);
55+
56+
Local<Value> argv[3] = {argStack, Local<Value>::New(Number::New(si->si_signo)), Local<Value>::New(Number::New((unsigned long long)si->si_addr))};
57+
callback->Call(Context::GetCurrent()->Global(), 3, argv);
58+
}
59+
else {
60+
#ifdef __APPLE__
61+
unw_cursor_t cursor;
62+
unw_context_t context;
63+
unw_word_t pc;
64+
65+
unw_getcontext(&context);
66+
unw_init_local(&cursor, &context);
67+
68+
snprintf(buffer, sizeof(buffer), "atos -p %i", pid);
69+
70+
int frames = 0;
71+
while (unw_step(&cursor) > 0) {
72+
frames++;
73+
unw_get_reg(&cursor, UNW_REG_IP, &pc);
74+
int len = strlen(buffer);
75+
snprintf(buffer + len, sizeof(buffer) - len, " 0x%llx", pc);
76+
}
77+
78+
if (frames > 0) {
79+
FILE* program = popen(buffer, "r");
80+
if (program != NULL) {
81+
Local<Array> argStack = Local<Array>::New(Array::New(frames));
82+
for (int i = 0; i < frames; i++) {
83+
if (fgets(buffer, sizeof(buffer), program) == NULL) {
84+
buffer[0] = '\0';
85+
}
86+
int len = strlen(buffer);
87+
if (len > 0 && buffer[len - 1] == '\n') {
88+
buffer[len - 1] = '\0';
89+
}
90+
argStack->Set(i, String::New(buffer));
91+
}
92+
pclose(program);
93+
94+
Local<Value> argv[3] = {argStack, Local<Value>::New(Number::New(si->si_signo)), Local<Value>::New(Number::New((unsigned long long)si->si_addr))};
95+
callback->Call(Context::GetCurrent()->Global(), 3, argv);
96+
}
97+
else {
98+
emptyCallback(si);
99+
}
100+
}
101+
else {
102+
emptyCallback(si);
103+
}
104+
#else
105+
emptyCallback(si);
106+
#endif
44107
}
45-
Local<Value> argv[3] = {argStack, Local<Value>::New(Number::New(si->si_signo)), Local<Value>::New(Number::New((long)si->si_addr))};
46-
callback->Call(Context::GetCurrent()->Global(), 3, argv);
47-
free(stack);
48108
}
49109

50110
// Re-send the signal, this time a default handler will be called
@@ -101,7 +161,7 @@ Handle<Value> RegisterHandler(const Arguments& args) {
101161
struct sigaction sa;
102162
memset(&sa, 0, sizeof(struct sigaction));
103163
sigemptyset(&sa.sa_mask);
104-
sa.sa_sigaction = segfault_handler;
164+
sa.sa_sigaction = segfaultHandler;
105165
sa.sa_flags = SA_SIGINFO | SA_RESETHAND; // We set SA_RESETHAND so that our handler is called only once
106166
sigaction(SIGSEGV, &sa, NULL);
107167
sigaction(SIGBUS, &sa, NULL);

0 commit comments

Comments
 (0)