]> Cypherpunks repositories - gostls13.git/commitdiff
libmach: update for Go 1.2 pcln table
authorRuss Cox <rsc@golang.org>
Thu, 18 Jul 2013 14:12:28 +0000 (10:12 -0400)
committerRuss Cox <rsc@golang.org>
Thu, 18 Jul 2013 14:12:28 +0000 (10:12 -0400)
The change to addr2line makes it easy to test by hand.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/11485044

src/cmd/addr2line/main.c
src/libmach/sym.c

index 9faadc27bb33041ffbc30507ade9baa57427c38e..54c4d90b5cdd2cb05b95c53ce76a2797007ed13e 100644 (file)
@@ -31,7 +31,7 @@ void
 main(int argc, char **argv)
 {
        int fd;
-       char *p;
+       char *p, *q;
        uvlong pc;
        Symbol s;
        Fhdr fhdr;
@@ -67,6 +67,17 @@ main(int argc, char **argv)
                if(p == nil)
                        break;
                p[Blinelen(&bin)-1] = '\0';
+               q = strchr(p, ':');
+               if(q != nil) {
+                       // reverse: translate file:line to pc
+                       *q++ = '\0';
+                       pc = file2pc(p, atoi(q));
+                       if(pc == ~(uvlong)0)
+                               Bprint(&bout, "!%r\n");
+                       else
+                               Bprint(&bout, "0x%llux\n", pc);
+                       continue;
+               }                       
                pc = strtoull(p, 0, 16);
                if(!findsym(pc, CTEXT, &s))
                        s.name = "??";
index 28c80d64131890b2fd00527de8654050795a309f..d8cd8ea1d9ebc9b77c83c227680e38c9d38bd2a8 100644 (file)
@@ -102,6 +102,17 @@ static int symerrmsg(int, char*);
 static int     txtcomp(const void*, const void*);
 static int     filecomp(const void*, const void*);
 
+/*
+ * Go 1.2 pcln table (also contains pcsp).
+ */
+#define Go12PclnMagic 0xfffffffb
+#define Go12PclnMagicRev 0xfbffffff
+static int     isgo12pcline(void);
+static uvlong go12pc2sp(uvlong);
+static int32 go12fileline(char*, int, uvlong);
+static void    go12clean(void);
+static uvlong go12file2pc(char*, int);
+
 /*
  *     initialize the symbol tables
  */
@@ -444,6 +455,7 @@ cleansyms(void)
        if(pcline)
                free(pcline);
        pcline = 0;
+       go12clean();
 }
 
 /*
@@ -998,12 +1010,14 @@ file2pc(char *file, int32 line)
        uvlong pc, start, end;
        short *name;
 
+       if(isgo12pcline())
+               return go12file2pc(file, line);
        if(buildtbls() == 0 || files == 0)
-               return ~0;
+               return ~(uvlong)0;
        name = encfname(file);
        if(name == 0) {                 /* encode the file name */
                werrstr("file %s not found", file);
-               return ~0;
+               return ~(uvlong)0;
        }
                /* find this history stack */
        for(i = 0, fp = files; i < nfiles; i++, fp++)
@@ -1012,7 +1026,7 @@ file2pc(char *file, int32 line)
        free(name);
        if(i >= nfiles) {
                werrstr("line %d in file %s not found", line, file);
-               return ~0;
+               return ~(uvlong)0;
        }
        start = fp->addr;               /* first text addr this file */
        if(i < nfiles-1)
@@ -1026,9 +1040,9 @@ file2pc(char *file, int32 line)
        if(debug)
                print("find pc for %d - between: %llux and %llux\n", line, start, end);
        pc = line2addr(line, start, end);
-       if(pc == ~0) {
+       if(pc == ~(uvlong)0) {
                werrstr("line %d not in file %s", line, file);
-               return ~0;
+               return ~(uvlong)0;
        }
        return pc;
 }
@@ -1169,6 +1183,9 @@ fileline(char *str, int n, uvlong dot)
        int32 line, top, bot, mid;
        File *f;
 
+       if(isgo12pcline())
+               return go12fileline(str, n, dot);
+
        *str = 0;
        if(buildtbls() == 0)
                return 0;
@@ -1368,13 +1385,16 @@ pc2sp(uvlong pc)
        uchar *c, u;
        uvlong currpc, currsp;
 
+       if(isgo12pcline())
+               return go12pc2sp(pc);
+
        if(spoff == 0)
-               return ~0;
+               return ~(uvlong)0;
        currsp = 0;
        currpc = txtstart - mach->pcquant;
 
        if(pc<currpc || pc>txtend)
-               return ~0;
+               return ~(uvlong)0;
        for(c = spoff; c < spoffend; c++) {
                if (currpc >= pc)
                        return currsp;
@@ -1391,7 +1411,7 @@ pc2sp(uvlong pc)
                        currpc += mach->pcquant*(u-129);
                currpc += mach->pcquant;
        }
