| // 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"); |
| } |