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  }