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.