summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2008-11-25 09:23:36 -0800
committerRuss Cox <rsc@golang.org>2008-11-25 09:23:36 -0800
commit22fb1175911f2631207aee68d9a0f8ddf73bc5bd (patch)
treebf560d5844b4a60303cd6a986382ceb9ccc0a111
parentc2bc9b1490f473959869c337c53d253709fe0b59 (diff)
downloadgolang-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.c8
-rw-r--r--src/runtime/runtime.h11
-rw-r--r--src/runtime/symtab.c248
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;