This is OEObject.m in view mode; [Download] [Up]
static const char *rcsid = "$Id: OEObject.m,v 1.3 1997/10/23 02:06:09 art Exp $ cc: "__DATE__" "__TIME__; // Suppress compiler warning about rcsid being unused, yet prevent assembler // code for this function from being produced. inline extern const char *suppressCompilerWarning(void) { return rcsid; } // // --------------------- OEObject Class Implementation ------------------------ // // (see .h for information) // // 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. // // Things to fix: // 1. Handle functions better // a. Perhaps use frame length to figure it out? // b. Compiler can probably help // 2. Find the return value and use that information on Windows // 3. Test more on hppa and sparc. Problem here is that the information // is not actually on the stack, it's in registers which get blown away by // the next call. // 4. Localization // ---------------------------------------------------------------------------- // // ----------------------------- Header Files --------------------------------- #import <Foundation/Foundation.h> #import <Foundation/NSDebug.h> #import <objc/Object.h> #import <objc/objc-class.h> #import <objc/objc-runtime.h> #ifndef WIN32 #import <sys/signal.h> #else WIN32 #import <signal.h> #import <windows.h> #endif WIN32 #import "OEObject.h" // ---------------- Typedef, Struct, and Union Declarations ------------------- #ifndef WIN32 typedef struct _signalItem { int number; BOOL isOn; NSString *message; } OESignalItem_t; #endif WIN32 typedef struct _objcTypeDesc { NSString *format; NSString *name; } OEObjcTypeDesc_t; typedef struct _objcType { char encoding; OEObjcTypeDesc_t description; } OEObjcType_t; typedef struct _returnInfo { int type; int size; } OEReturnInfo_t; // --------------------- Constant and Enum Definitions ------------------------ // Default number of function arguments printed. static unsigned functionArgCountG = 4; // Default number of stack frames printed. static unsigned frameCountG = 50; // Default maximum argument description length. static unsigned maxArgDescriptionLengthG = 255; // Name of exception raised to continue execution. static NSString *crashExceptionG = @"Crash"; // Name of defaults variables that can be used to set the function argument and // stack frame counts and maximum argument description length. static NSString *functionArgCountDefaultsNameG = @"OEFunctionArgCount"; static NSString *frameCountDefaultsNameG = @"OEFrameCount"; static NSString *maxArgDescriptionLengthDefaultsNameG = @"OEMaxArgDescriptionLength"; // Telltale string that occurs in error message when a freed object is // messaged. static NSString *freedObjectMessageG = @"freed object"; // Class name printed in backtrace for a freed object. static NSString *freedObjectNameG = @"<FreedObject>"; #ifndef WIN32 static NSString *endOfLineG = @"\n"; #else WIN32 // Make stack backtrace display nicely in NT's EventViewer. static NSString *endOfLineG = @"\r\n"; #endif WIN32 // 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? // WIN32 assumptions // Stack layout is the same, except in cases where the return value from the // current frame is a structure, when all arguments get shifted away. // Stack unwind definitions. These are offsets from the frame pointer where // the previous frame pointer is stored, and where the return pointer is // stored. (These offsets don't seem to be used, so why are they defined??) #if defined(i386) || defined(m68k) #define FP_WORD_OFFSET 0 #define RP_WORD_OFFSET 1 #elif defined(hppa) #define FP_WORD_OFFSET 0 #define RP_WORD_OFFSET -5 #define STACK_GROWS_UP 1 #elif defined(sparc) #define FP_WORD_OFFSET 14 #define RP_WORD_OFFSET 15 #else #error Stack unwind not defined for this architecture #endif // Mach m68k/i486 assumptions // Given the frame pointer, where are the arguments? static int argStartPositionG = 8; // Given the location of the arguments, where are self and the selector? #if defined(STACK_GROWS_UP) static int selfIndexG = -1; static int sELIndexG = -2; #else static int selfIndexG = 0; static int sELIndexG = 1; #endif #ifndef WIN32 #define ON 1 #define OFF 0 static OESignalItem_t OESignals[] = { {0, OFF, @"Exit from the shell"}, {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"} }; #endif WIN32 static OEObjcType_t OEEncodings[] = { {_C_ID, {@"%@", @"id"}}, {_C_CLASS, {@"%@", @"Class"}}, {_C_SEL, {@"%s", @"SEL"}}, {_C_CHR, {@"%c", @"char"}}, {_C_UCHR, {@"%c", @"unsigned char"}}, {_C_SHT, {@"%hd", @"short"}}, {_C_USHT, {@"%hu", @"unsigned short"}}, {_C_INT, {@"%d", @"int"}}, {_C_UINT, {@"%u", @"unsigned"}}, {_C_LNG, {@"%ld", @"long"}}, {_C_ULNG, {@"%lu", @"unsigned long"}}, {_C_FLT, {@"%f", @"float"}}, {_C_DBL, {@"%f", @"double"}}, {_C_VOID, {@"%#08x", @"void"}}, {_C_PTR, {@"%#08x", @"ptr"}}, {_C_CHARPTR, {@"%.*s", @"char *"}}, {_C_STRUCT_B, {@"%x", @"struct"}} }; // ------------------------- Function Declarations ---------------------------- #ifndef WIN32 static void handle_signal(int aSignal); #else WIN32 static int filter(LPEXCEPTION_POINTERS theInfo); #endif WIN32 // The _error() function prototype has an Object rather than NSObject first // argument type. static void (*_originalError)(Object *anObject, const char *aFormat, va_list theArguments); static void _objectError(Object *anObject, const char *aFormat, va_list theArguments); @interface OEObject(Private) // ---------------------- Private Method Declarations ------------------------- #ifndef WIN32 + (void)_setSignalHandler:(void (*)())aHandler; #endif WIN32 + (NSString *)_prepareToPrintBacktrace:(NSString *)aMessage; + (NSString *)_printFrame:(void *)aFramePointer withMessage:(NSString *)aMessage; + (NSString *)_functionMessageFromFP:(void *)aFramePointer; + (NSString *)_methodMessageWithFP:(void *)aFramePointer selector:(SEL)aSelector; + (BOOL)_isReturnStructInRegistersWithSize:(int)aSize; // returnValue argument is always NULL - future enhancement?? + (id)_selfWithFrame:(void *)anArgumentFrame returnValue:(OEReturnInfo_t *)aReturnValue; + (SEL)_selectorWithFrame:(void *)anArgumentFrame returnValue:(OEReturnInfo_t *)aReturnValue; + (NSString *)_argumentStringWithObjcType:(const char *)anObjcType offset:(void *)anOffset; + (void)_logMessage:(NSString *)aMessage; @end @implementation OEObject // --------------------- Class Variable Declarations -------------------------- static BOOL continueAfterErrorC; static BOOL ignoreCrashesC; static BOOL isSetUpC; static unsigned frameCountC; static unsigned freedAddressC; static unsigned functionArgCountC; static unsigned maxArgDescriptionLengthC; static NSMutableDictionary *objcTypeEncodingsC; #ifndef WIN32 static NSMutableDictionary *signalMessagesC; #endif WIN32 // ----------------------- Class Method Definitions --------------------------- + (void)initialize { if (self == [OEObject class]) { continueAfterErrorC = NO; ignoreCrashesC = NO; isSetUpC = NO; freedAddressC = 0; objcTypeEncodingsC = nil; #ifndef WIN32 signalMessagesC = nil; #endif WIN32 } } // Pose as the NSObject class. + (void)setup { if (!isSetUpC) { NSUserDefaults *userDefaultsL = [NSUserDefaults standardUserDefaults]; NSNumber *functionArgCountL = [userDefaultsL objectForKey:functionArgCountDefaultsNameG]; NSNumber *frameCountL = [userDefaultsL objectForKey:frameCountDefaultsNameG]; NSNumber *maxArgDescriptionLengthL = [userDefaultsL objectForKey:maxArgDescriptionLengthDefaultsNameG]; if (functionArgCountL == nil) { functionArgCountC = functionArgCountG; } else { functionArgCountC = [functionArgCountL unsignedIntValue]; } if (frameCountL == nil) { frameCountC = frameCountG; } else { frameCountC = [frameCountL unsignedIntValue]; } if (maxArgDescriptionLengthL == nil) { maxArgDescriptionLengthC = maxArgDescriptionLengthG; } else { maxArgDescriptionLengthC = [maxArgDescriptionLengthL unsignedIntValue]; } [self poseAsClass:[NSObject class]]; _originalError = _error; _error = _objectError; #ifndef WIN32 signalMessagesC = [[NSMutableDictionary alloc] initWithCapacity:sizeof(OESignals) / sizeof(OESignalItem_t)]; [self _setSignalHandler:handle_signal]; #else WIN32 SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)filter); #endif WIN32 isSetUpC = YES; } } + (void)setContinueAfterError:(BOOL)aFlag { continueAfterErrorC = aFlag; } + (void)resumeHandlingCrashes { #ifndef WIN32 [self _setSignalHandler:handle_signal]; #endif WIN32 ignoreCrashesC = NO; } + (void)stopHandlingCrashes { #ifndef WIN32 [self _setSignalHandler:(void (*)())SIG_DFL]; #endif WIN32 ignoreCrashesC = YES; } + (NSString *)printBacktrace:(NSString *)aMessage skippedFrameCount:(unsigned)aCount { // Counter for number of frames printed unsigned frameCountL; unsigned maxFrameCountL; // Pointer to current frame void *framePointerL; aMessage = [self _prepareToPrintBacktrace:aMessage]; maxFrameCountL = frameCountC + aCount; // Skip aCount OEObject frames. 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've probably got enough info to see a whole cycle. for (frameCountL = aCount; frameCountL < maxFrameCountL; frameCountL++) { // Set framePointer to current frame. framePointerL = NSFrameAddress(frameCountL); if (framePointerL == NULL) break; aMessage = [self _printFrame:framePointerL withMessage:aMessage]; } freedAddressC = 0; return aMessage; } #ifdef WIN32 + (NSString *)printBacktrace:(NSString *)aMessage address:(void *)aFramePointer { // Counter for number of frames printed unsigned frameCountL; aMessage = [self _prepareToPrintBacktrace:aMessage]; for (frameCountL = 0; frameCountL < frameCountC; frameCountL++) { if (aFramePointer == NULL) break; aMessage = [self _printFrame:aFramePointer withMessage:aMessage]; // Increment void * aFramePointer! Don't try this at home, kids. aFramePointer = *(void **)aFramePointer; } freedAddressC = 0; return aMessage; } #endif WIN32 + (NSString *)crashException { return crashExceptionG; } + (NSString *)functionArgCountDefaultsName { return functionArgCountDefaultsNameG; } + (NSString *)frameCountDefaultsName { return frameCountDefaultsNameG; } + (NSString *)maxArgDescriptionLengthDefaultsName { return maxArgDescriptionLengthDefaultsNameG; } // ---------------- Overridden Instance Method Definitions -------------------- - (void)doesNotRecognizeSelector:(SEL)aSelector { NS_DURING [super doesNotRecognizeSelector:aSelector]; NS_HANDLER #ifdef WIN32 unsigned skippedFrameCountL = 3; #else WIN32 unsigned skippedFrameCountL = 4; #endif WIN32 Class selfClassL = [self class]; [selfClassL _logMessage:[selfClassL printBacktrace:endOfLineG skippedFrameCount:skippedFrameCountL]]; NS_ENDHANDLER } // -------------------- New Instance Method Definitions ----------------------- // ----------------- Delegate Instance Method Definitions --------------------- @end @implementation OEObject(Private) // ---------------------- Private Method Definitions -------------------------- #ifndef WIN32 + (void)_setSignalHandler:(void (*)())aHandler { OESignalItem_t *signalItemL; for (signalItemL = OESignals + (sizeof(OESignals) / sizeof(OESignalItem_t)) - 1; 0 < signalItemL->number; signalItemL--) { if (signalItemL->isOn) { [signalMessagesC setObject:signalItemL->message forKey:[NSNumber numberWithInt:signalItemL->number]]; signal(signalItemL->number, aHandler); } } } #endif WIN32 + (NSString *)_prepareToPrintBacktrace:(NSString *)aMessage { NSScanner *scannerL = [NSScanner scannerWithString:aMessage]; // Identify message to freed object error message and extract the address // of the freed object so that it can be used to identify the object in the // stack frame report. if ([scannerL scanUpToString:freedObjectMessageG intoString:NULL] && [scannerL scanString:freedObjectMessageG intoString:NULL]) { [scannerL setScanLocation:[scannerL scanLocation] + 1]; [scannerL scanHexInt:&freedAddressC]; } aMessage = [aMessage stringByAppendingFormat:@"Attempting stack frame backtrace:%@", endOfLineG]; // Try to avoid re-entry problems. [self stopHandlingCrashes]; return aMessage; } + (NSString *)_printFrame:(void *)aFramePointer withMessage:(NSString *)aMessage { // This cast may be bogus, but it shuts up the compiler. SEL possibleSelectorL = [self _selectorWithFrame:(void *)((unsigned)aFramePointer + argStartPositionG) returnValue:NULL]; if (sel_isMapped(possibleSelectorL)) { aMessage = [aMessage stringByAppendingString:[self _methodMessageWithFP:aFramePointer selector:possibleSelectorL]]; } else { aMessage = [aMessage stringByAppendingString:[self _functionMessageFromFP:aFramePointer]]; } return aMessage; } + (NSString *)_functionMessageFromFP:(void *)aFramePointer { void *argStartL; unsigned argNumL; // Index into arguments; NSString *messageL; // This cast may be bogus, but it shuts up the compiler. argStartL = (void *)((unsigned)aFramePointer + argStartPositionG); messageL = @"function("; for (argNumL = 0; argNumL < functionArgCountC; argNumL++) { NSString *punctuationL; if (argNumL != 0) { punctuationL = @", "; } else { punctuationL = @""; } messageL = [messageL stringByAppendingFormat:@"%@%#08x", punctuationL, *((unsigned*)argStartL + argNumL)]; } return [messageL stringByAppendingFormat:@")%@", endOfLineG]; } + (NSString *)_methodMessageWithFP:(void *)aFramePointer selector:(SEL)aSelector { NSString *messageL; // This cast may be bogus, but it shuts up the compiler. id objectL = [self _selfWithFrame:(void *)((unsigned)aFramePointer + argStartPositionG) returnValue:NULL]; if (freedAddressC == (int)objectL) { // Cause of crash is freed object, so no need to print method info. messageL = [NSString stringWithFormat:@"? [%@ %@]", freedObjectNameG, NSStringFromSelector(aSelector)]; } else { char methodCharL; Method methodL; // Using runtime functions rather than Objective-C messages to return // the name and class is a little safer than depending on the class // method in case of the object being freed (this code should never be // executed in that case) or a custom root object not responding to the // class method. const char *classNameL = object_getClassName(objectL); Class classL = objc_lookUpClass(classNameL); if (objectL == classL) { methodCharL = '+'; methodL = class_getClassMethod(classL, aSelector); } else { methodCharL = '-'; methodL = class_getInstanceMethod(classL, aSelector); } messageL = [NSString stringWithFormat:@"%c [%s ", methodCharL, classNameL]; if (methodL != NULL) { NSString *selectorWithArgsL; int argCountL = method_getNumberOfArguments(methodL); NSString *selectorStringL = NSStringFromSelector(aSelector); if (2 < argCountL) { unsigned argNumL; NSString *selectorComponentL; void *argStartL = (void *)((unsigned)aFramePointer + argStartPositionG); NSScanner *argScannerL = [NSScanner scannerWithString:selectorStringL]; selectorWithArgsL = nil; // Skip the first two args which are self and _cmd. for (argNumL = 2; argNumL < argCountL; argNumL++) { const char *typeL; int offsetL; // Deal with case in which argument includes no // description. if (![argScannerL scanUpToString:@":" intoString:&selectorComponentL]) { selectorComponentL = @""; } if (selectorWithArgsL != nil) { selectorWithArgsL = [selectorWithArgsL stringByAppendingFormat:@" %@", selectorComponentL]; } else { selectorWithArgsL = selectorComponentL; } method_getArgumentInfo(methodL, argNumL, &typeL, &offsetL); selectorWithArgsL = [selectorWithArgsL stringByAppendingString:[self _argumentStringWithObjcType:typeL offset:(void *)((unsigned)argStartL + offsetL)]]; [argScannerL scanString:@":" intoString:NULL]; } } else { selectorWithArgsL = selectorStringL; } messageL = [messageL stringByAppendingFormat:@"%@]", selectorWithArgsL]; } else { messageL = [messageL stringByAppendingString:@" <unknown method>]"]; } } return [messageL stringByAppendingString:endOfLineG]; } // The following encapsulates how to find self and selectors on the various // architectures as best I know how. + (BOOL)_isReturnStructInRegistersWithSize:(int)aSize { #if defined(sparc) || defined(__alpha__) // Sparc, PDO (alpha, sparc) never put struct in reg on return return NO; #else // these are heuristics (i.e. wrong in many cases) // nextstep hppa #if defined(hppa) && !defined(hpux) return (BOOL)(aSize == 1 || aSize == 2 || aSize == 4); #elif defined(m68k) || defined(i386) || defined(hppa) return (BOOL)(aSize == 1 || aSize == 2 || aSize == 4 || aSize == 8); #else #error dont know how to compute structure-in-registers decision #endif #endif } + (id)_selfWithFrame:(void *)anArgumentFrame returnValue:(OEReturnInfo_t *)aReturnValue { if (aReturnValue == NULL) { // Take our best guess. return ((id *)anArgumentFrame)[selfIndexG]; } #if defined(__alpha__) { int offsetL; if (aReturnValue->type == NSObjCStructType) { offsetL = 1; } else { offsetL = 0; } return ((id *)anArgumentFrame)[selfIndexG + offsetL]; } #elif defined(WIN32) { // If the return type is a struct, and the struct is NOT passed in // registers, then the address of the struct return is on the stack // in the 0th slot. Therefore, all other normal parameters are shifted // by one position. if ((aReturnValue->type == NSObjCStructType) && ![self _isReturnStructInRegistersWithSize:aReturnValue->size]) { return ((id *)anArgumentFrame)[selfIndexG + 1]; } // if it's not a struct return OR if the struct is in registers // (i.e., it's less than 8 bytes) then just return the selfIndex. return ((id *)anArgumentFrame)[selfIndexG]; } #else // ! __alpha__ return ((id *)anArgumentFrame)[selfIndexG]; #endif } + (SEL)_selectorWithFrame:(void *)anArgumentFrame returnValue:(OEReturnInfo_t *)aReturnValue { if (aReturnValue == NULL) { // Take our best guess. return ((SEL *)anArgumentFrame)[sELIndexG]; } #if defined(__alpha__) { int offsetL; if (aReturnValue->type == NSObjCStructType) { offsetL = 1; } else { offsetL = 0; } return ((SEL *)anArgumentFrame)[sELIndexG + offsetL]; } #elif defined(WIN32) { // If the return type is a struct, and the struct is NOT passed in // registers, then the address of the struct return is on the stack // in the 0th slot. Therefore, all other normal parameters are shifted // by one position. if ((aReturnValue->type == NSObjCStructType) && ![self _isReturnStructInRegistersWithSize:aReturnValue->size]) { return ((SEL *)anArgumentFrame)[sELIndexG + 1]; } // if it's not a struct return OR if the struct is in registers // (i.e., it's less than 8 bytes) then just return the sELIndex. return ((SEL *)anArgumentFrame)[sELIndexG]; } #else // ! __alpha__ return ((SEL *)anArgumentFrame)[sELIndexG]; #endif } + (NSString *)_argumentStringWithObjcType:(const char *)anObjcType offset:(void *)anOffset { NSData *descriptionL; if (objcTypeEncodingsC == nil) { int indexL; int sizeL = sizeof(OEEncodings) / sizeof(OEObjcType_t); objcTypeEncodingsC = [[NSMutableDictionary alloc] initWithCapacity:sizeL]; for (indexL = sizeL - 1; 0 <= indexL; indexL--) { OEObjcType_t encodingL = OEEncodings[indexL]; NSNumber *charEncodingL = [NSNumber numberWithChar:encodingL.encoding]; OEObjcTypeDesc_t objcTypeDescL = encodingL.description; descriptionL = [NSData dataWithBytes:(void *)&objcTypeDescL length:sizeof(OEObjcTypeDesc_t)]; [objcTypeEncodingsC setObject:descriptionL forKey:charEncodingL]; } } descriptionL = [objcTypeEncodingsC objectForKey:[NSNumber numberWithChar:anObjcType[0]]]; if (descriptionL != nil) { OEObjcTypeDesc_t objcTypeDescL; NSString *formatL; [descriptionL getBytes:(void *)&objcTypeDescL length:sizeof(OEObjcTypeDesc_t)]; formatL = [@":(%@)" stringByAppendingString:objcTypeDescL.format]; switch (anObjcType[0]) { case _C_ID: { id objectL = *(id *)anOffset; if ([objectL respondsToSelector:@selector(description)]) { NSString *objectDescriptionL = [objectL description]; if (maxArgDescriptionLengthC < [objectDescriptionL length]) { // Limit length of description to // maxArgDescriptionLength. objectDescriptionL = [objectDescriptionL substringToIndex:maxArgDescriptionLengthC]; } return [NSString stringWithFormat:formatL, objcTypeDescL.name, objectDescriptionL]; } else { return [NSString stringWithFormat:@":(%@)%#08x", objcTypeDescL.name, objectL]; } } case _C_CHARPTR: // Limit length of description to maxArgDescriptionLength. return [NSString stringWithFormat:formatL, objcTypeDescL.name, maxArgDescriptionLengthC, *(char **)anOffset]; case _C_CHR: case _C_UCHR: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(char *)anOffset]; case _C_SHT: case _C_USHT: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(short *)anOffset]; case _C_LNG: case _C_ULNG: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(long *)anOffset]; case _C_FLT: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(float *)anOffset]; case _C_DBL: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(double *)anOffset]; default: return [NSString stringWithFormat:formatL, objcTypeDescL.name, *(int *)anOffset]; } } else { // This cast may be bogus, but it shuts up the compiler. return [NSString stringWithFormat:@" :(<unknown type>)%#08x", *(int *)anOffset]; } } + (void)_logMessage:(NSString *)aMessage { // If continuing after the error, leave the method of reporting the stack // backtrace to a process-specific exception handler. if (continueAfterErrorC) { [self resumeHandlingCrashes]; // Don't add an AppKit dependency here by opening Alert panel to warn // the user. [NSException raise:crashExceptionG format:aMessage]; } // Don't continue, so log the stack backtrace. else { NSLog(aMessage); exit(1); } } @end // ------------------------- Function Definitions ----------------------------- #ifndef WIN32 static void handle_signal(int aSignal) { NSString *messageL; NSString *signalMessageL = [signalMessagesC objectForKey:[NSNumber numberWithInt:aSignal]]; if (signalMessageL != nil) { messageL = [NSString stringWithFormat:@"Caught signal #%d: \"%@\"%@", aSignal, signalMessageL, endOfLineG]; } else { messageL = [NSString stringWithFormat:@"Caught unrecognized signal #%d%@", aSignal, endOfLineG]; } [OEObject _logMessage:[OEObject printBacktrace:messageL skippedFrameCount:2]]; } #endif WIN32 static void _objectError(Object *anObject, const char *aFormat, va_list theArguments) { char bufferL[BUFSIZ]; NSString *messageL; vsprintf(bufferL, aFormat, theArguments); messageL = [NSString stringWithFormat:@"%s%@", bufferL, endOfLineG]; _error = _originalError; messageL = [OEObject printBacktrace:messageL skippedFrameCount:3]; _error = _objectError; [OEObject _logMessage:messageL]; } #ifdef WIN32 static int filter(LPEXCEPTION_POINTERS theInfo) { NSString *messageL; NSString *exceptionMessageL; int codeL = theInfo->ExceptionRecord->ExceptionCode; switch (codeL) { case STATUS_ABANDONED_WAIT_0: exceptionMessageL = @"STATUS_ABANDONED_WAIT_0"; break; case STATUS_USER_APC: exceptionMessageL = @"STATUS_USER_APC"; break; case STATUS_TIMEOUT: exceptionMessageL = @"STATUS_TIMEOUT"; break; case STATUS_PENDING: exceptionMessageL = @"STATUS_PENDING"; break; case STATUS_SEGMENT_NOTIFICATION: exceptionMessageL = @"STATUS_SEGMENT_NOTIFICATION"; break; case STATUS_GUARD_PAGE_VIOLATION: exceptionMessageL = @"STATUS_GUARD_PAGE_VIOLATION"; break; case STATUS_DATATYPE_MISALIGNMENT: exceptionMessageL = @"STATUS_DATATYPE_MISALIGNMENT"; break; case STATUS_BREAKPOINT: exceptionMessageL = @"STATUS_BREAKPOINT"; break; case STATUS_SINGLE_STEP: exceptionMessageL = @"STATUS_SINGLE_STEP"; break; case STATUS_ACCESS_VIOLATION: exceptionMessageL = [NSString stringWithFormat:@"Access Violation on %@ at address %#08x", theInfo->ExceptionRecord->ExceptionInformation[0] ? @"write" : @"read", theInfo->ExceptionRecord->ExceptionInformation[1]]; break; case STATUS_IN_PAGE_ERROR: exceptionMessageL = @"STATUS_IN_PAGE_ERROR"; break; case STATUS_INVALID_HANDLE: exceptionMessageL = @"STATUS_INVALID_HANDLE"; break; case STATUS_NO_MEMORY: exceptionMessageL = @"STATUS_NO_MEMORY"; break; case STATUS_ILLEGAL_INSTRUCTION: exceptionMessageL = @"STATUS_ILLEGAL_INSTRUCTION"; break; case STATUS_NONCONTINUABLE_EXCEPTION: exceptionMessageL = @"STATUS_NONCONTINUABLE_EXCEPTION"; break; case STATUS_INVALID_DISPOSITION: exceptionMessageL = @"STATUS_INVALID_DISPOSITION"; break; case STATUS_ARRAY_BOUNDS_EXCEEDED: exceptionMessageL = @"STATUS_ARRAY_BOUNDS_EXCEEDED"; break; case STATUS_FLOAT_DENORMAL_OPERAND: exceptionMessageL = @"STATUS_FLOAT_DENORMAL_OPERAND"; break; case STATUS_FLOAT_DIVIDE_BY_ZERO: exceptionMessageL = @"STATUS_FLOAT_DIVIDE_BY_ZERO"; break; case STATUS_FLOAT_INEXACT_RESULT: exceptionMessageL = @"STATUS_FLOAT_INEXACT_RESULT"; break; case STATUS_FLOAT_INVALID_OPERATION: exceptionMessageL = @"STATUS_FLOAT_INVALID_OPERATION"; break; case STATUS_FLOAT_OVERFLOW: exceptionMessageL = @"STATUS_FLOAT_OVERFLOW"; break; case STATUS_FLOAT_STACK_CHECK: exceptionMessageL = @"STATUS_FLOAT_STACK_CHECK"; break; case STATUS_FLOAT_UNDERFLOW: exceptionMessageL = @"STATUS_FLOAT_UNDERFLOW"; break; case STATUS_INTEGER_DIVIDE_BY_ZERO: exceptionMessageL = @"STATUS_INTEGER_DIVIDE_BY_ZERO"; break; case STATUS_INTEGER_OVERFLOW: exceptionMessageL = @"STATUS_INTEGER_OVERFLOW"; break; case STATUS_PRIVILEGED_INSTRUCTION: exceptionMessageL = @"STATUS_PRIVILEGED_INSTRUCTION"; break; case STATUS_STACK_OVERFLOW: exceptionMessageL = @"STATUS_STACK_OVERFLOW"; break; case STATUS_CONTROL_C_EXIT: exceptionMessageL = @"STATUS_CONTROL_C_EXIT"; break; default: exceptionMessageL = nil; } if (exceptionMessageL != nil) { messageL = [NSString stringWithFormat:@"Caught WIN32 exception %#08x: \"%@\"%@", codeL, exceptionMessageL, endOfLineG]; } else { messageL = [NSString stringWithFormat:@"Caught unrecognized WIN32 exception %#08x", codeL, endOfLineG]; } if (theInfo->ContextRecord->ContextFlags & CONTEXT_CONTROL) { [OEObject _logMessage:[OEObject printBacktrace:messageL address:(void *)theInfo->ContextRecord->Ebp]]; } else { // Don't know how many frames to skip, so don't skip any. [OEObject _logMessage:[OEObject printBacktrace:messageL skippedFrameCount:0]]; } return EXCEPTION_CONTINUE_SEARCH; } #endif WIN32
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.