| // 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 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 | |