Skip to content

Allow user to register handlers for signals other than SIGSEGV #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ Now you can start debugging using tools like "objdump -dS module.node" to try an

Cheers, enjoy. And happy hunting.

# Looking at other signals.

On OSX and Linux you can also register handlers for other (presumably
unexpected) signals by specifying an extra parameter:
```javascript

var SegfaultHandler = require('segfault-handler');

SegfaultHandler.registerHandler(SegfaultHandler.SIGSEGV);
SegfaultHandler.registerHandler("crash.log", SegfaultHandler.SIGABRT);
```
The last logfile name registered takes effect.

# License

We are using the callstack walker project from [Walking the Callstack](http://www.codeproject.com/Articles/11132/Walking-the-callstack).
Expand Down
73 changes: 66 additions & 7 deletions src/segfault-handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ SEGFAULT_HANDLER {
#ifndef _WIN32
void *array[32]; // Array to store backtrace symbols
size_t size; // To store the size of the stack backtrace
int signal; // Which signal was received?
#endif
char sbuff[BUFF_SIZE];
int n; // chars written to buffer
Expand All @@ -83,14 +84,24 @@ SEGFAULT_HANDLER {
address = (long)exceptionInfo->ExceptionRecord->ExceptionAddress;
#else
address = (long)si->si_addr;
signal = si->si_signo;
#endif

// Write the header line
n = SNPRINTF(
sbuff,
BUFF_SIZE,
"PID %d received SIGSEGV for address: 0x%lx\n",
"PID %d received "
#ifdef _WIN32
"segfault"
#else
"signal %d"
#endif
" for address: 0x%lx\n",
pid,
#ifndef _WIN32
signal,
#endif
address
);

Expand Down Expand Up @@ -159,11 +170,11 @@ NAN_METHOD(CauseSegfault) {
}

NAN_METHOD(RegisterHandler) {
int sigArg = -1, signal = SIGSEGV;
// if passed a path, we'll set the log name to whatever is provided
// this will allow users to use the logs in error reporting without redirecting
// sdterr
logPath[0] = '\0';
if (info.Length() == 1) {
// this will allow users to use the logs in error reporting without
// redirecting stderr
if (info.Length() >= 1) {
if (info[0]->IsString()) {
v8::String::Utf8Value utf8Value(info[0]->ToString());

Expand All @@ -172,11 +183,19 @@ NAN_METHOD(RegisterHandler) {
len = len > BUFF_SIZE ? BUFF_SIZE : len;

strncpy(logPath, *utf8Value, len);
logPath[127] = '\0';
logPath[BUFF_SIZE-1] = '\0';
if (info.Length() >= 2 && info[1]->IsNumber()) {
sigArg = 1;
}
} else if (info[0]->IsNumber()) {
sigArg = 0;
} else {
return ThrowError("First argument must be a string.");
}
}
if (sigArg >= 0) {
signal = Nan::To<int32_t>(info[sigArg]).FromMaybe(SIGSEGV);
}

#ifdef _WIN32
AddVectoredExceptionHandler(1, segfault_handler);
Expand All @@ -186,14 +205,54 @@ NAN_METHOD(RegisterHandler) {
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = segfault_handler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(signal, &sa, NULL);
#endif
}

extern "C" {
NAN_MODULE_INIT(init) {
logPath[0] = '\0';
Nan::SetMethod(target, "registerHandler", RegisterHandler);
Nan::SetMethod(target, "causeSegfault", CauseSegfault);
// Export signal names and values.
#define EXPORT(signal) \
Nan::ForceSet(target, Nan::New<v8::String>(#signal).ToLocalChecked(), Nan::New(signal), v8::ReadOnly)
// Not all of these make sense to register handlers on, but we'll let
// the user decide that. Presumably you're using this package because
// you're seeing an unexpected signal of some sort. Hopefully it's
// included below. (And if not, just pass it by integer value.)
EXPORT(SIGHUP);
EXPORT(SIGINT);
EXPORT(SIGQUIT);
EXPORT(SIGILL);
EXPORT(SIGTRAP);
EXPORT(SIGABRT);
EXPORT(SIGBUS);
EXPORT(SIGFPE);
EXPORT(SIGKILL);
EXPORT(SIGUSR1);
EXPORT(SIGUSR2);
EXPORT(SIGSEGV);
EXPORT(SIGUSR2);
EXPORT(SIGPIPE);
EXPORT(SIGALRM);
EXPORT(SIGTERM);
//EXPORT(SIGSTKFLT); // not present on OSX
EXPORT(SIGCHLD);
EXPORT(SIGCONT);
EXPORT(SIGSTOP);
EXPORT(SIGTSTP);
EXPORT(SIGTTIN);
EXPORT(SIGTTOU);
EXPORT(SIGURG);
EXPORT(SIGXCPU);
EXPORT(SIGXFSZ);
EXPORT(SIGVTALRM);
EXPORT(SIGPROF);
EXPORT(SIGWINCH);
EXPORT(SIGIO);
//EXPORT(SIGPWR); // not present on OSX
EXPORT(SIGSYS);
}

NODE_MODULE(segfault_handler, init)
Expand Down