Home | History | Annotate | Download | only in runtime
      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 runtimepanicking;
     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 	gcUnwindBarriers(gp, sp)
     33 	gp.sched.sp = sp
     34 	gp.sched.pc = pc
     35 	gp.sched.lr = 0
     36 	gp.sched.ret = 1
     37 	gogo(&gp.sched)
     38 }
     39 
     40 func startpanic_m() {
     41 	_g_ := getg()
     42 	if mheap_.cachealloc.size == 0 { // very early
     43 		print("runtime: panic before malloc heap initialized\n")
     44 		_g_.m.mallocing = 1 // tell rest of panic not to try to malloc
     45 	} else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
     46 		_g_.m.mcache = allocmcache()
     47 	}
     48 
     49 	switch _g_.m.dying {
     50 	case 0:
     51 		_g_.m.dying = 1
     52 		if _g_ != nil {
     53 			_g_.writebuf = nil
     54 		}
     55 		xadd(&panicking, 1)
     56 		lock(&paniclk)
     57 		if debug.schedtrace > 0 || debug.scheddetail > 0 {
     58 			schedtrace(true)
     59 		}
     60 		freezetheworld()
     61 		return
     62 	case 1:
     63 		// Something failed while panicing, probably the print of the
     64 		// argument to panic().  Just print a stack trace and exit.
     65 		_g_.m.dying = 2
     66 		print("panic during panic\n")
     67 		dopanic(0)
     68 		exit(3)
     69 		fallthrough
     70 	case 2:
     71 		// This is a genuine bug in the runtime, we couldn't even
     72 		// print the stack trace successfully.
     73 		_g_.m.dying = 3
     74 		print("stack trace unavailable\n")
     75 		exit(4)
     76 		fallthrough
     77 	default:
     78 		// Can't even print!  Just exit.
     79 		exit(5)
     80 	}
     81 }
     82 
     83 var didothers bool
     84 var deadlock mutex
     85 
     86 func dopanic_m(gp *g, pc, sp uintptr) {
     87 	if gp.sig != 0 {
     88 		print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
     89 	}
     90 
     91 	var docrash bool
     92 	_g_ := getg()
     93 	if t := gotraceback(&docrash); t > 0 {
     94 		if gp != gp.m.g0 {
     95 			print("\n")
     96 			goroutineheader(gp)
     97 			traceback(pc, sp, 0, gp)
     98 		} else if t >= 2 || _g_.m.throwing > 0 {
     99 			print("\nruntime stack:\n")
    100 			traceback(pc, sp, 0, gp)
    101 		}
    102 		if !didothers {
    103 			didothers = true
    104 			tracebackothers(gp)
    105 		}
    106 	}
    107 	unlock(&paniclk)
    108 
    109 	if xadd(&panicking, -1) != 0 {
    110 		// Some other m is panicking too.
    111 		// Let it print what it needs to print.
    112 		// Wait forever without chewing up cpu.
    113 		// It will exit when it's done.
    114 		lock(&deadlock)
    115 		lock(&deadlock)
    116 	}
    117 
    118 	if docrash {
    119 		crash()
    120 	}
    121 
    122 	exit(2)
    123 }
    124 
    125 //go:nosplit
    126 func canpanic(gp *g) bool {
    127 	// Note that g is m->gsignal, different from gp.
    128 	// Note also that g->m can change at preemption, so m can go stale
    129 	// if this function ever makes a function call.
    130 	_g_ := getg()
    131 	_m_ := _g_.m
    132 
    133 	// Is it okay for gp to panic instead of crashing the program?
    134 	// Yes, as long as it is running Go code, not runtime code,
    135 	// and not stuck in a system call.
    136 	if gp == nil || gp != _m_.curg {
    137 		return false
    138 	}
    139 	if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
    140 		return false
    141 	}
    142 	status := readgstatus(gp)
    143 	if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
    144 		return false
    145 	}
    146 	if GOOS == "windows" && _m_.libcallsp != 0 {
    147 		return false
    148 	}
    149 	return true
    150 }
    151