1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package debug contains facilities for programs to debug themselves while
6 // they are running.
7 package debug
8
9 import (
10 "internal/poll"
11 "os"
12 "runtime"
13 _ "unsafe" // for linkname
14 )
15
16 // PrintStack prints to standard error the stack trace returned by [runtime.Stack].
17 func PrintStack() {
18 os.Stderr.Write(Stack())
19 }
20
21 // Stack returns a formatted stack trace of the goroutine that calls it.
22 // It calls [runtime.Stack] with a large enough buffer to capture the entire trace.
23 func Stack() []byte {
24 buf := make([]byte, 1024)
25 for {
26 n := runtime.Stack(buf, false)
27 if n < len(buf) {
28 return buf[:n]
29 }
30 buf = make([]byte, 2*len(buf))
31 }
32 }
33
34 // CrashOptions provides options that control the formatting of the
35 // fatal crash message.
36 type CrashOptions struct {
37 /* for future expansion */
38 }
39
40 // SetCrashOutput configures a single additional file where unhandled
41 // panics and other fatal errors are printed, in addition to standard error.
42 // There is only one additional file: calling SetCrashOutput again overrides
43 // any earlier call.
44 // SetCrashOutput duplicates f's file descriptor, so the caller may safely
45 // close f as soon as SetCrashOutput returns.
46 // To disable this additional crash output, call SetCrashOutput(nil).
47 // If called concurrently with a crash, some in-progress output may be written
48 // to the old file even after an overriding SetCrashOutput returns.
49 func SetCrashOutput(f *os.File, opts CrashOptions) error {
50 fd := ^uintptr(0)
51 if f != nil {
52 // The runtime will write to this file descriptor from
53 // low-level routines during a panic, possibly without
54 // a G, so we must call f.Fd() eagerly. This creates a
55 // danger that the file descriptor is no longer
56 // valid at the time of the write, because the caller
57 // (incorrectly) called f.Close() and the kernel
58 // reissued the fd in a later call to open(2), leading
59 // to crashes being written to the wrong file.
60 //
61 // So, we duplicate the fd to obtain a private one
62 // that cannot be closed by the user.
63 // This also alleviates us from concerns about the
64 // lifetime and finalization of f.
65 // (DupCloseOnExec returns an fd, not a *File, so
66 // there is no finalizer, and we are responsible for
67 // closing it.)
68 //
69 // The new fd must be close-on-exec, otherwise if the
70 // crash monitor is a child process, it may inherit
71 // it, so it will never see EOF from the pipe even
72 // when this process crashes.
73 //
74 // A side effect of Fd() is that it calls SetBlocking,
75 // which is important so that writes of a crash report
76 // to a full pipe buffer don't get lost.
77 fd2, _, err := poll.DupCloseOnExec(int(f.Fd()))
78 if err != nil {
79 return err
80 }
81 runtime.KeepAlive(f) // prevent finalization before dup
82 fd = uintptr(fd2)
83 }
84 if prev := runtime_setCrashFD(fd); prev != ^uintptr(0) {
85 // We use NewFile+Close because it is portable
86 // unlike syscall.Close, whose parameter type varies.
87 os.NewFile(prev, "").Close() // ignore error
88 }
89 return nil
90 }
91
92 //go:linkname runtime_setCrashFD runtime.setCrashFD
93 func runtime_setCrashFD(uintptr) uintptr
94
View as plain text