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
{
#if DEBUG
void *framePointer;
unsigned int frameCount;
#endif
[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.