diff options
author | Russ Cox <rsc@golang.org> | 2008-11-25 09:23:36 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2008-11-25 09:23:36 -0800 |
commit | 22fb1175911f2631207aee68d9a0f8ddf73bc5bd (patch) | |
tree | bf560d5844b4a60303cd6a986382ceb9ccc0a111 | |
parent | c2bc9b1490f473959869c337c53d253709fe0b59 (diff) | |
download | golang-22fb1175911f2631207aee68d9a0f8ddf73bc5bd.tar.gz |
use pc/ln table to print source lines in traceback
r45=; 6.out
oops
panic PC=0x400316
0x400316?zi /home/rsc/go/src/runtime/rt0_amd64_linux.s:83
main·g(4195177, 0, 4205661, ...)
main·g(0x400369, 0x402c5d, 0x403e49, ...)
0x40034c?zi /home/rsc/go/src/runtime/x.go:24
main·f(4205661, 0, 4210249, ...)
main·f(0x402c5d, 0x403e49, 0x1, ...)
0x400368?zi /home/rsc/go/src/runtime/x.go:37
main·main(4210249, 0, 1, ...)
main·main(0x403e49, 0x1, 0x7fff9d894bd8, ...)
0x402c5c?zi /home/rsc/go/src/runtime/rt0_amd64.s:70
mainstart(1, 0, 2643020760, ...)
mainstart(0x1, 0x7fff9d894bd8, 0x0, ...)
r45=;
R=r
DELTA=251 (198 added, 25 deleted, 28 changed)
OCL=19965
CL=19979
-rw-r--r-- | src/runtime/rt2_amd64.c | 8 | ||||
-rw-r--r-- | src/runtime/runtime.h | 11 | ||||
-rw-r--r-- | src/runtime/symtab.c | 248 |
3 files changed, 220 insertions, 47 deletions
diff --git a/src/runtime/rt2_amd64.c b/src/runtime/rt2_amd64.c index 5a388bfe0..3d4ff7cb5 100644 --- a/src/runtime/rt2_amd64.c +++ b/src/runtime/rt2_amd64.c @@ -11,8 +11,6 @@ extern uint8 end; void traceback(uint8 *pc, uint8 *sp, void* r15) { - int32 spoff; - int8* spp; uint8* callpc; int32 counter; int32 i; @@ -60,7 +58,11 @@ traceback(uint8 *pc, uint8 *sp, void* r15) /* print this frame */ prints("0x"); sys·printpointer(callpc - 1); // -1 to get to CALL instr. - prints("?zi\n"); + prints("?zi "); + sys·printstring(f->src); + prints(":"); + sys·printint(funcline(f, (uint64)callpc-1)); // -1 to get to CALL instr. + prints("\n"); prints("\t"); sys·printstring(name); prints("("); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 7ec9c7d9b..409228d73 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -189,9 +189,13 @@ struct SigTab struct Func { string name; - string type; - uint64 entry; - int64 frame; + string type; // go type string + string src; // src file name + uint64 entry; // entry pc + int64 frame; // stack frame size + Array pcln; // pc/ln tab for this func + int64 pc0; // starting pc, ln for table + int32 ln0; }; /* @@ -261,6 +265,7 @@ void signalstack(byte*, int32); G* malg(int32); void minit(void); Func* findfunc(uint64); +int32 funcline(Func*, uint64); /* * mutual exclusion locks. in the uncontended case, diff --git a/src/runtime/symtab.c b/src/runtime/symtab.c index 734f39100..80c49e01a 100644 --- a/src/runtime/symtab.c +++ b/src/runtime/symtab.c @@ -2,21 +2,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include "runtime.h" +// Runtime symbol table access. Work in progress. +// The Plan 9 symbol table is not in a particularly convenient form. +// The routines here massage it into a more usable form; eventually +// we'll change 6l to do this for us, but it is easier to experiment +// here than to change 6l and all the other tools. +// +// The symbol table also needs to be better integrated with the type +// strings table in the future. This is just a quick way to get started +// and figure out exactly what we want. -// Runtime symbol table access. -// Very much a work in progress. +#include "runtime.h" #define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l #define SYMDATA ((byte*)(0x99LL<<32) + 8) // Return a pointer to a byte array containing the symbol table segment. -// -// NOTE(rsc): I expect that we will clean up both the method of getting -// at the symbol table and the exact format of the symbol table at some -// point in the future. It probably needs to be better integrated with -// the type strings table too. This is just a quick way to get started -// and figure out what we want from/can do with it. void sys·symdat(Array *symtab, Array *pclntab) { @@ -50,7 +51,7 @@ struct Sym }; // Walk over symtab, calling fn(&s) for each symbol. -void +static void walksymtab(void (*fn)(Sym*)) { int32 *v; @@ -68,10 +69,10 @@ walksymtab(void (*fn)(Sym*)) break; s.symtype = p[4] & ~0x80; p += 5; + s.name = p; if(s.symtype == 'z' || s.symtype == 'Z') { // path reference string - skip first byte, // then 2-byte pairs ending at two zeros. - // for now, just skip over it and ignore it. q = p+1; for(;;) { if(q+2 > ep) @@ -81,12 +82,10 @@ walksymtab(void (*fn)(Sym*)) q += 2; } p = q+2; - s.name = nil; }else{ q = mchr(p, '\0', ep); if(q == nil) break; - s.name = p; p = q+1; } q = mchr(p, '\0', ep); @@ -100,33 +99,198 @@ walksymtab(void (*fn)(Sym*)) // Symtab walker; accumulates info about functions. -Func *func; -int32 nfunc; +static Func *func; +static int32 nfunc; + +static byte **fname; +static int32 nfname; static void dofunc(Sym *sym) { - static byte *lastfuncname; - static Func *lastfunc; Func *f; - if(lastfunc && sym->symtype == 'm') { - lastfunc->frame = sym->value; - return; + switch(sym->symtype) { + case 't': + case 'T': + if(strcmp(sym->name, (byte*)"etext") == 0) + break; + if(func == nil) { + nfunc++; + break; + } + f = &func[nfunc++]; + f->name = gostring(sym->name); + f->entry = sym->value; + break; + case 'm': + if(nfunc > 0 && func != nil) + func[nfunc-1].frame = sym->value; + break; + case 'f': + if(fname == nil) { + if(sym->value >= nfname) + nfname = sym->value+1; + break; + } + fname[sym->value] = sym->name; + break; } - if(sym->symtype != 'T' && sym->symtype != 't') - return; - if(strcmp(sym->name, (byte*)"etext") == 0) - return; - if(func == nil) { - nfunc++; +} + +// put together the path name for a z entry. +// the f entries have been accumulated into fname already. +static void +makepath(byte *buf, int32 nbuf, byte *path) +{ + int32 n, len; + byte *p, *ep, *q; + + if(nbuf <= 0) return; + + p = buf; + ep = buf + nbuf; + *p = '\0'; + for(;;) { + if(path[0] == 0 && path[1] == 0) + break; + n = (path[0]<<8) | path[1]; + path += 2; + if(n >= nfname) + break; + q = fname[n]; + len = findnull(q); + if(p+1+len >= ep) + break; + if(p > buf && p[-1] != '/') + *p++ = '/'; + mcpy(p, q, len+1); + p += len; + } +} + +// walk symtab accumulating path names for use by pc/ln table. +// don't need the full generality of the z entry history stack because +// there are no includes in go (and only sensible includes in our c). +static void +dosrcline(Sym *sym) +{ + static byte srcbuf[1000]; + static string srcstring; + static int32 lno, incstart; + static int32 nf, nhist; + Func *f; + + switch(sym->symtype) { + case 't': + case 'T': + f = &func[nf++]; + f->src = srcstring; + f->ln0 += lno; + break; + case 'z': + if(sym->value == 1) { + // entry for main source file for a new object. + makepath(srcbuf, sizeof srcbuf, sym->name+1); + srcstring = gostring(srcbuf); + lno = 0; + nhist = 0; + } else { + // push or pop of included file. + makepath(srcbuf, sizeof srcbuf, sym->name+1); + if(srcbuf[0] != '\0') { + if(nhist++ == 0) + incstart = sym->value; + }else{ + if(--nhist == 0) + lno -= sym->value - incstart; + } + } + } +} + +enum { PcQuant = 1 }; + +// Interpret pc/ln table, saving the subpiece for each func. +static void +splitpcln(void) +{ + int32 line; + uint64 pc; + byte *p, *ep; + Func *f, *ef; + int32 *v; + + // pc/ln table bounds + v = SYMCOUNTS; + p = SYMDATA; + p += v[0]; + ep = p+v[1]; + + f = func; + ef = func + nfunc; + f->pcln.array = p; + pc = func[0].entry; // text base + line = 0; + for(; p < ep; p++) { + if(f < ef && pc >= (f+1)->entry) { + f->pcln.nel = p - f->pcln.array; + f->pcln.cap = f->pcln.nel; + f++; + f->pcln.array = p; + f->pc0 = pc; + f->ln0 = line; + } + if(*p == 0) { + // 4 byte add to line + line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; + p += 4; + } else if(*p <= 64) { + line += *p; + } else if(*p <= 128) { + line -= *p - 64; + } else { + pc += PcQuant*(*p - 129); + } + pc += PcQuant; } + if(f < ef) { + f->pcln.nel = p - f->pcln.array; + f->pcln.cap = f->pcln.nel; + } +} + + +// Return actual file line number for targetpc in func f. +// (Source file is f->src.) +int32 +funcline(Func *f, uint64 targetpc) +{ + byte *p, *ep; + uint64 pc; + int32 line; - f = &func[nfunc++]; - f->name = gostring(sym->name); - f->entry = sym->value; - lastfunc = f; + p = f->pcln.array; + ep = p + f->pcln.nel; + pc = f->pc0; + line = f->ln0; + for(; p < ep; p++) { + if(pc >= targetpc) + return line; + if(*p == 0) { + line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; + p += 4; + } else if(*p <= 64) { + line += *p; + } else if(*p <= 128) { + line -= *p - 64; + } else { + pc += PcQuant*(*p - 129); + } + pc += PcQuant; + } + return line; } static void @@ -136,19 +300,30 @@ buildfuncs(void) if(func != nil) return; + // count funcs, fnames nfunc = 0; + nfname = 0; walksymtab(dofunc); + + // initialize tables func = mal((nfunc+1)*sizeof func[0]); + func[nfunc].entry = (uint64)etext; + fname = mal(nfname*sizeof fname[0]); nfunc = 0; walksymtab(dofunc); - func[nfunc].entry = (uint64)etext; + + // split pc/ln table by func + splitpcln(); + + // record src file and line info for each func + walksymtab(dosrcline); } Func* findfunc(uint64 addr) { Func *f; - int32 i, nf, n; + int32 nf, n; if(func == nil) buildfuncs(); @@ -157,15 +332,6 @@ findfunc(uint64 addr) if(addr < func[0].entry || addr >= func[nfunc].entry) return nil; - // linear search, for debugging - if(0) { - for(i=0; i<nfunc; i++) { - if(func[i].entry <= addr && addr < func[i+1].entry) - return &func[i]; - } - return nil; - } - // binary search to find func with entry <= addr. f = func; nf = nfunc; |