-       return ~0;
+       return ~(uvlong)0;
 }
 
 /*
@@ -1412,7 +1432,7 @@ pc2line(uvlong pc)
        else
                currpc = txtstart-mach->pcquant;
        if(pc<currpc || pc>txtend)
-               return ~0;
+               return -1;
 
        for(c = pcline; c < pclineend && currpc < pc; c++) {
                u = *c;
@@ -1448,11 +1468,11 @@ line2addr(int32 line, uvlong basepc, uvlong endpc)
        int found;
 
        if(pcline == 0 || line == 0)
-               return ~0;
+               return ~(uvlong)0;
 
        currline = 0;
        currpc = txtstart-mach->pcquant;
-       pc = ~0;
+       pc = ~(uvlong)0;
        found = 0;
        delta = HUGEINT;
 
@@ -1485,7 +1505,7 @@ line2addr(int32 line, uvlong basepc, uvlong endpc)
        }
        if(found)
                return pc;
-       return ~0;
+       return ~(uvlong)0;
 }
 
 /*
@@ -1539,3 +1559,316 @@ dumphist(char *name)
                free(fname);
 }
 #endif
+
+// Go 1.2 pcln table
+// See golang.org/s/go12symtab.
+
+static int32 pcquantum;
+static int32 pcptrsize;
+static uvlong (*pcswav)(uvlong);
+static uint32 (*pcswal)(uint32);
+static uvlong (*pcuintptr)(uchar*);
+static uchar *functab;
+static uint32 nfunctab;
+static uint32 *filetab;
+static uint32 nfiletab;
+
+static uint32
+xswal(uint32 v)
+{
+       return (v>>24) | ((v>>8)&0xFF00) | ((v<<8)&0xFF0000) | v<<24;
+}
+
+static uvlong
+xswav(uvlong v)
+{
+       return (uvlong)xswal(v)<<32 | xswal(v>>32);
+}
+
+static uvlong
+noswav(uvlong v)
+{
+       return v;
+}
+
+static uint32
+noswal(uint32 v)
+{
+       return v;
+}
+
+static uvlong
+readuintptr64(uchar *p)
+{
+       return pcswav(*(uvlong*)p);
+}
+
+static uvlong
+readuintptr32(uchar *p)
+{
+       return pcswal(*(uint32*)p);
+}
+
+static void
+go12clean(void)
+{
+       pcquantum = 0;
+       pcswav = nil;
+       pcswal = nil;
+       functab = nil;
+       nfunctab = 0;
+       filetab = nil;
+       nfiletab = 0;
+}
+
+static void
+go12init(void)
+{
+       uint32 m;
+       uchar *p;
+
+       if(pcquantum != 0)
+               return;
+       pcquantum = -1; // not go 1.2
+       if(pcline == nil || pclineend - pcline < 16 ||
+               pcline[4] != 0 || pcline[5] != 0 ||
+               (pcline[6] != 1 && pcline[6] != 4) ||
+               (pcline[7] != 4 && pcline[7] != 8))
+               return;
+
+       // header is magic, 00 00 pcquantum ptrsize
+       m = *(uint32*)pcline;
+       if(m == Go12PclnMagic) {
+               pcswav = noswav;
+               pcswal = noswal;
+       } else {
+               pcswav = xswav;
+               pcswal = xswal;
+       }
+       pcptrsize = pcline[7];
+       
+       if(pcptrsize == 4)
+               pcuintptr = readuintptr32;
+       else
+               pcuintptr = readuintptr64;
+
+       nfunctab = pcuintptr(pcline+8);
+       functab = pcline + 8 + pcptrsize;
+       
+       // functab is 2*nfunctab pointer-sized values.
+       // The offset to the file table follows.
+       p = functab + nfunctab*2*pcptrsize + pcptrsize;
+       if(p+4 > pclineend)
+               return;
+       filetab = (uint32*)(pcline + pcswal(*(uint32*)p));
+       if((uchar*)filetab+4 > pclineend)
+               return;
+       
+       // File table begins with count.
+       nfiletab = pcswal(filetab[0]);
+       if((uchar*)(filetab + nfiletab) > pclineend)
+               return;
+
+       // Committed.
+       pcquantum = pcline[6];
+}
+
+static int
+isgo12pcline(void)
+{
+       go12init();
+       return pcquantum > 0;
+}
+
+static uchar*
+go12findfunc(uvlong pc)
+{
+       uchar *f, *fm;
+       int32 nf, m;
+
+       if(pc < pcuintptr(functab) || pc >= pcuintptr(functab+2*nfunctab*pcptrsize))
+               return nil;
+
+       // binary search to find func with entry <= addr.
+       f = functab;
+       nf = nfunctab;
+       while(nf > 0) {
+               m = nf/2;
+               fm = f + 2*pcptrsize*m;
+               if(pcuintptr(fm) <= pc && pc < pcuintptr(fm+2*pcptrsize)) {
+                       f = pcline + pcuintptr(fm+pcptrsize);
+                       if(f >= pclineend)
+                               return nil;
+                       return f;
+               } else if(pc < pcuintptr(fm))
+                       nf = m;
+               else {
+                       f += (m+1)*2*pcptrsize;
+                       nf -= m+1;
+               }
+       }
+       return nil;
+}
+
+static uint32
+readvarint(uchar **pp)
+{
+       uchar *p;
+       uint32 v;
+       int32 shift;
+       
+       v = 0;
+       p = *pp;
+       for(shift = 0;; shift += 7) {
+               v |= (*p & 0x7F) << shift;
+               if(!(*p++ & 0x80))
+                       break;
+       }
+       *pp = p;
+       return v;
+}
+
+static char*
+pcstring(uint32 off)
+{
+       if(off == 0 || off >= pclineend - pcline ||
+          memchr(pcline + off, '\0', pclineend - (pcline + off)) == nil)
+               return "?";
+       return (char*)pcline+off;
+}
+
+
+static int
+step(uchar **pp, uvlong *pc, int32 *value, int first)
+{
+       uint32 uvdelta, pcdelta;
+       int32 vdelta;
+
+       uvdelta = readvarint(pp);
+       if(uvdelta == 0 && !first)
+               return 0;
+       if(uvdelta&1)
+               uvdelta = ~(uvdelta>>1);
+       else
+               uvdelta >>= 1;
+       vdelta = (int32)uvdelta;
+       pcdelta = readvarint(pp) * pcquantum;
+       *value += vdelta;
+       *pc += pcdelta;
+       return 1;
+}
+
+static int32
+pcvalue(uint32 off, uvlong entry, uvlong targetpc)
+{
+       uvlong pc;
+       int32 val;
+       uchar *p;
+       
+       val = -1;
+       pc = entry;
+       if(off == 0 || off >= pclineend - pcline)
+               return -1;      
+       p = pcline + off;
+       while(step(&p, &pc, &val, pc == entry)) {
+               if(targetpc < pc)
+                       return val;
+       }
+       return -1;
+}
+
+static uvlong
+go12pc2sp(uvlong pc)
+{
+       uchar *f;
+       uint32 off;
+       uvlong entry;
+       int32 sp;
+
+       f = go12findfunc(pc);
+       if(f == nil)
+               return ~(uvlong)0;
+       entry = pcuintptr(f);
+       off = pcswal(*(uint32*)(f+pcptrsize+6*4));
+       sp = pcvalue(off, entry, pc);
+       if(sp < 0)
+               return ~(uvlong)0;
+       return sp;
+}
+
+static int32
+go12fileline(char *str, int n, uvlong pc)
+{
+       uchar *f;
+       uint32 fileoff, lineoff;
+       uvlong entry;
+       int lno, fno;
+
+       f = go12findfunc(pc);
+       if(f == nil)
+               return 0;
+       entry = pcuintptr(f);
+       fileoff = pcswal(*(uint32*)(f+pcptrsize+7*4));
+       lineoff = pcswal(*(uint32*)(f+pcptrsize+8*4));
+       lno = pcvalue(lineoff, entry, pc);
+       fno = pcvalue(fileoff, entry, pc);
+       if(lno < 0 || fno <= 0 || fno >= nfiletab) {
+               return 0;
+       }
+       snprint(str, n, "%s:%d", pcstring(pcswal(filetab[fno])), lno);
+       return 1;
+}
+
+static uvlong
+go12file2pc(char *file, int line)
+{
+       int fno;
+       int32 i, fval, lval;
+       uchar *func, *fp, *lp;
+       uvlong fpc, lpc, fstartpc, lstartpc, entry;
+
+       // Map file to file number.
+       // NOTE(rsc): Could introduce a hash table for repeated
+       // lookups if anyone ever calls this.
+       for(fno=1; fno<nfiletab; fno++)
+               if(strcmp(pcstring(pcswal(filetab[fno])), file) == 0)
+                       goto havefile;
+       werrstr("cannot find file");
+       return ~(uvlong)0;
+
+havefile:
+       // Consider each func.
+       // Run file number program to find file match,
+       // then run line number program to find line match.
+       // Most file number programs are tiny, and most will
+       // not mention the file number, so this should be fairly
+       // quick.
+       for(i=0; i<nfunctab; i++) {
+               func = pcline + pcuintptr(functab+i*2*pcptrsize+pcptrsize);
+               entry = pcuintptr(func);
+               fp = pcline + pcswal(*(uint32*)(func+pcptrsize+7*4));
+               lp = pcline + pcswal(*(uint32*)(func+pcptrsize+8*4));
+               fval = lval = -1;
+               fpc = lpc = entry;
+               fstartpc = fpc;
+               while(step(&fp, &fpc, &fval, fpc==entry)) {
+                       if(fval == fno && fstartpc < fpc) {
+                               lstartpc = lpc;
+                               while(lpc < fpc && step(&lp, &lpc, &lval, lpc==entry)) {
+                                       if(lval == line) {
+                                               if(fstartpc <= lstartpc) {
+                                                       return lstartpc;
+                                               }
+                                               if(fstartpc < lpc) {
+                                                       return fstartpc;
+                                               }
+                                       }
+                                       lstartpc = lpc;
+                               }
+                       }
+                       fstartpc = fpc;
+               }
+       }
+       werrstr("cannot find line in file");
+       return ~(uvlong)0;
+}