summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/panic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/panic.c')
-rw-r--r--src/pkg/runtime/panic.c566
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");
-}