From e0aedfb496f414e1a869d27175b4dfcc6baef407 Mon Sep 17 00:00:00 2001 From: Rhys Hiltner Date: Tue, 25 Oct 2016 11:56:29 -0700 Subject: [PATCH] runtime: include pre-panic/throw logs in core dumps When a Go program crashes with GOTRACEBACK=crash, the OS creates a core dump. Include the text-formatted output of some of the cause of that crash in the core dump. Output printed by the runtime before crashing is maintained in a circular buffer to allow access to messages that may be printed immediately before calling runtime.throw. The stack traces printed by the runtime as it crashes are not stored. The information required to recreate them should be included in the core file. Updates #16893 There are no tests covering the generation of core dumps; this change has not added any. This adds (reentrant) locking to runtime.gwrite, which may have an undesired performance impact. Change-Id: Ia2463be3c12429354d290bdec5f3c8d565d1a2c3 Reviewed-on: https://go-review.googlesource.com/32013 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/runtime/print.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/runtime/print.go b/src/runtime/print.go index 5f82335244..8fa3d39905 100644 --- a/src/runtime/print.go +++ b/src/runtime/print.go @@ -4,7 +4,10 @@ package runtime -import "unsafe" +import ( + "runtime/internal/atomic" + "unsafe" +) // The compiler knows that a print of a value of this type // should use printhex instead of printuint (decimal). @@ -19,6 +22,36 @@ func bytes(s string) (ret []byte) { return } +var ( + // printBacklog is a circular buffer of messages written with the builtin + // print* functions, for use in postmortem analysis of core dumps. + printBacklog [512]byte + printBacklogIndex int +) + +// recordForPanic maintains a circular buffer of messages written by the +// runtime leading up to a process crash, allowing the messages to be +// extracted from a core dump. +// +// The text written during a process crash (following "panic" or "fatal +// error") is not saved, since the goroutine stacks will generally be readable +// from the runtime datastructures in the core file. +func recordForPanic(b []byte) { + printlock() + + if atomic.Load(&panicking) == 0 { + // Not actively crashing: maintain circular buffer of print output. + for i := 0; i < len(b); { + n := copy(printBacklog[printBacklogIndex:], b[i:]) + i += n + printBacklogIndex += n + printBacklogIndex %= len(printBacklog) + } + } + + printunlock() +} + var debuglock mutex // The compiler emits calls to printlock and printunlock around @@ -53,6 +86,7 @@ func gwrite(b []byte) { if len(b) == 0 { return } + recordForPanic(b) gp := getg() if gp == nil || gp.writebuf == nil { writeErr(b) -- 2.50.0