OEObject.m


max21 Unternehmensgruppe
#import "Aprica.h"
//	Aprica2
//	copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
//	all Rights reserved;
#ifndef GNUSTEP
#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>
#endif WIN32
#import "OEObject.h"
// ---------------- Typedef, Struct, and Union Declarations -------------------
typedef struct _signalItem
{
    int number;
    BOOL isOn;
    NSString *message;
} OESignalItem_t;
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 ------------------------
// Name of exception raised to continue execution.
NSString *OECrashException = @"Crash";
// Name of defaults variables that can be used to set the function argument and
// stack frame counts.
NSString *OEFunctionArgCountDefaultsName = @"OEFunctionArgCount";
NSString *OEFrameCountDefaultsName = @"OEFrameCount";
// Default number of function arguments printed.
static unsigned functionArgCountG = 4;
// Default number of stack frames printed.
static unsigned frameCountG = 50;
// 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??)
// 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
#define ON 1
#define OFF 0
#ifndef WIN32
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"}
};
#else WIN32
static OESignalItem_t OESignals[] =
{
    {0, 	OFF, 	@"Exit from the shell"},
    {SIGINT, 	OFF, 	@"Interrupt"},
    {SIGILL, 	ON, 	@"Illegal instruction"},
    {SIGFPE, 	ON, 	@"Floating point exception"},
    {SIGSEGV, 	ON, 	@"Segmentation violation"},
    {SIGTERM, 	OFF, 	@"Software termination"},
    {SIGBREAK, 	ON, 	@"Cntrl-Break sequence"},
    {SIGABRT, 	ON, 	@"Abnormal termination triggered by abort call"}
};
#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,		{@"%s",		@"short"}},
    {_C_USHT,		{@"%c",		@"unsigned short"}},
    {_C_INT,		{@"%d",		@"int"}},
    {_C_UINT,		{@"%d",		@"unsigned"}},
    {_C_LNG,		{@"%l",		@"long"}},
    {_C_ULNG,		{@"%l",		@"unsigned long"}},
    {_C_FLT,		{@"%f",		@"float"}},
    {_C_DBL,		{@"%f",		@"double"}},
    {_C_VOID,		{@"0x%06x",	@"void"}},
    {_C_PTR,		{@"0x%06x",	@"ptr"}},
    {_C_CHARPTR,	{@"%s",		@"char *"}},
    {_C_STRUCT_B,	{@"%x",		@"struct"}}
};
// ------------------------- Function Declarations ----------------------------
static void handle_signal(int aSignal);
// The _error() function prototype has an Object rather than NSObject first
// argument type.
static void (*_originalError)(Object *anObject, const char *format,
                              va_list ap);
static void _objectError(Object *anObject, const char *aFormat,
                         va_list theArguments);
@interface OEObject(Private)
// ---------------------- Private Method Declarations -------------------------
+ (void)_setSignalHandler:(void (*)())aHandler;
+ (NSString *)_functionMessageFromFP:(void *)aFramePointer;
+ (NSString *)_methodMessageWithFP:(void *)aFramePointer
                          selector:(SEL)aSelector;
