aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/symstabs.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:29:25 +0000
committerrsc <devnull@localhost>2004-04-19 19:29:25 +0000
commita84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (patch)
tree59a0e921597e5aa53e83d487c16727a7bf01547a /src/libmach/symstabs.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/symstabs.c')
-rw-r--r--src/libmach/symstabs.c401
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;
+}