# include "gc←private.h" # define START←FLAG ((word)0xfedcedcb) # define END←FLAG ((word)0xbcdecdef) /* Stored both one past the end of user object, and one before */ /* the end of the object as seen by the allocator. */ /* Object header */ typedef struct { char * oh←string; /* object descriptor string */ word oh←int; /* object descriptor integers */ word oh←sz; /* Original malloc arg. */ word oh←sf; /* start flag */ } oh; /* The size of the above structure is assumed not to dealign things, */ /* and to be a multiple of the word length. */ #define DEBUG←BYTES (sizeof (oh) + sizeof (word)) #define ROUNDED←UP←WORDS(n) BYTES←TO←WORDS((n) + WORDS←TO←BYTES(1) - 1) bool GC←debugging←started = FALSE; /* Check whether object with base pointer p has debugging info */ /* p is assumed to point to a legitimate object in our part */ /* of the heap. */ bool GC←has←debug←info(p) ptr←t p; { register oh * ohdr = (oh *)p; register ptr←t body = (ptr←t)(ohdr + 1); register word sz = GC←size((ptr←t) ohdr); if (HBLKPTR((ptr←t)ohdr) != HBLKPTR((ptr←t)body) || sz < sizeof (oh)) { return(FALSE); } if (ohdr -> oh←sf == (START←FLAG ↑ (word)body)) return(TRUE); if (((word *)ohdr)[BYTES←TO←WORDS(sz)-1] == (END←FLAG ↑ (word)body)) { return(TRUE); } return(FALSE); } /* Store debugging info into p. Return displaced pointer. */ /* Assumes we don't hold allocation lock. */ ptr←t GC←store←debug←info(p, sz, string, integer) register ptr←t p; /* base pointer */ word sz; /* bytes */ char * string; word integer; { register word * result = (word *)((oh *)p + 1); DCL←LOCK←STATE; /* There is some argument that we should dissble signals here. */ /* But that's expensive. And this way things should only appear */ /* inconsistent while we're in the handler. */ LOCK(); ((oh *)p) -> oh←string = string; ((oh *)p) -> oh←int = integer; ((oh *)p) -> oh←sz = sz; ((oh *)p) -> oh←sf = START←FLAG ↑ (word)result; ((word *)p)[BYTES←TO←WORDS(GC←size(p))-1] = result[ROUNDED←UP←WORDS(sz)] = END←FLAG ↑ (word)result; UNLOCK(); return((ptr←t)result); } /* Check the object with debugging info at p */ /* return NIL if it's OK. Else return clobbered */ /* address. */ ptr←t GC←check←annotated←obj(ohdr) register oh * ohdr; { register ptr←t body = (ptr←t)(ohdr + 1); register word gc←sz = GC←size((ptr←t)ohdr); if (ohdr -> oh←sz + DEBUG←BYTES > gc←sz) { return((ptr←t)(&(ohdr -> oh←sz))); } if (ohdr -> oh←sf != (START←FLAG ↑ (word)body)) { return((ptr←t)(&(ohdr -> oh←sf))); } if (((word *)ohdr)[BYTES←TO←WORDS(gc←sz)-1] != (END←FLAG ↑ (word)body)) { return((ptr←t)((word *)ohdr + BYTES←TO←WORDS(gc←sz)-1)); } if (((word *)body)[ROUNDED←UP←WORDS(ohdr -> oh←sz)] != (END←FLAG ↑ (word)body)) { return((ptr←t)((word *)body + ROUNDED←UP←WORDS(ohdr -> oh←sz))); } return(0); } void GC←print←obj(p) ptr←t p; { register oh * ohdr = (oh *)GC←base(p); GC←err←printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh)); GC←err←puts(ohdr -> oh←string); GC←err←printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh←int), (unsigned long)(ohdr -> oh←sz)); } void GC←print←smashed←obj(p, clobbered←addr) ptr←t p, clobbered←addr; { register oh * ohdr = (oh *)GC←base(p); GC←err←printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered←addr, (unsigned long)p); if (clobbered←addr <= (ptr←t)(&(ohdr -> oh←sz))) { GC←err←printf1("<smashed>, appr. sz = %ld)\n", BYTES←TO←WORDS(GC←size((ptr←t)ohdr))); } else { GC←err←puts(ohdr -> oh←string); GC←err←printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh←int), (unsigned long)(ohdr -> oh←sz)); } } # ifdef ←←STDC←← extern←ptr←t GC←debug←malloc(size←t lb, char * s, int i) # else extern←ptr←t GC←debug←malloc(lb, s, i) size←t lb; char * s; int i; # endif { extern←ptr←t result = GC←malloc(lb + DEBUG←BYTES); if (result == 0) { GC←err←printf1("GC←debug←malloc(%ld) returning NIL (", (unsigned long) lb); GC←err←puts(s); GC←err←printf1(":%ld)\n", (unsigned long)i); return(0); } if (!GC←debugging←started) { GC←debugging←started = TRUE; GC←register←displacement((word)sizeof(oh)); } return (GC←store←debug←info(result, (word)lb, s, (word)i)); } # ifdef ←←STDC←← extern←ptr←t GC←debug←malloc←atomic(size←t lb, char * s, int i) # else extern←ptr←t GC←debug←malloc←atomic(lb, s, i) size←t lb; char * s; int i; # endif { extern←ptr←t result = GC←malloc←atomic(lb + DEBUG←BYTES); if (result == 0) { GC←err←printf1("GC←debug←malloc←atomic(%ld) returning NIL (", (unsigned long) lb); GC←err←puts(s); GC←err←printf1(":%ld)\n", (unsigned long)i); return(0); } if (!GC←debugging←started) { GC←debugging←started = TRUE; GC←register←displacement((word)sizeof(oh)); } return (GC←store←debug←info(result, (word)lb, s, (word)i)); } # ifdef ←←STDC←← void GC←debug←free(extern←ptr←t p) # else void GC←debug←free(p) extern←ptr←t p; # endif { register extern←ptr←t base = GC←base(p); register ptr←t clobbered; if (base == 0) { GC←err←printf1("Attempt to free invalid pointer %lx\n", (unsigned long)p); ABORT("free(invalid pointer)"); } if ((ptr←t)p - (ptr←t)base != sizeof(oh)) { GC←err←printf1( "GC←debug←free called on pointer %lx wo debugging info\n", (unsigned long)p); } else { clobbered = GC←check←annotated←obj((oh *)base); if (clobbered != 0) { GC←err←printf0("GC←debug←free: found smashed object at "); GC←print←smashed←obj(p, clobbered); } } GC←free(GC←base(p)); } # ifdef ←←STDC←← extern←ptr←t GC←debug←realloc(extern←ptr←t p, size←t lb, char *s, int i) # else extern←ptr←t GC←debug←realloc(p, lb, s, i) extern←ptr←t p; size←t lb; char *s; int i; # endif { register extern←ptr←t base = GC←base(p); register ptr←t clobbered; register extern←ptr←t result = GC←debug←malloc(lb, s, i); register size←t copy←sz = lb; register size←t old←sz; if (base == 0) { GC←err←printf1( "Attempt to free invalid pointer %lx\n", (unsigned long)p); ABORT("realloc(invalid pointer)"); } if ((ptr←t)p - (ptr←t)base != sizeof(oh)) { GC←err←printf1( "GC←debug←realloc called on pointer %lx wo debugging info\n", (unsigned long)p); return(GC←realloc(p, lb)); } clobbered = GC←check←annotated←obj((oh *)base); if (clobbered != 0) { GC←err←printf0("GC←debug←realloc: found smashed object at "); GC←print←smashed←obj(p, clobbered); } old←sz = ((oh *)base) -> oh←sz; if (old←sz < copy←sz) copy←sz = old←sz; if (result == 0) return(0); bcopy((char *)p, (char *)result, (int) copy←sz); return(result); } /* Check all marked objects in the given block for validity */ /*ARGSUSED*/ void GC←check←heap←block(hbp, dummy) register struct hblk *hbp; /* ptr to current heap block */ word dummy; { register struct hblkhdr * hhdr = HDR(hbp); register word sz = hhdr -> hb←sz; register int word←no; register word *p, *plim; p = (word *)(hbp->hb←body); word←no = HDR←WORDS; plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS←TO←BYTES(sz)); /* go through all words in block */ do { if( mark←bit←from←hdr(hhdr, word←no) && GC←has←debug←info((ptr←t)p)) { ptr←t clobbered = GC←check←annotated←obj((oh *)p); if (clobbered != 0) { GC←err←printf0( "GC←check←heap←block: found smashed object at "); GC←print←smashed←obj((ptr←t)p, clobbered); } } word←no += sz; p += sz; } while( p <= plim ); } /* This assumes that all accessible objects are marked, and that */ /* I hold the allocation lock. Normally called by collector. */ void GC←check←heap() { GC←apply←to←all←blocks(GC←check←heap←block, (word)0); } struct closure { GC←finalization←proc cl←fn; extern←ptr←t cl←data; }; # ifdef ←←STDC←← void * GC←make←closure(GC←finalization←proc fn, void * data) # else extern←ptr←t GC←make←closure(fn, data) GC←finalization←proc fn; extern←ptr←t data; # endif { struct closure * result = (struct closure *) GC←malloc(sizeof (struct closure)); result -> cl←fn = fn; result -> cl←data = data; return((extern←ptr←t)result); } # ifdef ←←STDC←← void GC←debug←invoke←finalizer(void * obj, void * data) # else void GC←debug←invoke←finalizer(obj, data) char * obj; char * data; # endif { register struct closure * cl = (struct closure *) data; (*(cl -> cl←fn))((extern←ptr←t)((char *)obj + sizeof(oh)), cl -> cl←data); }