+ (void)_tryToContinue;
+ (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 ignoreCrashesC;
static BOOL continueAfterErrorC;
static unsigned freedAddressC;
static unsigned functionArgCountC;
static unsigned frameCountC;
static NSMutableDictionary *signalMessagesC;
static NSMutableDictionary *objcTypeEncodingsC;
// ----------------------- Class Method Definitions ---------------------------
+ (void)initialize
{
    if (self == [OEObject class])
    {
        signalMessagesC = nil;
        objcTypeEncodingsC = nil;
        freedAddressC = 0;
        ignoreCrashesC = NO;
        functionArgCountC = functionArgCountG;
        frameCountC = frameCountG;
        continueAfterErrorC = NO;
    }
}
// Pose as the NSObject class.
+ (void)setup
{
    if (signalMessagesC == nil)
    {
        NSUserDefaults *userDefaultsL = [NSUserDefaults standardUserDefaults];
        NSNumber *functionArgCountL = [userDefaultsL
            ofk:OEFunctionArgCountDefaultsName];
        NSNumber *frameCountL = [userDefaultsL
            ofk:OEFrameCountDefaultsName];
        if (functionArgCountL != nil)
        {
            functionArgCountC = [functionArgCountL unsignedIntValue];
        }
        if (frameCountL != nil)
        {
            frameCountC = [frameCountL unsignedIntValue];
        }
        [self poseAsClass:[NSObject class]];
        _originalError = _error;
        _error = _objectError;
        signalMessagesC = [[NSMutableDictionary alloc]
            initWithCapacity:sizeof(OESignals) / sizeof(OESignalItem_t)];
        [self _setSignalHandler:handle_signal];
    }
}
+ (void)setContinueAfterError:(BOOL)aFlag
{
    continueAfterErrorC = aFlag;
}
+ (void)resumeHandlingCrashes
{
    [self _setSignalHandler:handle_signal];
    ignoreCrashesC = NO;
}
+ (void)stopHandlingCrashes
{
    [self _setSignalHandler:(void (*)())SIG_DFL];
    ignoreCrashesC = YES;
}
+ (void)printCurrentStack;
{
    [OEObject printCurrentStack:30];
}
+ (void)printCurrentStackShort;
{
    [OEObject printCurrentStack:2];
}
+ (void)printCurrentStack:(int)stackDepth;
{
// Counter for number of frames printed
    unsigned frameCountL;
    unsigned maxFrameCountL;
    
// Pointer to current frame
    void *framePointerL;
    NSMutableString *aMessage = [NSMutableString stringWithCapacity:2048];
    NSString *s;
    [aMessage setString:@"current Stack:\n======================================================================\n"];
    maxFrameCountL = frameCountC + 3;
    stackDepth+=3;
    for (frameCountL = 2; frameCountL < stackDepth; frameCountL++)
      {
        SEL possibleSelectorL;
        
    // Start the frame pointer off at our frame.
        framePointerL = NSFrameAddress(frameCountL);
        if (framePointerL == NULL) break;
        
    // This cast may be bogus, but it shuts up the compiler.
        possibleSelectorL = [self
        _selectorWithFrame:(void *)((unsigned)framePointerL +
                                    argStartPositionG)
               returnValue:NULL];
        if (sel_isMapped(possibleSelectorL))
          {
            s = [self _methodMessageWithFP:framePointerL selector:possibleSelectorL];
          }
        else
          {
            s = [self _functionMessageFromFP:framePointerL];
          }
        if([s length]>256)s = [[s substringToIndex:256] stringByAppendingString:@"...\n"];
        [aMessage appendString:s];
      }
    LOG(aMessage);
}
+ (NSString *)printBacktrace:(NSString *)aMessage
{
    // Counter for number of frames printed
    unsigned frameCountL;
    unsigned maxFrameCountL;
    // Pointer to current frame
    void *framePointerL;
    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];
    maxFrameCountL = frameCountC + 3;
    // Skip 3 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 = 3; frameCountL < maxFrameCountL; frameCountL++)
    {
        SEL possibleSelectorL;
        // Start the frame pointer off at our frame.
        framePointerL = NSFrameAddress(frameCountL);
        if (framePointerL == NULL) break;
        // This cast may be bogus, but it shuts up the compiler.
        possibleSelectorL = [self
            _selectorWithFrame:(void *)((unsigned)framePointerL +
                                        argStartPositionG)
                   returnValue:NULL];
        if (sel_isMapped(possibleSelectorL))
        {
            aMessage = [aMessage stringByAppendingString:[self
               _methodMessageWithFP:framePointerL selector:possibleSelectorL]];
        }
        else
        {
            aMessage = [aMessage stringByAppendingString:[self
                _functionMessageFromFP:framePointerL]];
        }
    }
    freedAddressC = 0;
    return aMessage;
}
// ---------------- Overridden Instance Method Definitions --------------------
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
    NS_DURING
        [super doesNotRecognizeSelector:aSelector];
    NS_HANDLER
        Class selfClassL = [self class];
        [selfClassL _logMessage:[selfClassL printBacktrace:[[localException
            reason] stringByAppendingString:endOfLineG]]];
    NS_ENDHANDLER
}
// -------------------- New Instance Method Definitions -----------------------
// ----------------- Delegate Instance Method Definitions ---------------------
@end
@implementation OEObject(Private)
// ---------------------- Private Method Definitions --------------------------
+ (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);
        }
    }
}
+ (NSString *)_functionMessageFromFP:(void *)aFramePointer
{
    void *argStartL;
    unsigned argNumL;	// Index into arguments;
    NSString *messageL = @"function(";
    // This cast may be bogus, but it shuts up the compiler.
    argStartL = (void *)((unsigned)aFramePointer + argStartPositionG);
    for (argNumL = 0; argNumL < functionArgCountC; argNumL++)
    {
        NSString *punctuationL;
        if (argNumL != 0)
        {
            punctuationL = @", ";
        }
        else
        {
            punctuationL = EON;
        }
        messageL = [messageL stringByAppendingFormat:@"%@0x%06x",
            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 = [NSSWF@"? [%@ %@]", freedObjectNameG,
            NSStringFromSelector(aSelector)];
    }
    else
    {
        char methodCharL;
        Method methodL;
        Class classL = [objectL class];
        if (objectL == classL)
        {
            methodCharL = '+';
            methodL = class_getClassMethod(classL, aSelector);
        }
        else
        {
            methodCharL = '-';
            methodL = class_getInstanceMethod(classL, aSelector);
        }
        messageL = [NSSWF@"%c [%@ ", methodCharL,
            NSStringFromClass(classL)];
        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 = EON;
                    }
                    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];
}
// Two implementations of _tryToContinue are provided.  Select the desired
// implementation by defining OE_SELF_CONTAINED or not.
// #define OE_SELF_CONTAINED
#ifndef OE_SELF_CONTAINED
// This implementation requires that NSApplication's run method be overridden
// such that when OECrashException is caught, the main run loop is reentered.
// This implementation feels less hackish because raising NSAbortModalException
// for a non-existent modal run loop isn't required.
+ (void)_tryToContinue
{
    ignoreCrashesC = NO;
    [self resumeHandlingCrashes];
    // OECrashException should be caught such that main run loop can be
    // reentered.
    [NSException raise:OECrashException format:@"Trying to continue...%@",
        endOfLineG];
}
#else OE_SELF_CONTAINED
// This implementation is "self-contained" in that it doesn't require that
// NSApplication's run method be overridden.  However, this implementation
// feels hackish because raising NSAbortModalException for a non-existent modal
// run loop is required.
+ (void)_tryToContinue
{
    ignoreCrashesC = NO;
    // Attempts to raise an exception that can be caught in NSApp's run method
    // can fail under NT for reasons I don't understand.  Therefore, resort to
    // the approach used by HKCrashTrap.
    if (NSRunCriticalAlertPanel(nil, @"An internal error has occurred.  Try to save any unsaved changes.  Continuing may result in repeated errors.  If so, quit and restart %@.",
                                @"Continue", @"Quit", nil,
                                [[NSProcessInfo processInfo] processName]) ==
        NSAlertDefaultReturn)
    {
        [self resumeHandlingCrashes];
        // HKCrashTrap uses abortModal to return to the main run loop.  This
        // feels hackish because there is no modal run loop to abort.  It also
        // results in an "abort modal" message being logged which could be
        // confusing.
//        [NSApp abortModal];
//        LOGS(@"Trying to continue...%@", endOfLineG);
        // OECrashException seems to be caught by some AppKit method.  This
        // returns to the main run loop and logs a more informative message.
        // Is this just luck?  If so, revert to the HKCrashTrap implementation.
        [NSException raise:OECrashException
                    format:@"Trying to continue...%@", endOfLineG];
    }
    else
    {
        exit(1);
    }
}
#endif OE_SELF_CONTAINED
// 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
        return NO;
    # 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 setSecureObject:descriptionL
                                   forKey:(NSString *)charEncodingL];
        }
    }
    descriptionL = [objcTypeEncodingsC ofk:[NSNumber
        numberWithChar:anObjcType[0]]];
    if (descriptionL != nil)
    {
        OEObjcTypeDesc_t objcTypeDescL;
        NSString *formatL;
        [descriptionL getBytes:(void *)&objcTypeDescL
                        length:sizeof(OEObjcTypeDesc_t)];
        formatL = [@":(%@)" stringByAppendingString:objcTypeDescL.format];
        // This cast may be bogus, but it shuts up the compiler.
        return [NSSWF formatL, objcTypeDescL.name,*(unsigned *)anOffset];
    }
    else
    {
        // This cast may be bogus, but it shuts up the compiler.
        return [NSSWF @" :(<unknown type>)0x%06x",*(unsigned *)anOffset];
    }
}
+ (void)_logMessage:(NSString *)aMessage
{
    LOGS(aMessage);
    if (continueAfterErrorC)
    {
        [OEObject _tryToContinue];
    }
    else
    {
        exit(1);
    }
}
@end
// ------------------------- Function Definitions -----------------------------
static void handle_signal(int aSignal)
{
    NSString *messageL;
    NSString *signalMessageL = [signalMessagesC ofk:[NSNumber
        numberWithInt:aSignal]];
    if (signalMessageL != nil)
    {
        messageL = [NSSWF@"Caught signal #%d: \"%@\"%@",
            aSignal, signalMessageL, endOfLineG];
    }
    else
    {
        messageL = [NSString
            stringWithFormat:@"Caught unrecognized signal #%d%@", aSignal,
            endOfLineG];
    }
    [OEObject _logMessage:[OEObject printBacktrace:messageL]];
}
static void _objectError(Object *anObject, const char *aFormat,
                         va_list theArguments)
{
    char bufferL[BUFSIZ];
    NSString *messageL;
    vsprintf(bufferL, aFormat, theArguments);
    messageL = [NSSWF@"%s%@", bufferL, endOfLineG]; 
    _error = _originalError;
    messageL = [OEObject printBacktrace:messageL];
    _error = _objectError;
    [OEObject _logMessage:messageL];
}
#else /* GNUSTEP */
#include <execinfo.h>
#define BT_MAX 64
@implementation OEObject
+ (void)setup;
{}
+ (void)printCurrentStack;
{
  NSMutableString *stck = [NSMutableString stringWithCapacity: 1024];
  char **strs;
  void *btdata[BT_MAX];
  int i,c;
  c = backtrace (btdata,BT_MAX);
  strs = backtrace_symbols(btdata,c);
  for (i=0;i<c;i++) {
      [stck appendFormat:@"BT %i/%i: %s\n",i,c,strs[i]];
  }
  LOGS(stck);
}
@end
#endif /* GNUSTEP */
Foto