github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/debug/stack.go (about) 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 // SetCrashOutput configures a single additional file where unhandled 35 // panics and other fatal errors are printed, in addition to standard error. 36 // There is only one additional file: calling SetCrashOutput again overrides 37 // any earlier call. 38 // SetCrashOutput duplicates f's file descriptor, so the caller may safely 39 // close f as soon as SetCrashOutput returns. 40 // To disable this additional crash output, call SetCrashOutput(nil). 41 // If called concurrently with a crash, some in-progress output may be written 42 // to the old file even after an overriding SetCrashOutput returns. 43 func SetCrashOutput(f *os.File) error { 44 fd := ^uintptr(0) 45 if f != nil { 46 // The runtime will write to this file descriptor from 47 // low-level routines during a panic, possibly without 48 // a G, so we must call f.Fd() eagerly. This creates a 49 // danger that that the file descriptor is no longer 50 // valid at the time of the write, because the caller 51 // (incorrectly) called f.Close() and the kernel 52 // reissued the fd in a later call to open(2), leading 53 // to crashes being written to the wrong file. 54 // 55 // So, we duplicate the fd to obtain a private one 56 // that cannot be closed by the user. 57 // This also alleviates us from concerns about the 58 // lifetime and finalization of f. 59 // (DupCloseOnExec returns an fd, not a *File, so 60 // there is no finalizer, and we are responsible for 61 // closing it.) 62 // 63 // The new fd must be close-on-exec, otherwise if the 64 // crash monitor is a child process, it may inherit 65 // it, so it will never see EOF from the pipe even 66 // when this process crashes. 67 // 68 // A side effect of Fd() is that it calls SetBlocking, 69 // which is important so that writes of a crash report 70 // to a full pipe buffer don't get lost. 71 fd2, _, err := poll.DupCloseOnExec(int(f.Fd())) 72 if err != nil { 73 return err 74 } 75 runtime.KeepAlive(f) // prevent finalization before dup 76 fd = uintptr(fd2) 77 } 78 if prev := runtime_setCrashFD(fd); prev != ^uintptr(0) { 79 // We use NewFile+Close because it is portable 80 // unlike syscall.Close, whose parameter type varies. 81 os.NewFile(prev, "").Close() // ignore error 82 } 83 return nil 84 } 85 86 //go:linkname runtime_setCrashFD runtime.setCrashFD 87 func runtime_setCrashFD(uintptr) uintptr