mirror of https://go.googlesource.com/go
94 lines
3.2 KiB
Go
94 lines
3.2 KiB
Go
// Copyright 2011 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.
|
|
|
|
// Package debug contains facilities for programs to debug themselves while
|
|
// they are running.
|
|
package debug
|
|
|
|
import (
|
|
"internal/poll"
|
|
"os"
|
|
"runtime"
|
|
_ "unsafe" // for linkname
|
|
)
|
|
|
|
// PrintStack prints to standard error the stack trace returned by runtime.Stack.
|
|
func PrintStack() {
|
|
os.Stderr.Write(Stack())
|
|
}
|
|
|
|
// Stack returns a formatted stack trace of the goroutine that calls it.
|
|
// It calls [runtime.Stack] with a large enough buffer to capture the entire trace.
|
|
func Stack() []byte {
|
|
buf := make([]byte, 1024)
|
|
for {
|
|
n := runtime.Stack(buf, false)
|
|
if n < len(buf) {
|
|
return buf[:n]
|
|
}
|
|
buf = make([]byte, 2*len(buf))
|
|
}
|
|
}
|
|
|
|
// CrashOptions provides options that control the formatting of the
|
|
// fatal crash message.
|
|
type CrashOptions struct {
|
|
/* for future expansion */
|
|
}
|
|
|
|
// SetCrashOutput configures a single additional file where unhandled
|
|
// panics and other fatal errors are printed, in addition to standard error.
|
|
// There is only one additional file: calling SetCrashOutput again overrides
|
|
// any earlier call.
|
|
// SetCrashOutput duplicates f's file descriptor, so the caller may safely
|
|
// close f as soon as SetCrashOutput returns.
|
|
// To disable this additional crash output, call SetCrashOutput(nil).
|
|
// If called concurrently with a crash, some in-progress output may be written
|
|
// to the old file even after an overriding SetCrashOutput returns.
|
|
func SetCrashOutput(f *os.File, opts CrashOptions) error {
|
|
fd := ^uintptr(0)
|
|
if f != nil {
|
|
// The runtime will write to this file descriptor from
|
|
// low-level routines during a panic, possibly without
|
|
// a G, so we must call f.Fd() eagerly. This creates a
|
|
// danger that that the file descriptor is no longer
|
|
// valid at the time of the write, because the caller
|
|
// (incorrectly) called f.Close() and the kernel
|
|
// reissued the fd in a later call to open(2), leading
|
|
// to crashes being written to the wrong file.
|
|
//
|
|
// So, we duplicate the fd to obtain a private one
|
|
// that cannot be closed by the user.
|
|
// This also alleviates us from concerns about the
|
|
// lifetime and finalization of f.
|
|
// (DupCloseOnExec returns an fd, not a *File, so
|
|
// there is no finalizer, and we are responsible for
|
|
// closing it.)
|
|
//
|
|
// The new fd must be close-on-exec, otherwise if the
|
|
// crash monitor is a child process, it may inherit
|
|
// it, so it will never see EOF from the pipe even
|
|
// when this process crashes.
|
|
//
|
|
// A side effect of Fd() is that it calls SetBlocking,
|
|
// which is important so that writes of a crash report
|
|
// to a full pipe buffer don't get lost.
|
|
fd2, _, err := poll.DupCloseOnExec(int(f.Fd()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runtime.KeepAlive(f) // prevent finalization before dup
|
|
fd = uintptr(fd2)
|
|
}
|
|
if prev := runtime_setCrashFD(fd); prev != ^uintptr(0) {
|
|
// We use NewFile+Close because it is portable
|
|
// unlike syscall.Close, whose parameter type varies.
|
|
os.NewFile(prev, "").Close() // ignore error
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//go:linkname runtime_setCrashFD runtime.setCrashFD
|
|
func runtime_setCrashFD(uintptr) uintptr
|