1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Implementation of runtime/debug.WriteHeapDump. Writes all
6 // objects in the heap plus additional info (roots, threads,
7 // finalizers, etc.) to a file.
9 // The format of the dumped file is described at
10 // http://code.google.com/p/go-wiki/wiki/heapdump13
19 #define KindNoPointers GO_NO_POINTERS
40 TagQueuedFinalizer
= 11,
48 TypeInfo_Conservative
= 127,
51 // static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
52 // static void dumpfields(uintptr *prog);
53 static void dumpefacetypes(void *obj
, uintptr size
, const Type
*type
, uintptr kind
);
55 // fd to write the dump to.
56 static uintptr dumpfd
;
58 // buffer of pending write data
62 static byte buf
[BufSize
];
66 hwrite(const byte
*data
, uintptr len
)
68 if(len
+ nbuf
<= BufSize
) {
69 runtime_memmove(buf
+ nbuf
, data
, len
);
73 runtime_write(dumpfd
, buf
, nbuf
);
75 runtime_write(dumpfd
, data
, len
);
78 runtime_memmove(buf
, data
, len
);
86 runtime_write(dumpfd
, buf
, nbuf
);
90 // Cache of types that have been serialized already.
91 // We use a type's hash field to pick a bucket.
92 // Inside a bucket, we keep a list of types that
93 // have been serialized so far, most recently used first.
94 // Note: when a bucket overflows we may end up
95 // serializing a type more than once. That's ok.
97 TypeCacheBuckets
= 256, // must be a power of 2
100 typedef struct TypeCacheBucket TypeCacheBucket
;
101 struct TypeCacheBucket
{
102 const Type
*t
[TypeCacheAssoc
];
104 static TypeCacheBucket typecache
[TypeCacheBuckets
];
106 // dump a uint64 in a varint format parseable by encoding/binary
127 // dump varint uint64 length followed by memory contents
129 dumpmemrange(const byte
*data
, uintptr len
)
138 dumpmemrange(s
.str
, s
.len
);
142 dumpcstr(const int8
*c
)
144 dumpmemrange((const byte
*)c
, runtime_findnull((const byte
*)c
));
147 // dump information for a type
149 dumptype(const Type
*t
)
158 // If we've definitely serialized the type before,
159 // no need to do it again.
160 b
= &typecache
[t
->hash
& (TypeCacheBuckets
-1)];
161 if(t
== b
->t
[0]) return;
162 for(i
= 1; i
< TypeCacheAssoc
; i
++) {
165 for(j
= i
; j
> 0; j
--) {
172 // Might not have been dumped yet. Dump it and
173 // remember we did so.
174 for(j
= TypeCacheAssoc
-1; j
> 0; j
--) {
183 if(t
->__uncommon
== nil
|| t
->__uncommon
->__pkg_path
== nil
|| t
->__uncommon
->__name
== nil
) {
184 dumpstr(*t
->__reflection
);
186 dumpint(t
->__uncommon
->__pkg_path
->len
+ 1 + t
->__uncommon
->__name
->len
);
187 hwrite(t
->__uncommon
->__pkg_path
->str
, t
->__uncommon
->__pkg_path
->len
);
188 hwrite((const byte
*)".", 1);
189 hwrite(t
->__uncommon
->__name
->str
, t
->__uncommon
->__name
->len
);
191 dumpbool(t
->__size
> PtrSize
|| (t
->__code
& KindNoPointers
) == 0);
192 // dumpfields((uintptr*)t->gc + 1);
195 // returns true if object is scannable
199 uintptr
*b
, off
, shift
;
201 off
= (uintptr
*)obj
- (uintptr
*)runtime_mheap
.arena_start
; // word offset
202 b
= (uintptr
*)runtime_mheap
.arena_start
- off
/wordsPerBitmapWord
- 1;
203 shift
= off
% wordsPerBitmapWord
;
204 return ((*b
>> shift
) & bitScan
) != 0;
209 dumpobj(byte
*obj
, uintptr size
, const Type
*type
, uintptr kind
)
213 dumpefacetypes(obj
, size
, type
, kind
);
217 dumpint((uintptr
)obj
);
218 dumpint((uintptr
)type
);
220 dumpmemrange(obj
, size
);
224 dumpotherroot(const char *description
, byte
*to
)
226 dumpint(TagOtherRoot
);
227 dumpcstr((const int8
*)description
);
228 dumpint((uintptr
)to
);
232 dumpfinalizer(byte
*obj
, FuncVal
*fn
, const FuncType
* ft
, const PtrType
*ot
)
234 dumpint(TagFinalizer
);
235 dumpint((uintptr
)obj
);
236 dumpint((uintptr
)fn
);
237 dumpint((uintptr
)fn
->fn
);
238 dumpint((uintptr
)ft
);
239 dumpint((uintptr
)ot
);
242 typedef struct ChildInfo ChildInfo
;
244 // Information passed up from the callee frame about
245 // the layout of the outargs region.
246 uintptr argoff
; // where the arguments start in the frame
247 uintptr arglen
; // size of args region
248 BitVector args
; // if args.n >= 0, pointer map of args region
250 byte
*sp
; // callee sp
251 uintptr depth
; // depth in call stack (0 == most recent)
261 dumpint(TagGoRoutine
);
262 dumpint((uintptr
)gp
);
266 dumpint(gp
->atomicstatus
);
267 dumpbool(gp
->issystem
);
268 dumpbool(gp
->isbackground
);
269 dumpint(gp
->waitsince
);
270 dumpstr(gp
->waitreason
);
272 dumpint((uintptr
)gp
->m
);
273 dumpint((uintptr
)gp
->_defer
);
274 dumpint((uintptr
)gp
->_panic
);
277 // child.args.n = -1;
281 // if(!ScanStackByFrames)
282 // runtime_throw("need frame info to dump stacks");
283 // runtime_gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false);
285 // dump defer & panic records
286 for(d
= gp
->_defer
; d
!= nil
; d
= d
->link
) {
289 dumpint((uintptr
)gp
);
290 dumpint((uintptr
)d
->arg
);
291 dumpint((uintptr
)d
->frame
);
292 dumpint((uintptr
)d
->pfn
);
294 dumpint((uintptr
)d
->link
);
296 for (p
= gp
->_panic
; p
!= nil
; p
= p
->link
) {
299 dumpint((uintptr
)gp
);
300 dumpint((uintptr
)p
->arg
._type
);
301 dumpint((uintptr
)p
->arg
.data
);
303 dumpint((uintptr
)p
->link
);
313 // goroutines & stacks
314 for(i
= 0; i
< runtime_getallglen(); i
++) {
315 gp
= runtime_getallg(i
);
316 switch(gp
->atomicstatus
){
318 runtime_printf("unexpected G.status %d\n", gp
->atomicstatus
);
319 runtime_throw("mark - bad status");
332 finq_callback(FuncVal
*fn
, void *obj
, const FuncType
*ft
, const PtrType
*ot
)
334 dumpint(TagQueuedFinalizer
);
335 dumpint((uintptr
)obj
);
336 dumpint((uintptr
)fn
);
337 dumpint((uintptr
)fn
->fn
);
338 dumpint((uintptr
)ft
);
339 dumpint((uintptr
)ot
);
346 MSpan
*s
, **allspans
;
349 SpecialFinalizer
*spf
;
354 // dumpint((uintptr)data);
355 // dumpmemrange(data, edata - data);
356 // dumpfields((uintptr*)gcdata + 1);
360 // dumpint((uintptr)bss);
361 // dumpmemrange(bss, ebss - bss);
362 // dumpfields((uintptr*)gcbss + 1);
365 allspans
= runtime_mheap
.allspans
;
366 for(spanidx
=0; spanidx
<runtime_mheap
.nspan
; spanidx
++) {
367 s
= allspans
[spanidx
];
368 if(s
->state
== MSpanInUse
) {
369 // The garbage collector ignores type pointers stored in MSpan.types:
370 // - Compiler-generated types are stored outside of heap.
371 // - The reflect package has runtime-generated types cached in its data structures.
372 // The garbage collector relies on finding the references via that cache.
373 switch(s
->types
.compression
) {
379 dumpotherroot("runtime type info", (byte
*)s
->types
.data
);
384 for(sp
= s
->specials
; sp
!= nil
; sp
= sp
->next
) {
385 if(sp
->kind
!= KindSpecialFinalizer
)
387 spf
= (SpecialFinalizer
*)sp
;
388 p
= (byte
*)((s
->start
<< PageShift
) + spf
->offset
);
389 dumpfinalizer(p
, spf
->fn
, spf
->ft
, spf
->ot
);
395 runtime_iterate_finq(finq_callback
);
398 // Bit vector of free marks.
399 // Needs to be as big as the largest number of objects per span.
400 static byte hfree
[PageSize
/8];
405 uintptr i
, j
, size
, n
, off
, shift
, *bitp
, bits
, ti
, kind
;
411 for(i
= 0; i
< runtime_mheap
.nspan
; i
++) {
412 s
= runtime_mheap
.allspans
[i
];
413 if(s
->state
!= MSpanInUse
)
415 p
= (byte
*)(s
->start
<< PageShift
);
417 n
= (s
->npages
<< PageShift
) / size
;
419 runtime_throw("free array doesn't have enough entries");
420 for(l
= s
->freelist
; l
!= nil
; l
= l
->next
) {
421 hfree
[((byte
*)l
- p
) / size
] = true;
423 for(j
= 0; j
< n
; j
++, p
+= size
) {
428 off
= (uintptr
*)p
- (uintptr
*)runtime_mheap
.arena_start
;
429 bitp
= (uintptr
*)runtime_mheap
.arena_start
- off
/wordsPerBitmapWord
- 1;
430 shift
= off
% wordsPerBitmapWord
;
431 bits
= *bitp
>> shift
;
433 // Skip FlagNoGC allocations (stacks)
434 if((bits
& bitAllocated
) == 0)
437 // extract type and kind
438 ti
= runtime_gettype(p
);
439 t
= (Type
*)(ti
& ~(uintptr
)(PtrSize
-1));
440 kind
= ti
& (PtrSize
-1);
443 if(kind
== TypeInfo_Chan
)
444 t
= ((const ChanType
*)t
)->__element_type
; // use element type for chan encoding
445 if(t
== nil
&& scannable(p
))
446 kind
= TypeInfo_Conservative
; // special kind for conservatively scanned objects
447 dumpobj(p
, size
, t
, kind
);
460 dumpbool(false); // little-endian ptrs
462 dumpbool(true); // big-endian ptrs
465 dumpint((uintptr
)runtime_mheap
.arena_start
);
466 dumpint((uintptr
)runtime_mheap
.arena_used
);
468 dumpcstr((const int8
*)"");
469 dumpint(runtime_ncpu
);
477 for(mp
= runtime_getallm(); mp
!= nil
; mp
= mp
->alllink
) {
478 dumpint(TagOSThread
);
479 dumpint((uintptr
)mp
);
490 dumpint(TagMemStats
);
491 dumpint(mstats()->alloc
);
492 dumpint(mstats()->total_alloc
);
493 dumpint(mstats()->sys
);
494 dumpint(mstats()->nlookup
);
495 dumpint(mstats()->nmalloc
);
496 dumpint(mstats()->nfree
);
497 dumpint(mstats()->heap_alloc
);
498 dumpint(mstats()->heap_sys
);
499 dumpint(mstats()->heap_idle
);
500 dumpint(mstats()->heap_inuse
);
501 dumpint(mstats()->heap_released
);
502 dumpint(mstats()->heap_objects
);
503 dumpint(mstats()->stacks_inuse
);
504 dumpint(mstats()->stacks_sys
);
505 dumpint(mstats()->mspan_inuse
);
506 dumpint(mstats()->mspan_sys
);
507 dumpint(mstats()->mcache_inuse
);
508 dumpint(mstats()->mcache_sys
);
509 dumpint(mstats()->buckhash_sys
);
510 dumpint(mstats()->gc_sys
);
511 dumpint(mstats()->other_sys
);
512 dumpint(mstats()->next_gc
);
513 dumpint(mstats()->last_gc
);
514 dumpint(mstats()->pause_total_ns
);
515 for(i
= 0; i
< 256; i
++)
516 dumpint(mstats()->pause_ns
[i
]);
517 dumpint(mstats()->numgc
);
521 dumpmemprof_callback(Bucket
*b
, uintptr nstk
, Location
*stk
, uintptr size
, uintptr allocs
, uintptr frees
)
530 for(i
= 0; i
< nstk
; i
++) {
532 if(stk
[i
].function
.len
== 0) {
533 runtime_snprintf(buf
, sizeof(buf
), "%X", (uint64
)pc
);
534 dumpcstr((int8
*)buf
);
535 dumpcstr((const int8
*)"?");
538 dumpstr(stk
[i
].function
);
539 dumpstr(stk
[i
].filename
);
540 dumpint(stk
[i
].lineno
);
547 static FuncVal dumpmemprof_callbackv
= {(void(*)(void))dumpmemprof_callback
};
552 MSpan
*s
, **allspans
;
558 runtime_iterate_memprof(&dumpmemprof_callbackv
);
560 allspans
= runtime_mheap
.allspans
;
561 for(spanidx
=0; spanidx
<runtime_mheap
.nspan
; spanidx
++) {
562 s
= allspans
[spanidx
];
563 if(s
->state
!= MSpanInUse
)
565 for(sp
= s
->specials
; sp
!= nil
; sp
= sp
->next
) {
566 if(sp
->kind
!= KindSpecialProfile
)
568 spp
= (SpecialProfile
*)sp
;
569 p
= (byte
*)((s
->start
<< PageShift
) + spp
->offset
);
570 dumpint(TagAllocSample
);
572 dumpint((uintptr
)spp
->b
);
584 // make sure we're done sweeping
585 for(i
= 0; i
< runtime_mheap
.nspan
; i
++) {
586 s
= runtime_mheap
.allspans
[i
];
587 if(s
->state
== MSpanInUse
)
588 runtime_MSpan_EnsureSwept(s
);
591 runtime_memclr((byte
*)&typecache
[0], sizeof(typecache
));
592 hdr
= (const byte
*)"go1.3 heap dump\n";
593 hwrite(hdr
, runtime_findnull(hdr
));
605 gp
->atomicstatus
= _Grunning
;
609 void runtime_debug_WriteHeapDump(uintptr
)
610 __asm__(GOSYM_PREFIX
"runtime_debug.WriteHeapDump");
613 runtime_debug_WriteHeapDump(uintptr fd
)
619 runtime_acquireWorldsema();
621 m
->preemptoff
= runtime_gostringnocopy((const byte
*)"write heap dump");
622 runtime_stopTheWorldWithSema();
624 // Update stats so we can dump them.
625 // As a side effect, flushes all the MCaches so the MSpan.freelist
626 // lists contain all the free objects.
627 runtime_updatememstats(nil
);
632 // Call dump routine on M stack.
634 g
->atomicstatus
= _Gwaiting
;
635 g
->waitreason
= runtime_gostringnocopy((const byte
*)"dumping heap");
636 runtime_mcall(mdump
);
641 // Start up the world again.
642 runtime_startTheWorldWithSema();
643 runtime_releaseWorldsema();
644 m
->preemptoff
= runtime_gostringnocopy(nil
);
647 // Runs the specified gc program. Calls the callback for every
648 // pointer-like field specified by the program and passes to the
649 // callback the kind and offset of that field within the object.
650 // offset is the offset in the object of the start of the program.
651 // Returns a pointer to the opcode that ended the gc program (either
652 // GC_END or GC_ARRAY_NEXT).
655 playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg)
657 uintptr len, elemsize, i, *end;
664 callback(arg, FieldKindPtr, offset + prog[1]);
668 callback(arg, FieldKindPtr, offset + prog[1]);
675 for(i = 0; i < len; i++) {
676 end = playgcprog(offset + prog[1] + i * elemsize, prog + 4, callback, arg);
677 if(end[0] != GC_ARRAY_NEXT)
678 runtime_throw("GC_ARRAY_START did not have matching GC_ARRAY_NEXT");
685 playgcprog(offset + prog[1], (uintptr*)((byte*)prog + *(int32*)&prog[2]), callback, arg);
689 callback(arg, FieldKindPtr, offset + prog[1]);
693 callback(arg, FieldKindString, offset + prog[1]);
697 callback(arg, FieldKindEface, offset + prog[1]);
701 callback(arg, FieldKindIface, offset + prog[1]);
705 callback(arg, FieldKindSlice, offset + prog[1]);
709 playgcprog(offset + prog[1], (uintptr*)prog[3] + 1, callback, arg);
713 runtime_printf("%D\n", (uint64)prog[0]);
714 runtime_throw("bad gc op");
720 dump_callback(void *p, uintptr kind, uintptr offset)
727 // dumpint() the kind & offset of each field in an object.
729 dumpfields(uintptr *prog)
731 playgcprog(0, prog, dump_callback, nil);
732 dumpint(FieldKindEol);
736 dumpeface_callback(void *p, uintptr kind, uintptr offset)
740 if(kind != FieldKindEface)
742 e = (Eface*)((byte*)p + offset);
743 dumptype(e->__type_descriptor);
747 // The heap dump reader needs to be able to disambiguate
748 // Eface entries. So it needs to know every type that might
749 // appear in such an entry. The following two routines accomplish
752 // Dump all the types that appear in the type field of
753 // any Eface contained in obj.
755 dumpefacetypes(void *obj
__attribute__ ((unused
)), uintptr size
, const Type
*type
, uintptr kind
)
760 case TypeInfo_SingleObject
:
761 //playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj);
764 for(i
= 0; i
<= size
- type
->__size
; i
+= type
->__size
) {
765 //playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
769 if(type
->__size
== 0) // channels may have zero-sized objects in them
771 for(i
= hchanSize
; i
<= size
- type
->__size
; i
+= type
->__size
) {
772 //playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);