diff options
author | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:29:25 +0000 |
commit | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch) | |
tree | 59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/symstabs.c | |
parent | 0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff) | |
download | plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2 plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip |
libmach
Diffstat (limited to 'src/libmach/symstabs.c')
-rw-r--r-- | src/libmach/symstabs.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/src/libmach/symstabs.c b/src/libmach/symstabs.c new file mode 100644 index 00000000..8c1ddac8 --- /dev/null +++ b/src/libmach/symstabs.c @@ -0,0 +1,401 @@ +#include <u.h> +#include <libc.h> +#include <mach.h> +#include "stabs.h" + +static int +strcmpcolon(char *a, char *bcolon) +{ + int i, len; + char *p; + + p = strchr(bcolon, ':'); + if(p == nil) + return strcmp(a, bcolon); + len = p-bcolon; + i = strncmp(a, bcolon, len); + if(i) + return i; + if(a[len] == 0) + return 0; + return 1; +} + +static int +stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i) +{ + char *p; + + /* + * Zero out the : to avoid allocating a new name string. + * The type info can be found by looking past the NUL. + * This is going to get us in trouble... + */ + if((p = strchr(stab->name, ':')) != nil) + *p++ = 0; + else + p = stab->name+strlen(stab->name)+1; + + sym->name = stab->name; + sym->u.stabs.dir = dir; + sym->u.stabs.file = file; + sym->u.stabs.i = i; + switch(stab->type){ + default: + return -1; + case N_FUN: + sym->class = CTEXT; + switch(*p){ + default: + return -1; + case 'F': /* global function */ + sym->type = 'T'; + break; + case 'Q': /* static procedure */ + case 'f': /* static function */ + case 'I': /* nested procedure */ + case 'J': /* nested function */ + sym->type = 't'; + break; + } + sym->loc.type = LADDR; + sym->loc.addr = stab->value; + break; + case N_GSYM: + case N_PSYM: + case N_LSYM: + case N_LCSYM: + sym->class = CDATA; + sym->loc.type = LADDR; + sym->loc.addr = stab->value; + switch(*p){ + default: + return -1; + case 'S': /* file-scope static variable */ + sym->type = 'd'; + break; + case 'G': /* global variable */ + sym->type = 'D'; + sym->loc.type = LNONE; + break; + case 'r': /* register variable */ + sym->class = CAUTO; + sym->type = 'a'; + sym->loc.type = LREG; + sym->loc.reg = "XXX"; + break; + case 's': /* local variable */ + sym->class = CAUTO; + sym->type = 'a'; + sym->loc.type = LOFFSET; + sym->loc.offset = stab->value; + sym->loc.reg = "XXX"; + break; + case 'a': /* by reference */ + case 'D': /* f.p. parameter */ + case 'i': /* register parameter */ + case 'p': /* "normal" parameter */ + case 'P': /* register parameter */ + case 'v': /* by reference */ + case 'X': /* function return variable */ + sym->class = CPARAM; + sym->type = 'p'; + if(*p == 'i'){ + sym->loc.type = LREG; + sym->loc.reg = "XXX"; + }else{ + sym->loc.type = LOFFSET; + sym->loc.offset = stab->value; + sym->loc.reg = "XXX"; + } + break; + } + break; + } + return 0; +} + +static int +stabssyminit(Fhdr *fp) +{ + int i; + char *dir, *file; + Stab *stabs; + StabSym sym, lastfun; + Symbol s, *fun; + char **inc, **xinc; + int ninc, minc; + int locals, autos, params; + + stabs = &fp->stabs; + if(stabs == nil){ + werrstr("no stabs info"); + return -1; + } + + dir = nil; + file = nil; + inc = nil; + fun = nil; + ninc = 0; + minc = 0; + locals = 0; + params = 0; + autos = 0; + memset(&lastfun, 0, sizeof lastfun); + for(i=0; stabsym(stabs, i, &sym)>=0; i++){ + switch(sym.type){ + case N_SO: + if(sym.name == nil || *sym.name == 0){ + file = nil; + break; + } + if(sym.name[strlen(sym.name)-1] == '/') + dir = sym.name; + else + file = sym.name; + break; + case N_BINCL: + if(ninc >= minc){ + xinc = realloc(inc, (ninc+32)*sizeof(inc[0])); + if(xinc){ + memset(xinc+ninc, 0, 32*sizeof(inc[0])); + inc = xinc; + } + ninc += 32; + } + if(ninc < minc) + inc[ninc] = sym.name; + ninc++; + break; + case N_EINCL: + if(ninc > 0) + ninc--; + break; + case N_EXCL: + /* condensed include - same effect as previous BINCL/EINCL pair */ + break; + case N_GSYM: /* global variable */ + /* only includes type, so useless for now */ + break; + case N_FUN: + if(sym.name == nil){ + /* marks end of function */ + if(fun){ + fun->hiloc.type = LADDR; + fun->hiloc.addr = fun->loc.addr + sym.value; + } + break; + } + if(fun && lastfun.value==sym.value && lastfun.name==sym.name){ + fun->u.stabs.locals = i; + break; + } + /* create new symbol, add it */ + lastfun = sym; + fun = nil; + if(stabcvtsym(&sym, &s, dir, file, i) < 0) + continue; + if((fun = addsym(fp, &s)) == nil) + goto err; + locals = 0; + params = 0; + autos = 0; + break; + case N_PSYM: + case N_LSYM: + case N_LCSYM: + if(fun){ + if(fun->u.stabs.frameptr == -1){ + /* + * Try to distinguish functions with a real frame pointer + * from functions with a virtual frame pointer, based on + * whether the first parameter is in the right location and + * whether the autos have negative offsets. + * + * This heuristic works most of the time. On the 386, we + * cannot distinguish between a v. function with no autos + * but a frame of size 4 and a f.p. function with no autos and + * no frame. Anything else we'll get right. + * + * Another way to go about this would be to have + * mach-specific functions to inspect the function + * prologues when we're not sure. What we have + * already should be enough, though. + */ + if(params==0 && sym.type == N_PSYM){ + if(sym.value != 8 && sym.value >= 4){ + /* XXX 386 specific, but let's find another system before generalizing */ + fun->u.stabs.frameptr = 0; + fun->u.stabs.framesize = sym.value - 4; + } + }else if(sym.type == N_LSYM){ + if(sym.value >= 0){ + fun->u.stabs.frameptr = 0; + if(params) + fun->u.stabs.framesize = 8 - 4; + }else + fun->u.stabs.frameptr = 1; + } + } + if(sym.type == N_PSYM) + params++; + if(sym.type == N_LSYM) + autos++; + } + break; + + case N_STSYM: /* static file-scope variable */ + /* create new symbol, add it */ + if(stabcvtsym(&sym, &s, dir, file, i) < 0) + continue; + if(addsym(fp, &s) < 0) + goto err; + break; + } + } + free(inc); + return 0; + +err: + free(inc); + return -1; +} + +static int +stabspc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *pline) +{ + int i; + Symbol *s; + StabSym ss; + ulong line, basepc; + Loc l; + + l.type = LADDR; + l.addr = pc; + if((s = ffindsym(fhdr, l, CTEXT)) == nil + || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0) + return -1; + + line = ss.desc; + basepc = ss.value; + for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){ + if(ss.type == N_FUN && ss.name == nil) + break; + if(ss.type == N_SLINE){ + if(basepc+ss.value > pc) + break; + else + line = ss.desc; + } + } + *pline = line; + if(s->u.stabs.dir) + snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file); + else + snprint(buf, nbuf, "%s", s->u.stabs.file); + return 0; +} + +static int +stabsline2pc(Fhdr *fhdr, ulong startpc, ulong line, ulong *pc) +{ + int i, trigger; + Symbol *s; + StabSym ss; + ulong basepc; + Loc l; + + l.type = LADDR; + l.addr = startpc; + if((s = ffindsym(fhdr, l, CTEXT)) == nil) + return -1; + + trigger = 0; + line = ss.desc; + basepc = ss.value; + for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){ + if(ss.type == N_FUN) + basepc = ss.value; + if(ss.type == N_SLINE){ + if(basepc+ss.value >= startpc) + trigger = 1; + if(trigger && ss.desc >= line){ + *pc = basepc+ss.value; + return 0; + } + } + } + return -1; +} + +static int +stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s) +{ + int i; + StabSym ss; + + for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){ + if(ss.type == N_FUN && ss.name == nil) + break; + switch(ss.type){ + case N_PSYM: + case N_LSYM: + case N_LCSYM: + if(name){ + if(strcmpcolon(name, ss.name) != 0) + break; + }else if(l.type){ + /* wait for now */ + }else{ + if(j-- > 0) + break; + } + if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0) + return -1; + if(s->loc.type == LOFFSET){ + if(p->u.stabs.frameptr == 0) + s->loc.reg = mach->sp; + else + s->loc.reg = mach->fp; + } + if(l.type && loccmp(&l, &s->loc) != 0) + break; + return 0; + } + } + return -1; +} + +static Loc zl; + +static int +stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s) +{ + return stabslenum(fhdr, p, name, 0, zl, s); +} + +static int +stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s) +{ + return stabslenum(fhdr, p, nil, i, zl, s); +} + +static int +stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s) +{ + return stabslenum(fhdr, p, nil, 0, l, s); +} + +int +symstabs(Fhdr *fp) +{ + if(stabssyminit(fp) < 0) + return -1; + fp->pc2file = stabspc2file; + fp->line2pc = stabsline2pc; + fp->lookuplsym = stabslookuplsym; + fp->indexlsym = stabsindexlsym; + fp->findlsym = stabsfindlsym; + return 0; +} |