symdwarf.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 }