From: Russ Cox Date: Thu, 18 Jul 2013 14:12:28 +0000 (-0400) Subject: libmach: update for Go 1.2 pcln table X-Git-Tag: go1.2rc2~1011 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=08ce3c313376b6d600c08b977103d6c51350b3f6;p=gostls13.git libmach: update for Go 1.2 pcln table The change to addr2line makes it easy to test by hand. R=golang-dev, r CC=golang-dev https://golang.org/cl/11485044 --- diff --git a/src/cmd/addr2line/main.c b/src/cmd/addr2line/main.c index 9faadc27bb..54c4d90b5c 100644 --- a/src/cmd/addr2line/main.c +++ b/src/cmd/addr2line/main.c @@ -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 = "??"; diff --git a/src/libmach/sym.c b/src/libmach/sym.c index 28c80d6413..d8cd8ea1d9 100644 --- a/src/libmach/sym.c +++ b/src/libmach/sym.c @@ -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(pctxtend) - 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(pctxtend) - 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