blob: 4c0eb405859d201867aabfc1df6f3bff94ec9a41 [file] [log] [blame]
Russ Coxd98553a2014-11-11 17:04:34 -05001// 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
5package runtime
6
Russ Coxd98553a2014-11-11 17:04:34 -05007// Code related to defer, panic and recover.
8// TODO: Merge into panic.go.
9
10//uint32 runtime·panicking;
11var paniclk mutex
12
Russ Cox09d92b62014-12-05 19:13:20 -050013const hasLinkRegister = GOARCH == "arm" || GOARCH == "ppc64" || GOARCH == "ppc64le"
Russ Coxd98553a2014-11-11 17:04:34 -050014
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.
18func recovery(gp *g) {
19 // Info about defer passed in G struct.
Keith Randall53c52262014-12-08 14:18:58 -080020 sp := gp.sigcode0
21 pc := gp.sigcode1
Russ Coxd98553a2014-11-11 17:04:34 -050022
23 // d's arguments need to be in the stack.
Keith Randall53c52262014-12-08 14:18:58 -080024 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 Randallb2a950b2014-12-27 20:58:00 -080026 throw("bad recovery")
Russ Coxd98553a2014-11-11 17:04:34 -050027 }
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 Randall53c52262014-12-08 14:18:58 -080032 gp.sched.sp = sp
Russ Coxd98553a2014-11-11 17:04:34 -050033 gp.sched.pc = pc
34 gp.sched.lr = 0
35 gp.sched.ret = 1
36 gogo(&gp.sched)
37}
38
39func 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
82var didothers bool
83var deadlock mutex
84
Russ Cox656be312014-11-12 14:54:31 -050085func dopanic_m(gp *g, pc, sp uintptr) {
Russ Coxd98553a2014-11-11 17:04:34 -050086 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 Cox656be312014-11-12 14:54:31 -050091 _g_ := getg()
Russ Coxd98553a2014-11-11 17:04:34 -050092 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
125func 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 Clements28b51182015-01-30 15:30:41 -0500138 if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
Russ Coxd98553a2014-11-11 17:04:34 -0500139 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}