1
0
mirror of https://github.com/golang/go synced 2024-09-30 02:14:29 -06:00

runtime/debug: add SetTraceback

Programs that call panic to crash after detecting a serious problem
may wish to use SetTraceback to force printing of all goroutines first.

Change-Id: Ib23ad9336f405485aabb642ca73f454a14c8baf3
Reviewed-on: https://go-review.googlesource.com/18043
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Russ Cox 2015-12-18 11:19:38 -05:00
parent ea5b9d5bd3
commit bb0567b304
3 changed files with 50 additions and 22 deletions

View File

@ -157,3 +157,14 @@ func SetPanicOnFault(enabled bool) bool {
// it to the given file descriptor.
// The heap dump format is defined at https://golang.org/s/go13heapdump.
func WriteHeapDump(fd uintptr)
// SetTraceback sets the amount of detail printed by the runtime in
// the traceback it prints before exiting due to an unrecovered panic
// or an internal runtime error.
// The level argument takes the same values as the GOTRACEBACK
// environment variable. For example, SetTraceback("all") ensure
// that the program prints all goroutines when it crashes.
// See the package runtime documentation for details.
// If SetTraceback is called with a level lower than that of the
// environment variable, the call is ignored.
func SetTraceback(level string)

View File

@ -127,6 +127,10 @@ manner instead of exiting. For example, on Unix systems, the crash raises
SIGABRT to trigger a core dump.
For historical reasons, the GOTRACEBACK settings 0, 1, and 2 are synonyms for
none, all, and system, respectively.
The runtime/debug package's SetTraceback function allows increasing the
amount of output at run time, but it cannot reduce the amount below that
specified by the environment variable.
See https://golang.org/pkg/runtime/debug/#SetTraceback.
The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
the set of Go environment variables. They influence the building of Go programs

View File

@ -22,6 +22,7 @@ const (
)
var traceback_cache uint32 = 2 << tracebackShift
var traceback_env uint32
// gotraceback returns the current traceback settings.
//
@ -39,9 +40,10 @@ func gotraceback() (level int32, all, crash bool) {
level = int32(_g_.m.traceback)
return
}
crash = traceback_cache&tracebackCrash != 0
all = all || traceback_cache&tracebackAll != 0
level = int32(traceback_cache >> tracebackShift)
t := atomic.Load(&traceback_cache)
crash = t&tracebackCrash != 0
all = all || t&tracebackAll != 0
level = int32(t >> tracebackShift)
return
}
@ -382,25 +384,8 @@ func parsedebugvars() {
}
}
switch p := gogetenv("GOTRACEBACK"); p {
case "none":
traceback_cache = 0
case "single", "":
traceback_cache = 1 << tracebackShift
case "all":
traceback_cache = 1<<tracebackShift | tracebackAll
case "system":
traceback_cache = 2<<tracebackShift | tracebackAll
case "crash":
traceback_cache = 2<<tracebackShift | tracebackAll | tracebackCrash
default:
traceback_cache = uint32(atoi(p))<<tracebackShift | tracebackAll
}
// when C owns the process, simply exit'ing the process on fatal errors
// and panics is surprising. Be louder and abort instead.
if islibrary || isarchive {
traceback_cache |= tracebackCrash
}
setTraceback(gogetenv("GOTRACEBACK"))
traceback_env = traceback_cache
if debug.gcstackbarrierall > 0 {
firstStackBarrierOffset = 0
@ -414,6 +399,34 @@ func parsedebugvars() {
}
}
//go:linkname setTraceback runtime/debug.SetTraceback
func setTraceback(level string) {
var t uint32
switch level {
case "none":
t = 0
case "single", "":
t = 1 << tracebackShift
case "all":
t = 1<<tracebackShift | tracebackAll
case "system":
t = 2<<tracebackShift | tracebackAll
case "crash":
t = 2<<tracebackShift | tracebackAll | tracebackCrash
default:
t = uint32(atoi(level))<<tracebackShift | tracebackAll
}
// when C owns the process, simply exit'ing the process on fatal errors
// and panics is surprising. Be louder and abort instead.
if islibrary || isarchive {
t |= tracebackCrash
}
t |= traceback_env
atomic.Store(&traceback_cache, t)
}
// Poor mans 64-bit division.
// This is a very special function, do not use it if you are not sure what you are doing.
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.