This is ObjectError.m in view mode; [Download] [Up]
/* * ObjectError * * You may freely copy, distribute and reuse the code in this example. * This code is provided AS IS without warranty of any kind, expressed * or implied, as to its fitness for any particular use. * * Copyright 1995 Ralph Zazula (rzazula@next.com). All Rights Reserved. * * Based on the original ObjectError by Julie Zelenski * */ #import "ObjectError.h" #import <appkit/nextstd.h> #import <sys/signal.h> #import <strings.h> #import <stdio.h> typedef struct _sig { int number; BOOL isOn; char *message; } SignalItem; typedef struct _type { char encoding; char *format; char *name; } ObjcType; extern SignalItem signals[]; extern ObjcType encodings[]; @implementation ObjectError static void handle_signal (int signal); static BOOL ignoreCrashes; + setup { [self poseAs:[Object class]]; [self setSignalHandler:handle_signal]; ignoreCrashes = NO; return self; } + setSignalHandler:(void(*)())handler { SignalItem *cur; for(cur = signals; cur->number; cur++) { if(cur->isOn) { signal(cur->number, handler); } } return self; } + resumeHandlingCrashes { [self setSignalHandler:handle_signal]; ignoreCrashes = NO; return self; } + stopHandlingCrashes { [[self class] setSignalHandler:(void (*)())SIG_DFL]; ignoreCrashes = YES; return self; } #define MAX_FUNCTION_ARGS 4 + printFunctionFromFP:(void *)framePointer { char buffer[256]; char line[1024]; void *argStart; long argNum; sprintf(line, "function ("); argStart = framePointer + 8; for(argNum = 0; argNum < MAX_FUNCTION_ARGS; argNum++) { sprintf(buffer, "%s0x%06lx", (argNum != 0 ? ", " : ""), *(((long *)argStart) + argNum)); strcat(line, buffer); } strcat(line, ")"); NXLogError("%s\n",line); return self; } #define IS_CLASS(object) ([object class] == object) + printMethodFromFP:(void *)framePointer { char buffer[256]; char line[1024]; SEL selector; id object; Method m; BOOL isClassMethod; object = *(id *)(framePointer + 8); selector = *(SEL *)(framePointer + 12); isClassMethod = IS_CLASS(object); sprintf(line, "%c[%s %s",(isClassMethod ? '+' : '-'), object_getClassName(object), sel_getName(selector)); m = (isClassMethod ? class_getClassMethod([object class], selector) : class_getInstanceMethod([object class], selector)); if(m) { void *argStart = (framePointer + 8); int argNum, numArgs, offset; char *type; numArgs = method_getNumberOfArguments(m); argNum = 2; while(argNum < numArgs) { ObjcType *cur; method_getArgumentInfo(m, argNum, &type, &offset); for(cur = encodings; cur->encoding; cur++) { if(cur->encoding == type[0]) { sprintf(buffer, " :(%s)", cur->name); strcat(line,buffer); sprintf(buffer,cur->format,*(long*)(argStart+offset)); strcat(line,buffer); break; } } argNum++; } } else { strcat(line, " Unknown Method"); } strcat(line, "]"); NXLogError("%s\n",line); return self; } #define MAX_FRAMES 50 + printBacktrace { void *framePointer; unsigned int frameCount; [self stopHandlingCrashes]; #if DEBUG framePointer = ((void *) &self) - 8; frameCount = 0; while(frameCount < MAX_FRAMES && framePointer) { if(sel_isMapped(*(SEL *)(framePointer + 12))) { [self printMethodFromFP:framePointer]; } else { [self printFunctionFromFP:framePointer]; } framePointer = (void *)*(long *)framePointer; } #endif return self; } + dumpBacktrace:(const char *)message { NXLogError("%s: %s\n", [self name], message); [self printBacktrace]; return self; } static void handle_signal(int signal) { const char *msg = NULL; char buf[256]; SignalItem *cur; msg = "Unrecognized signal"; for(cur = signals; cur->number; cur++) { if(cur->number == signal) { msg = cur->message; break; } } sprintf(buf, "Caught signal #%d: \"%s\"",signal, msg); [ObjectError dumpBacktrace:buf]; } - error:(const char *)aString, ...; { va_list ap; char buffer[1024]; va_start(ap, aString); vsprintf(buffer, aString, ap); va_end(ap); if(!ignoreCrashes) { [[self class] dumpBacktrace:buffer]; [[self class] resumeHandlingCrashes]; } else { return [super error:buffer]; } return self; } + error:(const char *)aString, ...; { va_list ap; char buffer[1024]; va_start(ap, aString); vsprintf(buffer, aString, ap); va_end(ap); if(!ignoreCrashes) { [[self class] dumpBacktrace:buffer]; [[self class] resumeHandlingCrashes]; } else { return [super error:buffer]; } return self; } #define ON 1 #define OFF 0 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 pipe with no reader"}, { 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 has changed"}, { SIGTTIN , OFF, "background read attempted from control terminal"}, { SIGTTOU , OFF, "background write attempted to control terminal"}, { SIGIO , OFF, "i/o is impossible on descriptor"}, { SIGXCPU , OFF, "cpu time limit exceeded"}, { SIGXFSZ , OFF, "file size limit exceeded"}, { SIGVTALRM , OFF, "virtual time alarm"}, { SIGPROF , OFF, "profiling timer alarm"}, { SIGWINCH , OFF, "window size changed"}, { SIGUSR1 , OFF, "user defined #1"}, { SIGUSR2 , OFF, "user defined #2"}, {0}, }; ObjcType encodings[] = { { _C_ID, "0x%06lx", "id"}, { _C_CLASS, "0x%06lx", "Class"}, { _C_SEL, "%s", "SEL"}, { _C_CHR, "%c", "char"}, { _C_UCHR, "%c", "unsigned char"}, { _C_SHT, "%s", "short"}, { _C_USHT, "%s", "unsigned short"}, { _C_INT, "%d", "int"}, { _C_UINT, "%d", "unsigned int"}, { _C_LNG, "%l", "long"}, { _C_ULNG, "%l", "unsigned long"}, { _C_FLT, "%f", "float"}, { _C_DBL, "%f", "double"}, { _C_VOID, "0x%06lx", "void"}, { _C_PTR, "0x%06lx", "pointer"}, { _C_CHARPTR, "*s", "char *"}, { _C_STRUCT_B,"%x", "struct"}, { 0, "0x%06lx", "Unknown"}, }; @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.