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