This is TRHCrashTrap.m in view mode; [Download] [Up]
/*+++
* title: TRHCrashTrap.m
* abstract: Implementation of of TRHCrashTrap class.
* author: various
* created: Dec 1998, by Tom Hageman <tom@basil.icce.rug.nl>
* modified: Jan 1999
* copyleft: (see below)
* description:
*
* [adapted for use in Mail.app by means of MailCrashTrap plugin]
*
* XXX TODO:
* - make thread-safe;
* v add delegate to handle user-interaction;
* v gracefully handle nested crash;
* v throw & catch dedicated exception instead of abusing abortModal;
* - watch out for character buffer overflows;
* - port stack backtrace to hppa, sparc;
* - autodoc.
*
* Based on:
//
// HKCrashTrap version 1.0
//
// Based on ObjectError
// Original class by:
// Bill Bumgarner, Andrew Stone, Mike Morton, and Julie Zelenski
//
// Modifications by:
// Ivo Rothschild (ivo@hasc.ca)
//
// A class that [poses as object and] does crash-reporting.
// *** This version does _not_ pose as Object anymore, it turns out not
// *** to be necessary.
// Catches terminating signals (ie seg faults, bus errors)
// and fatal Objective-C runtime errors and writes a backtrace
// out to the console using some shady hacks. This could be modified
// to write backtrace to a file, mail message, etc... if desired.
//
//
// You may freely copy, distribute, and reuse the code in this class.
//
// NO WARRANTY:
// ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
// IS HEREBY DISCLAIMED. IN NO EVENT WILL THE AFOREMENTIONED PARTIES BE LIABLE
// FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF OR INABILITY TO USE THIS CODE.
//
*---*/
static const char * const RCSid = ((void)&RCSid,
"@(#)TRHCrashTrap.m,v 1.15 1999/01/10 17:05:20 tom Exp");
#define RCS_TRHCrashTrap_ID
#import "TRHCrashTrap.h"
#import "objcTypeDecode.h"
#import <appkit/appkit.h>
#import <string.h>
#import <stdio.h>
#import <signal.h>
#import <ctype.h>
#import <objc/objc-runtime.h>
#import <defaults/defaults.h>
#ifdef POSE_AS_OBJECT
/* According to the docs, -[Object error] calls _error,
which we already handle so this poser should not be necessary.
And indeed the docs are right. */
@interface _TRHCrashTrapObjectPoser : Object
+ (void)_crashTrapSetup;
- error:(const char *)aString, ...;
+ error:(const char *)aString, ...;
@end
#endif
static const char *signal_descriptions[NSIG];
static BOOL should_handle_signals[NSIG];
static void init_signal_tables(void);
/* fills in the tables above. */
static void (*org_signal_handlers[NSIG])();
static BOOL ignoreCrashes;
static BOOL continueAfterError;
static int selfOffset, _cmdOffset;
static Class crashTrapHandlerClass;
static id delegate;
#define FREED_OBJECT_NAME "<FreedObject>"
// Factory default values.
#define MAX_FRAMES 50 // Print at most this number of stack frames.
#define MAX_FUNCTION_ARGS 4 // Print at most this number of args to a function.
#define MAX_ARG_VAL_LENGTH 256 // limit length of printed argument values.
// User default names.
#define MAX_FRAMES_DEFAULT_NAME "CrashTrap_MaxFrameCount"
#define MAX_FUNCTION_ARGS_DEFAULT_NAME "CrashTrap_FunctionArgCount"
#define MAX_ARG_VAL_LENGTH_DEFAULT_NAME "CrashTrap_MaxArgDescriptionLength"
#define DUMP_BACKTRACE_DEFAULT_NAME "CrashTrap_DumpBacktrace"
static unsigned maxFrames = MAX_FRAMES;
static unsigned maxFunctionArgs = MAX_FUNCTION_ARGS;
static unsigned maxArgValLength = MAX_ARG_VAL_LENGTH;
static BOOL dumpBacktrace = YES;
// XXX Should define this elsewhere -- indirection to force macro expansion.
#define STRINGIZE(X) _STRINGIZE(X)
#define _STRINGIZE(X) #X
// ASSUMPTION: The layout of a stack frame for a method invocation is:
// fp+0 bytes: calling frame
// fp+4 bytes: calling pc
// fp+8 bytes: self
// fp+12 bytes: selector for method invoked
// fp+16 bytes: first argument
//
// ASSUMPTION: The layout of a stack frame for a function invocation is:
// fp+0 bytes: calling frame
// fp+4 bytes: calling pc
// fp+8 bytes: first argument
//
// Clearly these are shady assumptions, however we're already
// in the process of crashing, so what harm can be done?
//
// XXX These assumptions are only valid for m68k and i386;
// XXX hppa, sparc and ppc are _not_ yet supported.
#if (__m68k__ || __i386__)
# define FRAME_ARG_OFFSET 8
#endif
#if 0 // NOTYET
#if (__hppa__)
# define FRAME_ARG_OFFSET 0 // really?
# define INITIAL_FRAME(first_arg_address) __asm__("%%r4") XXX Does not work with 3.3 cc (gcc 2.5.8)
# define ARG_DIRECTION (-1)
#endif
#if (__sparc__)
# define FRAME_ARG_OFFSET 8 // really?
# define INITIAL_FRAME(first_arg_address) __asm__("%%fp") XXX see above
#endif
#endif // NOTYET
#ifndef FRAME_ARG_OFFSET
# warning XXX stack backtrace not yet implemented for this architecture.
# define FRAME_ARG_OFFSET 0
# define INITIAL_FRAME(first_arg_addr) = NULL
#endif
#ifndef FRAME_NEXT_OFFSET
# define FRAME_NEXT_OFFSET 0
#endif
#ifndef FRAME_RETURN_OFFSET
# define FRAME_RETURN_OFFSET 4
#endif
#ifndef ARG_DIRECTION
# define ARG_DIRECTION (+1)
#endif
#ifndef INITIAL_FRAME
# define INITIAL_FRAME(first_arg_address) \
= ((void*)((char*)(first_arg_address) - FRAME_ARG_OFFSET))
#endif
#ifndef NEXT_FRAME
# define NEXT_FRAME(fp) \
(*(void**)((char*)(fp) + FRAME_NEXT_OFFSET))
#endif
#ifndef FRAME_ARG_START
# define FRAME_ARG_START(fp) \
((void *)((char *)(fp) + FRAME_ARG_OFFSET))
#endif
#ifndef FRAME_RETURN_ADDRESS
# define FRAME_RETURN_ADDRESS(fp) \
(*(void**)((char*)(fp) + FRAME_RETURN_OFFSET))
#endif
// in OPENSTEP 4.1 and later we can use NSFrameAddress() instead.
static void *FramePointer(unsigned frame)
{
register void *fp INITIAL_FRAME(&frame);
// Unwind fp the requested number of frames
// (+ 1 additional to compensate for self)
do
{
if (fp == NULL) break;
fp = NEXT_FRAME(fp);
}
while (frame-- > 0);
return fp;
}
typedef void (*ObjcErrorHandler)(Object *, const char *, va_list);
static ObjcErrorHandler _originalError;
static ObjcErrorHandler SetObjcErrorHandler(ObjcErrorHandler newHandler)
{
ObjcErrorHandler oldHandler = _error;
_error = newHandler;
return oldHandler;
}
/* error/signal handler callback functions. */
static void handle_objc_error(Object *anObject, const char *format, va_list ap)
{
[crashTrapHandlerClass handleObjcError:anObject format:format args:ap];
}
static void handle_signal(int signal)
{
[crashTrapHandlerClass handleSignal:signal];
}
static void error_reporter(NXHandler *errorState)
{
switch (errorState->code)
{
case CrashTrap_Crash:
// Already reported the error, so nothing to do here...
break;
case CrashTrap_Continue:
#if DEBUG
NXLogError("CrashTrap: ...continuing.");
#endif
break;
case CrashTrap_RecursiveCrash:
NXLogError("CrashTrap: INTERNAL ERROR: uncaught recursive crash.");
break;
default:
NXLogError("CrashTrap: unknown error code %ld\n", errorState->code);
}
}
// User defaults helper functions.
static unsigned getUnsignedDefaultValue(const char *owner, const char *name, unsigned defaultValue)
{
const char *stringValue;
unsigned result = defaultValue;
NXUpdateDefault(owner, name); // Make sure value is up-to-date.
stringValue = NXGetDefaultValue(owner, name);
if (stringValue && isdigit(*stringValue))
{
sscanf(stringValue, "%u", &result);
}
return result;
}
static BOOL getBoolDefaultValue(const char *owner, const char *name, BOOL defaultValue)
{
const char *stringValue;
BOOL result = defaultValue;
NXUpdateDefault(owner, name); // Make sure value is up-to-date.
stringValue = NXGetDefaultValue(owner, name);
if (stringValue)
{
if (strcasecmp("YES", stringValue) == 0) result = YES;
else if (strcasecmp("NO", stringValue) == 0) result = NO;
}
return result;
}
static const char *appName()
{
const char *result = NULL;
if (NXApp) result = [NXApp appName];
if (result == NULL)
{
/* shady hack in case NXApp is not yet initialized. */
result = strrchr(NXArgv[0], '/');
if (result) ++result;
}
return result;
}
@implementation TRHCrashTrap
+ initialize
{
if (crashTrapHandlerClass == Nil)
{
// Determine offsets of hidden self, _cmd arguments.
Method m = class_getClassMethod(self, _cmd);
char *typeDummy;
method_getArgumentInfo(m, 0, &typeDummy, &selfOffset);
method_getArgumentInfo(m, 1, &typeDummy, &_cmdOffset);
init_signal_tables();
NXRegisterErrorReporter(CRASHTRAP_ERROR_BASE,
CRASHTRAP_ERROR_BASE + CRASHTRAP_ERROR_RANGE -1,
error_reporter);
[self setHandlerClass:[TRHCrashTrap class]];
}
return self;
}
+ (void)setup
{
[self setHandlerClass:[self class]];
_originalError = SetObjcErrorHandler(handle_objc_error);
[self setContinueAfterError:NO];
[self setDefaultValues];
[self resumeHandlingCrashes];
#ifdef POSE_AS_OBJECT
[_TRHCrashTrapObjectPoser _crashTrapSetup];
#endif
}
+ (void)setDefaultValues
{
static const NXDefaultsVector defaults = {
{ MAX_FRAMES_DEFAULT_NAME, STRINGIZE(MAX_FRAMES) },
{ MAX_FUNCTION_ARGS_DEFAULT_NAME, STRINGIZE(MAX_FUNCTION_ARGS) },
{ MAX_ARG_VAL_LENGTH_DEFAULT_NAME, STRINGIZE(MAX_ARG_VAL_LENGTH) },
{ DUMP_BACKTRACE_DEFAULT_NAME, "YES" },
{ NULL }
};
static BOOL initialized;
const char *owner = appName();
if (!initialized)
{
initialized = YES;
NXRegisterDefaults(owner, defaults);
}
// Obtain default values.
maxFrames = getUnsignedDefaultValue(owner, MAX_FRAMES_DEFAULT_NAME, MAX_FRAMES);
maxFunctionArgs = getUnsignedDefaultValue(owner, MAX_FUNCTION_ARGS_DEFAULT_NAME, MAX_FUNCTION_ARGS);
maxArgValLength = getUnsignedDefaultValue(owner, MAX_ARG_VAL_LENGTH_DEFAULT_NAME, MAX_ARG_VAL_LENGTH);
dumpBacktrace = getBoolDefaultValue(owner, DUMP_BACKTRACE_DEFAULT_NAME, YES);
}
+ (void)setContinueAfterError:(BOOL)flag;
{
continueAfterError = flag;
}
+ (BOOL)continueAfterError;
{
return continueAfterError;
}
+ (void)setDelegate:aDelegate;
{
delegate = aDelegate;
if (delegate && [delegate respondsTo:@selector(crashTrap:shouldContinueAfterError:)])
{
[self setContinueAfterError:YES];
}
}
+ delegate
{
return delegate;
}
+ (Class)handlerClass
{
return crashTrapHandlerClass;
}
+ (void)setHandlerClass:(Class)aClass
{
crashTrapHandlerClass = aClass;
// XXX should only allow self or subclasses of self?
}
+ (void)_setHandler:(void (*)())aHandler forSignal:(int)aSignal
{
// XXX probably should use sigvec instead to preserve signal flags as well.
void (*org_handler)() = signal(aSignal, ((aHandler == SIG_DFL) ?
org_signal_handlers[aSignal] :
aHandler));
if (aHandler != SIG_DFL && org_handler != aHandler)
{
org_signal_handlers[aSignal] = org_handler;
}
}
+ (BOOL)isHandlingSignal:(int)aSignal
{
if (aSignal <= 0 || aSignal >= NSIG) return NO;
return should_handle_signals[aSignal];
}
+ (void)setSignal:(int)aSignal handle:(BOOL)aValue
{
if (aSignal <= 0 || aSignal >= NSIG) return;
if (aValue) aValue = YES; // normalize value.
if (should_handle_signals[aSignal] != aValue)
{
should_handle_signals[aSignal] = aValue;
if (!ignoreCrashes)
{
[self _setHandler:(aValue ? handle_signal : SIG_DFL) forSignal:aSignal];
}
}
}
+ (void)setSignalHandler:(void (*)())handler
{
int sig;
/* [TRH] semantics of setSignalHandler:SIG_DFL has changed slightly:
now it restores the situation that was in effect just before the
CrashTrap handler was installed. */
for (sig = 1; sig < NSIG; sig++)
{
if (should_handle_signals[sig])
{
[self _setHandler:handler forSignal:sig];
}
}
}
+ (void)resumeHandlingCrashes
{
[self setSignalHandler:handle_signal];
ignoreCrashes = NO;
}
+ (void)stopHandlingCrashes
{
[self setSignalHandler:SIG_DFL];
ignoreCrashes = YES;
}
#define BACKTRACE_PREFIX_FORMAT "#%-2d 0x%08lx in "
+ (void)printFunctionFromFP:(void *)framePointer at:(void *)address index:(int)index
{
char line[1024];
char *buffer = line;
unsigned long *argStart;
long argNum; // Index into arguments;
sprintf(buffer, BACKTRACE_PREFIX_FORMAT, index, (long)address);
buffer += strlen(buffer);
sprintf(buffer, "function (");
buffer += strlen(buffer);
argStart = FRAME_ARG_START(framePointer);
for (argNum = 0; argNum < maxFunctionArgs; argNum++)
{
sprintf(buffer, "%s0x%08lx", ((argNum != 0) ? ", " : ""),
marg_getValue(argStart, selfOffset + argNum * sizeof(long) * ARG_DIRECTION, long));
buffer += strlen(buffer);
}
strcpy(buffer, ")");
[self logMessage:line];
}
+ (void)printMethodFromFP:(void *)framePointer at:(void *)address index:(int)index
{
char line[BUFSIZ];
char *buffer = line;
SEL selector;
const char *selName;
id object, class, classIsa;
char *argStart;
Method m;
BOOL isClassMethod;
NX_DURING
sprintf(buffer, BACKTRACE_PREFIX_FORMAT, index, (long)address);
buffer += strlen(buffer);
argStart = FRAME_ARG_START(framePointer);
object = marg_getValue(argStart, selfOffset, id);
selector = marg_getValue(argStart, _cmdOffset, SEL);
selName = sel_getName(selector);
if (selName == NULL) selName = "<invalid selector>";
class = nil;
classIsa = nil;
object_getInstanceVariable(object, "isa", (void **)&class);
if (class)
{
object_getInstanceVariable(class, "isa", (void **)&classIsa);
}
if (!classIsa)
{
// Freed object.
// (in practice classes are never freed, so assume instance method.)
sprintf(buffer, "%c[%s0x%06lx %s]", '-', FREED_OBJECT_NAME, (long)object, selName);
}
else
{
isClassMethod = IS_CLASS(object);
m = (isClassMethod ? class_getClassMethod(class, selector)
: class_getInstanceMethod(class, selector));
if (m)
{
int argNum, numArgs, offset;
char *type;
*buffer++ = (isClassMethod?'+':'-');
/* Get return type -- XXX assumption: Method types description
starts with return type. */
*buffer++ = '(';
decode_objc_encoded_type(buffer, sizeof(line) - (buffer - line),
m->method_types, 0);
buffer += strlen(buffer);
*buffer++ = ')';
*buffer++ = '[';
decode_objc_encoded_value_for_type(buffer, sizeof(line) - (buffer - line),
@encode(id), &object, DECODE_OBJC_VERBOSE);
buffer += strlen(buffer);
numArgs = method_getNumberOfArguments(m);
argNum = 2; // Skip the first two args which are self and _cmd
if (numArgs <= argNum)
{
sprintf(buffer, " %s", selName);
}
else
{
while (argNum < numArgs)
{
int argVerbosity = DECODE_OBJC_VERBOSE;
const char *se = strchr(selName, ':');
// intermix selector name parts and arguments.
if (se == NULL)
{
sprintf(buffer, (*selName) ? " %s " : ", ", selName);
selName += strlen(selName);
}
else
{
++se;
sprintf(buffer, " %.*s", (int)(se - selName), selName);
selName = se;
}
buffer += strlen(buffer);
// argument type.
method_getArgumentInfo(m, argNum, &type, &offset);
*buffer++ = '(';
decode_objc_encoded_type(buffer, sizeof(line) - (buffer - line), type, 0);
buffer += strlen(buffer);
*buffer++ = ')';
// argument value.
while (argVerbosity >= 0)
{
// Retry with less verbosity if recursive crash.
NX_DURING
decode_objc_encoded_value_for_type(buffer, maxArgValLength, type,
marg_getRef(argStart, offset, void),
argVerbosity);
argVerbosity = -1;
NX_HANDLER
// If recursive crash, retry with less verbosity.
if (argVerbosity & DECODE_OBJC_VERBOSE)
{
argVerbosity &= ~DECODE_OBJC_VERBOSE;
}
else
{
strcpy(buffer, "???");
argVerbosity = -1;
}
NX_ENDHANDLER
}
buffer += strlen(buffer);
argNum++;
}
}
strcat(buffer, "]");
}
else
{
*buffer++ = (isClassMethod?'+':'-');
*buffer++ = '[';
decode_objc_encoded_value_for_type(buffer, sizeof(line) - (buffer - line),
@encode(id), &object, DECODE_OBJC_VERBOSE);
buffer += strlen(buffer);
sprintf(buffer, " %s] <unknown method>", selName);
}
}
NX_HANDLER
static const char recursiveCrashMessage[] = " *** recursive crash ***";
if (strlen(line) <= sizeof(line) - sizeof(recursiveCrashMessage))
{
strcat(line, recursiveCrashMessage);
}
NX_ENDHANDLER
[self logMessage:line];
}
+ (void)dumpBacktrace
{
return [self dumpBacktraceAtFrame:1];
}
+ (void)dumpBacktraceAtFrame:(unsigned)startFrameNumber
{
unsigned int frameCount = 0; // counter for number of frames printed
void *returnAddress;
void *framePointer;
if (maxFrames <= 0) return;
framePointer = FramePointer(startFrameNumber);
if (framePointer == NULL)
{
if (FramePointer(0) == NULL)
{
[self logMessage:"*** stack frame Backtrace not yet supported for architecture "__ARCHITECTURE__", sorry..."];
}
else
{
[self logMessage:"*** stack frame Backtrace -- sorry, I'm lost!"];
}
return;
}
[self logMessage:"*** stack frame Backtrace follows:"];
// Get initial return address.
returnAddress = FRAME_RETURN_ADDRESS(framePointer);
// Assume that a whole lotta frames means either (a) we're trashed or
// (b) we're in a recursive deathtrap. In the latter case, we have
// probably got enough info to see a whole cycle.
// initial NEXT_FRAME to skip self.
while (frameCount < maxFrames && (framePointer = NEXT_FRAME(framePointer)))
{
void *argStart = FRAME_ARG_START(framePointer);
SEL sel = marg_getValue(argStart, _cmdOffset, SEL);
// If this frame is a method call we will have a valid
// selector as second argument.
if (sel && sel_isMapped(sel))
{
[self printMethodFromFP:framePointer at:returnAddress index:frameCount];
}
else
{
[self printFunctionFromFP:framePointer at:returnAddress index:frameCount];
}
++frameCount;
returnAddress = FRAME_RETURN_ADDRESS(framePointer);
}
if (framePointer) [self logMessage:"... (more frames follow, not listed)"];
}
+ (BOOL)handleError:(const char *)message
{
return [self handleError:message atFrame:1];
}
+ (BOOL)handleError:(const char *)message atFrame:(unsigned)startFrameNumber
{
if (!ignoreCrashes)
{
static BOOL crashing;
if (!crashing)
{
crashing = YES;
[self logStart];
[self logMessage:message];
if (dumpBacktrace) [self dumpBacktraceAtFrame:(startFrameNumber + 1)];
[self logStop];
if (continueAfterError && [self shouldContinue:message])
{
#if DEBUG
NXLogError("CrashTrap: trying to continue...");
#endif
crashing = NO;
NX_RAISE(CrashTrap_Continue, NULL, NULL);
return YES;
}
[self stopHandlingCrashes];
crashing = NO;
}
else
{
#if DEBUG
fprintf(stderr, "CrashTrap: recursive crash \"%s\"\n", message);
#endif
NX_RAISE(CrashTrap_RecursiveCrash, NULL, NULL);
return YES;
}
}
return NO;
}
+ (BOOL)shouldContinue:(const char *)message
{
/* XXX this introduces AppKit dependencies. A better solution might be
to exlusively let the delegate handle it. */
if (delegate && [delegate respondsTo:@selector(crashTrap:shouldContinueAfterError:)])
{
return [delegate crashTrap:self shouldContinueAfterError:message];
}
// XXX Localize?
// XXX should preallocate this alert panel to be more crashproof?
if (NXRunAlertPanel("Error Alert!",
"%s\n\nAn internal error has occurred."
" Try to save work,"
" then quit and restart the %s application.\n"
"(see the console for details)",
"Continue", "CRASH!", NULL, message, appName()) != NX_ALERTDEFAULT)
{
return NO;
}
return YES;
}
+ (void)handleObjcError:object format:(const char *)format args:(va_list)args
{
char buf[BUFSIZ];
sprintf(buf, "objc: <%s> ", object_getClassName(object));
vsprintf(buf + strlen(buf), format, args);
if ([self handleError:buf atFrame:3]) return;
// skip self, invoking error handler function, and -error:.
/* invoke original error handler. */
_originalError(object, format, args);
}
+ (void)handleSignal:(int)sig
{
const char *desc = NULL;
char buf[256];
// unblock this signal.
unsigned long mask = sigblock(0) & ~sigmask(sig);
sigsetmask(mask);
if (0 < sig && sig < NSIG) desc = signal_descriptions[sig];
if (desc == NULL) desc = "Unrecognized signal";
sprintf(buf, "Caught signal #%d (%s)", sig, desc);
if ([self handleError:buf atFrame:2]) return;
// skip self, and signal handler.
/* Here the original signal handler is in effect (or should be, at least.)
Re-raise signal to get original intended handling (or lack thereof). */
kill(getpid(), sig);
}
// Logging.
+ (void)logStart {}
+ (void)logMessage:(const char *)message
{
NXLogError("%s\n", message);
}
+ (void)logStop {}
@end // TRHCrashTrap
#ifdef POSE_AS_CLASS
@implementation _TRHCrashTrapObjectPoser
+ (void)_crashTrapSetup
{
[self poseAs:[self superclass]];
}
- error:(const char *)aFormat, ...
{
va_list ap;
char buffer[BUFSIZ];
va_start(ap, aFormat);
vsprintf(buffer, aFormat, ap);
va_end(ap);
if ([[TRHCrashTrap handlerClass] handleError:buffer]) return self;
return [super error:"%s", buffer];
}
+ error:(const char *)aFormat, ...
{
va_list ap;
char buffer[BUFSIZ];
va_start(ap, aFormat);
vsprintf(buffer, aFormat, ap);
va_end(ap);
if ([[TRHCrashTrap handlerClass] handleError:buffer]) return self;
return [super error:"%s", buffer];
}
@end // _TRHCrashTrapObjectPoser
#endif
typedef struct _sig {
short number;
BOOL isOn;
const char *message;
} SignalItem;
#define ON 1
#define OFF 0
static const SignalItem signals[] = {
{SIGHUP, OFF, "Hangup"},
{SIGINT, OFF, "Interrupt"},
{SIGQUIT, ON, "Quit"},
{SIGILL, ON, "Illegal instruction"},
{SIGTRAP, ON, "Trace trap"},
{SIGIOT, ON, "IOT instruction"},
{SIGEMT, ON, "EMT instruction"},
{SIGFPE, ON, "Floating point exception"},
{SIGKILL, OFF, "Kill"},
{SIGBUS, ON, "Bus error"},
{SIGSEGV, ON, "Segmentation violation"},
{SIGSYS, ON, "Bad argument to system call"},
{SIGPIPE, OFF, "Write on a pipe with no one to read it"},
{SIGALRM, OFF, "Alarm clock"},
{SIGTERM, OFF, "Software termination"},
{SIGURG, OFF, "Urgent condition present on socket"},
{SIGSTOP, OFF, "Stop"},
{SIGTSTP, OFF, "Stop signal generated from keyboard"},
{SIGCONT, OFF, "Continue after stop"},
{SIGCHLD, OFF, "Child status changed"},
{SIGTTIN, OFF, "Background read attempted from control terminal"},
{SIGTTOU, OFF, "Background write attempted to control terminal"},
{SIGIO, OFF, "I/O is possible on a descriptor"},
{SIGXCPU, OFF, "CPU time limit is exceeded"},
{SIGXFSZ, OFF, "File size limit exceeded"},
{SIGVTALRM, OFF, "Virtual timer alarm"},
{SIGPROF, OFF, "Profiling timer alarm"},
{SIGWINCH, OFF, "Window size change"},
{SIGUSR1, OFF, "User defined signal 1"},
{SIGUSR2, OFF, "User defined signal 2"},
{0},
};
static void init_signal_tables()
{
const SignalItem *cur;
for (cur = signals; cur->number; cur++)
{
signal_descriptions[cur->number] = cur->message;
should_handle_signals[cur->number] = cur->isOn;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.