This source file includes following definitions.
- newdefer
- freedefer
- runtime·deferproc
- runtime·deferreturn
- runtime·testdefersizes
- rundefer
- printpanics
- runtime·panic
- abortpanic
- recovery
- runtime·unwindstack
- runtime·recover
- runtime·startpanic
- runtime·dopanic
- runtime·panicindex
- runtime·panicslice
- runtime·throwreturn
- runtime·throwinit
- runtime·canpanic
- runtime·throw
- runtime·panicstring
- runtime·Goexit
- runtime·panicdivide
#include "runtime.h"
#include "arch_GOARCH.h"
#include "stack.h"
#include "malloc.h"
#include "../../cmd/ld/textflag.h"
uint32 runtime·panicking;
static Lock paniclk;
#define DEFERCLASS(sz) (((sz)+7)>>4)
#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
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) {
total = TOTALSIZE(siz);
d = runtime·malloc(total);
}
d->siz = siz;
d->special = 0;
d->link = g->defer;
g->defer = d;
return d;
}
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;
} else
runtime·free(d);
}
#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);
else
d->argp = (byte*)(&fn+1);
runtime·memmove(d->args, d->argp, d->siz);
return 0;
}
#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;
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);
}
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];
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");
}
}
}
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);
}
}
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 };
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;
g->defer = d->link;
g->ispanic = true;
argp = d->argp;
pc = d->pc;
dabort.link = g->defer;
g->defer = &dabort;
p.defer = d;
runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
if(g->defer != &dabort)
runtime·throw("bad defer entry in panic");
g->defer = dabort.link;
freedefer(d);
if(p.recovered) {
g->panic = p.link;
while(g->panic && g->panic->aborted) {
freedefer(g->panic->defer);
g->panic = g->panic->link;
}
if(g->panic == nil)
g->sig = 0;
g->sigcode0 = (uintptr)argp;
g->sigcode1 = (uintptr)pc;
runtime·mcall(recovery);
runtime·throw("recovery failed");
}
}
runtime·startpanic();
printpanics(g->panic);
runtime·dopanic(0);
runtime·exit(1);
}
static void
abortpanic(Panic *p)
{
p->aborted = true;
}
static void
recovery(G *gp)
{
void *argp;
uintptr pc;
argp = (void*)gp->sigcode0;
pc = (uintptr)gp->sigcode1;
runtime·unwindstack(gp, argp);
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);
}
void
runtime·unwindstack(G *gp, byte *sp)
{
Stktop *top;
byte *stk;
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");
}
}
#pragma textflag NOSPLIT
void
runtime·recover(byte *argp, GoOutput retbase, ...)
{
Panic *p;
Stktop *top;
Eface *ret;
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) {
runtime·printf("runtime: panic before malloc heap initialized\n");
m->mallocing = 1;
} else if(m->mcache == nil)
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:
m->dying = 2;
runtime·printf("panic during panic\n");
runtime·dopanic(0);
runtime·exit(3);
case 2:
m->dying = 3;
runtime·printf("stack trace unavailable\n");
runtime·exit(4);
default:
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) {
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)
{
runtime·throw("no return at end of a typed function - compiler is broken");
}
void
runtime·throwinit(void)
{
runtime·throw("recursive call during initialization - linker skew");
}
bool
runtime·canpanic(G *gp)
{
byte g;
USED(&g);
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;
runtime·exit(1);
}
void
runtime·panicstring(int8 *s)
{
Eface err;
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");
}