1 /* 2 * Dwarf info parse and search. 3 */ 4 5 #include <precomp.h> 6 #define NDEBUG 7 #include <debug.h> 8 9 enum 10 { 11 DwarfAttrSibling = 0x01, 12 DwarfAttrLocation = 0x02, 13 DwarfAttrName = 0x03, 14 DwarfAttrOrdering = 0x09, 15 DwarfAttrByteSize = 0x0B, 16 DwarfAttrBitOffset = 0x0C, 17 DwarfAttrBitSize = 0x0D, 18 DwarfAttrStmtList = 0x10, 19 DwarfAttrLowpc = 0x11, 20 DwarfAttrHighpc = 0x12, 21 DwarfAttrLanguage = 0x13, 22 DwarfAttrDiscr = 0x15, 23 DwarfAttrDiscrValue = 0x16, 24 DwarfAttrVisibility = 0x17, 25 DwarfAttrImport = 0x18, 26 DwarfAttrStringLength = 0x19, 27 DwarfAttrCommonRef = 0x1A, 28 DwarfAttrCompDir = 0x1B, 29 DwarfAttrConstValue = 0x1C, 30 DwarfAttrContainingType = 0x1D, 31 DwarfAttrDefaultValue = 0x1E, 32 DwarfAttrInline = 0x20, 33 DwarfAttrIsOptional = 0x21, 34 DwarfAttrLowerBound = 0x22, 35 DwarfAttrProducer = 0x25, 36 DwarfAttrPrototyped = 0x27, 37 DwarfAttrReturnAddr = 0x2A, 38 DwarfAttrStartScope = 0x2C, 39 DwarfAttrStrideSize = 0x2E, 40 DwarfAttrUpperBound = 0x2F, 41 DwarfAttrAbstractOrigin = 0x31, 42 DwarfAttrAccessibility = 0x32, 43 DwarfAttrAddrClass = 0x33, 44 DwarfAttrArtificial = 0x34, 45 DwarfAttrBaseTypes = 0x35, 46 DwarfAttrCalling = 0x36, 47 DwarfAttrCount = 0x37, 48 DwarfAttrDataMemberLoc = 0x38, 49 DwarfAttrDeclColumn = 0x39, 50 DwarfAttrDeclFile = 0x3A, 51 DwarfAttrDeclLine = 0x3B, 52 DwarfAttrDeclaration = 0x3C, 53 DwarfAttrDiscrList = 0x3D, 54 DwarfAttrEncoding = 0x3E, 55 DwarfAttrExternal = 0x3F, 56 DwarfAttrFrameBase = 0x40, 57 DwarfAttrFriend = 0x41, 58 DwarfAttrIdentifierCase = 0x42, 59 DwarfAttrMacroInfo = 0x43, 60 DwarfAttrNamelistItem = 0x44, 61 DwarfAttrPriority = 0x45, 62 DwarfAttrSegment = 0x46, 63 DwarfAttrSpecification = 0x47, 64 DwarfAttrStaticLink = 0x48, 65 DwarfAttrType = 0x49, 66 DwarfAttrUseLocation = 0x4A, 67 DwarfAttrVarParam = 0x4B, 68 DwarfAttrVirtuality = 0x4C, 69 DwarfAttrVtableElemLoc = 0x4D, 70 DwarfAttrAllocated = 0x4E, 71 DwarfAttrAssociated = 0x4F, 72 DwarfAttrDataLocation = 0x50, 73 DwarfAttrStride = 0x51, 74 DwarfAttrEntrypc = 0x52, 75 DwarfAttrUseUTF8 = 0x53, 76 DwarfAttrExtension = 0x54, 77 DwarfAttrRanges = 0x55, 78 DwarfAttrTrampoline = 0x56, 79 DwarfAttrCallColumn = 0x57, 80 DwarfAttrCallFile = 0x58, 81 DwarfAttrCallLine = 0x59, 82 DwarfAttrDescription = 0x5A, 83 DwarfAttrMax, 84 85 FormAddr = 0x01, 86 FormDwarfBlock2 = 0x03, 87 FormDwarfBlock4 = 0x04, 88 FormData2 = 0x05, 89 FormData4 = 0x06, 90 FormData8 = 0x07, 91 FormString = 0x08, 92 FormDwarfBlock = 0x09, 93 FormDwarfBlock1 = 0x0A, 94 FormData1 = 0x0B, 95 FormFlag = 0x0C, 96 FormSdata = 0x0D, 97 FormStrp = 0x0E, 98 FormUdata = 0x0F, 99 FormRefAddr = 0x10, 100 FormRef1 = 0x11, 101 FormRef2 = 0x12, 102 FormRef4 = 0x13, 103 FormRef8 = 0x14, 104 FormRefUdata = 0x15, 105 FormIndirect = 0x16 106 }; 107 108 static int parseattrs(Dwarf *d, DwarfBuf*, ulong, ulong, DwarfAbbrev*, DwarfAttrs*); 109 static int getulong(DwarfBuf*, int, ulong, ulong*, int*); 110 static int getuchar(DwarfBuf*, int, uchar*); 111 static int getstring(Dwarf *d, DwarfBuf*, int, char**); 112 static int getblock(DwarfBuf*, int, DwarfBlock*); 113 static int skipform(Dwarf *d, DwarfBuf*, int); 114 115 int 116 dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s) 117 { 118 DwarfSym compunit = { }; 119 if(dwarfenumunit(d, unit, &compunit) < 0) 120 return -1; 121 while(dwarfnextsymat(d, &compunit, s) == 0) { 122 werrstr("got %s looking for %s\n", s->attrs.name, name); 123 if(s->attrs.name && strcmp(s->attrs.name, name) == 0) 124 return 0; 125 } 126 werrstr("symbol '%s' not found", name); 127 return -1; 128 } 129 130 int 131 dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s) 132 { 133 *s = *parent; 134 while(dwarfnextsymat(d, parent, s)) 135 if(s->attrs.name && strcmp(s->attrs.name, name) == 0) 136 return 0; 137 werrstr("symbol '%s' not found", name); 138 return -1; 139 } 140 141 int 142 dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s) 143 { 144 int rsym = dwarfnextsymat(d, parent, s); 145 while (rsym == 0 && s->attrs.tag != tag) { 146 if (s->attrs.haskids) { 147 DwarfSym p = *s; 148 int csym = dwarflookupchildtag(d, &p, tag, s); 149 if (csym == 0) { 150 return csym; 151 } 152 } 153 rsym = dwarfnextsym(d, s); 154 } 155 return rsym; 156 } 157 158 int 159 dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s) 160 { 161 DwarfSym compunit = { }; 162 if (dwarfenumunit(d, unit, &compunit) < 0) { 163 return -1; 164 } 165 do { 166 if (compunit.attrs.tag == tag) { 167 *s = compunit; 168 return 0; 169 } 170 if (dwarflookupchildtag(d, &compunit, tag, s) == 0) 171 return 0; 172 } while(dwarfnextsym(d, &compunit) == 0); 173 werrstr("symbol with tag 0x%lux not found", tag); 174 return -1; 175 } 176 177 int 178 dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s) 179 { 180 DwarfSym compunit = { }; 181 if(dwarfenumunit(d, unit, &compunit) < 0) 182 return -1; 183 werrstr("dwarfseeksym: unit %x off %x\n", unit, off); 184 s->b.d = d; 185 s->b.p = d->info.data + unit + off; 186 s->b.ep = compunit.b.ep; 187 if(dwarfnextsymat(d, &compunit, s) == -1) 188 return -1; 189 werrstr("dwarfseeksym: unit %x off %x, tag %x", unit, off, s->attrs.tag); 190 return 0; 191 } 192 193 int 194 dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s) 195 { 196 DwarfSym compunit = { }; 197 if(dwarfenumunit(d, unit, &compunit) < 0) 198 return -1; 199 while(dwarfnextsymat(d, &compunit, s) == 0){ 200 if(s->attrs.tag != TagSubprogram) 201 continue; 202 if(s->attrs.lowpc <= pc && pc < s->attrs.highpc) 203 return 0; 204 } 205 werrstr("fn containing pc 0x%lux not found", pc); 206 return -1; 207 } 208 209 int 210 dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s) 211 { 212 int i; 213 ulong aoff, len; 214 215 if(unit >= d->info.len){ 216 werrstr("dwarf unit address 0x%x >= 0x%x out of range", unit, d->info.len); 217 return -1; 218 } 219 memset(s, 0, sizeof *s); 220 memset(&s->b, 0, sizeof s->b); 221 222 s->b.d = d; 223 s->b.p = d->info.data + unit; 224 s->b.ep = d->info.data + d->info.len; 225 len = dwarfget4(&s->b); 226 s->unit = unit; 227 s->nextunit = unit + 4 + len; 228 s->b.ep = d->info.data + s->nextunit; 229 230 if(s->b.ep - s->b.p < len){ 231 badheader: 232 werrstr("bad dwarf unit header at unit 0x%lux end %x start %x len %x", unit, s->b.ep - d->info.data, s->b.p - d->info.data, len); 233 return -1; 234 } 235 s->b.ep = s->b.p+len; 236 if((i=dwarfget2(&s->b)) > 4) 237 goto badheader; 238 aoff = dwarfget4(&s->b); 239 s->b.addrsize = dwarfget1(&s->b); 240 if(d->addrsize == 0) 241 d->addrsize = s->b.addrsize; 242 if(s->b.p == nil) 243 goto badheader; 244 245 s->aoff = aoff; 246 247 return dwarfnextsym(d, s); 248 } 249 250 int 251 dwarfnextsym(Dwarf *d, DwarfSym *s) 252 { 253 ulong num; 254 DwarfAbbrev *a; 255 256 werrstr("sym at %x (left %x)\n", s->b.p - d->info.data, s->b.ep - s->b.p); 257 258 num = dwarfget128(&s->b); 259 werrstr("abbrev num %x\n", num); 260 s->num = num; 261 if(num == 0){ 262 return -1; 263 } 264 265 a = dwarfgetabbrev(d, s->aoff, num); 266 werrstr("a %p\n", a); 267 if(a == nil){ 268 werrstr("getabbrev %x %x for %x", s->aoff, num, s->unit); 269 return -1; 270 } 271 272 if(parseattrs(d, &s->b, s->attrs.tag, s->unit, a, &s->attrs) < 0) { 273 return -1; 274 } 275 276 if (s->attrs.haskids) { 277 DwarfSym childSkip = { }; 278 s->childoff = s->b.p - d->info.data; 279 werrstr("Set childoff at %x\n", s->childoff); 280 int r = dwarfnextsymat(d, s, &childSkip); 281 while (r == 0) { 282 r = dwarfnextsym(d, &childSkip); 283 } 284 s->b = childSkip.b; 285 } else { 286 s->childoff = 0; 287 } 288 return 0; 289 } 290 291 int 292 dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child) 293 { 294 uint sib; 295 296 if (!parent->attrs.haskids || !parent->childoff) 297 return -1; 298 299 child->unit = parent->unit; 300 child->aoff = parent->aoff; 301 child->depth = parent->depth + 1; 302 if(child->attrs.have.sibling){ 303 sib = child->attrs.sibling; 304 if(sib < d->info.len && d->info.data+sib > child->b.p) 305 child->b.p = d->info.data+sib; 306 else if (sib >= d->info.len) { 307 werrstr("sibling reported as out of bounds %d vs %d", sib, d->info.len); 308 return -1; 309 } else if (d->info.data+sib+parent->unit < child->b.p) { 310 werrstr("subsequent sibling is listed before prev %d vs %d", sib+parent->unit, child->b.p - d->info.data); 311 return -1; 312 } 313 } 314 315 // Uninitialized 316 if (!child->b.d) { 317 child->b = parent->b; 318 child->b.p = parent->childoff + parent->b.d->info.data; 319 werrstr("Rewound to childoff %x\n", parent->childoff); 320 } 321 322 return dwarfnextsym(d, child); 323 } 324 325 typedef struct Parse Parse; 326 struct Parse { 327 const char *namestr; 328 int name; 329 int off; 330 int haveoff; 331 int type; 332 }; 333 334 #define ATTR(x) (#x)+9, x 335 #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x) 336 337 static Parse plist[] = { /* Font Tab 4 */ 338 { ATTR(DwarfAttrAbstractOrigin), OFFSET(abstractorigin), TReference }, 339 { ATTR(DwarfAttrAccessibility), OFFSET(accessibility), TConstant }, 340 { ATTR(DwarfAttrAddrClass), OFFSET(addrclass), TConstant }, 341 { ATTR(DwarfAttrBaseTypes), OFFSET(basetypes), TReference }, 342 { ATTR(DwarfAttrBitOffset), OFFSET(bitoffset), TConstant }, 343 { ATTR(DwarfAttrBitSize), OFFSET(bitsize), TConstant }, 344 { ATTR(DwarfAttrByteSize), OFFSET(bytesize), TConstant }, 345 { ATTR(DwarfAttrCalling), OFFSET(calling), TConstant }, 346 { ATTR(DwarfAttrCommonRef), OFFSET(commonref), TReference }, 347 { ATTR(DwarfAttrCompDir), OFFSET(compdir), TString }, 348 { ATTR(DwarfAttrConstValue), OFFSET(constvalue), TString|TConstant|TBlock }, 349 { ATTR(DwarfAttrContainingType), OFFSET(containingtype), TReference }, 350 { ATTR(DwarfAttrCount), OFFSET(count), TConstant|TReference }, 351 { ATTR(DwarfAttrDataMemberLoc), OFFSET(datamemberloc), TBlock|TConstant|TReference }, 352 { ATTR(DwarfAttrDeclColumn), OFFSET(declcolumn), TConstant }, 353 { ATTR(DwarfAttrDeclFile), OFFSET(declfile), TConstant }, 354 { ATTR(DwarfAttrDeclLine), OFFSET(declline), TConstant }, 355 { ATTR(DwarfAttrDefaultValue), OFFSET(defaultvalue), TReference }, 356 { ATTR(DwarfAttrDiscr), OFFSET(discr), TReference }, 357 { ATTR(DwarfAttrDiscrList), OFFSET(discrlist), TBlock }, 358 { ATTR(DwarfAttrDiscrValue), OFFSET(discrvalue), TConstant }, 359 { ATTR(DwarfAttrEncoding), OFFSET(encoding), TConstant }, 360 { ATTR(DwarfAttrFrameBase), OFFSET(framebase), TBlock|TConstant }, 361 { ATTR(DwarfAttrFriend), OFFSET(friend), TReference }, 362 { ATTR(DwarfAttrHighpc), OFFSET(highpc), TAddress }, 363 { ATTR(DwarfAttrEntrypc), OFFSET(entrypc), TAddress }, 364 { ATTR(DwarfAttrIdentifierCase), OFFSET(identifiercase), TConstant }, 365 { ATTR(DwarfAttrImport), OFFSET(import), TReference }, 366 { ATTR(DwarfAttrInline), OFFSET(inlined), TConstant }, 367 { ATTR(DwarfAttrArtificial), OFFSET(isartificial), TFlag }, 368 { ATTR(DwarfAttrDeclaration), OFFSET(isdeclaration), TFlag }, 369 { ATTR(DwarfAttrExternal), OFFSET(isexternal), TFlag }, 370 { ATTR(DwarfAttrIsOptional), OFFSET(isoptional), TFlag }, 371 { ATTR(DwarfAttrPrototyped), OFFSET(isprototyped), TFlag }, 372 { ATTR(DwarfAttrVarParam), OFFSET(isvarparam), TFlag }, 373 { ATTR(DwarfAttrLanguage), OFFSET(language), TConstant }, 374 { ATTR(DwarfAttrLocation), OFFSET(location), TReference|TBlock }, 375 { ATTR(DwarfAttrLowerBound), OFFSET(lowerbound), TConstant|TReference }, 376 { ATTR(DwarfAttrLowpc), OFFSET(lowpc), TAddress }, 377 { ATTR(DwarfAttrMacroInfo), OFFSET(macroinfo), TConstant }, 378 { ATTR(DwarfAttrName), OFFSET(name), TString }, 379 { ATTR(DwarfAttrNamelistItem), OFFSET(namelistitem), TBlock }, 380 { ATTR(DwarfAttrOrdering), OFFSET(ordering), TConstant }, 381 { ATTR(DwarfAttrPriority), OFFSET(priority), TReference }, 382 { ATTR(DwarfAttrProducer), OFFSET(producer), TString }, 383 { ATTR(DwarfAttrRanges), OFFSET(ranges), TReference }, 384 { ATTR(DwarfAttrReturnAddr), OFFSET(returnaddr), TBlock|TConstant }, 385 { ATTR(DwarfAttrSegment), OFFSET(segment), TBlock|TConstant }, 386 { ATTR(DwarfAttrSibling), OFFSET(sibling), TReference }, 387 { ATTR(DwarfAttrSpecification), OFFSET(specification), TReference }, 388 { ATTR(DwarfAttrStartScope), OFFSET(startscope), TConstant }, 389 { ATTR(DwarfAttrStaticLink), OFFSET(staticlink), TBlock|TConstant }, 390 { ATTR(DwarfAttrStmtList), OFFSET(stmtlist), TConstant }, 391 { ATTR(DwarfAttrStrideSize), OFFSET(stridesize), TConstant }, 392 { ATTR(DwarfAttrStringLength), OFFSET(stringlength), TBlock|TConstant }, 393 { ATTR(DwarfAttrType), OFFSET(type), TReference }, 394 { ATTR(DwarfAttrUpperBound), OFFSET(upperbound), TConstant|TReference }, 395 { ATTR(DwarfAttrUseLocation), OFFSET(uselocation), TBlock|TConstant }, 396 { ATTR(DwarfAttrVirtuality), OFFSET(virtuality), TConstant }, 397 { ATTR(DwarfAttrVisibility), OFFSET(visibility), TConstant }, 398 { ATTR(DwarfAttrVtableElemLoc), OFFSET(vtableelemloc), TBlock|TReference }, 399 { } 400 }; 401 402 static Parse ptab[DwarfAttrMax]; 403 404 static int 405 parseattrs(Dwarf *d, DwarfBuf *b, ulong tag, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs) 406 { 407 int i, f, n, got; 408 static int nbad; 409 void *v; 410 411 /* initialize ptab first time through for quick access */ 412 if(ptab[DwarfAttrName].name != DwarfAttrName) 413 for(i=0; plist[i].name; i++) 414 ptab[plist[i].name] = plist[i]; 415 416 memset(attrs, 0, sizeof *attrs); 417 attrs->tag = a->tag; 418 attrs->haskids = a->haskids; 419 420 for(i=0; i<a->nattr; i++){ 421 n = a->attr[i].name; 422 f = a->attr[i].form; 423 werrstr("struct: (@%x) n %x f %x (%d %d)\n", b->p - d->info.data, n, f, ptab[n].haveoff, ptab[n].off); 424 if(n < 0 || n >= DwarfAttrMax || ptab[n].name==0) { 425 if (skipform(d, b, f) < 0) { 426 if(++nbad == 1) 427 werrstr("dwarf parse attrs: cannot skip form %d", f); 428 return -1; 429 } 430 continue; 431 } 432 v = (char*)attrs + ptab[n].off; 433 got = 0; 434 if(f == FormIndirect) 435 f = dwarfget128(b); 436 if((ptab[n].type&(TConstant|TReference|TAddress)) 437 && getulong(b, f, unit, v, &got) >= 0) 438 ; 439 else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0) 440 got = TFlag; 441 else if((ptab[n].type&TString) && getstring(d, b, f, v) >= 0) 442 got = TString; 443 else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0) { 444 got = TBlock; 445 } else { 446 werrstr("Skipping form %x\n", f); 447 if(skipform(d, b, f) < 0){ 448 //if(++nbad == 1) 449 werrstr("dwarf parse attrs: cannot skip form %d", f); 450 return -1; 451 } 452 } 453 #if 0 454 if(got == TBlock && (ptab[n].type&TConstant)) 455 got = constblock(b->d, v, v); 456 #endif 457 *((uchar*)attrs+ptab[n].haveoff) = got; 458 } 459 460 if (attrs->have.name) 461 werrstr("%s: tag %x kids %d (last %x)\n", attrs->name, attrs->tag, attrs->haskids, b->p - b->d->info.data); 462 463 return 0; 464 } 465 466 static int 467 getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type) 468 { 469 static int nbad; 470 uvlong uv; 471 472 switch(form){ 473 default: 474 return -1; 475 476 /* addresses */ 477 case FormAddr: 478 *type = TAddress; 479 *u = dwarfgetaddr(b); 480 return 0; 481 482 /* references */ 483 case FormRefAddr: 484 /* absolute ref in .debug_info */ 485 *type = TReference; 486 *u = dwarfgetaddr(b); 487 return 0; 488 case FormRef1: 489 *u = dwarfget1(b); 490 goto relativeref; 491 case FormRef2: 492 *u = dwarfget2(b); 493 goto relativeref; 494 case FormRef4: 495 *u = dwarfget4(b); 496 goto relativeref; 497 case FormRef8: 498 *u = dwarfget8(b); 499 goto relativeref; 500 case FormRefUdata: 501 *u = dwarfget128(b); 502 relativeref: 503 *u += unit; 504 *type = TReference; 505 return 0; 506 507 /* constants */ 508 case FormData1: 509 *u = dwarfget1(b); 510 goto constant; 511 case FormData2: 512 *u = dwarfget2(b); 513 goto constant; 514 case FormData4: 515 *u = dwarfget4(b); 516 goto constant; 517 case FormData8: 518 uv = dwarfget8(b); 519 *u = uv; 520 if(uv != *u && ++nbad == 1) 521 werrstr("dwarf: truncating 64-bit attribute constants"); 522 goto constant; 523 case FormSdata: 524 *u = dwarfget128s(b); 525 goto constant; 526 case FormUdata: 527 *u = dwarfget128(b); 528 constant: 529 *type = TConstant; 530 return 0; 531 } 532 } 533 534 static int 535 getuchar(DwarfBuf *b, int form, uchar *u) 536 { 537 switch(form){ 538 default: 539 return -1; 540 541 case FormFlag: 542 *u = dwarfget1(b); 543 return 0; 544 } 545 } 546 547 static int 548 getstring(Dwarf *d, DwarfBuf *b, int form, char **s) 549 { 550 static int nbad; 551 ulong u, x; 552 553 switch(form){ 554 default: 555 return -1; 556 557 case FormString: 558 x = b->p - d->info.data; 559 *s = dwarfgetstring(b); 560 for (u = 0; (*s)[u]; u++) { 561 assert(isprint((*s)[u])); 562 } 563 return 0; 564 565 case FormStrp: 566 u = dwarfget4(b); 567 if(u >= b->d->str.len){ 568 if(++nbad == 1) 569 werrstr("dwarf: bad string pointer 0x%lux in attribute", u); 570 /* don't return error - maybe can proceed */ 571 *s = nil; 572 }else 573 *s = (char*)b->d->str.data + u; 574 return 0; 575 576 } 577 } 578 579 static int 580 getblock(DwarfBuf *b, int form, DwarfBlock *bl) 581 { 582 ulong n; 583 584 switch(form){ 585 default: 586 return -1; 587 case FormDwarfBlock: 588 n = dwarfget128(b); 589 goto copyn; 590 case FormDwarfBlock1: 591 n = dwarfget1(b); 592 goto copyn; 593 case FormDwarfBlock2: 594 n = dwarfget2(b); 595 goto copyn; 596 case FormDwarfBlock4: 597 n = dwarfget4(b); 598 copyn: 599 bl->data = dwarfgetnref(b, n); 600 bl->len = n; 601 if(bl->data == nil) 602 return -1; 603 return 0; 604 } 605 } 606 607 /* last resort */ 608 static int 609 skipform(Dwarf *d, DwarfBuf *b, int form) 610 { 611 int type; 612 DwarfVal val; 613 614 if(getulong(b, form, 0, &val.c, &type) < 0 615 && getuchar(b, form, (uchar*)&val) < 0 616 && getstring(d, b, form, &val.s) < 0 617 && getblock(b, form, &val.b) < 0) 618 return -1; 619 return 0; 620 } 621 622 void stackinit(DwarfStack *stack) 623 { 624 memset(stack, 0, sizeof(*stack)); 625 stack->data = stack->storage; 626 stack->length = 0; stack->max = sizeof(stack->storage) / sizeof(stack->storage[0]); 627 } 628 629 void stackpush(DwarfStack *stack, ulong value) 630 { 631 if (stack->length == stack->max) { 632 ulong *newstack = malloc(sizeof(ulong)*stack->max*2); 633 memcpy(newstack, stack->data, sizeof(ulong)*stack->length); 634 if (stack->data != stack->storage) 635 free(stack->data); 636 stack->data = newstack; 637 stack->max *= 2; 638 } 639 werrstr("stack[%d] = %x", stack->length, value); 640 stack->data[stack->length++] = value; 641 } 642 643 ulong stackpop(DwarfStack *stack) 644 { 645 ASSERT(stack->length > 0); 646 ulong val = stack->data[--stack->length]; 647 werrstr("pop stack[%d] -> %x", stack->length, val); 648 return val; 649 } 650 651 void stackfree(DwarfStack *stack) 652 { 653 if (stack->data != stack->storage) 654 free(stack->data); 655 } 656 657 // Returns -1 on failure 658 int dwarfgetarg(Dwarf *d, const char *name, DwarfBuf *buf, ulong cfa, PROSSYM_REGISTERS registers, ulong *result) 659 { 660 int ret = 0; 661 DwarfStack stack = { }; 662 stackinit(&stack); 663 stackpush(&stack, cfa); 664 while (buf->p < buf->ep) { 665 int opcode = dwarfget1(buf); 666 werrstr("opcode %x", opcode); 667 switch (opcode) { 668 case 0: 669 buf->p = buf->ep; 670 break; 671 case OpAddr: 672 if (d->addrsize == 4) { 673 stackpush(&stack, dwarfget4(buf)); 674 break; 675 } else { 676 werrstr("%s: we only support 4 byte addrs", name); 677 goto fatal; 678 } 679 case OpConst1s: { 680 signed char c = dwarfget1(buf); 681 stackpush(&stack, c); 682 } break; 683 case OpConst1u: 684 stackpush(&stack, dwarfget1(buf)); 685 break; 686 case OpConst2s: { 687 signed short s = dwarfget2(buf); 688 stackpush(&stack, s); 689 } break; 690 case OpConst2u: 691 stackpush(&stack, dwarfget2(buf)); 692 break; 693 case OpConst4s: { 694 signed int i = dwarfget4(buf); 695 stackpush(&stack, i); 696 } break; 697 case OpConst4u: 698 stackpush(&stack, dwarfget4(buf)); 699 break; 700 case OpConst8s: 701 case OpConst8u: 702 werrstr("const 8 not yet supported"); 703 goto fatal; 704 case OpConsts: 705 stackpush(&stack, dwarfget128s(buf)); 706 break; 707 case OpConstu: 708 stackpush(&stack, dwarfget128(buf)); 709 break; 710 case OpDup: { 711 ulong popped = stackpop(&stack); 712 stackpush(&stack, popped); 713 stackpush(&stack, popped); 714 } break; 715 case OpDrop: 716 stackpop(&stack); 717 break; 718 case OpOver: { 719 if (stack.length < 2) goto fatal; 720 stackpush(&stack, stack.data[stack.length-2]); 721 } break; 722 case OpPick: { 723 ulong arg = dwarfget1(buf); 724 if (arg >= stack.length) goto fatal; 725 arg = stack.data[stack.length-1-arg]; 726 stackpush(&stack, arg); 727 } break; 728 case OpSwap: { 729 ulong a = stackpop(&stack), b = stackpop(&stack); 730 stackpush(&stack, b); 731 stackpush(&stack, a); 732 } break; 733 case OpRot: { 734 ulong a = stackpop(&stack), b = stackpop(&stack), c = stackpop(&stack); 735 stackpush(&stack, b); 736 stackpush(&stack, c); 737 stackpush(&stack, a); 738 } break; 739 case OpXderef: 740 case OpXderefSize: 741 werrstr("Xderef not yet supported"); 742 goto fatal; 743 case OpAbs: { 744 long a = stackpop(&stack); 745 stackpush(&stack, a < 0 ? -a : a); 746 } break; 747 case OpAnd: 748 stackpush(&stack, stackpop(&stack) & stackpop(&stack)); 749 break; 750 case OpDiv: { 751 ulong a = stackpop(&stack), b = stackpop(&stack); 752 stackpush(&stack, b / a); 753 } break; 754 case OpMinus: { 755 ulong a = stackpop(&stack), b = stackpop(&stack); 756 stackpush(&stack, b - a); 757 } break; 758 case OpMod: { 759 ulong a = stackpop(&stack), b = stackpop(&stack); 760 stackpush(&stack, b % a); 761 } break; 762 case OpMul: 763 stackpush(&stack, stackpop(&stack) * stackpop(&stack)); 764 break; 765 case OpNeg: 766 stackpush(&stack, -stackpop(&stack)); 767 break; 768 case OpNot: 769 stackpush(&stack, ~stackpop(&stack)); 770 break; 771 case OpOr: 772 stackpush(&stack, stackpop(&stack) | stackpop(&stack)); 773 break; 774 case OpPlus: 775 stackpush(&stack, stackpop(&stack) + stackpop(&stack)); 776 break; 777 case OpPlusUconst: 778 stackpush(&stack, stackpop(&stack) + dwarfget128(buf)); 779 break; 780 case OpShl: { 781 ulong a = stackpop(&stack), b = stackpop(&stack); 782 stackpush(&stack, b << a); 783 } break; 784 case OpShr: { 785 ulong a = stackpop(&stack), b = stackpop(&stack); 786 stackpush(&stack, b >> a); 787 } break; 788 case OpShra: { 789 ulong a = stackpop(&stack); 790 long b = stackpop(&stack); 791 if (b < 0) 792 b = -(-b >> a); 793 else 794 b = b >> a; 795 stackpush(&stack, b); 796 } break; 797 case OpXor: 798 stackpush(&stack, stackpop(&stack) ^ stackpop(&stack)); 799 break; 800 case OpSkip: 801 buf->p += dwarfget2(buf); 802 break; 803 case OpBra: { 804 ulong a = dwarfget2(buf); 805 if (stackpop(&stack)) 806 buf->p += a; 807 } break; 808 case OpEq: 809 stackpush(&stack, stackpop(&stack) == stackpop(&stack)); 810 break; 811 case OpGe: { 812 ulong a = stackpop(&stack), b = stackpop(&stack); 813 stackpush(&stack, b >= a); 814 } break; 815 case OpGt: { 816 ulong a = stackpop(&stack), b = stackpop(&stack); 817 stackpush(&stack, b > a); 818 } break; 819 case OpLe: { 820 ulong a = stackpop(&stack), b = stackpop(&stack); 821 stackpush(&stack, b <= a); 822 } break; 823 case OpLt: { 824 ulong a = stackpop(&stack), b = stackpop(&stack); 825 stackpush(&stack, b < a); 826 } break; 827 case OpNe: 828 stackpush(&stack, stackpop(&stack) != stackpop(&stack)); 829 break; 830 case OpNop: 831 break; 832 case OpDeref: { 833 ulong val; 834 void* addr = (void*)stackpop(&stack); 835 if (!RosSymCallbacks.MemGetProc 836 (d->pe->fd, 837 &val, 838 addr, 839 d->addrsize)) 840 goto fatal; 841 stackpush(&stack, val); 842 } break; 843 case OpDerefSize: { 844 ulong val, size = dwarfget1(buf); 845 void* addr = (void*)stackpop(&stack); 846 if (!RosSymCallbacks.MemGetProc 847 (d->pe->fd, 848 &val, 849 addr, 850 size)) 851 goto fatal; 852 stackpush(&stack, val); 853 } break; 854 case OpFbreg: { 855 ulong val, offset = dwarfget128s(buf); 856 void* addr = (void*)cfa; 857 werrstr("FBREG cfa %x offset %x", cfa, offset); 858 if (!RosSymCallbacks.MemGetProc 859 (d->pe->fd, 860 &val, 861 (PVOID)((ULONG_PTR)addr+offset), 862 d->addrsize)) 863 goto fatal; 864 stackpush(&stack, val); 865 } break; 866 case OpPiece: 867 werrstr("OpPiece not supported"); 868 goto fatal; 869 default: 870 if (opcode >= OpLit0 && opcode < OpReg0) 871 stackpush(&stack, opcode - OpLit0); 872 else if (opcode >= OpReg0 && opcode < OpBreg0) { 873 ulong reg = opcode - OpReg0; 874 werrstr("REG[%d] value %x", reg, (ulong)registers->Registers[reg]); 875 stackpush(&stack, registers->Registers[reg]); 876 } else if (opcode >= OpBreg0 && opcode < OpRegx) { 877 ulong val, 878 reg = opcode - OpBreg0, 879 offset = dwarfget128s(buf); 880 void* addr = (void*)(ULONG_PTR)registers->Registers[reg]; 881 werrstr("BREG[%d] reg %x offset %x", reg, addr, offset); 882 if (!RosSymCallbacks.MemGetProc 883 ((PVOID)d->pe->fd, 884 &val, 885 (PVOID)((ULONG_PTR)addr + offset), 886 d->addrsize)) 887 goto fatal; 888 stackpush(&stack, val); 889 } else { 890 werrstr("opcode %x not supported", opcode); 891 goto fatal; 892 } 893 break; 894 } 895 } 896 if (stack.length < 1) goto fatal; 897 *result = stackpop(&stack); 898 werrstr("%s: value %x", name, *result); 899 goto finish; 900 901 fatal: 902 ret = -1; 903 904 finish: 905 stackfree(&stack); 906 return ret; 907 } 908 909 int dwarfargvalue(Dwarf *d, DwarfSym *proc, ulong pc, ulong cfa, PROSSYM_REGISTERS registers, DwarfParam *parameter) 910 { 911 int gotarg; 912 DwarfSym unit = { }; 913 914 if (dwarfenumunit(d, proc->unit, &unit) == -1) 915 return -1; 916 917 werrstr("lookup in unit %x-%x, pc %x", unit.attrs.lowpc, unit.attrs.highpc, pc); 918 pc -= unit.attrs.lowpc; 919 920 werrstr("paramblock %s -> unit %x type %x fde %x len %d registers %x", 921 parameter->name, 922 parameter->unit, 923 parameter->type, 924 parameter->fde, 925 parameter->len, 926 registers); 927 928 // Seek our range in loc 929 DwarfBuf locbuf; 930 DwarfBuf instream = { }; 931 932 locbuf.d = d; 933 locbuf.addrsize = d->addrsize; 934 935 if (parameter->loctype == TConstant) { 936 locbuf.p = d->loc.data + parameter->fde; 937 locbuf.ep = d->loc.data + d->loc.len; 938 ulong start, end, len; 939 do { 940 len = 0; 941 start = dwarfget4(&locbuf); 942 end = dwarfget4(&locbuf); 943 if (start && end) { 944 len = dwarfget2(&locbuf); 945 instream = locbuf; 946 instream.ep = instream.p + len; 947 locbuf.p = instream.ep; 948 } 949 werrstr("ip %x s %x e %x (%x bytes)", pc, start, end, len); 950 } while (start && end && (start > pc || end <= pc)); 951 } else if (parameter->loctype == TBlock) { 952 instream = locbuf; 953 instream.p = (void *)parameter->fde; 954 instream.ep = instream.p + parameter->len; 955 } else { 956 werrstr("Wrong block type for parameter %s", parameter->name); 957 return -1; 958 } 959 960 gotarg = dwarfgetarg(d, parameter->name, &instream, cfa, registers, ¶meter->value); 961 if (gotarg == -1) 962 return -1; 963 964 return 0; 965 } 966 967 void 968 dwarfdumpsym(Dwarf *d, DwarfSym *s) 969 { 970 int j; 971 werrstr("tag %x\n", s->attrs.tag); 972 for (j = 0; plist[j].name; j++) { 973 char *have = ((char*)&s->attrs) + plist[j].haveoff; 974 char *attr = ((char*)&s->attrs) + plist[j].off; 975 if (*have == TString) { 976 char *str = *((char **)attr); 977 werrstr("%s: %s\n", plist[j].namestr, str); 978 } else if (*have == TReference) { 979 DwarfVal *val = ((DwarfVal*)attr); 980 werrstr("%s: %x:%x\n", plist[j].namestr, val->b.data, val->b.len); 981 } else if (*have) 982 werrstr("%s: (%x)\n", plist[j].namestr, *have); 983 } 984 } 985 986 int 987 dwarfgetparams(Dwarf *d, DwarfSym *s, ulong pc, int pnum, DwarfParam *paramblocks) 988 { 989 int ip = 0; 990 DwarfSym param = { }; 991 int res = dwarfnextsymat(d, s, ¶m); 992 while (res == 0 && ip < pnum) { 993 if (param.attrs.tag == TagFormalParameter && 994 param.attrs.have.name && 995 param.attrs.have.location) { 996 paramblocks[ip].name = malloc(strlen(param.attrs.name)+1); 997 strcpy(paramblocks[ip].name, param.attrs.name); 998 paramblocks[ip].unit = param.unit; 999 paramblocks[ip].type = param.attrs.type; 1000 paramblocks[ip].loctype = param.attrs.have.location; 1001 paramblocks[ip].len = param.attrs.location.b.len; 1002 paramblocks[ip].fde = (ulong)param.attrs.location.b.data; 1003 werrstr("param[%d] block %s -> type %x loctype %x fde %x len %x", 1004 ip, 1005 paramblocks[ip].name, 1006 paramblocks[ip].type, 1007 paramblocks[ip].loctype, 1008 paramblocks[ip].fde, 1009 paramblocks[ip].len); 1010 ip++; 1011 } 1012 res = dwarfnextsymat(d, s, ¶m); 1013 } 1014 return ip; 1015 } 1016