diff options
Diffstat (limited to 'src/pkg/runtime/heapdump.c')
-rw-r--r-- | src/pkg/runtime/heapdump.c | 981 |
1 files changed, 0 insertions, 981 deletions
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c deleted file mode 100644 index 744c59f9b..000000000 --- a/src/pkg/runtime/heapdump.c +++ /dev/null @@ -1,981 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Implementation of runtime/debug.WriteHeapDump. Writes all -// objects in the heap plus additional info (roots, threads, -// finalizers, etc.) to a file. - -// The format of the dumped file is described at -// http://code.google.com/p/go-wiki/wiki/heapdump13 - -#include "runtime.h" -#include "arch_GOARCH.h" -#include "malloc.h" -#include "mgc0.h" -#include "type.h" -#include "typekind.h" -#include "funcdata.h" -#include "zaexperiment.h" -#include "../../cmd/ld/textflag.h" - -extern byte data[]; -extern byte edata[]; -extern byte bss[]; -extern byte ebss[]; -extern byte gcdata[]; -extern byte gcbss[]; - -enum { - FieldKindEol = 0, - FieldKindPtr = 1, - FieldKindString = 2, - FieldKindSlice = 3, - FieldKindIface = 4, - FieldKindEface = 5, - - TagEOF = 0, - TagObject = 1, - TagOtherRoot = 2, - TagType = 3, - TagGoRoutine = 4, - TagStackFrame = 5, - TagParams = 6, - TagFinalizer = 7, - TagItab = 8, - TagOSThread = 9, - TagMemStats = 10, - TagQueuedFinalizer = 11, - TagData = 12, - TagBss = 13, - TagDefer = 14, - TagPanic = 15, - TagMemProf = 16, - TagAllocSample = 17, - - TypeInfo_Conservative = 127, -}; - -static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg); -static void dumpfields(uintptr *prog); -static void dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind); -static void dumpbvtypes(BitVector *bv, byte *base); - -// fd to write the dump to. -static uintptr dumpfd; - -// buffer of pending write data -enum { - BufSize = 4096, -}; -#pragma dataflag NOPTR -static byte buf[BufSize]; -static uintptr nbuf; - -static void -write(byte *data, uintptr len) -{ - if(len + nbuf <= BufSize) { - runtime·memmove(buf + nbuf, data, len); - nbuf += len; - return; - } - runtime·write(dumpfd, buf, nbuf); - if(len >= BufSize) { - runtime·write(dumpfd, data, len); - nbuf = 0; - } else { - runtime·memmove(buf, data, len); - nbuf = len; - } -} - -static void -flush(void) -{ - runtime·write(dumpfd, buf, nbuf); - nbuf = 0; -} - -// Cache of types that have been serialized already. -// We use a type's hash field to pick a bucket. -// Inside a bucket, we keep a list of types that -// have been serialized so far, most recently used first. -// Note: when a bucket overflows we may end up -// serializing a type more than once. That's ok. -enum { - TypeCacheBuckets = 256, // must be a power of 2 - TypeCacheAssoc = 4, -}; -typedef struct TypeCacheBucket TypeCacheBucket; -struct TypeCacheBucket { - Type *t[TypeCacheAssoc]; -}; -static TypeCacheBucket typecache[TypeCacheBuckets]; - -// dump a uint64 in a varint format parseable by encoding/binary -static void -dumpint(uint64 v) -{ - byte buf[10]; - int32 n; - n = 0; - while(v >= 0x80) { - buf[n++] = v | 0x80; - v >>= 7; - } - buf[n++] = v; - write(buf, n); -} - -static void -dumpbool(bool b) -{ - dumpint(b ? 1 : 0); -} - -// dump varint uint64 length followed by memory contents -static void -dumpmemrange(byte *data, uintptr len) -{ - dumpint(len); - write(data, len); -} - -static void -dumpstr(String s) -{ - dumpmemrange(s.str, s.len); -} - -static void -dumpcstr(int8 *c) -{ - dumpmemrange((byte*)c, runtime·findnull((byte*)c)); -} - -// dump information for a type -static void -dumptype(Type *t) -{ - TypeCacheBucket *b; - int32 i, j; - - if(t == nil) { - return; - } - - // If we've definitely serialized the type before, - // no need to do it again. - b = &typecache[t->hash & (TypeCacheBuckets-1)]; - if(t == b->t[0]) return; - for(i = 1; i < TypeCacheAssoc; i++) { - if(t == b->t[i]) { - // Move-to-front - for(j = i; j > 0; j--) { - b->t[j] = b->t[j-1]; - } - b->t[0] = t; - return; - } - } - // Might not have been dumped yet. Dump it and - // remember we did so. - for(j = TypeCacheAssoc-1; j > 0; j--) { - b->t[j] = b->t[j-1]; - } - b->t[0] = t; - - // dump the type - dumpint(TagType); - dumpint((uintptr)t); - dumpint(t->size); - if(t->x == nil || t->x->pkgPath == nil || t->x->name == nil) { - dumpstr(*t->string); - } else { - dumpint(t->x->pkgPath->len + 1 + t->x->name->len); - write(t->x->pkgPath->str, t->x->pkgPath->len); - write((byte*)".", 1); - write(t->x->name->str, t->x->name->len); - } - dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0); - dumpfields((uintptr*)t->gc + 1); -} - -// returns true if object is scannable -static bool -scannable(byte *obj) -{ - uintptr *b, off, shift; - - off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start; // word offset - b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; - shift = off % wordsPerBitmapWord; - return ((*b >> shift) & bitScan) != 0; -} - -// dump an object -static void -dumpobj(byte *obj, uintptr size, Type *type, uintptr kind) -{ - if(type != nil) { - dumptype(type); - dumpefacetypes(obj, size, type, kind); - } - - dumpint(TagObject); - dumpint((uintptr)obj); - dumpint((uintptr)type); - dumpint(kind); - dumpmemrange(obj, size); -} - -static void -dumpotherroot(int8 *description, byte *to) -{ - dumpint(TagOtherRoot); - dumpcstr(description); - dumpint((uintptr)to); -} - -static void -dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot) -{ - dumpint(TagFinalizer); - dumpint((uintptr)obj); - dumpint((uintptr)fn); - dumpint((uintptr)fn->fn); - dumpint((uintptr)fint); - dumpint((uintptr)ot); -} - -typedef struct ChildInfo ChildInfo; -struct ChildInfo { - // Information passed up from the callee frame about - // the layout of the outargs region. - uintptr argoff; // where the arguments start in the frame - uintptr arglen; // size of args region - BitVector args; // if args.n >= 0, pointer map of args region - - byte *sp; // callee sp - uintptr depth; // depth in call stack (0 == most recent) -}; - -// dump kinds & offsets of interesting fields in bv -static void -dumpbv(BitVector *bv, uintptr offset) -{ - uintptr i; - - for(i = 0; i < bv->n; i += BitsPerPointer) { - switch(bv->data[i/32] >> i%32 & 3) { - case BitsDead: - case BitsScalar: - break; - case BitsPointer: - dumpint(FieldKindPtr); - dumpint(offset + i / BitsPerPointer * PtrSize); - break; - case BitsMultiWord: - switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { - case BitsString: - dumpint(FieldKindString); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += BitsPerPointer; - break; - case BitsSlice: - dumpint(FieldKindSlice); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += 2 * BitsPerPointer; - break; - case BitsIface: - dumpint(FieldKindIface); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += BitsPerPointer; - break; - case BitsEface: - dumpint(FieldKindEface); - dumpint(offset + i / BitsPerPointer * PtrSize); - i += BitsPerPointer; - break; - } - } - } -} - -static bool -dumpframe(Stkframe *s, void *arg) -{ - Func *f; - ChildInfo *child; - uintptr pc, off, size; - int32 pcdata; - StackMap *stackmap; - int8 *name; - BitVector bv; - - child = (ChildInfo*)arg; - f = s->fn; - - // Figure out what we can about our stack map - pc = s->pc; - if(pc != f->entry) - pc--; - pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc); - if(pcdata == -1) { - // We do not have a valid pcdata value but there might be a - // stackmap for this function. It is likely that we are looking - // at the function prologue, assume so and hope for the best. - pcdata = 0; - } - stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - - // Dump any types we will need to resolve Efaces. - if(child->args.n >= 0) - dumpbvtypes(&child->args, (byte*)s->sp + child->argoff); - if(stackmap != nil && stackmap->n > 0) { - bv = runtime·stackmapdata(stackmap, pcdata); - dumpbvtypes(&bv, s->varp - bv.n / BitsPerPointer * PtrSize); - } else { - bv.n = -1; - } - - // Dump main body of stack frame. - dumpint(TagStackFrame); - dumpint(s->sp); // lowest address in frame - dumpint(child->depth); // # of frames deep on the stack - dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack - dumpmemrange((byte*)s->sp, s->fp - s->sp); // frame contents - dumpint(f->entry); - dumpint(s->pc); - dumpint(s->continpc); - name = runtime·funcname(f); - if(name == nil) - name = "unknown function"; - dumpcstr(name); - - // Dump fields in the outargs section - if(child->args.n >= 0) { - dumpbv(&child->args, child->argoff); - } else { - // conservative - everything might be a pointer - for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) { - dumpint(FieldKindPtr); - dumpint(off); - } - } - - // Dump fields in the local vars section - if(stackmap == nil) { - // No locals information, dump everything. - for(off = child->arglen; off < s->varp - (byte*)s->sp; off += PtrSize) { - dumpint(FieldKindPtr); - dumpint(off); - } - } else if(stackmap->n < 0) { - // Locals size information, dump just the locals. - size = -stackmap->n; - for(off = s->varp - size - (byte*)s->sp; off < s->varp - (byte*)s->sp; off += PtrSize) { - dumpint(FieldKindPtr); - dumpint(off); - } - } else if(stackmap->n > 0) { - // Locals bitmap information, scan just the pointers in - // locals. - dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - (byte*)s->sp); - } - dumpint(FieldKindEol); - - // Record arg info for parent. - child->argoff = s->argp - (byte*)s->fp; - child->arglen = s->arglen; - child->sp = (byte*)s->sp; - child->depth++; - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap != nil) - child->args = runtime·stackmapdata(stackmap, pcdata); - else - child->args.n = -1; - return true; -} - -static void -dumpgoroutine(G *gp) -{ - uintptr sp, pc, lr; - ChildInfo child; - Defer *d; - Panic *p; - - if(gp->syscallstack != (uintptr)nil) { - sp = gp->syscallsp; - pc = gp->syscallpc; - lr = 0; - } else { - sp = gp->sched.sp; - pc = gp->sched.pc; - lr = gp->sched.lr; - } - - dumpint(TagGoRoutine); - dumpint((uintptr)gp); - dumpint((uintptr)sp); - dumpint(gp->goid); - dumpint(gp->gopc); - dumpint(gp->status); - dumpbool(gp->issystem); - dumpbool(gp->isbackground); - dumpint(gp->waitsince); - dumpcstr(gp->waitreason); - dumpint((uintptr)gp->sched.ctxt); - dumpint((uintptr)gp->m); - dumpint((uintptr)gp->defer); - dumpint((uintptr)gp->panic); - - // dump stack - child.args.n = -1; - child.arglen = 0; - child.sp = nil; - child.depth = 0; - if(!ScanStackByFrames) - runtime·throw("need frame info to dump stacks"); - runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false); - - // dump defer & panic records - for(d = gp->defer; d != nil; d = d->link) { - dumpint(TagDefer); - dumpint((uintptr)d); - dumpint((uintptr)gp); - dumpint((uintptr)d->argp); - dumpint((uintptr)d->pc); - dumpint((uintptr)d->fn); - dumpint((uintptr)d->fn->fn); - dumpint((uintptr)d->link); - } - for (p = gp->panic; p != nil; p = p->link) { - dumpint(TagPanic); - dumpint((uintptr)p); - dumpint((uintptr)gp); - dumpint((uintptr)p->arg.type); - dumpint((uintptr)p->arg.data); - dumpint((uintptr)p->defer); - dumpint((uintptr)p->link); - } -} - -static void -dumpgs(void) -{ - G *gp; - uint32 i; - - // goroutines & stacks - for(i = 0; i < runtime·allglen; i++) { - gp = runtime·allg[i]; - switch(gp->status){ - default: - runtime·printf("unexpected G.status %d\n", gp->status); - runtime·throw("mark - bad status"); - case Gdead: - break; - case Grunnable: - case Gsyscall: - case Gwaiting: - dumpgoroutine(gp); - break; - } - } -} - -static void -finq_callback(FuncVal *fn, byte *obj, uintptr nret, Type *fint, PtrType *ot) -{ - dumpint(TagQueuedFinalizer); - dumpint((uintptr)obj); - dumpint((uintptr)fn); - dumpint((uintptr)fn->fn); - dumpint((uintptr)fint); - dumpint((uintptr)ot); - USED(&nret); -} - - -static void -dumproots(void) -{ - MSpan *s, **allspans; - uint32 spanidx; - Special *sp; - SpecialFinalizer *spf; - byte *p; - - // data segment - dumpint(TagData); - dumpint((uintptr)data); - dumpmemrange(data, edata - data); - dumpfields((uintptr*)gcdata + 1); - - // bss segment - dumpint(TagBss); - dumpint((uintptr)bss); - dumpmemrange(bss, ebss - bss); - dumpfields((uintptr*)gcbss + 1); - - // MSpan.types - allspans = runtime·mheap.allspans; - for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { - s = allspans[spanidx]; - if(s->state == MSpanInUse) { - // The garbage collector ignores type pointers stored in MSpan.types: - // - Compiler-generated types are stored outside of heap. - // - The reflect package has runtime-generated types cached in its data structures. - // The garbage collector relies on finding the references via that cache. - switch(s->types.compression) { - case MTypes_Empty: - case MTypes_Single: - break; - case MTypes_Words: - case MTypes_Bytes: - dumpotherroot("runtime type info", (byte*)s->types.data); - break; - } - - // Finalizers - for(sp = s->specials; sp != nil; sp = sp->next) { - if(sp->kind != KindSpecialFinalizer) - continue; - spf = (SpecialFinalizer*)sp; - p = (byte*)((s->start << PageShift) + spf->offset); - dumpfinalizer(p, spf->fn, spf->fint, spf->ot); - } - } - } - - // Finalizer queue - runtime·iterate_finq(finq_callback); -} - -// Bit vector of free marks. -// Needs to be as big as the largest number of objects per span. -static byte free[PageSize/8]; - -static void -dumpobjs(void) -{ - uintptr i, j, size, n, off, shift, *bitp, bits, ti, kind; - MSpan *s; - MLink *l; - byte *p; - Type *t; - - for(i = 0; i < runtime·mheap.nspan; i++) { - s = runtime·mheap.allspans[i]; - if(s->state != MSpanInUse) - continue; - p = (byte*)(s->start << PageShift); - size = s->elemsize; - n = (s->npages << PageShift) / size; - if(n > PageSize/8) - runtime·throw("free array doesn't have enough entries"); - for(l = s->freelist; l != nil; l = l->next) { - free[((byte*)l - p) / size] = true; - } - for(j = 0; j < n; j++, p += size) { - if(free[j]) { - free[j] = false; - continue; - } - off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start; - bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; - shift = off % wordsPerBitmapWord; - bits = *bitp >> shift; - - // Skip FlagNoGC allocations (stacks) - if((bits & bitAllocated) == 0) - continue; - - // extract type and kind - ti = runtime·gettype(p); - t = (Type*)(ti & ~(uintptr)(PtrSize-1)); - kind = ti & (PtrSize-1); - - // dump it - if(kind == TypeInfo_Chan) - t = ((ChanType*)t)->elem; // use element type for chan encoding - if(t == nil && scannable(p)) - kind = TypeInfo_Conservative; // special kind for conservatively scanned objects - dumpobj(p, size, t, kind); - } - } -} - -static void -dumpparams(void) -{ - byte *x; - - dumpint(TagParams); - x = (byte*)1; - if(*(byte*)&x == 1) - dumpbool(false); // little-endian ptrs - else - dumpbool(true); // big-endian ptrs - dumpint(PtrSize); - dumpint(runtime·Hchansize); - dumpint((uintptr)runtime·mheap.arena_start); - dumpint((uintptr)runtime·mheap.arena_used); - dumpint(thechar); - dumpcstr(GOEXPERIMENT); - dumpint(runtime·ncpu); -} - -static void -itab_callback(Itab *tab) -{ - Type *t; - - dumpint(TagItab); - dumpint((uintptr)tab); - t = tab->type; - dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0); -} - -static void -dumpitabs(void) -{ - runtime·iterate_itabs(itab_callback); -} - -static void -dumpms(void) -{ - M *mp; - - for(mp = runtime·allm; mp != nil; mp = mp->alllink) { - dumpint(TagOSThread); - dumpint((uintptr)mp); - dumpint(mp->id); - dumpint(mp->procid); - } -} - -static void -dumpmemstats(void) -{ - int32 i; - - dumpint(TagMemStats); - dumpint(mstats.alloc); - dumpint(mstats.total_alloc); - dumpint(mstats.sys); - dumpint(mstats.nlookup); - dumpint(mstats.nmalloc); - dumpint(mstats.nfree); - dumpint(mstats.heap_alloc); - dumpint(mstats.heap_sys); - dumpint(mstats.heap_idle); - dumpint(mstats.heap_inuse); - dumpint(mstats.heap_released); - dumpint(mstats.heap_objects); - dumpint(mstats.stacks_inuse); - dumpint(mstats.stacks_sys); - dumpint(mstats.mspan_inuse); - dumpint(mstats.mspan_sys); - dumpint(mstats.mcache_inuse); - dumpint(mstats.mcache_sys); - dumpint(mstats.buckhash_sys); - dumpint(mstats.gc_sys); - dumpint(mstats.other_sys); - dumpint(mstats.next_gc); - dumpint(mstats.last_gc); - dumpint(mstats.pause_total_ns); - for(i = 0; i < 256; i++) - dumpint(mstats.pause_ns[i]); - dumpint(mstats.numgc); -} - -static void -dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees) -{ - uintptr i, pc; - Func *f; - byte buf[20]; - String file; - int32 line; - - dumpint(TagMemProf); - dumpint((uintptr)b); - dumpint(size); - dumpint(nstk); - for(i = 0; i < nstk; i++) { - pc = stk[i]; - f = runtime·findfunc(pc); - if(f == nil) { - runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc); - dumpcstr((int8*)buf); - dumpcstr("?"); - dumpint(0); - } else { - dumpcstr(runtime·funcname(f)); - // TODO: Why do we need to back up to a call instruction here? - // Maybe profiler should do this. - if(i > 0 && pc > f->entry) { - if(thechar == '6' || thechar == '8') - pc--; - else - pc -= 4; // arm, etc - } - line = runtime·funcline(f, pc, &file); - dumpstr(file); - dumpint(line); - } - } - dumpint(allocs); - dumpint(frees); -} - -static void -dumpmemprof(void) -{ - MSpan *s, **allspans; - uint32 spanidx; - Special *sp; - SpecialProfile *spp; - byte *p; - - runtime·iterate_memprof(dumpmemprof_callback); - - allspans = runtime·mheap.allspans; - for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { - s = allspans[spanidx]; - if(s->state != MSpanInUse) - continue; - for(sp = s->specials; sp != nil; sp = sp->next) { - if(sp->kind != KindSpecialProfile) - continue; - spp = (SpecialProfile*)sp; - p = (byte*)((s->start << PageShift) + spp->offset); - dumpint(TagAllocSample); - dumpint((uintptr)p); - dumpint((uintptr)spp->b); - } - } -} - -static void -mdump(G *gp) -{ - byte *hdr; - uintptr i; - MSpan *s; - - // make sure we're done sweeping - for(i = 0; i < runtime·mheap.nspan; i++) { - s = runtime·mheap.allspans[i]; - if(s->state == MSpanInUse) - runtime·MSpan_EnsureSwept(s); - } - - runtime·memclr((byte*)&typecache[0], sizeof(typecache)); - hdr = (byte*)"go1.3 heap dump\n"; - write(hdr, runtime·findnull(hdr)); - dumpparams(); - dumpitabs(); - dumpobjs(); - dumpgs(); - dumpms(); - dumproots(); - dumpmemstats(); - dumpmemprof(); - dumpint(TagEOF); - flush(); - - gp->param = nil; - gp->status = Grunning; - runtime·gogo(&gp->sched); -} - -void -runtime∕debug·WriteHeapDump(uintptr fd) -{ - // Stop the world. - runtime·semacquire(&runtime·worldsema, false); - m->gcing = 1; - m->locks++; - runtime·stoptheworld(); - - // Update stats so we can dump them. - // As a side effect, flushes all the MCaches so the MSpan.freelist - // lists contain all the free objects. - runtime·updatememstats(nil); - - // Set dump file. - dumpfd = fd; - - // Call dump routine on M stack. - g->status = Gwaiting; - g->waitreason = "dumping heap"; - runtime·mcall(mdump); - - // Reset dump file. - dumpfd = 0; - - // Start up the world again. - m->gcing = 0; - runtime·semrelease(&runtime·worldsema); - runtime·starttheworld(); - m->locks--; -} - -// Runs the specified gc program. Calls the callback for every -// pointer-like field specified by the program and passes to the -// callback the kind and offset of that field within the object. -// offset is the offset in the object of the start of the program. -// Returns a pointer to the opcode that ended the gc program (either -// GC_END or GC_ARRAY_NEXT). -static uintptr* -playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg) -{ - uintptr len, elemsize, i, *end; - - for(;;) { - switch(prog[0]) { - case GC_END: - return prog; - case GC_PTR: - callback(arg, FieldKindPtr, offset + prog[1]); - prog += 3; - break; - case GC_APTR: - callback(arg, FieldKindPtr, offset + prog[1]); - prog += 2; - break; - case GC_ARRAY_START: - len = prog[2]; - elemsize = prog[3]; - end = nil; - for(i = 0; i < len; i++) { - end = playgcprog(offset + prog[1] + i * elemsize, prog + 4, callback, arg); - if(end[0] != GC_ARRAY_NEXT) - runtime·throw("GC_ARRAY_START did not have matching GC_ARRAY_NEXT"); - } - prog = end + 1; - break; - case GC_ARRAY_NEXT: - return prog; - case GC_CALL: - playgcprog(offset + prog[1], (uintptr*)((byte*)prog + *(int32*)&prog[2]), callback, arg); - prog += 3; - break; - case GC_CHAN_PTR: - callback(arg, FieldKindPtr, offset + prog[1]); - prog += 3; - break; - case GC_STRING: - callback(arg, FieldKindString, offset + prog[1]); - prog += 2; - break; - case GC_EFACE: - callback(arg, FieldKindEface, offset + prog[1]); - prog += 2; - break; - case GC_IFACE: - callback(arg, FieldKindIface, offset + prog[1]); - prog += 2; - break; - case GC_SLICE: - callback(arg, FieldKindSlice, offset + prog[1]); - prog += 3; - break; - case GC_REGION: - playgcprog(offset + prog[1], (uintptr*)prog[3] + 1, callback, arg); - prog += 4; - break; - default: - runtime·printf("%D\n", (uint64)prog[0]); - runtime·throw("bad gc op"); - } - } -} - -static void -dump_callback(void *p, uintptr kind, uintptr offset) -{ - USED(&p); - dumpint(kind); - dumpint(offset); -} - -// dumpint() the kind & offset of each field in an object. -static void -dumpfields(uintptr *prog) -{ - playgcprog(0, prog, dump_callback, nil); - dumpint(FieldKindEol); -} - -static void -dumpeface_callback(void *p, uintptr kind, uintptr offset) -{ - Eface *e; - - if(kind != FieldKindEface) - return; - e = (Eface*)((byte*)p + offset); - dumptype(e->type); -} - -// The heap dump reader needs to be able to disambiguate -// Eface entries. So it needs to know every type that might -// appear in such an entry. The following two routines accomplish -// that. - -// Dump all the types that appear in the type field of -// any Eface contained in obj. -static void -dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind) -{ - uintptr i; - - switch(kind) { - case TypeInfo_SingleObject: - playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj); - break; - case TypeInfo_Array: - for(i = 0; i <= size - type->size; i += type->size) - playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj); - break; - case TypeInfo_Chan: - if(type->size == 0) // channels may have zero-sized objects in them - break; - for(i = runtime·Hchansize; i <= size - type->size; i += type->size) - playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj); - break; - } -} - -// Dump all the types that appear in the type field of -// any Eface described by this bit vector. -static void -dumpbvtypes(BitVector *bv, byte *base) -{ - uintptr i; - - for(i = 0; i < bv->n; i += BitsPerPointer) { - if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord) - continue; - switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { - case BitsString: - case BitsIface: - i += BitsPerPointer; - break; - case BitsSlice: - i += 2 * BitsPerPointer; - break; - case BitsEface: - dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize)); - i += BitsPerPointer; - break; - } - } -} |