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.