github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/runtime/panic1.go (about) 1 // Copyright 2012 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 runtime 6 7 // Code related to defer, panic and recover. 8 // TODO: Merge into panic.go. 9 10 //uint32 runtime·panicking; 11 var paniclk mutex 12 13 const hasLinkRegister = GOARCH == "arm" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le" 14 15 // Unwind the stack after a deferred function calls recover 16 // after a panic. Then arrange to continue running as though 17 // the caller of the deferred function returned normally. 18 func recovery(gp *g) { 19 // Info about defer passed in G struct. 20 sp := gp.sigcode0 21 pc := gp.sigcode1 22 23 // d's arguments need to be in the stack. 24 if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) { 25 print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n") 26 throw("bad recovery") 27 } 28 29 // Make the deferproc for this d return again, 30 // this time returning 1. The calling function will 31 // jump to the standard return epilogue. 32 gp.sched.sp = sp 33 gp.sched.pc = pc 34 gp.sched.lr = 0 35 gp.sched.ret = 1 36 gogo(&gp.sched) 37 } 38 39 func startpanic_m() { 40 _g_ := getg() 41 if mheap_.cachealloc.size == 0 { // very early 42 print("runtime: panic before malloc heap initialized\n") 43 _g_.m.mallocing = 1 // tell rest of panic not to try to malloc 44 } else if _g_.m.mcache == nil { // can happen if called from signal handler or throw 45 _g_.m.mcache = allocmcache() 46 } 47 48 switch _g_.m.dying { 49 case 0: 50 _g_.m.dying = 1 51 if _g_ != nil { 52 _g_.writebuf = nil 53 } 54 xadd(&panicking, 1) 55 lock(&paniclk) 56 if debug.schedtrace > 0 || debug.scheddetail > 0 { 57 schedtrace(true) 58 } 59 freezetheworld() 60 return 61 case 1: 62 // Something failed while panicing, probably the print of the 63 // argument to panic(). Just print a stack trace and exit. 64 _g_.m.dying = 2 65 print("panic during panic\n") 66 dopanic(0) 67 exit(3) 68 fallthrough 69 case 2: 70 // This is a genuine bug in the runtime, we couldn't even 71 // print the stack trace successfully. 72 _g_.m.dying = 3 73 print("stack trace unavailable\n") 74 exit(4) 75 fallthrough 76 default: 77 // Can't even print! Just exit. 78 exit(5) 79 } 80 } 81 82 var didothers bool 83 var deadlock mutex 84 85 func dopanic_m(gp *g, pc, sp uintptr) { 86 if gp.sig != 0 { 87 print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n") 88 } 89 90 var docrash bool 91 _g_ := getg() 92 if t := gotraceback(&docrash); t > 0 { 93 if gp != gp.m.g0 { 94 print("\n") 95 goroutineheader(gp) 96 traceback(pc, sp, 0, gp) 97 } else if t >= 2 || _g_.m.throwing > 0 { 98 print("\nruntime stack:\n") 99 traceback(pc, sp, 0, gp) 100 } 101 if !didothers { 102 didothers = true 103 tracebackothers(gp) 104 } 105 } 106 unlock(&paniclk) 107 108 if xadd(&panicking, -1) != 0 { 109 // Some other m is panicking too. 110 // Let it print what it needs to print. 111 // Wait forever without chewing up cpu. 112 // It will exit when it's done. 113 lock(&deadlock) 114 lock(&deadlock) 115 } 116 117 if docrash { 118 crash() 119 } 120 121 exit(2) 122 } 123 124 //go:nosplit 125 func canpanic(gp *g) bool { 126 // Note that g is m->gsignal, different from gp. 127 // Note also that g->m can change at preemption, so m can go stale 128 // if this function ever makes a function call. 129 _g_ := getg() 130 _m_ := _g_.m 131 132 // Is it okay for gp to panic instead of crashing the program? 133 // Yes, as long as it is running Go code, not runtime code, 134 // and not stuck in a system call. 135 if gp == nil || gp != _m_.curg { 136 return false 137 } 138 if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 { 139 return false 140 } 141 status := readgstatus(gp) 142 if status&^_Gscan != _Grunning || gp.syscallsp != 0 { 143 return false 144 } 145 if GOOS == "windows" && _m_.libcallsp != 0 { 146 return false 147 } 148 return true 149 }