]> Cypherpunks repositories - gostls13.git/commitdiff
use pc/ln table to print source lines in traceback
authorRuss Cox <rsc@golang.org>
Tue, 25 Nov 2008 17:23:36 +0000 (09:23 -0800)
committerRuss Cox <rsc@golang.org>
Tue, 25 Nov 2008 17:23:36 +0000 (09:23 -0800)
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

src/runtime/rt2_amd64.c
src/runtime/runtime.h
src/runtime/symtab.c

index 5a388bfe0262a53a268aa4213b30028e82a2027b..3d4ff7cb508bf0f75f0cbfbb59609bad7e25c825 100644 (file)
@@ -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("(");
index 7ec9c7d9bb46faf04f2489e89b0f02d06be448f9..409228d73fa3aa74ef2fb93685c4d67c0b441594 100644 (file)
@@ -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,
index 734f39100b2b72529b3684e1fa49ac8b9a0f5d33..80c49e01a0be5d9b796f1f9be56aac9fd1647eec 100644 (file)
@@ -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;