aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/symdwarf.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/symdwarf.c
parent0e3cc9f456ea49919459bf1164d0c8309a6134fa (diff)
downloadplan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.gz
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.tar.bz2
plan9port-a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46.zip
libmach
Diffstat (limited to 'src/libmach/symdwarf.c')
-rw-r--r--src/libmach/symdwarf.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/src/libmach/symdwarf.c b/src/libmach/symdwarf.c
new file mode 100644
index 00000000..8ced09f4
--- /dev/null
+++ b/src/libmach/symdwarf.c
@@ -0,0 +1,466 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#include "elf.h"
+#include "dwarf.h"
+
+static void dwarfsymclose(Fhdr*);
+static int dwarfpc2file(Fhdr*, ulong, char*, uint, ulong*);
+static int dwarfline2pc(Fhdr*, ulong, ulong, ulong*);
+static int dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
+static int dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
+static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
+static void dwarfsyminit(Fhdr*);
+static int dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
+static int _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next);
+
+int
+symdwarf(Fhdr *hdr)
+{
+ if(hdr->dwarf == nil){
+ werrstr("no dwarf debugging symbols");
+ return -1;
+ }
+
+ hdr->symclose = dwarfsymclose;
+ hdr->pc2file = dwarfpc2file;
+ hdr->line2pc = dwarfline2pc;
+ hdr->lookuplsym = dwarflookuplsym;
+ hdr->indexlsym = dwarfindexlsym;
+ hdr->findlsym = dwarffindlsym;
+ hdr->unwind = _dwarfunwind;
+ dwarfsyminit(hdr);
+
+ return 0;
+}
+
+static void
+dwarfsymclose(Fhdr *hdr)
+{
+ dwarfclose(hdr->dwarf);
+ hdr->dwarf = nil;
+}
+
+static int
+dwarfpc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *line)
+{
+ char *cdir, *dir, *file;
+
+ if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
+ return -1;
+
+ if(file[0] == '/' || (dir==nil && cdir==nil))
+ strecpy(buf, buf+nbuf, file);
+ else if((dir && dir[0] == '/') || cdir==nil)
+ snprint(buf, nbuf, "%s/%s", dir, file);
+ else
+ snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
+ cleanname(buf);
+ return 0;;
+}
+
+static int
+dwarfline2pc(Fhdr *fhdr, ulong basepc, ulong line, ulong *pc)
+{
+ werrstr("dwarf line2pc not implemented");
+ return -1;
+}
+
+static uint
+typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
+{
+ DwarfSym ds;
+
+top:
+ if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
+ cannot:
+ fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
+ name, unit, tref);
+ return 0;
+ }
+
+ if(ds.attrs.have.bytesize)
+ return ds.attrs.bytesize;
+
+ switch(ds.attrs.tag){
+ case TagVolatileType:
+ case TagRestrictType:
+ case TagTypedef:
+ if(ds.attrs.have.type != TReference)
+ goto cannot;
+ tref = ds.attrs.type;
+ goto top;
+ }
+
+ goto cannot;
+}
+
+static int
+roundup(int s, int n)
+{
+ return (s+n-1)&~(n-1);
+}
+
+static int
+dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
+{
+ int depth, bpoff;
+ DwarfSym ds;
+ Symbol s1;
+
+ if(p == nil)
+ return -1;
+
+ if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
+ return -1;
+
+ ds.depth = 1;
+ depth = 1;
+
+ bpoff = 8;
+ while(dwarfnextsym(fhdr->dwarf, &ds, 1) == 1 && depth < ds.depth){
+ if(ds.attrs.tag != TagVariable){
+ if(ds.attrs.tag != TagFormalParameter
+ && ds.attrs.tag != TagUnspecifiedParameters)
+ continue;
+ if(ds.depth != depth+1)
+ continue;
+ }
+ if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
+ continue;
+ /* XXX move this out once there is another architecture */
+ /*
+ * gcc tells us the registers where the parameters might be
+ * held for an instruction or two. use the parameter list to
+ * recompute the actual stack locations.
+ */
+ if(fhdr->mtype == M386)
+ if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
+ if(s1.loc.type==LOFFSET
+ && strcmp(s1.loc.reg, "BP")==0
+ && s1.loc.offset >= 8)
+ bpoff = s1.loc.offset;
+ else{
+ s1.loc.type = LOFFSET;
+ s1.loc.reg = "BP";
+ s1.loc.offset = bpoff;
+ }
+ if(ds.attrs.tag == TagFormalParameter){
+ if(ds.attrs.have.type)
+ bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
+ else
+ fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
+ }
+ }
+ if(name){
+ if(strcmp(ds.attrs.name, name) != 0)
+ continue;
+ }else if(l.type){
+ if(loccmp(&s1.loc, &l) != 0)
+ continue;
+ }else{
+ if(j-- > 0)
+ continue;
+ }
+ *s = s1;
+ return 0;
+ }
+ return -1;
+}
+
+static Loc zl;
+
+static int
+dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
+{
+ return dwarflenum(fhdr, p, name, 0, zl, s);
+}
+
+static int
+dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
+{
+ return dwarflenum(fhdr, p, nil, i, zl, s);
+}
+
+static int
+dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
+{
+ return dwarflenum(fhdr, p, nil, 0, l, s);
+}
+
+static void
+dwarfsyminit(Fhdr *fp)
+{
+ Dwarf *d;
+ DwarfSym s;
+ Symbol sym;
+
+ d = fp->dwarf;
+ if(dwarfenum(d, &s) < 0)
+ return;
+
+ while(dwarfnextsym(d, &s, s.depth!=1) == 1){
+ if(s.depth != 1)
+ continue;
+ if(s.attrs.name == nil)
+ continue;
+ switch(s.attrs.tag){
+ case TagSubprogram:
+ case TagVariable:
+ if(dwarftosym(fp, d, &s, &sym, 0) < 0)
+ continue;
+ addsym(fp, &sym);
+ }
+ }
+}
+
+static char*
+regname(Dwarf *d, int i)
+{
+ if(i < 0 || i >= d->nreg)
+ return nil;
+ return d->reg[i];
+}
+
+static int
+dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
+{
+ DwarfBuf buf;
+ DwarfBlock b;
+
+ memset(s, 0, sizeof *s);
+ s->u.dwarf.uoff = ds->uoff;
+ s->u.dwarf.unit = ds->unit;
+ switch(ds->attrs.tag){
+ default:
+ return -1;
+ case TagUnspecifiedParameters:
+ ds->attrs.name = "...";
+ s->type = 'p';
+ goto sym;
+ case TagFormalParameter:
+ s->type = 'p';
+ s->class = CPARAM;
+ goto sym;
+ case TagSubprogram:
+ s->type = 't';
+ s->class = CTEXT;
+ goto sym;
+ case TagVariable:
+ if(infn){
+ s->type = 'a';
+ s->class = CAUTO;
+ }else{
+ s->type = 'd';
+ s->class = CDATA;
+ }
+ sym:
+ s->name = ds->attrs.name;
+ if(ds->attrs.have.lowpc){
+ s->loc.type = LADDR;
+ s->loc.addr = ds->attrs.lowpc;
+ if(ds->attrs.have.highpc){
+ s->hiloc.type = LADDR;
+ s->hiloc.addr = ds->attrs.highpc;
+ }
+ }else if(ds->attrs.have.location == TConstant){
+ s->loc.type = LADDR;
+ s->loc.addr = ds->attrs.location.c;
+ }else if(ds->attrs.have.location == TBlock){
+ b = ds->attrs.location.b;
+ if(b.len == 0)
+ return -1;
+ buf.p = b.data+1;
+ buf.ep = b.data+b.len;
+ buf.d = d;
+ buf.addrsize = 0;
+ if(b.data[0]==OpAddr){
+ if(b.len != 5)
+ return -1;
+ s->loc.type = LADDR;
+ s->loc.addr = dwarfgetaddr(&buf);
+ }else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
+ if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
+ return -1;
+ s->loc.type = LREG;
+ }else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
+ s->loc.type = LOFFSET;
+ s->loc.reg = regname(d, b.data[0]-0x70);
+ s->loc.offset = dwarfget128s(&buf);
+ if(s->loc.reg == nil)
+ return -1;
+ }else if(b.data[0] == OpRegx){
+ s->loc.type = LREG;
+ s->loc.reg = regname(d, dwarfget128(&buf));
+ if(s->loc.reg == nil)
+ return -1;
+ }else if(b.data[0] == OpFbreg){
+ s->loc.type = LOFFSET;
+ s->loc.reg = mach->fp;
+ s->loc.offset = dwarfget128s(&buf);
+ }else if(b.data[0] == OpBregx){
+ s->loc.type = LOFFSET;
+ s->loc.reg = regname(d, dwarfget128(&buf));
+ s->loc.offset = dwarfget128s(&buf);
+ if(s->loc.reg == nil)
+ return -1;
+ }else
+ s->loc.type = LNONE;
+ if(buf.p != buf.ep)
+ s->loc.type = LNONE;
+ }else
+ return -1;
+ if(ds->attrs.isexternal)
+ s->type += 'A' - 'a';
+ if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
+ s->type += 'b' - 'd';
+ s->fhdr = fp;
+ return 0;
+ }
+}
+
+static int
+dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, ulong *u)
+{
+ int i;
+ u32int u4;
+ ulong uu;
+
+ switch(e.type){
+ case RuleUndef:
+ *u = 0;
+ return 0;
+ case RuleSame:
+ if(rno == -1){
+ werrstr("pc cannot be `same'");
+ return -1;
+ }
+ return rget(regs, regname(d, rno), u);
+ case RuleRegister:
+ if((i = windindex(regname(d, e.reg))) < 0)
+ return -1;
+ return rget(regs, regname(d, i), u);
+ case RuleCfaOffset:
+ if(cfa == 0){
+ werrstr("unknown cfa");
+ return -1;
+ }
+ if(get4(map, cfa + e.offset, &u4) < 0)
+ return -1;
+ *u = u4;
+ return 0;
+ case RuleRegOff:
+ if(rget(regs, regname(d, e.reg), &uu) < 0)
+ return -1;
+ if(get4(map, uu+e.offset, &u4) < 0)
+ return -1;
+ *u = u4;
+ return 0;
+ case RuleLocation:
+ werrstr("not evaluating dwarf loc expressions");
+ return -1;
+ }
+ werrstr("not reached in dwarfeval");
+ return -1;
+}
+
+#if 0
+static int
+dwarfexprfmt(Fmt *fmt)
+{
+ DwarfExpr *e;
+
+ if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
+ return fmtstrcpy(fmt, "<nil>");
+
+ switch(e->type){
+ case RuleUndef:
+ return fmtstrcpy(fmt, "undef");
+ case RuleSame:
+ return fmtstrcpy(fmt, "same");
+ case RuleCfaOffset:
+ return fmtprint(fmt, "%ld(cfa)", e->offset);
+ case RuleRegister:
+ return fmtprint(fmt, "r%ld", e->reg);
+ case RuleRegOff:
+ return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
+ case RuleLocation:
+ return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
+ default:
+ return fmtprint(fmt, "?%d", e->type);
+ }
+}
+#endif
+
+static int
+_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
+{
+ char *name;
+ int i, j;
+ ulong cfa, pc, u;
+ Dwarf *d;
+ DwarfExpr *e, epc, ecfa;
+
+
+ /*
+ * Use dwarfunwind to tell us what to do.
+ */
+ d = fhdr->dwarf;
+ e = malloc(d->nreg*sizeof(e[0]));
+ if(e == nil)
+ return -1;
+ if(rget(regs, mach->pc, &pc) < 0)
+ goto err;
+ if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
+ goto err;
+
+ /*
+ * Compute CFA.
+ */
+ switch(ecfa.type){
+ default:
+ werrstr("invalid call-frame-address in _dwarfunwind");
+ goto err;
+ case RuleRegister:
+ ecfa.offset = 0;
+ case RuleRegOff:
+ if((name = regname(d, ecfa.reg)) == nil){
+ werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
+ goto err;
+ }
+ if(rget(regs, name, &cfa) < 0){
+ werrstr("fetching %s for call-frame-address: %r", name);
+ goto err;
+ }
+ cfa += ecfa.offset;
+ }
+
+ /*
+ * Compute registers.
+ */
+ for(i=0; i<d->nreg; i++){
+ j = windindex(d->reg[i]);
+ if(j == -1)
+ continue;
+ if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
+ u = ~(ulong)0;
+ next[j] = u;
+ }
+
+ /*
+ * Compute caller pc
+ */
+ if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
+ werrstr("computing caller %s: %r", mach->pc);
+ goto err;
+ }
+ next[windindex(mach->pc)] = u;
+ free(e);
+ return 0;
+
+err:
+ free(e);
+ return -1;
+}
+