diff options
Diffstat (limited to 'src/pkg/runtime/panic.c')
-rw-r--r-- | src/pkg/runtime/panic.c | 566 |
1 files changed, 0 insertions, 566 deletions
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c deleted file mode 100644 index f577b37b5..000000000 --- a/src/pkg/runtime/panic.c +++ /dev/null @@ -1,566 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "arch_GOARCH.h" -#include "stack.h" -#include "malloc.h" -#include "../../cmd/ld/textflag.h" - -// Code related to defer, panic and recover. - -uint32 runtime·panicking; -static Lock paniclk; - -// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes. -// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header. -// This maps exactly to malloc size classes. - -// defer size class for arg size sz -#define DEFERCLASS(sz) (((sz)+7)>>4) -// total size of memory block for defer with arg size sz -#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr))) - -// Allocate a Defer, usually using per-P pool. -// Each defer must be released with freedefer. -static Defer* -newdefer(int32 siz) -{ - int32 total, sc; - Defer *d; - P *p; - - d = nil; - sc = DEFERCLASS(siz); - if(sc < nelem(p->deferpool)) { - p = m->p; - d = p->deferpool[sc]; - if(d) - p->deferpool[sc] = d->link; - } - if(d == nil) { - // deferpool is empty or just a big defer - total = TOTALSIZE(siz); - d = runtime·malloc(total); - } - d->siz = siz; - d->special = 0; - d->link = g->defer; - g->defer = d; - return d; -} - -// Free the given defer. -// The defer cannot be used after this call. -static void -freedefer(Defer *d) -{ - int32 sc; - P *p; - - if(d->special) - return; - sc = DEFERCLASS(d->siz); - if(sc < nelem(p->deferpool)) { - p = m->p; - d->link = p->deferpool[sc]; - p->deferpool[sc] = d; - // No need to wipe out pointers in argp/pc/fn/args, - // because we empty the pool before GC. - } else - runtime·free(d); -} - -// Create a new deferred function fn with siz bytes of arguments. -// The compiler turns a defer statement into a call to this. -// Cannot split the stack because it assumes that the arguments -// are available sequentially after &fn; they would not be -// copied if a stack split occurred. It's OK for this to call -// functions that split the stack. -#pragma textflag NOSPLIT -uintptr -runtime·deferproc(int32 siz, FuncVal *fn, ...) -{ - Defer *d; - - d = newdefer(siz); - d->fn = fn; - d->pc = runtime·getcallerpc(&siz); - if(thechar == '5') - d->argp = (byte*)(&fn+2); // skip caller's saved link register - else - d->argp = (byte*)(&fn+1); - runtime·memmove(d->args, d->argp, d->siz); - - // deferproc returns 0 normally. - // a deferred func that stops a panic - // makes the deferproc return 1. - // the code the compiler generates always - // checks the return value and jumps to the - // end of the function if deferproc returns != 0. - return 0; -} - -// Run a deferred function if there is one. -// The compiler inserts a call to this at the end of any -// function which calls defer. -// If there is a deferred function, this will call runtime·jmpdefer, -// which will jump to the deferred function such that it appears -// to have been called by the caller of deferreturn at the point -// just before deferreturn was called. The effect is that deferreturn -// is called again and again until there are no more deferred functions. -// Cannot split the stack because we reuse the caller's frame to -// call the deferred function. - -// The single argument isn't actually used - it just has its address -// taken so it can be matched against pending defers. -#pragma textflag NOSPLIT -void -runtime·deferreturn(uintptr arg0) -{ - Defer *d; - byte *argp; - FuncVal *fn; - - d = g->defer; - if(d == nil) - return; - argp = (byte*)&arg0; - if(d->argp != argp) - return; - - // Moving arguments around. - // Do not allow preemption here, because the garbage collector - // won't know the form of the arguments until the jmpdefer can - // flip the PC over to fn. - m->locks++; - runtime·memmove(argp, d->args, d->siz); - fn = d->fn; - g->defer = d->link; - freedefer(d); - m->locks--; - if(m->locks == 0 && g->preempt) - g->stackguard0 = StackPreempt; - runtime·jmpdefer(fn, argp); -} - -// Ensure that defer arg sizes that map to the same defer size class -// also map to the same malloc size class. -void -runtime·testdefersizes(void) -{ - P *p; - int32 i, siz, defersc, mallocsc; - int32 map[nelem(p->deferpool)]; - - for(i=0; i<nelem(p->deferpool); i++) - map[i] = -1; - for(i=0;; i++) { - defersc = DEFERCLASS(i); - if(defersc >= nelem(p->deferpool)) - break; - siz = TOTALSIZE(i); - mallocsc = runtime·SizeToClass(siz); - siz = runtime·class_to_size[mallocsc]; - // runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc); - if(map[defersc] < 0) { - map[defersc] = mallocsc; - continue; - } - if(map[defersc] != mallocsc) { - runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n", - i, siz, map[defersc], mallocsc); - runtime·throw("bad defer size class"); - } - } -} - -// Run all deferred functions for the current goroutine. -static void -rundefer(void) -{ - Defer *d; - - while((d = g->defer) != nil) { - g->defer = d->link; - reflect·call(d->fn, (byte*)d->args, d->siz, d->siz); - freedefer(d); - } -} - -// Print all currently active panics. Used when crashing. -static void -printpanics(Panic *p) -{ - if(p->link) { - printpanics(p->link); - runtime·printf("\t"); - } - runtime·printf("panic: "); - runtime·printany(p->arg); - if(p->recovered) - runtime·printf(" [recovered]"); - runtime·printf("\n"); -} - -static void recovery(G*); -static void abortpanic(Panic*); -static FuncVal abortpanicV = { (void(*)(void))abortpanic }; - -// The implementation of the predeclared function panic. -void -runtime·panic(Eface e) -{ - Defer *d, dabort; - Panic p; - void *pc, *argp; - - runtime·memclr((byte*)&p, sizeof p); - p.arg = e; - p.link = g->panic; - p.stackbase = g->stackbase; - g->panic = &p; - - dabort.fn = &abortpanicV; - dabort.siz = sizeof(&p); - dabort.args[0] = &p; - dabort.argp = NoArgs; - dabort.special = true; - - for(;;) { - d = g->defer; - if(d == nil) - break; - // take defer off list in case of recursive panic - g->defer = d->link; - g->ispanic = true; // rock for runtime·newstack, where runtime·newstackcall ends up - argp = d->argp; - pc = d->pc; - - // The deferred function may cause another panic, - // so newstackcall may not return. Set up a defer - // to mark this panic aborted if that happens. - dabort.link = g->defer; - g->defer = &dabort; - p.defer = d; - - runtime·newstackcall(d->fn, (byte*)d->args, d->siz); - - // Newstackcall did not panic. Remove dabort. - if(g->defer != &dabort) - runtime·throw("bad defer entry in panic"); - g->defer = dabort.link; - - freedefer(d); - if(p.recovered) { - g->panic = p.link; - // Aborted panics are marked but remain on the g->panic list. - // Recovery will unwind the stack frames containing their Panic structs. - // Remove them from the list and free the associated defers. - while(g->panic && g->panic->aborted) { - freedefer(g->panic->defer); - g->panic = g->panic->link; - } - if(g->panic == nil) // must be done with signal - g->sig = 0; - // Pass information about recovering frame to recovery. - g->sigcode0 = (uintptr)argp; - g->sigcode1 = (uintptr)pc; - runtime·mcall(recovery); - runtime·throw("recovery failed"); // mcall should not return - } - } - - // ran out of deferred calls - old-school panic now - runtime·startpanic(); - printpanics(g->panic); - runtime·dopanic(0); // should not return - runtime·exit(1); // not reached -} - -static void -abortpanic(Panic *p) -{ - p->aborted = true; -} - -// Unwind the stack after a deferred function calls recover -// after a panic. Then arrange to continue running as though -// the caller of the deferred function returned normally. -static void -recovery(G *gp) -{ - void *argp; - uintptr pc; - - // Info about defer passed in G struct. - argp = (void*)gp->sigcode0; - pc = (uintptr)gp->sigcode1; - - // Unwind to the stack frame with d's arguments in it. - runtime·unwindstack(gp, argp); - - // Make the deferproc for this d return again, - // this time returning 1. The calling function will - // jump to the standard return epilogue. - // The -2*sizeof(uintptr) makes up for the - // two extra words that are on the stack at - // each call to deferproc. - // (The pc we're returning to does pop pop - // before it tests the return value.) - // On the arm there are 2 saved LRs mixed in too. - if(thechar == '5') - gp->sched.sp = (uintptr)argp - 4*sizeof(uintptr); - else - gp->sched.sp = (uintptr)argp - 2*sizeof(uintptr); - gp->sched.pc = pc; - gp->sched.lr = 0; - gp->sched.ret = 1; - runtime·gogo(&gp->sched); -} - -// Free stack frames until we hit the last one -// or until we find the one that contains the sp. -void -runtime·unwindstack(G *gp, byte *sp) -{ - Stktop *top; - byte *stk; - - // Must be called from a different goroutine, usually m->g0. - if(g == gp) - runtime·throw("unwindstack on self"); - - while((top = (Stktop*)gp->stackbase) != 0 && top->stackbase != 0) { - stk = (byte*)gp->stackguard - StackGuard; - if(stk <= sp && sp < (byte*)gp->stackbase) - break; - gp->stackbase = top->stackbase; - gp->stackguard = top->stackguard; - gp->stackguard0 = gp->stackguard; - runtime·stackfree(gp, stk, top); - } - - if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) { - runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase); - runtime·throw("bad unwindstack"); - } -} - -// The implementation of the predeclared function recover. -// Cannot split the stack because it needs to reliably -// find the stack segment of its caller. -#pragma textflag NOSPLIT -void -runtime·recover(byte *argp, GoOutput retbase, ...) -{ - Panic *p; - Stktop *top; - Eface *ret; - - // Must be an unrecovered panic in progress. - // Must be on a stack segment created for a deferred call during a panic. - // Must be at the top of that segment, meaning the deferred call itself - // and not something it called. The top frame in the segment will have - // argument pointer argp == top - top->argsize. - // The subtraction of g->panicwrap allows wrapper functions that - // do not count as official calls to adjust what we consider the top frame - // while they are active on the stack. The linker emits adjustments of - // g->panicwrap in the prologue and epilogue of functions marked as wrappers. - ret = (Eface*)&retbase; - top = (Stktop*)g->stackbase; - p = g->panic; - if(p != nil && !p->recovered && top->panic && argp == (byte*)top - top->argsize - g->panicwrap) { - p->recovered = 1; - *ret = p->arg; - } else { - ret->type = nil; - ret->data = nil; - } -} - -void -runtime·startpanic(void) -{ - if(runtime·mheap.cachealloc.size == 0) { // very early - runtime·printf("runtime: panic before malloc heap initialized\n"); - m->mallocing = 1; // tell rest of panic not to try to malloc - } else if(m->mcache == nil) // can happen if called from signal handler or throw - m->mcache = runtime·allocmcache(); - switch(m->dying) { - case 0: - m->dying = 1; - if(g != nil) - g->writebuf = nil; - runtime·xadd(&runtime·panicking, 1); - runtime·lock(&paniclk); - if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0) - runtime·schedtrace(true); - runtime·freezetheworld(); - return; - case 1: - // Something failed while panicing, probably the print of the - // argument to panic(). Just print a stack trace and exit. - m->dying = 2; - runtime·printf("panic during panic\n"); - runtime·dopanic(0); - runtime·exit(3); - case 2: - // This is a genuine bug in the runtime, we couldn't even - // print the stack trace successfully. - m->dying = 3; - runtime·printf("stack trace unavailable\n"); - runtime·exit(4); - default: - // Can't even print! Just exit. - runtime·exit(5); - } -} - -void -runtime·dopanic(int32 unused) -{ - static bool didothers; - bool crash; - int32 t; - - if(g->sig != 0) - runtime·printf("[signal %x code=%p addr=%p pc=%p]\n", - g->sig, g->sigcode0, g->sigcode1, g->sigpc); - - if((t = runtime·gotraceback(&crash)) > 0){ - if(g != m->g0) { - runtime·printf("\n"); - runtime·goroutineheader(g); - runtime·traceback((uintptr)runtime·getcallerpc(&unused), (uintptr)runtime·getcallersp(&unused), 0, g); - } else if(t >= 2 || m->throwing > 0) { - runtime·printf("\nruntime stack:\n"); - runtime·traceback((uintptr)runtime·getcallerpc(&unused), (uintptr)runtime·getcallersp(&unused), 0, g); - } - if(!didothers) { - didothers = true; - runtime·tracebackothers(g); - } - } - runtime·unlock(&paniclk); - if(runtime·xadd(&runtime·panicking, -1) != 0) { - // Some other m is panicking too. - // Let it print what it needs to print. - // Wait forever without chewing up cpu. - // It will exit when it's done. - static Lock deadlock; - runtime·lock(&deadlock); - runtime·lock(&deadlock); - } - - if(crash) - runtime·crash(); - - runtime·exit(2); -} - -void -runtime·panicindex(void) -{ - runtime·panicstring("index out of range"); -} - -void -runtime·panicslice(void) -{ - runtime·panicstring("slice bounds out of range"); -} - -void -runtime·throwreturn(void) -{ - // can only happen if compiler is broken - runtime·throw("no return at end of a typed function - compiler is broken"); -} - -void -runtime·throwinit(void) -{ - // can only happen with linker skew - runtime·throw("recursive call during initialization - linker skew"); -} - -bool -runtime·canpanic(G *gp) -{ - byte g; - - USED(&g); // don't use global g, it points to gsignal - - // Is it okay for gp to panic instead of crashing the program? - // Yes, as long as it is running Go code, not runtime code, - // and not stuck in a system call. - if(gp == nil || gp != m->curg) - return false; - if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0) - return false; - if(gp->status != Grunning || gp->syscallsp != 0) - return false; -#ifdef GOOS_windows - if(m->libcallsp != 0) - return false; -#endif - return true; -} - -void -runtime·throw(int8 *s) -{ - if(m->throwing == 0) - m->throwing = 1; - runtime·startpanic(); - runtime·printf("fatal error: %s\n", s); - runtime·dopanic(0); - *(int32*)0 = 0; // not reached - runtime·exit(1); // even more not reached -} - -void -runtime·panicstring(int8 *s) -{ - Eface err; - - // m->softfloat is set during software floating point, - // which might cause a fault during a memory load. - // It increments m->locks to avoid preemption. - // If we're panicking, the software floating point frames - // will be unwound, so decrement m->locks as they would. - if(m->softfloat) { - m->locks--; - m->softfloat = 0; - } - - if(m->mallocing) { - runtime·printf("panic: %s\n", s); - runtime·throw("panic during malloc"); - } - if(m->gcing) { - runtime·printf("panic: %s\n", s); - runtime·throw("panic during gc"); - } - if(m->locks) { - runtime·printf("panic: %s\n", s); - runtime·throw("panic holding locks"); - } - runtime·newErrorCString(s, &err); - runtime·panic(err); -} - -void -runtime·Goexit(void) -{ - rundefer(); - runtime·goexit(); -} - -void -runtime·panicdivide(void) -{ - runtime·panicstring("integer divide by zero"); -} |