Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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 | |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 7 | // Code related to defer, panic and recover. |
| 8 | // TODO: Merge into panic.go. |
| 9 | |
| 10 | //uint32 runtime·panicking; |
| 11 | var paniclk mutex |
| 12 | |
Russ Cox | 09d92b6 | 2014-12-05 19:13:20 -0500 | [diff] [blame] | 13 | const hasLinkRegister = GOARCH == "arm" || GOARCH == "ppc64" || GOARCH == "ppc64le" |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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. |
Keith Randall | 53c5226 | 2014-12-08 14:18:58 -0800 | [diff] [blame] | 20 | sp := gp.sigcode0 |
| 21 | pc := gp.sigcode1 |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 22 | |
| 23 | // d's arguments need to be in the stack. |
Keith Randall | 53c5226 | 2014-12-08 14:18:58 -0800 | [diff] [blame] | 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") |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 26 | throw("bad recovery") |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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. |
Keith Randall | 53c5226 | 2014-12-08 14:18:58 -0800 | [diff] [blame] | 32 | gp.sched.sp = sp |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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 | |
Russ Cox | 656be31 | 2014-11-12 14:54:31 -0500 | [diff] [blame] | 85 | func dopanic_m(gp *g, pc, sp uintptr) { |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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 |
Russ Cox | 656be31 | 2014-11-12 14:54:31 -0500 | [diff] [blame] | 91 | _g_ := getg() |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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 | } |
Austin Clements | 28b5118 | 2015-01-30 15:30:41 -0500 | [diff] [blame] | 138 | if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 { |
Russ Cox | d98553a | 2014-11-11 17:04:34 -0500 | [diff] [blame] | 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 | } |