diff options
Diffstat (limited to 'src/pkg/runtime/symtab.c')
-rw-r--r-- | src/pkg/runtime/symtab.c | 454 |
1 files changed, 0 insertions, 454 deletions
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c deleted file mode 100644 index da4579734..000000000 --- a/src/pkg/runtime/symtab.c +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 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. - -#include "runtime.h" -#include "defs.h" -#include "os.h" -#include "arch.h" - -extern byte pclntab[], epclntab[], symtab[], esymtab[]; - -typedef struct Sym Sym; -struct Sym -{ - uintptr value; - byte symtype; - byte *name; -// byte *gotype; -}; - -// Walk over symtab, calling fn(&s) for each symbol. -static void -walksymtab(void (*fn)(Sym*)) -{ - byte *p, *ep, *q; - Sym s; - - p = symtab; - ep = esymtab; - while(p < ep) { - if(p + 7 > ep) - break; - s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]); - - if(!(p[4]&0x80)) - 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. - q = p+1; - for(;;) { - if(q+2 > ep) - return; - if(q[0] == '\0' && q[1] == '\0') - break; - q += 2; - } - p = q+2; - }else{ - q = runtime·mchr(p, '\0', ep); - if(q == nil) - break; - p = q+1; - } - p += 4; // go type - fn(&s); - } -} - -// Symtab walker; accumulates info about functions. - -static Func *func; -static int32 nfunc; - -static byte **fname; -static int32 nfname; - -static Lock funclock; - -static void -dofunc(Sym *sym) -{ - Func *f; - - switch(sym->symtype) { - case 't': - case 'T': - case 'l': - case 'L': - if(runtime·strcmp(sym->name, (byte*)"etext") == 0) - break; - if(func == nil) { - nfunc++; - break; - } - f = &func[nfunc++]; - f->name = runtime·gostringnocopy(sym->name); - f->entry = sym->value; - if(sym->symtype == 'L' || sym->symtype == 'l') - f->frame = -sizeof(uintptr); - break; - case 'm': - if(nfunc > 0 && func != nil) - func[nfunc-1].frame += sym->value; - break; - case 'p': - if(nfunc > 0 && func != nil) { - f = &func[nfunc-1]; - // args counts 32-bit words. - // sym->value is the arg's offset. - // don't know width of this arg, so assume it is 64 bits. - if(f->args < sym->value/4 + 2) - f->args = sym->value/4 + 2; - } - break; - case 'f': - if(fname == nil) { - if(sym->value >= nfname) { - if(sym->value >= 0x10000) { - runtime·printf("invalid symbol file index %p\n", sym->value); - runtime·throw("mangled symbol table"); - } - nfname = sym->value+1; - } - break; - } - fname[sym->value] = sym->name; - break; - } -} - -// 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 = runtime·findnull(q); - if(p+1+len >= ep) - break; - if(p > buf && p[-1] != '/') - *p++ = '/'; - runtime·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); -// assume code only appear in top-level files. -static void -dosrcline(Sym *sym) -{ - static byte srcbuf[1000]; - static struct { - String srcstring; - int32 aline; - int32 delta; - } files[200]; - static int32 incstart; - static int32 nfunc, nfile, nhist; - Func *f; - int32 i; - - switch(sym->symtype) { - case 't': - case 'T': - if(runtime·strcmp(sym->name, (byte*)"etext") == 0) - break; - f = &func[nfunc++]; - // find source file - for(i = 0; i < nfile - 1; i++) { - if (files[i+1].aline > f->ln0) - break; - } - f->src = files[i].srcstring; - f->ln0 -= files[i].delta; - break; - case 'z': - if(sym->value == 1) { - // entry for main source file for a new object. - makepath(srcbuf, sizeof srcbuf, sym->name+1); - nhist = 0; - nfile = 0; - if(nfile == nelem(files)) - return; - files[nfile].srcstring = runtime·gostring(srcbuf); - files[nfile].aline = 0; - files[nfile++].delta = 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; - if(nhist == 0 && nfile < nelem(files)) { - // new top-level file - files[nfile].srcstring = runtime·gostring(srcbuf); - files[nfile].aline = sym->value; - // this is "line 0" - files[nfile++].delta = sym->value - 1; - } - }else{ - if(--nhist == 0) - files[nfile-1].delta += sym->value - incstart; - } - } - } -} - -// Interpret pc/ln table, saving the subpiece for each func. -static void -splitpcln(void) -{ - int32 line; - uintptr pc; - byte *p, *ep; - Func *f, *ef; - int32 pcquant; - - if(pclntab == epclntab || nfunc == 0) - return; - - switch(thechar) { - case '5': - pcquant = 4; - break; - default: // 6, 8 - pcquant = 1; - break; - } - - // pc/ln table bounds - p = pclntab; - ep = epclntab; - - f = func; - ef = func + nfunc; - pc = func[0].entry; // text base - f->pcln.array = p; - f->pc0 = pc; - line = 0; - for(;;) { - while(p < ep && *p > 128) - pc += pcquant * (*p++ - 128); - // runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line); - if(*p == 0) { - if(p+5 > ep) - break; - // 4 byte add to line - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 5; - } else if(*p <= 64) - line += *p++; - else - line -= *p++ - 64; - - // pc, line now match. - // Because the state machine begins at pc==entry and line==0, - // it can happen - just at the beginning! - that the update may - // have updated line but left pc alone, to tell us the true line - // number for pc==entry. In that case, update f->ln0. - // Having the correct initial line number is important for choosing - // the correct file in dosrcline above. - if(f == func && pc == f->pc0) { - f->pcln.array = p; - f->pc0 = pc + pcquant; - f->ln0 = line; - } - - if(f < ef && pc >= (f+1)->entry) { - f->pcln.len = p - f->pcln.array; - f->pcln.cap = f->pcln.len; - do - f++; - while(f < ef && pc >= (f+1)->entry); - f->pcln.array = p; - // pc0 and ln0 are the starting values for - // the loop over f->pcln, so pc must be - // adjusted by the same pcquant update - // that we're going to do as we continue our loop. - f->pc0 = pc + pcquant; - f->ln0 = line; - } - - pc += pcquant; - } - if(f < ef) { - f->pcln.len = p - f->pcln.array; - f->pcln.cap = f->pcln.len; - } -} - - -// Return actual file line number for targetpc in func f. -// (Source file is f->src.) -// NOTE(rsc): If you edit this function, also edit extern.go:/FileLine -int32 -runtime·funcline(Func *f, uintptr targetpc) -{ - byte *p, *ep; - uintptr pc; - int32 line; - int32 pcquant; - - enum { - debug = 0 - }; - - switch(thechar) { - case '5': - pcquant = 4; - break; - default: // 6, 8 - pcquant = 1; - break; - } - - p = f->pcln.array; - ep = p + f->pcln.len; - pc = f->pc0; - line = f->ln0; - if(debug && !runtime·panicking) - runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n", - pc, targetpc, line, p, (int32)f->pcln.len); - for(;;) { - // Table is a sequence of updates. - - // Each update says first how to adjust the pc, - // in possibly multiple instructions... - while(p < ep && *p > 128) - pc += pcquant * (*p++ - 128); - - if(debug && !runtime·panicking) - runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line); - - // If the pc has advanced too far or we're out of data, - // stop and the last known line number. - if(pc > targetpc || p >= ep) - break; - - // ... and then how to adjust the line number, - // in a single instruction. - if(*p == 0) { - if(p+5 > ep) - break; - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 5; - } else if(*p <= 64) - line += *p++; - else - line -= *p++ - 64; - // Now pc, line pair is consistent. - if(debug && !runtime·panicking) - runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line); - - // PC increments implicitly on each iteration. - pc += pcquant; - } - return line; -} - -static void -buildfuncs(void) -{ - extern byte etext[]; - - if(func != nil) - return; - - // Memory profiling uses this code; - // can deadlock if the profiler ends - // up back here. - m->nomemprof++; - - // count funcs, fnames - nfunc = 0; - nfname = 0; - walksymtab(dofunc); - - // initialize tables - func = runtime·mal((nfunc+1)*sizeof func[0]); - func[nfunc].entry = (uint64)etext; - fname = runtime·mal(nfname*sizeof fname[0]); - nfunc = 0; - walksymtab(dofunc); - - // split pc/ln table by func - splitpcln(); - - // record src file and line info for each func - walksymtab(dosrcline); - - m->nomemprof--; -} - -Func* -runtime·findfunc(uintptr addr) -{ - Func *f; - int32 nf, n; - - runtime·lock(&funclock); - if(func == nil) - buildfuncs(); - runtime·unlock(&funclock); - - if(nfunc == 0) - return nil; - if(addr < func[0].entry || addr >= func[nfunc].entry) - return nil; - - // binary search to find func with entry <= addr. - f = func; - nf = nfunc; - while(nf > 0) { - n = nf/2; - if(f[n].entry <= addr && addr < f[n+1].entry) - return &f[n]; - else if(addr < f[n].entry) - nf = n; - else { - f += n+1; - nf -= n+1; - } - } - - // can't get here -- we already checked above - // that the address was in the table bounds. - // this can only happen if the table isn't sorted - // by address or if the binary search above is buggy. - runtime·prints("findfunc unreachable\n"); - return nil; -} |