This is EMErrorInfo.m in view mode; [Download] [Up]
#import "EMErrorDescription.h"
#import "EMErrorInfo.h"
#import "EMErrorManager.h"
#import <appkit/appkit.h>
#define MAX_FUNCTION_ARGS 3 // Print at most three args to a function
#define MAX_FRAMES 50
typedef struct _type
{
char encoding;
char *format;
char *name;
} ParType;
@implementation EMErrorInfo:Object
//--------------------------------------------------------------------------------
// GLOBALE VARIABLEN (mehr der Uebersicht halber hier)
//--------------------------------------------------------------------------------
static ParType encodings[] = {
{_C_ID, "0x%06lx", "id"},
{_C_CLASS, "0x%06lx", "Class"},
{_C_SEL, "@selector(%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 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", "ptr"},
{_C_CHARPTR, "\"%s\"", "char *"},
{_C_STRUCT_B, "%x", "struct"},
{0, "0x%06lx", "unknown type"}};
//--------------------------------------------------------------------------------
// INITIALIZER
//--------------------------------------------------------------------------------
+ newWithCode:(int)ncode userInfo:(const void *)a:(const void *)b;
{
return [[EMErrorInfo alloc] initWithCode:ncode userInfo:a:b];
}
+ newWithCode:(int)ncode userInfo:(const void *)a:(const void *)b
file:(const char *)loc line:(int)line;
{
return [[EMErrorInfo alloc] initWithCode:ncode userInfo:a:b
file:loc line:line];
}
//--------------------------------------------------------------------------------
// INIT & FREE
//--------------------------------------------------------------------------------
- initWithCode:(int)ncode userInfo:(const void *)a:(const void *)b;
{
return [self initWithCode:ncode userInfo:a:b file:"?" line:0];
}
- initWithCode:(int)ncode userInfo:(const void *)a:(const void *)b
file:(const char *)loc line:(int)line;
{
char buf[MAXPATHLEN+1]="?";
[super init];
if(line>0)
sprintf(buf,"%s %d",loc,line);
code=ncode;
location=NXCopyStringBufferFromZone(buf,[self zone]);
stackFrame=NULL;
userData1=a;
userData2=b;
time(&timet);
message=timeStamp=NULL;
return self;
}
- free
{
NXZoneFree([self zone],location);
if(timeStamp)
NXZoneFree([self zone],timeStamp);
if(message)
NXZoneFree([self zone],message);
if(stackFrame)
NXZoneFree([self zone],stackFrame);
if(userData1)
{
if(userData1Free=='s')
NX_FREE((void *)userData1);
else if(userData1Free=='o')
[(id)userData1 free];
}
if(userData2)
{
if(userData2Free=='s')
NX_FREE((void *)userData2);
else if(userData2Free=='o')
[(id)userData2 free];
}
return [super free];
}
//--------------------------------------------------------------------------------
// I-VAR
//--------------------------------------------------------------------------------
- setUDFreeSemantics:(const char *)desc;
{
userData1Free=desc[0];
userData2Free=desc[1];
return self;
}
//--------------------------------------------------------------------------------
// I-VAR
//--------------------------------------------------------------------------------
- (int)code;
{
return code;
}
- (time_t)time;
{
return timet;
}
- (const char *)location;
{
return location;
}
- (const char *)stack;
{
return stackFrame;
}
- (const void *)userData1;
{
return userData1;
}
- (const void *)userData2;
{
return userData2;
}
//--------------------------------------------------------------------------------
// Convenience
//--------------------------------------------------------------------------------
- (const char *)message;
{
if(!message)
{
char buf[1000];
sprintf(buf,[[ERROR_MANAGER errorDescriptionFor:code] msg],
userData1,userData2);
message=NXCopyStringBufferFromZone(buf,[self zone]);
}
return message;
}
- (const char *)timeStamp;
{
if(!timeStamp)
{
char buf[90];
strftime(buf,89,"%d %b %y %H:%M:%S %Z",localtime(&timet));
timeStamp=NXCopyStringBufferFromZone(buf,[self zone]);
}
return timeStamp;
}
- (NXAtom)exceptionClass;
{
return [[ERROR_MANAGER errorDescriptionFor:code] exceptionClass];
}
- (const char *)codeString;
{
static char string[20];
switch([self source])
{
case EMSourceApplication: sprintf(string,"A%d",code-EM_APPBASE); break;
case EMSourceSignal: sprintf(string,"S%d",code-EM_SIGBASE); break;
case EMSourceInternal: sprintf(string,"I%d",code-EM_INTBASE); break;
case EMSourceKit: sprintf(string,"K%d",code); break;
}
return string;
}
- (EMErrorSource)source;
{
if(code>=EM_APPBASE)
return EMSourceApplication;
else if(code>=EM_SIGBASE)
return EMSourceSignal;
else if(code>=EM_INTBASE)
return EMSourceInternal;
return EMSourceKit;
}
//--------------------------------------------------------------------------------
// Hilfsmethoden, um den Kontext zu speichern zu koennen.
//--------------------------------------------------------------------------------
// 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 (overt) 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?
//--------------------------------------------------------------------------------
- printFunctionFromFP:(void *)framePointer into:(char *)buffer
{
char argStrg[20];
void *argStart;
long argNum; // Index into arguments;
strcat(buffer,"function(");
argStart=framePointer+8;
for(argNum=0;argNum<MAX_FUNCTION_ARGS;argNum++)
{
sprintf(argStrg,"%s0x%06lx",
((argNum>0)?", ":""),*(((unsigned long *)argStart)+argNum));
strcat(buffer,argStrg);
}
strcat(buffer,")\n");
return self;
}
- printMethodFromFP:(void *)framePointer into:(char *)buffer
{
char tmp[256],selStrg[200],*selPart;
SEL selector;
id object;
Method m;
BOOL isClassMethod;
object=*(id *)(framePointer+8); // receiver is 8 bytes from fp
selector=*(SEL *)(framePointer+12); // selector is 12 bytes from fp
isClassMethod=([object class]==object);
sprintf(tmp,"%c[%s",(isClassMethod?'+':'-'),object_getClassName(object));
strcat(buffer,tmp);
strcpy(selStrg,sel_getName(selector));
if(isClassMethod)
m=class_getClassMethod([object class],selector);
else
m=class_getInstanceMethod([object class],selector);
if(m)
{
void *argStart=(framePointer+8);
int argNum,argCount,offset;
char *type;
argCount=method_getNumberOfArguments(m);
if(argCount==2)
{
strcat(buffer," ");
strcat(buffer,selStrg);
}
else
for(argNum=2,selPart=strtok(selStrg,":");
argNum<argCount;
argNum++,selPart=strtok(NULL,":"))
{
ParType *cur;
long arg;
method_getArgumentInfo(m,argNum,&type,&offset);
arg=*(long *)(argStart+offset);
for (cur=encodings;cur->encoding;cur++)
if (cur->encoding == type[0])
break;
if(selPart)
sprintf(tmp," %s:(%s)",selPart?selPart:"",cur->name);
else
sprintf(tmp,":(%s)",cur->name);
strcat(buffer,tmp);
if(arg==0 && type[0]==_C_SEL)
sprintf(tmp,"{unknown method}");
else
sprintf(tmp,cur->format,arg);
strcat(buffer,tmp);
}
strcat(buffer,"]\n");
}
else
{
sprintf(tmp," %s] {unknown method}\n",selStrg);
strcat(buffer,tmp);
}
return self;
}
- dumpBacktraceInto:(char *)buf;
{
void *framePointer; // pointer to current frame
unsigned int frameCount; // counter for number of frames printed
framePointer=((void *)&self)-8; // Start the frame pointer off at our frame
framePointer=(void *)*(long *)framePointer; // go up one frame
frameCount=0;
// 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.
while(frameCount<MAX_FRAMES && framePointer)
{ // If this frame is a method call we'll have a valid selector at (fp+12).
if (sel_isMapped(*(SEL *)(framePointer+12)))
[self printMethodFromFP:framePointer into:buf];
else
[self printFunctionFromFP:framePointer into:buf];
frameCount++;
framePointer=(void *)*(long *)framePointer; // go up one frame
}
return self;
}
- getContext;
{
char *buf;
time(&timet);
#if m68k || i386
buf=NXZoneCalloc([self zone],20*1024,sizeof(char));
[self dumpBacktraceInto:buf];
stackFrame=NXZoneRealloc([self zone],buf,strlen(buf+1));
#elif hppa || sparc
stackFrame=NXCopyStringBufferFromZone("<<Can't dump stack on "
"architecture " __ARCHITECTURE__ " yet>>\n",[self zone]);
#else
stackFrame=NXCopyStringBufferFromZone("<<Can't dump stack on "
"unknown architecture " __ARCHITECTURE__ ">>\n",[self zone]);
#endif
return self;
}
//--------------------------------------------------------------------------------
// THAT'S IT
//--------------------------------------------------------------------------------
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.