dwarfinfo.c (15367B)
1 /* 2 * Dwarf info parse and search. 3 */ 4 5 #include <u.h> 6 #include <libc.h> 7 #include <bio.h> 8 #include "elf.h" 9 #include "dwarf.h" 10 11 enum 12 { 13 DwarfAttrSibling = 0x01, 14 DwarfAttrLocation = 0x02, 15 DwarfAttrName = 0x03, 16 DwarfAttrOrdering = 0x09, 17 DwarfAttrByteSize = 0x0B, 18 DwarfAttrBitOffset = 0x0C, 19 DwarfAttrBitSize = 0x0D, 20 DwarfAttrStmtList = 0x10, 21 DwarfAttrLowpc = 0x11, 22 DwarfAttrHighpc = 0x12, 23 DwarfAttrLanguage = 0x13, 24 DwarfAttrDiscr = 0x15, 25 DwarfAttrDiscrValue = 0x16, 26 DwarfAttrVisibility = 0x17, 27 DwarfAttrImport = 0x18, 28 DwarfAttrStringLength = 0x19, 29 DwarfAttrCommonRef = 0x1A, 30 DwarfAttrCompDir = 0x1B, 31 DwarfAttrConstValue = 0x1C, 32 DwarfAttrContainingType = 0x1D, 33 DwarfAttrDefaultValue = 0x1E, 34 DwarfAttrInline = 0x20, 35 DwarfAttrIsOptional = 0x21, 36 DwarfAttrLowerBound = 0x22, 37 DwarfAttrProducer = 0x25, 38 DwarfAttrPrototyped = 0x27, 39 DwarfAttrReturnAddr = 0x2A, 40 DwarfAttrStartScope = 0x2C, 41 DwarfAttrStrideSize = 0x2E, 42 DwarfAttrUpperBound = 0x2F, 43 DwarfAttrAbstractOrigin = 0x31, 44 DwarfAttrAccessibility = 0x32, 45 DwarfAttrAddrClass = 0x33, 46 DwarfAttrArtificial = 0x34, 47 DwarfAttrBaseTypes = 0x35, 48 DwarfAttrCalling = 0x36, 49 DwarfAttrCount = 0x37, 50 DwarfAttrDataMemberLoc = 0x38, 51 DwarfAttrDeclColumn = 0x39, 52 DwarfAttrDeclFile = 0x3A, 53 DwarfAttrDeclLine = 0x3B, 54 DwarfAttrDeclaration = 0x3C, 55 DwarfAttrDiscrList = 0x3D, 56 DwarfAttrEncoding = 0x3E, 57 DwarfAttrExternal = 0x3F, 58 DwarfAttrFrameBase = 0x40, 59 DwarfAttrFriend = 0x41, 60 DwarfAttrIdentifierCase = 0x42, 61 DwarfAttrMacroInfo = 0x43, 62 DwarfAttrNamelistItem = 0x44, 63 DwarfAttrPriority = 0x45, 64 DwarfAttrSegment = 0x46, 65 DwarfAttrSpecification = 0x47, 66 DwarfAttrStaticLink = 0x48, 67 DwarfAttrType = 0x49, 68 DwarfAttrUseLocation = 0x4A, 69 DwarfAttrVarParam = 0x4B, 70 DwarfAttrVirtuality = 0x4C, 71 DwarfAttrVtableElemLoc = 0x4D, 72 DwarfAttrAllocated = 0x4E, 73 DwarfAttrAssociated = 0x4F, 74 DwarfAttrDataLocation = 0x50, 75 DwarfAttrStride = 0x51, 76 DwarfAttrEntrypc = 0x52, 77 DwarfAttrUseUTF8 = 0x53, 78 DwarfAttrExtension = 0x54, 79 DwarfAttrRanges = 0x55, 80 DwarfAttrTrampoline = 0x56, 81 DwarfAttrCallColumn = 0x57, 82 DwarfAttrCallFile = 0x58, 83 DwarfAttrCallLine = 0x59, 84 DwarfAttrDescription = 0x5A, 85 DwarfAttrMax, 86 87 FormAddr = 0x01, 88 FormDwarfBlock2 = 0x03, 89 FormDwarfBlock4 = 0x04, 90 FormData2 = 0x05, 91 FormData4 = 0x06, 92 FormData8 = 0x07, 93 FormString = 0x08, 94 FormDwarfBlock = 0x09, 95 FormDwarfBlock1 = 0x0A, 96 FormData1 = 0x0B, 97 FormFlag = 0x0C, 98 FormSdata = 0x0D, 99 FormStrp = 0x0E, 100 FormUdata = 0x0F, 101 FormRefAddr = 0x10, 102 FormRef1 = 0x11, 103 FormRef2 = 0x12, 104 FormRef4 = 0x13, 105 FormRef8 = 0x14, 106 FormRefUdata = 0x15, 107 FormIndirect = 0x16 108 }; 109 110 static int parseattrs(DwarfBuf*, ulong, DwarfAbbrev*, DwarfAttrs*); 111 static int getulong(DwarfBuf*, int, ulong, ulong*, int*); 112 static int getuchar(DwarfBuf*, int, uchar*); 113 static int getstring(DwarfBuf*, int, char**); 114 static int getblock(DwarfBuf*, int, DwarfBlock*); 115 static int skipform(DwarfBuf*, int); 116 static int constblock(Dwarf*, DwarfBlock*, ulong*); 117 118 int 119 dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s) 120 { 121 if(dwarfenumunit(d, unit, s) < 0) 122 return -1; 123 124 dwarfnextsymat(d, s, 0); /* s is now the CompileUnit */ 125 while(dwarfnextsymat(d, s, 1) == 1) 126 if(s->attrs.name && strcmp(s->attrs.name, name) == 0) 127 return 0; 128 werrstr("symbol '%s' not found", name); 129 return -1; 130 } 131 132 133 int 134 dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s) 135 { 136 *s = *parent; 137 while(dwarfnextsymat(d, s, parent->depth+1)) 138 if(s->attrs.name && strcmp(s->attrs.name, name) == 0) 139 return 0; 140 werrstr("symbol '%s' not found", name); 141 return -1; 142 } 143 144 int 145 dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s) 146 { 147 if(dwarfenumunit(d, unit, s) < 0) 148 return -1; 149 150 dwarfnextsymat(d, s, 0); /* s is now the CompileUnit */ 151 if(s->attrs.tag == tag) 152 return 0; 153 while(dwarfnextsymat(d, s, 1) == 1) 154 if(s->attrs.tag == tag) 155 return 0; 156 werrstr("symbol with tag 0x%lux not found", tag); 157 return -1; 158 } 159 160 int 161 dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s) 162 { 163 if(dwarfenumunit(d, unit, s) < 0) 164 return -1; 165 s->b.p = d->info.data + unit + off; 166 if(dwarfnextsymat(d, s, 0) != 1) 167 return -1; 168 return 0; 169 } 170 171 int 172 dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s) 173 { 174 if(dwarfenumunit(d, unit, s) < 0) 175 return -1; 176 177 if(dwarfnextsymat(d, s, 0) != 1) 178 return -1; 179 /* s is now the CompileUnit */ 180 181 while(dwarfnextsymat(d, s, 1) == 1){ 182 if(s->attrs.tag != TagSubprogram) 183 continue; 184 if(s->attrs.lowpc <= pc && pc < s->attrs.highpc) 185 return 0; 186 } 187 werrstr("fn containing pc 0x%lux not found", pc); 188 return -1; 189 } 190 191 int 192 dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s) 193 { 194 int i; 195 ulong aoff, len; 196 197 if(unit >= d->info.len){ 198 werrstr("dwarf unit address 0x%lux >= 0x%lux out of range", unit, d->info.len); 199 return -1; 200 } 201 memset(s, 0, sizeof *s); 202 memset(&s->b, 0, sizeof s->b); 203 s->b.d = d; 204 s->b.p = d->info.data + unit; 205 s->b.ep = d->info.data + d->info.len; 206 len = dwarfget4(&s->b); 207 s->nextunit = unit + 4 + len; 208 209 if(s->b.ep - s->b.p < len){ 210 badheader: 211 werrstr("bad dwarf unit header at unit 0x%lux", unit); 212 return -1; 213 } 214 s->b.ep = s->b.p+len; 215 if((i=dwarfget2(&s->b)) != 2) 216 goto badheader; 217 aoff = dwarfget4(&s->b); 218 s->b.addrsize = dwarfget1(&s->b); 219 if(d->addrsize == 0) 220 d->addrsize = s->b.addrsize; 221 if(s->b.p == nil) 222 goto badheader; 223 224 s->aoff = aoff; 225 s->unit = unit; 226 s->depth = 0; 227 return 0; 228 } 229 230 int 231 dwarfenum(Dwarf *d, DwarfSym *s) 232 { 233 if(dwarfenumunit(d, 0, s) < 0) 234 return -1; 235 s->allunits = 1; 236 return 0; 237 } 238 239 int 240 dwarfnextsym(Dwarf *d, DwarfSym *s) 241 { 242 ulong num; 243 DwarfAbbrev *a; 244 245 if(s->attrs.haskids) 246 s->depth++; 247 top: 248 if(s->b.p >= s->b.ep){ 249 if(s->allunits && s->nextunit < d->info.len){ 250 if(dwarfenumunit(d, s->nextunit, s) < 0) 251 return -1; 252 s->allunits = 1; 253 goto top; 254 } 255 return 0; 256 } 257 258 s->uoff = s->b.p - (d->info.data+s->unit); 259 num = dwarfget128(&s->b); 260 if(num == 0){ 261 if(s->depth == 0) 262 return 0; 263 if(s->depth > 0) 264 s->depth--; 265 goto top; 266 } 267 268 a = dwarfgetabbrev(d, s->aoff, num); 269 if(a == nil){ 270 fprint(2, "getabbrev %ud %ud for %ud,%ud: %r\n", s->aoff, num, s->unit, s->uoff); 271 abort(); 272 return -1; 273 } 274 if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0) 275 return -1; 276 return 1; 277 } 278 279 int 280 dwarfnextsymat(Dwarf *d, DwarfSym *s, int depth) 281 { 282 int r; 283 DwarfSym t; 284 uint sib; 285 286 if(s->depth == depth && s->attrs.have.sibling){ 287 sib = s->attrs.sibling; 288 if(sib < d->info.len && d->info.data+sib >= s->b.p) 289 s->b.p = d->info.data+sib; 290 s->attrs.haskids = 0; 291 } 292 293 /* 294 * The funny game with t and s make sure that 295 * if we get to the end of a run of a particular 296 * depth, we leave s so that a call to nextsymat with depth-1 297 * will actually produce the desired guy. We could change 298 * the interface to dwarfnextsym instead, but I'm scared 299 * to touch it. 300 */ 301 t = *s; 302 for(;;){ 303 if((r = dwarfnextsym(d, &t)) != 1) 304 return r; 305 if(t.depth < depth){ 306 /* went too far - nothing to see */ 307 return 0; 308 } 309 *s = t; 310 if(t.depth == depth) 311 return 1; 312 } 313 } 314 315 typedef struct Parse Parse; 316 struct Parse { 317 int name; 318 int off; 319 int haveoff; 320 int type; 321 }; 322 323 #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x) 324 325 static Parse plist[] = { /* Font Tab 4 */ 326 DwarfAttrAbstractOrigin, OFFSET(abstractorigin), TReference, 327 DwarfAttrAccessibility, OFFSET(accessibility), TConstant, 328 DwarfAttrAddrClass, OFFSET(addrclass), TConstant, 329 DwarfAttrArtificial, OFFSET(isartificial), TFlag, 330 DwarfAttrBaseTypes, OFFSET(basetypes), TReference, 331 DwarfAttrBitOffset, OFFSET(bitoffset), TConstant, 332 DwarfAttrBitSize, OFFSET(bitsize), TConstant, 333 DwarfAttrByteSize, OFFSET(bytesize), TConstant, 334 DwarfAttrCalling, OFFSET(calling), TConstant, 335 DwarfAttrCommonRef, OFFSET(commonref), TReference, 336 DwarfAttrCompDir, OFFSET(compdir), TString, 337 DwarfAttrConstValue, OFFSET(constvalue), TString|TConstant|TBlock, 338 DwarfAttrContainingType, OFFSET(containingtype), TReference, 339 DwarfAttrCount, OFFSET(count), TConstant|TReference, 340 DwarfAttrDataMemberLoc, OFFSET(datamemberloc), TBlock|TConstant|TReference, 341 DwarfAttrDeclColumn, OFFSET(declcolumn), TConstant, 342 DwarfAttrDeclFile, OFFSET(declfile), TConstant, 343 DwarfAttrDeclLine, OFFSET(declline), TConstant, 344 DwarfAttrDeclaration, OFFSET(isdeclaration), TFlag, 345 DwarfAttrDefaultValue, OFFSET(defaultvalue), TReference, 346 DwarfAttrDiscr, OFFSET(discr), TReference, 347 DwarfAttrDiscrList, OFFSET(discrlist), TBlock, 348 DwarfAttrDiscrValue, OFFSET(discrvalue), TConstant, 349 DwarfAttrEncoding, OFFSET(encoding), TConstant, 350 DwarfAttrExternal, OFFSET(isexternal), TFlag, 351 DwarfAttrFrameBase, OFFSET(framebase), TBlock|TConstant, 352 DwarfAttrFriend, OFFSET(friend), TReference, 353 DwarfAttrHighpc, OFFSET(highpc), TAddress, 354 DwarfAttrIdentifierCase, OFFSET(identifiercase), TConstant, 355 DwarfAttrImport, OFFSET(import), TReference, 356 DwarfAttrInline, OFFSET(inlined), TConstant, 357 DwarfAttrIsOptional, OFFSET(isoptional), TFlag, 358 DwarfAttrLanguage, OFFSET(language), TConstant, 359 DwarfAttrLocation, OFFSET(location), TBlock|TConstant, 360 DwarfAttrLowerBound, OFFSET(lowerbound), TConstant|TReference, 361 DwarfAttrLowpc, OFFSET(lowpc), TAddress, 362 DwarfAttrMacroInfo, OFFSET(macroinfo), TConstant, 363 DwarfAttrName, OFFSET(name), TString, 364 DwarfAttrNamelistItem, OFFSET(namelistitem), TBlock, 365 DwarfAttrOrdering, OFFSET(ordering), TConstant, 366 DwarfAttrPriority, OFFSET(priority), TReference, 367 DwarfAttrProducer, OFFSET(producer), TString, 368 DwarfAttrPrototyped, OFFSET(isprototyped), TFlag, 369 DwarfAttrRanges, OFFSET(ranges), TReference, 370 DwarfAttrReturnAddr, OFFSET(returnaddr), TBlock|TConstant, 371 DwarfAttrSegment, OFFSET(segment), TBlock|TConstant, 372 DwarfAttrSibling, OFFSET(sibling), TReference, 373 DwarfAttrSpecification, OFFSET(specification), TReference, 374 DwarfAttrStartScope, OFFSET(startscope), TConstant, 375 DwarfAttrStaticLink, OFFSET(staticlink), TBlock|TConstant, 376 DwarfAttrStmtList, OFFSET(stmtlist), TConstant, 377 DwarfAttrStrideSize, OFFSET(stridesize), TConstant, 378 DwarfAttrStringLength, OFFSET(stringlength), TBlock|TConstant, 379 DwarfAttrType, OFFSET(type), TReference, 380 DwarfAttrUpperBound, OFFSET(upperbound), TConstant|TReference, 381 DwarfAttrUseLocation, OFFSET(uselocation), TBlock|TConstant, 382 DwarfAttrVarParam, OFFSET(isvarparam), TFlag, 383 DwarfAttrVirtuality, OFFSET(virtuality), TConstant, 384 DwarfAttrVisibility, OFFSET(visibility), TConstant, 385 DwarfAttrVtableElemLoc, OFFSET(vtableelemloc), TBlock|TReference, 386 }; 387 388 static Parse ptab[DwarfAttrMax]; 389 390 static int 391 parseattrs(DwarfBuf *b, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs) 392 { 393 int i, f, n, got; 394 static int nbad; 395 void *v; 396 397 /* initialize ptab first time through for quick access */ 398 if(ptab[DwarfAttrName].name != DwarfAttrName) 399 for(i=0; i<nelem(plist); i++) 400 ptab[plist[i].name] = plist[i]; 401 402 memset(attrs, 0, sizeof *attrs); 403 attrs->tag = a->tag; 404 attrs->haskids = a->haskids; 405 406 for(i=0; i<a->nattr; i++){ 407 n = a->attr[i].name; 408 f = a->attr[i].form; 409 if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){ 410 if(++nbad == 1) 411 fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n); 412 return -1; 413 } 414 v = (char*)attrs + ptab[n].off; 415 got = 0; 416 if(f == FormIndirect) 417 f = dwarfget128(b); 418 if((ptab[n].type&(TConstant|TReference|TAddress)) 419 && getulong(b, f, unit, v, &got) >= 0) 420 ; 421 else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0) 422 got = TFlag; 423 else if((ptab[n].type&TString) && getstring(b, f, v) >= 0) 424 got = TString; 425 else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0) 426 got = TBlock; 427 else{ 428 if(skipform(b, f) < 0){ 429 if(++nbad == 1) 430 fprint(2, "dwarf parse attrs: cannot skip form %d\n", f); 431 return -1; 432 } 433 } 434 if(got == TBlock && (ptab[n].type&TConstant)) 435 got = constblock(b->d, v, v); 436 *((uchar*)attrs+ptab[n].haveoff) = got; 437 } 438 return 0; 439 } 440 441 static int 442 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type) 443 { 444 static int nbad; 445 uvlong uv; 446 447 switch(form){ 448 default: 449 return -1; 450 451 /* addresses */ 452 case FormAddr: 453 *type = TAddress; 454 *u = dwarfgetaddr(b); 455 return 0; 456 457 /* references */ 458 case FormRefAddr: 459 /* absolute ref in .debug_info */ 460 *type = TReference; 461 *u = dwarfgetaddr(b); 462 return 0; 463 case FormRef1: 464 *u = dwarfget1(b); 465 goto relativeref; 466 case FormRef2: 467 *u = dwarfget2(b); 468 goto relativeref; 469 case FormRef4: 470 *u = dwarfget4(b); 471 goto relativeref; 472 case FormRef8: 473 *u = dwarfget8(b); 474 goto relativeref; 475 case FormRefUdata: 476 *u = dwarfget128(b); 477 relativeref: 478 *u += unit; 479 *type = TReference; 480 return 0; 481 482 /* constants */ 483 case FormData1: 484 *u = dwarfget1(b); 485 goto constant; 486 case FormData2: 487 *u = dwarfget2(b); 488 goto constant; 489 case FormData4: 490 *u = dwarfget4(b); 491 goto constant; 492 case FormData8: 493 uv = dwarfget8(b); 494 *u = uv; 495 if(uv != *u && ++nbad == 1) 496 fprint(2, "dwarf: truncating 64-bit attribute constants\n"); 497 goto constant; 498 case FormSdata: 499 *u = dwarfget128s(b); 500 goto constant; 501 case FormUdata: 502 *u = dwarfget128(b); 503 constant: 504 *type = TConstant; 505 return 0; 506 } 507 } 508 509 static int 510 getuchar(DwarfBuf *b, int form, uchar *u) 511 { 512 switch(form){ 513 default: 514 return -1; 515 516 case FormFlag: 517 *u = dwarfget1(b); 518 return 0; 519 } 520 } 521 522 static int 523 getstring(DwarfBuf *b, int form, char **s) 524 { 525 static int nbad; 526 ulong u; 527 528 switch(form){ 529 default: 530 return -1; 531 532 case FormString: 533 *s = dwarfgetstring(b); 534 return 0; 535 536 case FormStrp: 537 u = dwarfget4(b); 538 if(u >= b->d->str.len){ 539 if(++nbad == 1) 540 fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u); 541 /* don't return error - maybe can proceed */ 542 *s = nil; 543 }else 544 *s = (char*)b->d->str.data + u; 545 return 0; 546 547 } 548 } 549 550 static int 551 getblock(DwarfBuf *b, int form, DwarfBlock *bl) 552 { 553 ulong n; 554 555 switch(form){ 556 default: 557 return -1; 558 case FormDwarfBlock: 559 n = dwarfget128(b); 560 goto copyn; 561 case FormDwarfBlock1: 562 n = dwarfget1(b); 563 goto copyn; 564 case FormDwarfBlock2: 565 n = dwarfget2(b); 566 goto copyn; 567 case FormDwarfBlock4: 568 n = dwarfget4(b); 569 copyn: 570 bl->data = dwarfgetnref(b, n); 571 bl->len = n; 572 if(bl->data == nil) 573 return -1; 574 return 0; 575 } 576 } 577 578 static int 579 constblock(Dwarf *d, DwarfBlock *bl, ulong *pval) 580 { 581 DwarfBuf b; 582 583 memset(&b, 0, sizeof b); 584 b.p = bl->data; 585 b.ep = bl->data+bl->len; 586 b.d = d; 587 588 switch(dwarfget1(&b)){ 589 case OpAddr: 590 *pval = dwarfgetaddr(&b); 591 return TConstant; 592 case OpConst1u: 593 *pval = dwarfget1(&b); 594 return TConstant; 595 case OpConst1s: 596 *pval = (schar)dwarfget1(&b); 597 return TConstant; 598 case OpConst2u: 599 *pval = dwarfget2(&b); 600 return TConstant; 601 case OpConst2s: 602 *pval = (s16int)dwarfget2(&b); 603 return TConstant; 604 case OpConst4u: 605 *pval = dwarfget4(&b); 606 return TConstant; 607 case OpConst4s: 608 *pval = (s32int)dwarfget4(&b); 609 return TConstant; 610 case OpConst8u: 611 *pval = (u64int)dwarfget8(&b); 612 return TConstant; 613 case OpConst8s: 614 *pval = (s64int)dwarfget8(&b); 615 return TConstant; 616 case OpConstu: 617 *pval = dwarfget128(&b); 618 return TConstant; 619 case OpConsts: 620 *pval = dwarfget128s(&b); 621 return TConstant; 622 case OpPlusUconst: 623 *pval = dwarfget128(&b); 624 return TConstant; 625 default: 626 return TBlock; 627 } 628 } 629 630 /* last resort */ 631 static int 632 skipform(DwarfBuf *b, int form) 633 { 634 int type; 635 DwarfVal val; 636 637 if(getulong(b, form, 0, &val.c, &type) < 0 638 && getuchar(b, form, (uchar*)&val) < 0 639 && getstring(b, form, &val.s) < 0 640 && getblock(b, form, &val.b) < 0) 641 return -1; 642 return 0; 643 }