/* Copyright 1989-93 GROUPE BULL -- See license conditions in file COPYRIGHT */ /*****************************************************************************\ * * * kldebug.c * * collection of misc debug routines for klone, only callable when compiled * * with -DDEBUG. Useful to be called under a C debugger (dbx, gdb, duel...) * * * \*****************************************************************************/ /* Functions available under a debugger: * *----------------------------------------------------------------------------- * Functions running the klone engine: * (will perturbate the malloc count and GC state) * * PO(obj) - print object * calls the klone engine to print the object * gdb: p PO(0x567bc) * POR(obj) - print object readably * same, but *print-readably* set * gdb: p POR(0x567bc) * POT(obj) - print object type * prints the type of object * KL(string) - execute klone text * executes the klone string. Returns the last value. * gdb: p KL("(load 'foo)") * BT() - normal stack dump, just like in klone * PSF(n) - print all stack frames verbosely * (n=0) print top * (n=-1) print whole, repeatedly * (n=-N) print whole but only N frames from top * (n=N) print from stack number N * *----------------------------------------------------------------------------- * Pure C Functions (dont malloc and dont exercise the klone engine) * P(obj) - prints object * prints an extended description of the object *VERY USEFUL!!! * can/should be extended to print nicely application-added types * (see the P_app function) * format: * (type)r: attributs.... * attributes: * for the name of atoms * NAMED:, which is an atom having obj as value * VAL: for the value of atoms * NUM: value of numbers * STRING: value of strings * SIZE: size of lists, elements are listed oneper line underneath * PN(string) - print named * calls P of value of atom named string * PS(n) - print stack * like PSF, but dont run klone * TN(type) - type name * returns the C string of teh name of the type, or a message if it is not * a type * NO(obj) - name of * prints the atoms having obj as value * PT(obj) - Pointing To * scans all possible places that can point to KlOs, and print what is * pointing to obj, and prints discrepancies in ref count. * Scans the whole malloc space, the stack, the symbol table, and * application can add their scans (KlDoExtendedcheck and PT_app_malloc) * and their types (PT_Aux_app) * * Valid(obj) - why isn't it a valid object??? * returns a string explaining the reason * * ----------------------------------------------------------------------------- * Functions to call in C code to trigger a stop in the debugger * * stop_if_in_dbx(string) - stops if under debugger * with string being a comment. Ignored if not under a debugger * KlCBreak - stops if under debugger * (cbreak [non-evaluated-tag] [condition] [value]) * klone-callable of the above, with conditional stop * * ----------------------------------------------------------------------------- * Tracing: * * the klone active value "trace-all" and KlSetTrace C function triggers a brute * force tracing that is obsolete but may be useful in difficult situations, * where the klone kernel may be damaged */ /******************** definitions. this module is only compiled with -DDEBUG */ #include #include #include #include #include #include #ifdef SYSV #include #endif #include "EXTERN.h" #include "klone.h" #ifdef SYSV_STRINGS #include #else #include #endif #include #include "kl_atom.h" #include "kl_coll.h" #include "kl_list.h" #include "kl_func.h" #include "kl_number.h" #include "kl_string.h" #include "kl_hash.h" #include "kl_stream.h" #include "kl_struct.h" #ifdef STATS extern KlO zrtstats(); extern KlO KlCfstats(); #endif /* STATS */ #ifdef MALLOCDEBUG0 #define MALLOCDEBUG #endif #ifdef MALLOCDEBUG extern KlO KlMDCheckKl(); #endif #ifndef USE_STANDARD_MALLOC extern char *KlMallocZoneBegin, *KlMallocZoneEnd; #endif DECLARE_strchr; DECLARE_strrchr; #ifdef DEBUG KlO P(); /***************************************************************** functions */ KlSendIsValid(message, object) int message; KlO object; { static int count; count++; if (!object) stop_if_in_dbx("NULL object!"); if (!KlObjectIsValid(object)) { KlError1s(KlE_NON_KlO, KlSelectors[message].name); if (!object->type[message]) stop_if_in_dbx("NULL method on object!"); } } /* "explanation" verbose function * this is never called from klone, but you may want to call it from a * debugger to see why KlObjectIsValid failed... */ char * Valid(obj) KlO obj; { KlType t; if (!obj) return "nil obj"; #ifdef DO_NOT_REDEFINE_MALLOC # ifndef USE_STANDARD_MALLOC else if (!KlOIsInMallocSpace(obj)) return "not in malloc space"; # endif /* !USE_STANDARD_MALLOC */ #else /* !DO_NOT_REDEFINE_MALLOC */ # ifndef USE_STANDARD_MALLOC else if (((char *) obj) < KlMallocZoneBegin) return "lower than malloc begin"; else if (((char *) obj) >= KlMallocZoneEnd) return "higher than malloc end"; # endif /* !USE_STANDARD_MALLOC */ #endif /* DO_NOT_REDEFINE_MALLOC */ #ifndef USE_STANDARD_MALLOC else if (*((void **) obj) == KlFREED_MAGIC_PTR) return "already freed"; else if (*((void **) obj) == KlUNINIT_MAGIC_PTR) return "allocated but not initialized"; #endif /* !USE_STANDARD_MALLOC */ else if ((t = obj->type) == 0) return "type field is NULL"; #ifdef DO_NOT_REDEFINE_MALLOC # ifndef USE_STANDARD_MALLOC else if (!KlOIsInMallocSpace(t)) return "type not in malloc space"; # endif /* !USE_STANDARD_MALLOC */ #else /* !DO_NOT_REDEFINE_MALLOC */ #ifndef USE_STANDARD_MALLOC else if (((char *) t) < KlMallocZoneBegin) return "type lower than malloc begin"; else if (((char *) t) >= KlMallocZoneEnd) return "type higher than malloc end"; # endif /* !USE_STANDARD_MALLOC */ #endif /* DO_NOT_REDEFINE_MALLOC */ #ifndef USE_STANDARD_MALLOC else if (*((void **) t) == KlFREED_MAGIC_PTR) return "type already freed"; else if (*((void **) t) == KlUNINIT_MAGIC_PTR) return "type allocated but not initialized"; #endif /* !USE_STANDARD_MALLOC */ else if (KlTypeTypeGet(t) != KlTypeType) return "type is not a klone type"; else return "OK"; } /*****************************************************************************\ * C Debugging (with gdb, dbx...) * \*****************************************************************************/ /*ARGSUSED*/ stop_if_in_dbx(why) char *why; { } /* used in dbx */ /* cbreak function * will trigger a break under a C debugger (gdb, dbx), when the klone function * (cbreak [non-evaluated-tag] [condition] [value]) is evaluated in klone * cbreak will return first arg */ /*ARGSUSED*/ KlCBreakPoint(tag, value) char *tag; KlO value; {} #ifndef __INSIGHT__ _Insight_trap_error() {} #endif KlO KlCBreak(argc, argv) int argc; KlString *argv; { KlO result; char *tag = 0; int condition = 1; KlO value = 0; if (argc) result = KlSend_eval(argv[0]); else result = NIL; if (argc > 0) { if (KlIsAString(argv[0])) tag = argv[0]->string; else tag = (char *) ((KlNumber)argv[0])->number; } if (argc > 1) { value = KlSend_eval(argv[1]); if (KlFalseP(value)) condition = 0; } if (argc > 2) { value = KlSend_eval(argv[2]); } if (condition) { KlCBreakPoint(tag, value); } return result; } /**************\ * jump-buffers * \**************/ /* JBTable is a table of JBs */ typedef struct _JB { struct _JB *next; int *jmp; jmp_buf buf; } *JB; static JB JBs; /* KlJmpbufCheck */ KlJmpbufCheck(jmpbuf) int *jmpbuf; { JB jb = JBs; while (jb) { if (jb->jmp == jmpbuf) { if (bcmp(jmpbuf, jb->buf, sizeof(jmp_buf))) { fprintf(stderr, "CORRUPTED Jump Buffer!\n"); stop_if_in_dbx("KlJmpbufCheck: corrupted buffer"); } return; } jb = jb->next; } fprintf(stderr, "NO SUCH Jump Buffer!\n"); stop_if_in_dbx("KlJmpbufCheck: no buffer"); } KlJmpbufAddCheck(jmpbuf) int *jmpbuf; { JB jb = JBs; while (jb) { if (jb->jmp == jmpbuf) { bcopy(jmpbuf, jb->buf, sizeof(jmp_buf)); return; } jb = jb->next; } jb = (JB) Calloc(sizeof(struct _JB), 1); jb->next = JBs; jb->jmp = jmpbuf; bcopy(jmpbuf, jb->buf, sizeof(jmp_buf)); JBs = jb; } /************************************************************ user functions */ /* TN = Type Name * from a type (pointer) returns name */ char * TN(kltype) KlType kltype; { KlType t; for (t = KlTypes; t; t = KlTypeNext(t)) { if (kltype == t) { return KlTypeCName(t); } } return "NOT A TYPE!"; } /* PO: try to see if it is an object and print it if so */ int PO(obj) KlO obj; { if (!KlObjectIsValid(obj)) { fprintf(stderr, "Non Klone Object: 0x%x\n", obj); fflush(stderr); return 0; } else { extern KlConstant KlA_StdoutOrig; KlO tab[2]; int prv = KlPrintReadably; tab[0] = obj; tab[1] = KlSend_eval(KlA_StdoutOrig); KlPrintReadably = 1; KlWrite(2, &tab[0]); KlPrintReadably = prv; KlFlush(0); return 1; } } /* Name Of (no) gives p_name of atom pointing to */ char * NO(obj) KlO obj; { extern int KlHashTableSize; extern KlAtom *KlAtomHashTable; KlAtom *slot; for (slot = KlAtomHashTable; slot < KlAtomHashTable + KlHashTableSize; slot++) { if (*slot && (*slot)->c_val == obj) { return((*slot)->p_name); } } return 0; } /* application-extendable debug */ int (*KlDoExtendedcheck)() = 0; int (*PT_aux_app)() = 0; int (*P_app)() = 0; int (*PT_app_malloc)() = 0; int PT_count; /* should increment */ KlO PT_obj; /* should compare to */ int PT_where; /* 0=malloc, 1= stack, 2=klone, 3=app */ int PT_level = 0; #define P_invalid(o, s) if (o) {puts(s);return obj;} /* P: prints as usefully as possible, but without mallocing or executing code */ KlO P(obj) KlO obj; { char *name = NO(obj); int add_newline = 1; P_invalid(!obj, ""); #ifndef USE_STANDARD_MALLOC P_invalid(obj == (KlO) KlFREED_MAGIC_PTR, ""); P_invalid(obj == (KlO) KlUNINIT_MAGIC_PTR, ""); #endif /* !USE_STANDARD_MALLOC */ P_invalid(!(obj->type), ""); #ifndef USE_STANDARD_MALLOC P_invalid(((void *)obj->type) == KlFREED_MAGIC_PTR, ""); P_invalid(((void *)obj->type) == KlUNINIT_MAGIC_PTR, ""); #endif /* !USE_STANDARD_MALLOC */ printf("0x%x (%s)r:%d%s, ", obj, KlTypeCName(obj->type), (obj->reference_count)/2, (obj->reference_count)%2 ? "" : "z"); if ((name = NO(obj)) && name[0] != ':' /* dont print keywords */ && obj != NIL && obj != TRU && obj != KlUndef /* () t *undefined* */ && obj != (KlO) KlNilString) /* nil string */ printf("NAMED: %s ", name); if (KlIsANumber(obj)) { printf("NUM: %d", ((KlNumber)obj)->number); } else if (KlIsAnAtom(obj)) { KlO val = ((KlAtom)obj)->c_val; printf("<%s> VAL: 0x%x", ((KlAtom)obj)->p_name, ((KlAtom)obj)->c_val); if (val == NIL) printf(" (NIL)"); else if (val == TRU) printf(" (t)"); else if (val == KlUndef) printf(" (*undefined*)"); else { printf(" (%s)", KlTypeCName(val->type)); if (KlIsAString(val)) printf(" \"%s\"", ((KlString)val)->string); if (KlIsANumber(val)) printf(" %d", ((KlNumber)val)->number); } } else if (KlIsAnAccessor(obj)) { if (KlIsANamedSymbol(obj)) { printf("ACCESSOR: <%s>", ((KlAtom)obj)->p_name); } else { if (obj->type == KlAccessorNumType) { printf("Anonymous AccessorNum: field .%d of ", ((KlNumber)((KlAccessor) obj)->field)->number); P(((KlAccessor) obj)->var); } else { printf("Anonymous Accessor: field .%s of ", ((KlAtom)((KlAccessor) obj)->field)->p_name); P(((KlAccessor) obj)->var); } } } else if (KlIsAString(obj)) { if (obj != (KlO) KlNilString) printf("STRING: \"%s\"", ((KlString)obj)->string); else printf("The NIL STRING: \"%s\"", ((KlString)obj)->string); } else if (KlFalseP(obj)) { if (obj == NIL) printf("NIL"); else printf(""); } else if (KlIsAList(obj)) { int i; printf("SIZE: %d, ELEMENTS:\n", ((KlList)obj)->size); for (i = 0; i < ((KlList)obj)->size; i++) { int j; for (j = 0; j < PT_level; j++) printf(" "); printf(" #%d: ", i); PT_level++; P(((KlList)obj)->list[i]); PT_level--; } add_newline = 0; } else if (KlIsAStructClass(obj)) { printf("NAME: %s", ((KlStructClass)obj)->name->p_name); } else if (KlIsAStruct(obj)) { printf("CLASS: %s (0x%x), PTR: 0x%x", ((KlStruct)obj)->structclass->name->p_name, ((KlStruct)obj)->structclass, ((KlStruct)obj)->ptr); } else if (KlIsABuiltInType(obj)) { /* nothing else */ } else if (KlIsADeclaredType(obj->type)) { if (P_app) CFAPPLY(P_app, (obj)); } else { puts(""); } if (add_newline) printf("\n"); return obj; } int KlIsADeclaredType(obj) KlType obj; { KlType t; for (t = KlTypes; t; t = KlTypeNext(t)) { if (t == obj) return 1; } return 0; } int KlIsABuiltInType(obj) KlO obj; { extern KlList KlListOfBuiltInTypes; int i; for (i = 0; i < KlListOfBuiltInTypes->size; i++) { if (KlListOfBuiltInTypes->list[i] == (KlO) (obj->type)) return 1; } return 0; } /* PN: prints object named */ KlO PN(name) char *name; { KlAtom *slot = (KlAtom *) KlHashSlot(name); if (slot && *slot) { P((*slot)->c_val); return (*slot)->c_val; } else { fprintf(stderr, "Non Defined symbol: %s\n", name); return 0; } } /*************************************** PT: prints objects pointing to objs */ /* this scans ALL allocated memory to find pointers to objecst, thus this is * only avbailable if klone malloc is used */ #ifndef USE_STANDARD_MALLOC #define PTB(type, slot) \ if (PT_obj == (KlO) ((type)obj)->slot) {PT_pointed_by(obj, KlSTROF(slot));} PT_pointed_by(obj, slot_name) KlO obj; char *slot_name; { int j; for (j = 0; j < PT_level; j++) printf(" "); printf("=>Field: %s of: ", slot_name); PT_level++; P(obj); PT_level--; PT_count++; } int PT_aux_malloc(obj, size, chunk_size) KlO obj; int size; /* malloced bytes or -frame */ int chunk_size; /* total of used bytes */ { int i; char N[20]; if (obj->type == KlAtomType || obj->type == KlConstantType || obj->type == KlKeywordType) { PTB(KlAtom, p_list); PTB(KlAtom, c_val); } else if (obj->type == KlListType || obj->type == KlVectorType) { for (i = 0; i < ((KlList)obj)->size; i++) { if (PT_obj == (KlO) ((KlList)obj)->list[i]) { sprintf(N, "#%d", i); PT_pointed_by(obj, N); } } } else if (obj->type == KlActiveType) { PTB(KlAtom, p_list); } else if (obj->type == KlKloneActiveType) { PTB(KlAtom, p_list); PTB(KlAtom, c_val); PTB(KlKloneActive, get); PTB(KlKloneActive, set); } else if (obj->type == KlSymbolSlotType) { PTB(KlSymbolSlot, symbol); } else if (obj->type == KlExprType || obj->type == KlFExprType || obj->type == KlMExprType) { for (i = 0; i < ((KlExpr)obj)->body_size; i++) { if (PT_obj == ((KlExpr)obj)->body[i]) { sprintf(N, "statement #%d", i); PT_pointed_by(obj, N); } } if (((KlExpr)obj)->arity) { for (i = 0; i < ((KlExpr)obj)->arity; i++) { if (PT_obj == (KlO) ((KlExpr)obj)->parameters[i]) { sprintf(N, "parameter #%d", i); PT_pointed_by(obj, N); } } } if (((KlExpr)obj)->lambdalist) { KlKeyDecls pk = ((KlExpr)obj)->lambdalist->key; KlO *p; if (p = ((KlExpr)obj)->lambdalist->optionals) { while (*p) { if (PT_obj == (KlO) *p) PT_pointed_by(obj, "optional parameter"); p++; } } if (PT_obj == (KlO) ((KlExpr)obj)->lambdalist->rest) PT_pointed_by(obj, "rest parameter"); if (PT_obj == (KlO) ((KlExpr)obj)->lambdalist->whole) PT_pointed_by(obj, "whole parameter"); if (pk) { while (pk->key) { if (PT_obj == (KlO) pk->key) PT_pointed_by(obj, "keyword"); if (PT_obj == (KlO) pk->init) PT_pointed_by(obj, "keyword init"); pk++; } } if (p = ((KlExpr)obj)->lambdalist->aux) { while (*p) { if (PT_obj == (KlO) *p) PT_pointed_by(obj, "aux"); p++; } } } } else if (obj->type == KlStreamType && ((KlStream)obj)->subtype == KlStreamStringType) { PTB(KlStreamString, klstring); } else if (obj->type == KlQuotedExprType) { PTB(KlQuotedExpr, expr); } else if (obj->type == KlHashType) { KlHash table = (KlHash) obj; KlHashCell old_cell, cell; for (i = 0; i < table->limit; i++) { if (table->table[i]) { cell = table->table[i]; do { if (table->ref_counted & KlHashRefV) if (PT_obj == (KlO) cell->object) { sprintf(N, "value of cell 0x%x", cell); PT_pointed_by(obj, N); } if (table->ref_counted & KlHashRefK) if (PT_obj == (KlO) cell->key) { sprintf(N, "vkey of cell 0x%x", cell); PT_pointed_by(obj, N); } old_cell = cell; cell = cell->next; } while (cell); } } } else if (obj->type == KlStructType) { PTB(KlStruct, structclass); } else if (obj->type == KlStructClassType) { PTB(KlStructClass, name); PTB(KlStructClass, slots); } else if (obj->type == KlStructArrayType) { } else { if (PT_app_malloc) CFAPPLY(PT_app_malloc, (obj, size)); /* non-refering objects */ /* } else if (obj->type == KlTypeType) { } else if (obj->type == KlAnyType) { } else if (obj->type == KlLinkType) { } else if (obj->type == KlProcessIdType) { } else if (obj->type == KlSequenceType) { } else if (obj->type == KlMagnitudeType) { } else if (obj->type == KlNumberType) { } else if (obj->type == KlIntType) { } else if (obj->type == KlRealType) { } else if (obj->type == KlStringType) { } else if (obj->type == KlRegexpType) { } else if (obj->type == KlFunctionType) { } else if (obj->type == KlSubrType) { } else if (obj->type == KlFSubrType) { } else if (obj->type == KlCollectionType) { } else if (obj->type == KlStructuredType) { } else if (obj->type == KlGenericFunctionType) { */ } } int PT_aux_stack(obj, frame, from) KlO obj; Int frame; KlO from; { if (obj == PT_obj) { PT_count++; printf(" In stack frame %d, ", frame); switch ((Int) KlStack[frame]) { case KlSFID_normal: printf("(normal)");break; case KlSFID_subr: printf("(subr)");break; case KlSFID_catch: printf("(catch)");break; case KlSFID_hook: printf("(hook)");break; } if (from) { printf(" previous val of: "); P(from); } else { printf(" as ref pointer\n"); } } } int PT(obj) KlO obj; { extern int KlHashTableSize; extern KlAtom *KlAtomHashTable; KlAtom *slot; if (!KlObjectIsValid(obj)) return -1; PT_count = 0; PT_obj = obj; PT_where = 0; PT_level = 0; for (slot = KlAtomHashTable; /* symbol table */ slot < KlAtomHashTable + KlHashTableSize; slot++) { if (*slot == (KlAtom) PT_obj) { PT_count++; printf(" from symbol table, slot 0x%x\n", slot); } } KlDoMallocBlocks(PT_aux_malloc); /* malloced objects */ PT_where = 1; KlDoStackFramePointedObs(PT_aux_stack); /* stack */ PT_where = 3; if (KlDoExtendedcheck) /* application-specific places */ CFAPPLY(KlDoExtendedcheck, (PT_aux_app)); /* returns count of found objects */ if (obj->reference_count/2 > PT_count) printf("Warning: could not explain %d references\n", obj->reference_count/2 - PT_count); if (obj->reference_count/2 < PT_count) printf("Warning: number of references less by %d of object count!\n", PT_count - obj->reference_count/2); return PT_count; } /*************************************************************** check lists */ /* checks the validity of list elements */ void CL_aux_malloc(); void CL_aux_stack(); int CL_result; int /* return 0 if OK */ CL() { CL_result = 0; KlDoMallocBlocks(CL_aux_malloc); /* malloced objects */ KlDoStackFramePointedObs(CL_aux_stack); return CL_result; } void CL_aux(obj) KlO obj; { int i; if (obj->type && (obj->type == KlListType || obj->type == KlVectorType)) { for (i = 0; i < ((KlList)obj)->size; i++) { KlO elt = (KlO) ((KlList)obj)->list[i]; if (elt) { /* null elts are OK in lists */ if (!KlObjectIsValid(elt)) { fprintf(stderr, "Element at index %d in list %x0x is invalid, reason: %s\n", i, obj, Valid(elt)); CL_result++; stop_if_in_dbx("CL: invalid"); } } } } } void CL_aux_malloc(obj, size, chunk_size) KlO obj; int size; /* malloced bytes or -frame */ int chunk_size; /* total of used bytes */ { CL_aux(obj); } void CL_aux_stack(obj, frame, from) KlO obj; Int frame; KlO from; { CL_aux(obj); } #endif /* !USE_STANDARD_MALLOC */ /* POR: PO with print-readably set */ int POR(obj) KlO obj; { int stackptr = KlStackPtr; int result; KlStackFramePush(1, &KlA_print_readably, NIL, NIL); KlSend_setq(KlA_print_readably, TRU); result = PO(obj); KlStackFramePopNormal(stackptr); return result; } /* POT: try to see if it is an object and print its type if so */ int POT(obj) KlO obj; { if (!KlObjectIsValid(obj)) { char buffer[1000]; sprintf(buffer, "Non Klone Object: 0x%x\n", obj); KlPuts(buffer); KlFlush(0); return 0; } else { KlPuts(KlTypeCName(obj->type)); KlFlush(0); return 1; } } KlO KL(string) char *string; { return KlExecuteString(string); } /*****************************************************************************\ * stack dump * \*****************************************************************************/ /* a klone stack dump in C. convenient function to be called from C debuggers */ extern int KlShowDebuggerStack; BT() { int odsds = !KlShowDebuggerStack; Int sp = KlStackPtr; KlList res; int ptr; int actual_ptr; KlO call; KlO *vars; int next_ptr; int varsize; int i; KlShowDebuggerStack = 1; while ((next_ptr = KlStackFrameInfo(sp, &call, &actual_ptr, &vars, &varsize)) != -1) { printf("[%d]0x%x: ", sp, call); POR(call); puts(""); for (i = 0; i < varsize / 2; i+=2) { printf(" | "); PO(vars[i]); printf(" = "); PO(KlSend_eval(vars[i])); printf("("); POT(KlSend_eval(vars[i])); printf(") WAS: "); POR(vars[i+1]); puts(""); } sp = next_ptr; } KlShowDebuggerStack = !odsds; } /******************************************* print-stack-frame from debugger */ /* PSF(0) print top * PSF(-1) print whole, repeatedly * PSF(-N) print whole but only N frames from top * PSF(N) print from stack number N */ static int PSF_dont_run_klone; char * PSF_id_print(id) int id; { static char tmp[1024], *p = tmp; if (id & KlSFID_normal) p = stpcpy(p, "|KlSFID_normal"); if (id & KlSFID_subr) p = stpcpy(p, "|KlSFID_subr"); if (id & KlSFID_catch) p = stpcpy(p, "|KlSFID_catch"); if (id & KlSFID_hook) p = stpcpy(p, "|KlSFID_hook"); if (id & KlSFIM_call) p = stpcpy(p, "|KlSFIM_call"); if (id & KlSFIM_listable) p = stpcpy(p, "|KlSFIM_listable"); *p = '\0'; if (p != tmp) return tmp+1; else return tmp; } KlO PSF_call(ptr) int ptr; { KlO call; if ((Int) (KlStack[ptr]) & KlSFIM_call) { /* Expr */ call = KlStack[ptr - KlSFO_call]; } else { /* Subr */ call = 0; } return call; } char * PSF_print_item(o) KlO o; { if (PSF_dont_run_klone) { P(o); } else { char ad[80]; KlO arg[10]; char *res; sprintf(ad, "0x%x", o); arg[0] = (KlO) KlStringType; arg[1] = (KlO) KlStringMake("%n0: %l1"); arg[2] = (KlO) KlStringMake(ad); arg[3] = o; res = ((KlString) KlPrintFormat(4, arg))->string; if (strlen(res) > 70) { res[69] = '|'; res[70] = '\0'; } return res; } } PSF_body(n) int n; { int numprinted = (n >=0 ? 1 : (n < -1 ? -n : 1 << 30)); int ptr = (n <= 0 ? KlStackPtr : n); KlO call; for ( ; numprinted; numprinted--) { if (ptr <= 0) return; printf("**Frame@[%d]: %d = %s, previous %d", ptr, KlStack[ptr], PSF_id_print(KlStack[ptr]), KlStackFramePrevious(ptr)); if (((Int) (KlStack[ptr]) & KlSFIM_call) && (call = PSF_call(ptr))) printf("\n Call: %s", PSF_print_item(call)); printf("\n"); /* normal */ if ((Int) (KlStack[ptr]) & KlSFID_normal) { /* print vars */ KlO *vars = KlStack + ((Int) (KlStack[ptr - KlSFO_previous])) + 1; int varsize = ptr - KlSFS_normal - (Int) (KlStack[ptr - KlSFO_previous]); int i; for (i = 0; i < varsize; i ++) { printf(" [%d] %s\n", i, PSF_print_item(vars[i])); } } /* catch */ if ((Int) (KlStack[ptr]) & KlSFID_catch) { UnwindPoint up = (UnwindPoint) (KlStack[ptr - KlSFO_catch]); if (up->tag) { /* catch */ printf(" Catch tag: %s\n", PSF_print_item(up->tag)); } else { printf(" Unwind-protect catchpoint\n"); } } ptr = KlStackFramePrevious(ptr); } } PSF(n) int n; { PSF_dont_run_klone = 0; PSF_body(n); } PS(n) int n; { PSF_dont_run_klone = 1; PSF_body(n); } KlO PSFKl(n) KlNumber n; { KlMustBeNumber(n, 0); PSF(n->number); return NIL; } #ifdef DEBUG2 /*****************************************************************************\ * tracing * \*****************************************************************************/ /* this is obsolete and has been replaced by a klone function * implemented on eval-hook... but when all goes wrong, this is simpler * and may be useful... */ /* tracing info */ KlO KlAtomEvalAndTrace(obj) KlAtom obj; { KlO result; if (KlTracingOn) { KlPutSpaces(KlStackFramePtrToNumber(KlStackPtr)); KlPuts("=| "); KlPrint(obj); KlPuts(" => "); } result = KlAtomEval(obj); if (KlTracingOn) { KlPrint(result); KlPuts("\n"); } return result; } KlO KlActiveEvalAndTrace(obj) KlActive obj; { KlO result; if (KlTracingOn) { KlPutSpaces(KlStackFramePtrToNumber(KlStackPtr)); KlPuts("=| "); KlPrint(obj); KlPuts(" => "); } result = KlActiveEval(obj); if (KlTracingOn) { KlPrint(result); KlPuts("\n"); } return result; } /* * KlListEvalAndTrace: same with tracing */ KlO KlListEvalAndTrace(obj) KlList obj; { KlO result; int tracing_level = KlStackFramePtrToNumber(KlStackPtr); if (KlTracingOn) { KlPutSpaces(tracing_level); KlPuts("-> "); KlPrint(obj); KlPuts("\n"); if (KlTracingOnEXPR) { KlTracingOn = 0; KlSend_eval(KlTracingOnEXPR); KlTracingOn = 1; } } result = KlListEval(obj); if (KlTracingOn) { if (KlTracingOnEXPR) { KlTracingOn = 0; KlSend_eval(KlTracingOnEXPR); if (KlStillTracing) KlTracingOn = 1; else KlStillTracing = 1; } KlPutSpaces(tracing_level); KlPuts("<- "); KlPrint(result); KlPuts("\n"); } return result; } /*ARGSUSED*/ KlO KlGetTrace(o) KlO o; { return (KlO) KlNumberMake(KlTracingOn); } /* (trace obj) * obj = expr, evals expr at each eval of list * obj = 0/1 turns tracing on/off (without resetting expr) * obj = t resets expr */ /*ARGSUSED*/ KlO KlSetTrace(obj, o) KlO obj; KlO o; { if (KlIsAnInteger(obj)) { KlTracingOn = ((KlNumber) obj)->number; KlListType[KlSelEval] = KlListEvalAndTrace; KlAtomType[KlSelEval] = KlAtomEvalAndTrace; KlConstantType[KlSelEval] = KlAtomEvalAndTrace; KlActiveType[KlSelEval] = KlActiveEvalAndTrace; } else if (obj == NIL) { KlTracingOn = 0; KlListType[KlSelEval] = KlListEval; KlAtomType[KlSelEval] = KlAtomEval; KlConstantType[KlSelEval] = KlAtomEval; KlActiveType[KlSelEval] = KlActiveEval; } else { KlTracingOn = 1; KlListType[KlSelEval] = KlListEvalAndTrace; KlAtomType[KlSelEval] = KlAtomEvalAndTrace; KlConstantType[KlSelEval] = KlAtomEvalAndTrace; KlActiveType[KlSelEval] = KlActiveEvalAndTrace; KlDecRef(KlTracingOnEXPR); if (obj == TRU) KlTracingOnEXPR = 0; else KlIncRef(KlTracingOnEXPR = obj); } KlStillTracing = KlTracingOn; return obj; } KlPutSpaces(n) int n; { char tmp[10]; sprintf(tmp, "%%-%dd", n); KlPrintf(tmp, n); } /* prints logical stack frame number */ int KlStackFramePtrToNumber(ptr) int ptr; { int number = 0; while (ptr) { if ((Int) (KlStack[ptr]) & KlSFID_normal) { ptr = (Int) (KlStack[ptr - KlSFO_previous]); } else { ptr -= KlSFS_special; } number++; } return number; } #endif /* DEBUG2 */ /************************************************************* end of module */ #endif /* DEBUG */