URI:
       tsymdwarf.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tsymdwarf.c (10005B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <mach.h>
            5 #include "elf.h"
            6 #include "dwarf.h"
            7 
            8 static void        dwarfsymclose(Fhdr*);
            9 static int        dwarfpc2file(Fhdr*, u64int, char*, uint, ulong*);
           10 static int        dwarfline2pc(Fhdr*, u64int, ulong, u64int*);
           11 static int        dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
           12 static int        dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
           13 static int        dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
           14 static void        dwarfsyminit(Fhdr*);
           15 static int        dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
           16 static int        _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol*);
           17 
           18 int
           19 symdwarf(Fhdr *hdr)
           20 {
           21         if(hdr->dwarf == nil){
           22                 werrstr("no dwarf debugging symbols");
           23                 return -1;
           24         }
           25 
           26         hdr->symclose = dwarfsymclose;
           27         hdr->pc2file = dwarfpc2file;
           28         hdr->line2pc = dwarfline2pc;
           29         hdr->lookuplsym = dwarflookuplsym;
           30         hdr->indexlsym = dwarfindexlsym;
           31         hdr->findlsym = dwarffindlsym;
           32         hdr->unwind = _dwarfunwind;
           33         dwarfsyminit(hdr);
           34 
           35         return 0;
           36 }
           37 
           38 static void
           39 dwarfsymclose(Fhdr *hdr)
           40 {
           41         dwarfclose(hdr->dwarf);
           42         hdr->dwarf = nil;
           43 }
           44 
           45 static int
           46 dwarfpc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *line)
           47 {
           48         char *cdir, *dir, *file;
           49 
           50         if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
           51                 return -1;
           52 
           53         if(file[0] == '/' || (dir==nil && cdir==nil))
           54                 strecpy(buf, buf+nbuf, file);
           55         else if((dir && dir[0] == '/') || cdir==nil)
           56                 snprint(buf, nbuf, "%s/%s", dir, file);
           57         else
           58                 snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
           59         cleanname(buf);
           60         return 0;;
           61 }
           62 
           63 static int
           64 dwarfline2pc(Fhdr *fhdr, u64int basepc, ulong line, u64int *pc)
           65 {
           66         werrstr("dwarf line2pc not implemented");
           67         return -1;
           68 }
           69 
           70 static uint
           71 typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
           72 {
           73         DwarfSym ds;
           74 
           75 top:
           76         if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
           77         cannot:
           78                 fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
           79                         name, unit, tref);
           80                 return 0;
           81         }
           82 
           83         if(ds.attrs.have.bytesize)
           84                 return ds.attrs.bytesize;
           85 
           86         switch(ds.attrs.tag){
           87         case TagVolatileType:
           88         case TagRestrictType:
           89         case TagTypedef:
           90                 if(ds.attrs.have.type != TReference)
           91                         goto cannot;
           92                 tref = ds.attrs.type;
           93                 goto top;
           94         }
           95 
           96         goto cannot;
           97 }
           98 
           99 static int
          100 roundup(int s, int n)
          101 {
          102         return (s+n-1)&~(n-1);
          103 }
          104 
          105 static int
          106 dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
          107 {
          108         int depth, bpoff;
          109         DwarfSym ds;
          110         Symbol s1;
          111 
          112         if(p == nil)
          113                 return -1;
          114 
          115         if(p->u.dwarf.unit == 0 && p->u.dwarf.uoff == 0)
          116                 return -1;
          117 
          118         if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
          119                 return -1;
          120 
          121         ds.depth = 1;
          122         depth = 1;
          123 
          124         bpoff = 8;
          125         while(dwarfnextsym(fhdr->dwarf, &ds) == 1 && depth < ds.depth){
          126                 if(ds.attrs.tag != TagVariable){
          127                         if(ds.attrs.tag != TagFormalParameter
          128                         && ds.attrs.tag != TagUnspecifiedParameters)
          129                                 continue;
          130                         if(ds.depth != depth+1)
          131                                 continue;
          132                 }
          133                 if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
          134                         continue;
          135                 /* XXX move this out once there is another architecture */
          136                 /*
          137                  * gcc tells us the registers where the parameters might be
          138                  * held for an instruction or two.  use the parameter list to
          139                  * recompute the actual stack locations.
          140                  */
          141                 if(fhdr->mtype == M386)
          142                 if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
          143                         if(s1.loc.type==LOFFSET
          144                         && strcmp(s1.loc.reg, "BP")==0
          145                         && s1.loc.offset >= 8)
          146                                 bpoff = s1.loc.offset;
          147                         else{
          148                                 s1.loc.type = LOFFSET;
          149                                 s1.loc.reg = "BP";
          150                                 s1.loc.offset = bpoff;
          151                         }
          152                         if(ds.attrs.tag == TagFormalParameter){
          153                                 if(ds.attrs.have.type)
          154                                         bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
          155                                 else
          156                                         fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
          157                         }
          158                 }
          159                 if(name){
          160                         if(strcmp(ds.attrs.name, name) != 0)
          161                                 continue;
          162                 }else if(l.type){
          163                         if(loccmp(&s1.loc, &l) != 0)
          164                                 continue;
          165                 }else{
          166                         if(j-- > 0)
          167                                 continue;
          168                 }
          169                 *s = s1;
          170                 return 0;
          171         }
          172         return -1;
          173 }
          174 
          175 static Loc zl;
          176 
          177 static int
          178 dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
          179 {
          180         return dwarflenum(fhdr, p, name, 0, zl, s);
          181 }
          182 
          183 static int
          184 dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
          185 {
          186         return dwarflenum(fhdr, p, nil, i, zl, s);
          187 }
          188 
          189 static int
          190 dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
          191 {
          192         return dwarflenum(fhdr, p, nil, 0, l, s);
          193 }
          194 
          195 static void
          196 dwarfsyminit(Fhdr *fp)
          197 {
          198         Dwarf *d;
          199         DwarfSym s;
          200         Symbol sym;
          201 
          202         d = fp->dwarf;
          203         if(dwarfenum(d, &s) < 0)
          204                 return;
          205 
          206         while(dwarfnextsymat(d, &s, 0) == 1)
          207         while(dwarfnextsymat(d, &s, 1) == 1){
          208                 if(s.attrs.name == nil)
          209                         continue;
          210                 switch(s.attrs.tag){
          211                 case TagSubprogram:
          212                 case TagVariable:
          213                         if(dwarftosym(fp, d, &s, &sym, 0) < 0)
          214                                 continue;
          215                         _addsym(fp, &sym);
          216                 }
          217         }
          218 }
          219 
          220 static char*
          221 regname(Dwarf *d, int i)
          222 {
          223         if(i < 0 || i >= d->nreg)
          224                 return nil;
          225         return d->reg[i];
          226 }
          227 
          228 static int
          229 dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
          230 {
          231         DwarfBuf buf;
          232         DwarfBlock b;
          233 
          234         memset(s, 0, sizeof *s);
          235         s->u.dwarf.uoff = ds->uoff;
          236         s->u.dwarf.unit = ds->unit;
          237         switch(ds->attrs.tag){
          238         default:
          239                 return -1;
          240         case TagUnspecifiedParameters:
          241                 ds->attrs.name = "...";
          242                 s->type = 'p';
          243                 goto sym;
          244         case TagFormalParameter:
          245                 s->type = 'p';
          246                 s->class = CPARAM;
          247                 goto sym;
          248         case TagSubprogram:
          249                 s->type = 't';
          250                 s->class = CTEXT;
          251                 goto sym;
          252         case TagVariable:
          253                 if(infn){
          254                         s->type = 'a';
          255                         s->class = CAUTO;
          256                 }else{
          257                         s->type = 'd';
          258                         s->class = CDATA;
          259                 }
          260         sym:
          261                 s->name = ds->attrs.name;
          262                 if(ds->attrs.have.lowpc){
          263                         s->loc.type = LADDR;
          264                         s->loc.addr = ds->attrs.lowpc;
          265                         if(ds->attrs.have.highpc){
          266                                 s->hiloc.type = LADDR;
          267                                 s->hiloc.addr = ds->attrs.highpc;
          268                         }
          269                 }else if(ds->attrs.have.location == TConstant){
          270                         s->loc.type = LADDR;
          271                         s->loc.addr = ds->attrs.location.c;
          272                 }else if(ds->attrs.have.location == TBlock){
          273                         b = ds->attrs.location.b;
          274                         if(b.len == 0)
          275                                 return -1;
          276                         buf.p = b.data+1;
          277                         buf.ep = b.data+b.len;
          278                         buf.d = d;
          279                         buf.addrsize = 0;
          280                         if(b.data[0]==OpAddr){
          281                                 if(b.len != 5)
          282                                         return -1;
          283                                 s->loc.type = LADDR;
          284                                 s->loc.addr = dwarfgetaddr(&buf);
          285                         }else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
          286                                 if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
          287                                         return -1;
          288                                 s->loc.type = LREG;
          289                         }else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
          290                                 s->loc.type = LOFFSET;
          291                                 s->loc.reg = regname(d, b.data[0]-0x70);
          292                                 s->loc.offset = dwarfget128s(&buf);
          293                                 if(s->loc.reg == nil)
          294                                         return -1;
          295                         }else if(b.data[0] == OpRegx){
          296                                 s->loc.type = LREG;
          297                                 s->loc.reg = regname(d, dwarfget128(&buf));
          298                                 if(s->loc.reg == nil)
          299                                         return -1;
          300                         }else if(b.data[0] == OpFbreg){
          301                                 s->loc.type = LOFFSET;
          302                                 s->loc.reg = mach->fp;
          303                                 s->loc.offset = dwarfget128s(&buf);
          304                         }else if(b.data[0] == OpBregx){
          305                                 s->loc.type = LOFFSET;
          306                                 s->loc.reg = regname(d, dwarfget128(&buf));
          307                                 s->loc.offset = dwarfget128s(&buf);
          308                                 if(s->loc.reg == nil)
          309                                         return -1;
          310                         }else
          311                                 s->loc.type = LNONE;
          312                         if(buf.p != buf.ep)
          313                                 s->loc.type = LNONE;
          314                 }else
          315                         return -1;
          316                 if(ds->attrs.isexternal)
          317                         s->type += 'A' - 'a';
          318                 if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
          319                         s->type += 'b' - 'd';
          320                 s->fhdr = fp;
          321                 return 0;
          322         }
          323 }
          324 
          325 static int
          326 dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, u64int *u)
          327 {
          328         int i;
          329         u32int u4;
          330         u64int uu;
          331 
          332         switch(e.type){
          333         case RuleUndef:
          334                 *u = 0;
          335                 return 0;
          336         case RuleSame:
          337                 if(rno == -1){
          338                         werrstr("pc cannot be `same'");
          339                         return -1;
          340                 }
          341                 return rget(regs, regname(d, rno), u);
          342         case RuleRegister:
          343                 if((i = windindex(regname(d, e.reg))) < 0)
          344                         return -1;
          345                 return rget(regs, regname(d, i), u);
          346         case RuleCfaOffset:
          347                 if(cfa == 0){
          348                         werrstr("unknown cfa");
          349                         return -1;
          350                 }
          351                 if(get4(map, cfa + e.offset, &u4) < 0)
          352                         return -1;
          353                 *u = u4;
          354                 return 0;
          355         case RuleRegOff:
          356                 if(rget(regs, regname(d, e.reg), &uu) < 0)
          357                         return -1;
          358                 if(get4(map, uu+e.offset, &u4) < 0)
          359                         return -1;
          360                 *u = u4;
          361                 return 0;
          362         case RuleLocation:
          363                 werrstr("not evaluating dwarf loc expressions");
          364                 return -1;
          365         }
          366         werrstr("not reached in dwarfeval");
          367         return -1;
          368 }
          369 
          370 #if 0
          371 static int
          372 dwarfexprfmt(Fmt *fmt)
          373 {
          374         DwarfExpr *e;
          375 
          376         if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
          377                 return fmtstrcpy(fmt, "<nil>");
          378 
          379         switch(e->type){
          380         case RuleUndef:
          381                 return fmtstrcpy(fmt, "undef");
          382         case RuleSame:
          383                 return fmtstrcpy(fmt, "same");
          384         case RuleCfaOffset:
          385                 return fmtprint(fmt, "%ld(cfa)", e->offset);
          386         case RuleRegister:
          387                 return fmtprint(fmt, "r%ld", e->reg);
          388         case RuleRegOff:
          389                 return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
          390         case RuleLocation:
          391                 return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
          392         default:
          393                 return fmtprint(fmt, "?%d", e->type);
          394         }
          395 }
          396 #endif
          397 
          398 static int
          399 _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol *sym)
          400 {
          401         char *name;
          402         int i, j;
          403         u64int cfa, pc, u;
          404         Dwarf *d;
          405         DwarfExpr *e, epc, ecfa;
          406 
          407 
          408         /*
          409          * Use dwarfunwind to tell us what to do.
          410          */
          411         d = fhdr->dwarf;
          412         e = malloc(d->nreg*sizeof(e[0]));
          413         if(e == nil)
          414                 return -1;
          415         if(rget(regs, mach->pc, &pc) < 0)
          416                 goto err;
          417         if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
          418                 goto err;
          419 
          420         /*
          421          * Compute CFA.
          422          */
          423         switch(ecfa.type){
          424         default:
          425                 werrstr("invalid call-frame-address in _dwarfunwind");
          426                 goto err;
          427         case RuleRegister:
          428                 ecfa.offset = 0;
          429         case RuleRegOff:
          430                 if((name = regname(d, ecfa.reg)) == nil){
          431                         werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
          432                         goto err;
          433                 }
          434                 if(rget(regs, name, &cfa) < 0){
          435                         werrstr("fetching %s for call-frame-address: %r", name);
          436                         goto err;
          437                 }
          438                 cfa += ecfa.offset;
          439         }
          440 
          441         /*
          442          * Compute registers.
          443          */
          444         for(i=0; i<d->nreg; i++){
          445                 j = windindex(d->reg[i]);
          446                 if(j == -1)
          447                         continue;
          448                 if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
          449                         u = ~(ulong)0;
          450                 next[j] = u;
          451         }
          452 
          453         /*
          454          * Compute caller pc
          455          */
          456         if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
          457                 werrstr("computing caller %s: %r", mach->pc);
          458                 goto err;
          459         }
          460         next[windindex(mach->pc)] = u;
          461         free(e);
          462         return 0;
          463 
          464 err:
          465         free(e);
          466         return -1;
          467 }