From 051c871939115445848058e8bef444c3c1bb55f3 Mon Sep 17 00:00:00 2001 From: "C. Scott Ananian" Date: Tue, 20 Oct 2015 11:53:09 -0400 Subject: [PATCH 1/2] Allow user to register handlers for signals other than SIGSEGV In my particular case I'm trying to hunt down a SIGABRT, but why not be general and allow for other unexpected uses. (The code comments actually mention that SIGILL is often generated by a deliberate dereference of a NULL pointer, for instance.) --- README.md | 13 +++++++++ src/segfault-handler.cpp | 60 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c1c188c..5dce740 100644 --- a/README.md +++ b/README.md @@ -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). diff --git a/src/segfault-handler.cpp b/src/segfault-handler.cpp index 7448dc0..c3f77d8 100644 --- a/src/segfault-handler.cpp +++ b/src/segfault-handler.cpp @@ -159,11 +159,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()); @@ -172,11 +172,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(info[sigArg]).FromMaybe(SIGSEGV); + } #ifdef _WIN32 AddVectoredExceptionHandler(1, segfault_handler); @@ -186,14 +194,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(#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) From 989380edebfe373724b154f07f0681cd1b6593e7 Mon Sep 17 00:00:00 2001 From: "C. Scott Ananian" Date: Tue, 20 Oct 2015 12:39:45 -0400 Subject: [PATCH 2/2] Include identity of signal in the stack trace --- src/segfault-handler.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/segfault-handler.cpp b/src/segfault-handler.cpp index c3f77d8..683b0c2 100644 --- a/src/segfault-handler.cpp +++ b/src/segfault-handler.cpp @@ -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 @@ -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 );