Commit 5d363c63 authored by Russ Cox's avatar Russ Cox

cmd/ld, runtime: new in-memory symbol table format

Design at http://golang.org/s/go12symtab.

This enables some cleanup of the garbage collector metadata
that will be done in future CLs.

This CL does not move the old symtab and pclntab back into
an unmapped section of the file. That's a bit tricky and will be
done separately.

Fixes #4020.

R=golang-dev, dave, cshapiro, iant, r
CC=golang-dev, nigeltao
https://golang.org/cl/11085043
parent 63e0ddc7
......@@ -197,8 +197,12 @@ enum as
AMULAWB,
AUSEFIELD,
ALOCALS,
ATYPE,
AFUNCDATA,
APCDATA,
// TODO: Remove these.
ALOCALS,
ANPTRS,
APTRS,
......
......@@ -172,6 +172,7 @@ struct Sym
char* dynimplib;
char* dynimpvers;
struct Section* sect;
struct Hist* hist;
// STEXT
Auto* autom;
......@@ -282,7 +283,7 @@ enum
MINSIZ = 64,
NENT = 100,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
MAXHIST = 40, /* limit of path elements for history symbols */
MINLC = 4,
};
......@@ -319,7 +320,6 @@ EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
EXTERN Sym* textp;
EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
EXTERN Prog zprg;
EXTERN int dtype;
......
......@@ -278,6 +278,7 @@ main(int argc, char *argv[])
span();
addexport();
// textaddress() functionality is handled in span()
functab();
pclntab();
symtab();
dodata();
......@@ -549,6 +550,7 @@ loop:
addhist(p->line, D_FILE); /* 'z' */
if(p->to.offset)
addhist(p->to.offset, D_FILE1); /* 'Z' */
savehist(p->line, p->to.offset);
histfrogp = 0;
goto loop;
......@@ -699,6 +701,7 @@ loop:
p->to.offset = autosize;
autosize += 4;
s->type = STEXT;
s->hist = gethist();
s->text = p;
s->value = pc;
s->args = p->to.offset2;
......
......@@ -759,15 +759,18 @@ enum as
AAESKEYGENASSIST,
APSHUFD,
APCLMULQDQ,
AUSEFIELD,
ALOCALS,
ATYPE,
AFUNCDATA,
APCDATA,
// TODO: Remove these.
ALOCALS,
ANPTRS,
APTRS,
APCLMULQDQ,
ALAST
};
......
......@@ -177,6 +177,7 @@ struct Sym
char* dynimplib;
char* dynimpvers;
struct Section* sect;
struct Hist* hist; // for ATEXT
// STEXT
Auto* autom;
......@@ -213,7 +214,7 @@ enum
STRINGSZ = 200,
MINLC = 1,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
MAXHIST = 40, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
......@@ -359,7 +360,6 @@ EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
EXTERN int tlsoffset;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN char* paramspace;
......
......@@ -289,6 +289,7 @@ main(int argc, char *argv[])
dope();
addexport();
textaddress();
functab();
pclntab();
symtab();
dodata();
......@@ -542,6 +543,7 @@ loop:
addhist(p->line, D_FILE); /* 'z' */
if(p->to.offset)
addhist(p->to.offset, D_FILE1); /* 'Z' */
savehist(p->line, p->to.offset);
histfrogp = 0;
goto loop;
......@@ -690,6 +692,7 @@ loop:
s->gotype = fromgotype;
}
s->type = STEXT;
s->hist = gethist();
s->value = pc;
s->args = p->to.offset >> 32;
s->nptrs = -1;
......
......@@ -1339,14 +1339,11 @@ Optab optab[] =
{ AAESKEYGENASSIST, yaes2, Pq, 0x3a,0xdf,(0) },
{ APSHUFD, yaes2, Pq, 0x70,(0) },
{ APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
{ ANPTRS },
{ APTRS },
{ APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 },
{ AFUNCDATA, ynop, Px, 0,0 },
{ APCDATA, ynop, Px, 0,0 },
{ AEND },
0
......
......@@ -578,8 +578,12 @@ enum as
APSHUFB,
AUSEFIELD,
ALOCALS,
ATYPE,
AFUNCDATA,
APCDATA,
// TODO: Remove these.
ALOCALS,
ANPTRS,
APTRS,
......
......@@ -159,6 +159,7 @@ struct Sym
char* dynimplib;
char* dynimpvers;
struct Section* sect;
struct Hist* hist; // for ATEXT
// STEXT
Auto* autom;
......@@ -187,7 +188,7 @@ enum
STRINGSZ = 200,
MINLC = 1,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
MAXHIST = 40, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
......@@ -313,7 +314,6 @@ EXTERN Sym* symlist;
EXTERN int32 symsize;
EXTERN Sym* textp;
EXTERN int32 textsize;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int tlsoffset;
......
......@@ -316,6 +316,7 @@ main(int argc, char *argv[])
span();
addexport();
textaddress();
functab();
pclntab();
symtab();
dodata();
......@@ -552,6 +553,7 @@ loop:
addhist(p->line, D_FILE); /* 'z' */
if(p->to.offset)
addhist(p->to.offset, D_FILE1); /* 'Z' */
savehist(p->line, p->to.offset);
histfrogp = 0;
goto loop;
......@@ -695,6 +697,7 @@ loop:
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
s->type = STEXT;
s->hist = gethist();
s->value = pc;
s->args = p->to.offset2;
s->nptrs = -1;
......
......@@ -1001,10 +1001,9 @@ Optab optab[] =
{ APSHUFB, ymshufb,Pq, 0x38, 0x00 },
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
{ ANPTRS },
{ APTRS },
{ AFUNCDATA, ynop, Px, 0,0 },
{ APCDATA, ynop, Px, 0,0 },
0
};
......@@ -415,6 +415,8 @@ Zconv(Fmt *fp)
s = sp->s;
se = s + sp->len;
// NOTE: Keep in sync with ../ld/go.c:/^Zconv.
while(s < se) {
n = chartorune(&r, s);
s += n;
......
......@@ -763,7 +763,7 @@ setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
s->p[off+i] = cast[inuxi8[i]];
break;
}
return off;
return off+wid;
}
vlong
......@@ -800,28 +800,28 @@ adduint64(Sym *s, uint64 v)
return adduintxx(s, v, 8);
}
void
vlong
setuint8(Sym *s, vlong r, uint8 v)
{
setuintxx(s, r, v, 1);
return setuintxx(s, r, v, 1);
}
void
vlong
setuint16(Sym *s, vlong r, uint16 v)
{
setuintxx(s, r, v, 2);
return setuintxx(s, r, v, 2);
}
void
vlong
setuint32(Sym *s, vlong r, uint32 v)
{
setuintxx(s, r, v, 4);
return setuintxx(s, r, v, 4);
}
void
vlong
setuint64(Sym *s, vlong r, uint64 v)
{
setuintxx(s, r, v, 8);
return setuintxx(s, r, v, 8);
}
vlong
......@@ -842,7 +842,7 @@ addaddrplus(Sym *s, Sym *t, vlong add)
r->siz = PtrSize;
r->type = D_ADDR;
r->add = add;
return i;
return i + r->siz;
}
static vlong
......@@ -863,7 +863,7 @@ addaddrplus4(Sym *s, Sym *t, vlong add)
r->siz = 4;
r->type = D_ADDR;
r->add = add;
return i;
return i + r->siz;
}
vlong
......@@ -884,7 +884,7 @@ addpcrelplus(Sym *s, Sym *t, vlong add)
r->add = add;
r->type = D_PCREL;
r->siz = 4;
return i;
return i + r->siz;
}
vlong
......@@ -911,7 +911,7 @@ setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
r->siz = PtrSize;
r->type = D_ADDR;
r->add = add;
return off;
return off + r->siz;
}
vlong
......@@ -937,7 +937,7 @@ addsize(Sym *s, Sym *t)
r->off = i;
r->siz = PtrSize;
r->type = D_SIZE;
return i;
return i + r->siz;
}
void
......
......@@ -613,7 +613,7 @@ markflood(void)
}
static char*
morename[] =
markextra[] =
{
"runtime.morestack",
"runtime.morestackx",
......@@ -629,6 +629,12 @@ morename[] =
"runtime.morestack32",
"runtime.morestack40",
"runtime.morestack48",
// on arm, lock in the div/mod helpers too
"_div",
"_divu",
"_mod",
"_modu",
};
static int
......@@ -676,8 +682,8 @@ deadcode(void)
mark(lookup(INITENTRY, 0));
if(flag_shared)
mark(lookup(LIBINITENTRY, 0));
for(i=0; i<nelem(morename); i++)
mark(lookup(morename[i], 0));
for(i=0; i<nelem(markextra); i++)
mark(lookup(markextra[i], 0));
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
......@@ -794,6 +800,8 @@ Zconv(Fmt *fp)
return fmtstrcpy(fp, "<nil>");
se = s + strlen(s);
// NOTE: Keep in sync with ../gc/go.c:/^Zconv.
while(s < se) {
n = chartorune(&r, s);
s += n;
......@@ -822,6 +830,9 @@ Zconv(Fmt *fp)
fmtrune(fp, '\\');
fmtrune(fp, r);
break;
case 0xFEFF: // BOM, basically disallowed in source code
fmtstrcpy(fp, "\\uFEFF");
break;
}
}
return 0;
......
This diff is collapsed.
......@@ -41,10 +41,12 @@ enum
STYPE,
SSTRING,
SGOSTRING,
SGOFUNC,
SRODATA,
SFUNCTAB,
STYPELINK,
SSYMTAB,
SPCLNTAB,
SSYMTAB, // TODO: move to unmapped section
SPCLNTAB, // TODO: move to unmapped section
SELFROSECT,
/* writable, non-executable */
......@@ -67,6 +69,7 @@ enum
SMACHOINDIRECTPLT,
SMACHOINDIRECTGOT,
SFILE,
SFILEPATH,
SCONST,
SDYNIMPORT,
SHOSTOBJ,
......@@ -129,9 +132,14 @@ struct Section
uvlong rellen;
};
typedef struct Hist Hist;
#pragma incomplete struct Hist
extern char symname[];
extern char **libdir;
extern int nlibdir;
extern int version;
EXTERN char* INITENTRY;
EXTERN char* thestring;
......@@ -194,6 +202,9 @@ void addlibpath(char *srcref, char *objref, char *file, char *pkg);
Section* addsection(Segment*, char*, int);
void copyhistfrog(char *buf, int nbuf);
void addhist(int32 line, int type);
void savehist(int32 line, int32 off);
Hist* gethist(void);
void getline(Hist*, int32 line, int32 *f, int32 *l);
void asmlc(void);
void histtoauto(void);
void collapsefrog(Sym *s);
......@@ -216,6 +227,7 @@ void objfile(char *file, char *pkg);
void libinit(void);
void pclntab(void);
void symtab(void);
void functab(void);
void Lflag(char *arg);
void usage(void);
void adddynrel(Sym*, Reloc*);
......@@ -251,10 +263,11 @@ vlong addpcrelplus(Sym*, Sym*, vlong);
vlong addsize(Sym*, Sym*);
vlong setaddrplus(Sym*, vlong, Sym*, vlong);
vlong setaddr(Sym*, vlong, Sym*);
void setuint8(Sym*, vlong, uint8);
void setuint16(Sym*, vlong, uint16);
void setuint32(Sym*, vlong, uint32);
void setuint64(Sym*, vlong, uint64);
vlong setuint8(Sym*, vlong, uint8);
vlong setuint16(Sym*, vlong, uint16);
vlong setuint32(Sym*, vlong, uint32);
vlong setuint64(Sym*, vlong, uint64);
vlong setuintxx(Sym*, vlong, uint64, vlong);
void asmsym(void);
void asmelfsym(void);
void asmplan9sym(void);
......@@ -284,6 +297,7 @@ void hostobjs(void);
void hostlink(void);
char* estrdup(char*);
void* erealloc(void*, long);
Sym* defgostring(char*);
int pathchar(void);
void* mal(uint32);
......
......@@ -466,7 +466,8 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
void
symtab(void)
{
Sym *s, *symtype, *symtypelink, *symgostring;
Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
dosymtype();
// Define these so that they'll get put into the symbol table.
......@@ -519,6 +520,12 @@ symtab(void)
s->reachable = 1;
symgostring = s;
s = lookup("go.func.*", 0);
s->type = SGOFUNC;
s->size = 0;
s->reachable = 1;
symgofunc = s;
symtypelink = lookup("typelink", 0);
symt = lookup("symtab", 0);
......@@ -548,6 +555,11 @@ symtab(void)
s->hide = 1;
s->outer = symgostring;
}
if(strncmp(s->name, "go.func.", 8) == 0) {
s->type = SGOFUNC;
s->hide = 1;
s->outer = symgofunc;
}
}
if(debug['s'])
......
......@@ -573,9 +573,9 @@ havem:
MOVL BP, 0(DI)
// Push arguments to cgocallbackg.
// Frame size here must match the frame size above
// Frame size here must match the frame size above plus the pushes
// to trick traceback routines into doing the right thing.
SUBL $12, DI
SUBL $20, DI
MOVL AX, 0(DI)
MOVL BX, 4(DI)
MOVL DX, 8(DI)
......@@ -587,9 +587,9 @@ havem:
// Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX)
MOVL g(CX), SI
MOVL 12(SP), BP
MOVL 20(SP), BP
MOVL BP, (g_sched+gobuf_pc)(SI)
LEAL (12+4)(SP), DI
LEAL (20+4)(SP), DI
MOVL DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
......
......@@ -609,9 +609,9 @@ havem:
MOVQ BP, 0(DI)
// Push arguments to cgocallbackg.
// Frame size here must match the frame size above
// Frame size here must match the frame size above plus the pushes
// to trick traceback routines into doing the right thing.
SUBQ $24, DI
SUBQ $40, DI
MOVQ AX, 0(DI)
MOVQ BX, 8(DI)
MOVQ DX, 16(DI)
......@@ -623,9 +623,9 @@ havem:
// Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX)
MOVQ g(CX), SI
MOVQ 24(SP), BP
MOVQ 40(SP), BP
MOVQ BP, (g_sched+gobuf_pc)(SI)
LEAQ (24+8)(SP), DI
LEAQ (40+8)(SP), DI
MOVQ DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
......
......@@ -368,12 +368,12 @@ havem:
MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
// Push gobuf.pc
// Frame size here must match the frame size above plus the push
// to trick traceback routines into doing the right thing.
MOVW (g_sched+gobuf_pc)(g), R5
MOVW.W R5, -16(R4)
MOVW.W R5, -20(R4)
// Push arguments to cgocallbackg.
// Frame size here must match the frame size above
// to trick traceback routines into doing the right thing.
MOVW R0, 4(R4)
MOVW R1, 8(R4)
MOVW R2, 12(R4)
......@@ -385,7 +385,7 @@ havem:
// Restore g->sched (== m->curg->sched) from saved values.
MOVW 0(R13), R5
MOVW R5, (g_sched+gobuf_pc)(g)
ADD $(12+4), R13, R4
ADD $(16+4), R13, R4
MOVW R4, (g_sched+gobuf_sp)(g)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
......
......@@ -78,18 +78,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool)
// It returns the number of entries written to pc.
func Callers(skip int, pc []uintptr) int
type Func struct { // Keep in sync with runtime.h:struct Func
name string
typ string // go type string
src string // src file name
pcln []byte // pc/ln tab for this func
entry uintptr // entry pc
pc0 uintptr // starting pc, ln for table
ln0 int32
frame int32 // stack frame size
args int32 // in/out args size
locals int32 // locals size
ptrs []int32 // pointer map
type Func struct {
opaque struct{} // unexported field to disallow conversions
}
// FuncForPC returns a *Func describing the function that contains the
......@@ -97,10 +87,14 @@ type Func struct { // Keep in sync with runtime.h:struct Func
func FuncForPC(pc uintptr) *Func
// Name returns the name of the function.
func (f *Func) Name() string { return f.name }
func (f *Func) Name() string {
return funcname_go(f)
}
// Entry returns the entry address of the function.
func (f *Func) Entry() uintptr { return f.entry }
func (f *Func) Entry() uintptr {
return funcentry_go(f)
}
// FileLine returns the file name and line number of the
// source code corresponding to the program counter pc.
......@@ -112,6 +106,8 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) {
// implemented in symtab.c
func funcline_go(*Func, uintptr) (string, int)
func funcname_go(*Func) string
func funcentry_go(*Func) uintptr
// SetFinalizer sets the finalizer associated with x to f.
// When the garbage collector finds an unreachable block
......
......@@ -1390,7 +1390,7 @@ addframeroots(Stkframe *frame, void*)
Func *f;
byte *ap;
int32 i, j, nuintptr;
uint32 w, b;
uint32 w, b, *ptrs;
// Scan local variables if stack frame has been allocated.
if(frame->varlen > 0)
......@@ -1399,11 +1399,12 @@ addframeroots(Stkframe *frame, void*)
// Scan arguments.
// Use pointer information if known.
f = frame->fn;
if(f->args > 0 && f->ptrs.array != nil) {
if(f->args > 0 && f->ptrslen > 0) {
ap = frame->argp;
nuintptr = f->args / sizeof(uintptr);
for(i = 0; i < f->ptrs.len; i++) {
w = ((uint32*)f->ptrs.array)[i];
ptrs = (uint32*)((byte*)f + f->ptrsoff);
for(i = 0; i < f->ptrslen; i++) {
w = ptrs[i];
b = 1;
j = nuintptr;
if(j > 32)
......
......@@ -294,12 +294,11 @@ runtime·Caller(intgo skip, uintptr retpc, String retfile, intgo retline, bool r
retbool = true; // have retpc at least
} else {
retpc = rpc[1];
retfile = f->src;
pc = retpc;
g = runtime·findfunc(rpc[0]);
if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
pc--;
retline = runtime·funcline(f, pc);
retline = runtime·funcline(f, pc, &retfile);
retbool = true;
}
FLUSH(&retpc);
......
......@@ -401,21 +401,25 @@ enum
SigIgnored = 1<<6, // the signal was ignored before we registered for it
};
// NOTE(rsc): keep in sync with extern.go:/type.Func.
// Eventually, the loaded symbol table should be closer to this form.
// layout of in-memory per-function information prepared by linker
// See http://golang.org/s/go12symtab.
struct Func
{
String name;
String type; // go type string
String src; // src file name
Slice pcln; // pc/ln tab for this func
uintptr entry; // entry pc
uintptr pc0; // starting pc, ln for table
int32 ln0;
int32 frame; // stack frame size
String *name; // function name
uintptr entry; // start pc
// TODO: Remove these fields.
int32 args; // in/out args size
int32 locals; // locals size
Slice ptrs; // pointer map
int32 frame; // legacy frame size; use pcsp if possible
int32 ptrsoff;
int32 ptrslen;
int32 pcsp;
int32 pcfile;
int32 pcln;
int32 npcdata;
int32 nfuncdata;
};
// layout of Itab known to compilers
......@@ -790,7 +794,9 @@ void runtime·unminit(void);
void runtime·signalstack(byte*, int32);
void runtime·symtabinit(void);
Func* runtime·findfunc(uintptr);
int32 runtime·funcline(Func*, uintptr);
int32 runtime·funcline(Func*, uintptr, String*);
int32 runtime·funcarglen(Func*, uintptr);
int32 runtime·funcspdelta(Func*, uintptr);
void* runtime·stackalloc(uint32);
void runtime·stackfree(void*, uintptr);
MCache* runtime·allocmcache(void);
......
This diff is collapsed.
......@@ -15,15 +15,18 @@ void _mod(void);
void _divu(void);
void _modu(void);
static String unknown = { (uint8*)"?", 1 };
int32
runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
{
int32 i, n, nprint, skip0;
int32 i, n, nprint, skip0, line;
uintptr x, tracepc;
bool waspanic, printing;
Func *f, *f2;
Stkframe frame;
Stktop *stk;
String file;
skip0 = skip;
......@@ -76,11 +79,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
// Derive frame pointer and link register.
if(frame.lr == 0)
frame.lr = *(uintptr*)frame.sp;
if(frame.fp == 0) {
frame.fp = frame.sp;
if(frame.pc > f->entry && f->frame >= sizeof(uintptr))
frame.fp += f->frame;
}
if(frame.fp == 0)
frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
// Derive size of arguments.
frame.argp = (byte*)frame.fp + sizeof(uintptr);
......@@ -96,7 +96,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
else if((f2 = runtime·findfunc(frame.lr)) != nil && f2->frame >= sizeof(uintptr))
frame.arglen = f2->frame; // conservative overestimate
else {
runtime·printf("runtime: unknown argument frame size for %S\n", f->name);
runtime·printf("runtime: unknown argument frame size for %S\n", *f->name);
if(!printing)
runtime·throw("invalid stack");
}
......@@ -113,7 +113,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.varlen = frame.fp - frame.sp;
} else {
if(f->locals > frame.fp - frame.sp) {
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %S\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, f->name);
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %S\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, *f->name);
runtime·throw("invalid stack");
}
frame.varp = (byte*)frame.fp - f->locals;
......@@ -138,7 +138,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc = frame.pc; // back up to CALL instruction for funcline.
if(n > 0 && frame.pc > f->entry && !waspanic)
tracepc -= sizeof(uintptr);
runtime·printf("%S(", f->name);
runtime·printf("%S(", *f->name);
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
if(i >= 5) {
runtime·prints(", ...");
......@@ -149,7 +149,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printhex(((uintptr*)frame.argp)[i]);
}
runtime·prints(")\n");
runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
line = runtime·funcline(f, tracepc, &file);
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
if(m->throwing && gp == m->curg)
......@@ -164,7 +165,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
waspanic = f->entry == (uintptr)runtime·sigpanic;
// Do not unwind past the bottom of the stack.
if(f->entry == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)_rt0_go)
if(f->entry == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)runtime·mcall || f->entry == (uintptr)_rt0_go)
break;
// Unwind to next frame.
......@@ -172,16 +173,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.lr = 0;
frame.sp = frame.fp;
frame.fp = 0;
// If this was div or divu or mod or modu, the caller had
// an extra 8 bytes on its stack. Adjust sp.
if(f->entry == (uintptr)_div || f->entry == (uintptr)_divu || f->entry == (uintptr)_mod || f->entry == (uintptr)_modu)
frame.sp += 8;
// If this was deferproc or newproc, the caller had an extra 12.
if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
frame.sp += 12;
// sighandler saves the lr on stack before faking a call to sigpanic
if(waspanic) {
x = *(uintptr*)frame.sp;
......@@ -203,16 +195,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
static void
printcreatedby(G *gp)
{
int32 line;
uintptr pc, tracepc;
Func *f;
String file;
if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
&& runtime·showframe(f, gp) && gp->goid != 1) {
runtime·printf("created by %S\n", f->name);
runtime·printf("created by %S\n", *f->name);
tracepc = pc; // back up to CALL instruction for funcline.
if(pc > f->entry)
tracepc -= sizeof(uintptr);
runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
line = runtime·funcline(f, tracepc, &file);
runtime·printf("\t%S:%d", file, line);
if(pc > f->entry)
runtime·printf(" +%p", (uintptr)(pc - f->entry));
runtime·printf("\n");
......
......@@ -16,6 +16,8 @@ void runtime·sigpanic(void);
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
static String unknown = { (uint8*)"?", 1 };
// Generic traceback. Handles runtime stack prints (pcbuf == nil),
// the runtime.Callers function (pcbuf != nil), as well as the garbage
// collector (callback != nil). A little clunky to merge these, but avoids
......@@ -23,12 +25,13 @@ void runtime·sigpanic(void);
int32
runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
{
int32 i, n, nprint;
int32 i, n, nprint, line;
uintptr tracepc;
bool waspanic, printing;
Func *f, *f2;
Func *f, *flr;
Stkframe frame;
Stktop *stk;
String file;
USED(lr0);
......@@ -62,33 +65,36 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.sp = stk->gobuf.sp;
frame.lr = 0;
frame.fp = 0;
frame.fn = nil;
if(printing && runtime·showframe(nil, gp))
runtime·printf("----- stack segment boundary -----\n");
stk = (Stktop*)stk->stackbase;
continue;
}
if(frame.pc <= 0x1000 || (frame.fn = f = runtime·findfunc(frame.pc)) == nil) {
if(callback != nil)
f = frame.fn;
if(f == nil && (frame.pc <= 0x1000 || (frame.fn = f = runtime·findfunc(frame.pc)) == nil)) {
if(callback != nil) {
runtime·printf("unknown pc %p\n", frame.pc);
runtime·throw("unknown pc");
}
break;
}
// Found an actual function.
// Derive frame pointer and link register.
if(frame.fp == 0) {
frame.fp = frame.sp;
if(frame.pc > f->entry && f->frame >= sizeof(uintptr))
frame.fp += f->frame;
else
frame.fp += sizeof(uintptr);
frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
frame.fp += sizeof(uintptr); // caller PC
}
if(frame.lr == 0)
frame.lr = ((uintptr*)frame.fp)[-1];
flr = runtime·findfunc(frame.lr);
// Derive size of arguments.
frame.argp = (byte*)frame.fp;
frame.arglen = 0;
if(f->args != ArgsSizeUnknown)
if(flr != nil && (i = runtime·funcarglen(flr, frame.lr)) >= 0)
frame.arglen = i;
else if(f->args != ArgsSizeUnknown)
frame.arglen = f->args;
else if(runtime·haszeroargs(f->entry))
frame.arglen = 0;
......@@ -96,10 +102,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.arglen = stk->argsize;
else if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
frame.arglen = 2*sizeof(uintptr) + *(int32*)frame.argp;
else if((f2 = runtime·findfunc(frame.lr)) != nil && f2->frame >= sizeof(uintptr))
frame.arglen = f2->frame; // conservative overestimate
else if(flr != nil && flr->frame >= sizeof(uintptr))
frame.arglen = flr->frame; // conservative overestimate
else {
runtime·printf("runtime: unknown argument frame size for %S\n", f->name);
runtime·printf("runtime: unknown argument frame size for %S called from %p [%S]\n", *f->name, frame.lr, flr ? *flr->name : unknown);
if(!printing)
runtime·throw("invalid stack");
}
......@@ -116,7 +122,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
frame.varlen = frame.fp - sizeof(uintptr) - frame.sp;
} else {
if(f->locals > frame.fp - sizeof(uintptr) - frame.sp) {
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %S\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, f->name);
runtime·printf("runtime: inconsistent locals=%p frame=%p fp=%p sp=%p for %S\n", (uintptr)f->locals, (uintptr)f->frame, frame.fp, frame.sp, *f->name);
runtime·throw("invalid stack");
}
frame.varp = (byte*)frame.fp - sizeof(uintptr) - f->locals;
......@@ -141,7 +147,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
tracepc = frame.pc; // back up to CALL instruction for funcline.
if(n > 0 && frame.pc > f->entry && !waspanic)
tracepc--;
runtime·printf("%S(", f->name);
runtime·printf("%S(", *f->name);
for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
if(i >= 5) {
runtime·prints(", ...");
......@@ -152,7 +158,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
runtime·printhex(((uintptr*)frame.argp)[i]);
}
runtime·prints(")\n");
runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
line = runtime·funcline(f, tracepc, &file);
runtime·printf("\t%S:%d", file, line);
if(frame.pc > f->entry)
runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
if(m->throwing && gp == m->curg)
......@@ -166,14 +173,12 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
skipped:
waspanic = f->entry == (uintptr)runtime·sigpanic;
if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
frame.fp += 2*sizeof(uintptr);
// Do not unwind past the bottom of the stack.
if(f->entry == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)_rt0_go)
if(f->entry == (uintptr)runtime·goexit || f->entry == (uintptr)runtime·mstart || f->entry == (uintptr)runtime·mcall || f->entry == (uintptr)_rt0_go)
break;
// Unwind to next frame.
frame.fn = flr;
frame.pc = frame.lr;
frame.lr = 0;
frame.sp = frame.fp;
......@@ -189,16 +194,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
static void
printcreatedby(G *gp)
{
int32 line;
String file;
uintptr pc, tracepc;
Func *f;
// Show what created goroutine, except main goroutine (goid 1).
if((pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil && gp->goid != 1) {
runtime·printf("created by %S\n", f->name);
runtime·printf("created by %S\n", *f->name);
tracepc = pc; // back up to CALL instruction for funcline.
if(pc > f->entry)
tracepc--;
runtime·printf("\t%S:%d", f->src, runtime·funcline(f, tracepc));
line = runtime·funcline(f, tracepc, &file);
runtime·printf("\t%S:%d", file, line);
if(pc > f->entry)
runtime·printf(" +%p", (uintptr)(pc - f->entry));
runtime·printf("\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment