/* * Dwarf info parse and search. */ #include #define NDEBUG #include enum { DwarfAttrSibling = 0x01, DwarfAttrLocation = 0x02, DwarfAttrName = 0x03, DwarfAttrOrdering = 0x09, DwarfAttrByteSize = 0x0B, DwarfAttrBitOffset = 0x0C, DwarfAttrBitSize = 0x0D, DwarfAttrStmtList = 0x10, DwarfAttrLowpc = 0x11, DwarfAttrHighpc = 0x12, DwarfAttrLanguage = 0x13, DwarfAttrDiscr = 0x15, DwarfAttrDiscrValue = 0x16, DwarfAttrVisibility = 0x17, DwarfAttrImport = 0x18, DwarfAttrStringLength = 0x19, DwarfAttrCommonRef = 0x1A, DwarfAttrCompDir = 0x1B, DwarfAttrConstValue = 0x1C, DwarfAttrContainingType = 0x1D, DwarfAttrDefaultValue = 0x1E, DwarfAttrInline = 0x20, DwarfAttrIsOptional = 0x21, DwarfAttrLowerBound = 0x22, DwarfAttrProducer = 0x25, DwarfAttrPrototyped = 0x27, DwarfAttrReturnAddr = 0x2A, DwarfAttrStartScope = 0x2C, DwarfAttrStrideSize = 0x2E, DwarfAttrUpperBound = 0x2F, DwarfAttrAbstractOrigin = 0x31, DwarfAttrAccessibility = 0x32, DwarfAttrAddrClass = 0x33, DwarfAttrArtificial = 0x34, DwarfAttrBaseTypes = 0x35, DwarfAttrCalling = 0x36, DwarfAttrCount = 0x37, DwarfAttrDataMemberLoc = 0x38, DwarfAttrDeclColumn = 0x39, DwarfAttrDeclFile = 0x3A, DwarfAttrDeclLine = 0x3B, DwarfAttrDeclaration = 0x3C, DwarfAttrDiscrList = 0x3D, DwarfAttrEncoding = 0x3E, DwarfAttrExternal = 0x3F, DwarfAttrFrameBase = 0x40, DwarfAttrFriend = 0x41, DwarfAttrIdentifierCase = 0x42, DwarfAttrMacroInfo = 0x43, DwarfAttrNamelistItem = 0x44, DwarfAttrPriority = 0x45, DwarfAttrSegment = 0x46, DwarfAttrSpecification = 0x47, DwarfAttrStaticLink = 0x48, DwarfAttrType = 0x49, DwarfAttrUseLocation = 0x4A, DwarfAttrVarParam = 0x4B, DwarfAttrVirtuality = 0x4C, DwarfAttrVtableElemLoc = 0x4D, DwarfAttrAllocated = 0x4E, DwarfAttrAssociated = 0x4F, DwarfAttrDataLocation = 0x50, DwarfAttrStride = 0x51, DwarfAttrEntrypc = 0x52, DwarfAttrUseUTF8 = 0x53, DwarfAttrExtension = 0x54, DwarfAttrRanges = 0x55, DwarfAttrTrampoline = 0x56, DwarfAttrCallColumn = 0x57, DwarfAttrCallFile = 0x58, DwarfAttrCallLine = 0x59, DwarfAttrDescription = 0x5A, DwarfAttrMax, FormAddr = 0x01, FormDwarfBlock2 = 0x03, FormDwarfBlock4 = 0x04, FormData2 = 0x05, FormData4 = 0x06, FormData8 = 0x07, FormString = 0x08, FormDwarfBlock = 0x09, FormDwarfBlock1 = 0x0A, FormData1 = 0x0B, FormFlag = 0x0C, FormSdata = 0x0D, FormStrp = 0x0E, FormUdata = 0x0F, FormRefAddr = 0x10, FormRef1 = 0x11, FormRef2 = 0x12, FormRef4 = 0x13, FormRef8 = 0x14, FormRefUdata = 0x15, FormIndirect = 0x16 }; static int parseattrs(Dwarf *d, DwarfBuf*, ulong, ulong, DwarfAbbrev*, DwarfAttrs*); static int getulong(DwarfBuf*, int, ulong, ulong*, int*); static int getuchar(DwarfBuf*, int, uchar*); static int getstring(Dwarf *d, DwarfBuf*, int, char**); static int getblock(DwarfBuf*, int, DwarfBlock*); static int skipform(Dwarf *d, DwarfBuf*, int); int dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s) { DwarfSym compunit = { }; if(dwarfenumunit(d, unit, &compunit) < 0) return -1; while(dwarfnextsymat(d, &compunit, s) == 0) { werrstr("got %s looking for %s\n", s->attrs.name, name); if(s->attrs.name && strcmp(s->attrs.name, name) == 0) return 0; } werrstr("symbol '%s' not found", name); return -1; } int dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s) { *s = *parent; while(dwarfnextsymat(d, parent, s)) if(s->attrs.name && strcmp(s->attrs.name, name) == 0) return 0; werrstr("symbol '%s' not found", name); return -1; } int dwarflookupchildtag(Dwarf *d, DwarfSym *parent, ulong tag, DwarfSym *s) { int rsym = dwarfnextsymat(d, parent, s); while (rsym == 0 && s->attrs.tag != tag) { if (s->attrs.haskids) { DwarfSym p = *s; int csym = dwarflookupchildtag(d, &p, tag, s); if (csym == 0) { return csym; } } rsym = dwarfnextsym(d, s); } return rsym; } int dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s) { DwarfSym compunit = { }; if (dwarfenumunit(d, unit, &compunit) < 0) { return -1; } do { if (compunit.attrs.tag == tag) { *s = compunit; return 0; } if (dwarflookupchildtag(d, &compunit, tag, s) == 0) return 0; } while(dwarfnextsym(d, &compunit) == 0); werrstr("symbol with tag 0x%lux not found", tag); return -1; } int dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s) { DwarfSym compunit = { }; if(dwarfenumunit(d, unit, &compunit) < 0) return -1; werrstr("dwarfseeksym: unit %x off %x\n", unit, off); s->b.d = d; s->b.p = d->info.data + unit + off; s->b.ep = compunit.b.ep; if(dwarfnextsymat(d, &compunit, s) == -1) return -1; werrstr("dwarfseeksym: unit %x off %x, tag %x", unit, off, s->attrs.tag); return 0; } int dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s) { DwarfSym compunit = { }; if(dwarfenumunit(d, unit, &compunit) < 0) return -1; while(dwarfnextsymat(d, &compunit, s) == 0){ if(s->attrs.tag != TagSubprogram) continue; if(s->attrs.lowpc <= pc && pc < s->attrs.highpc) return 0; } werrstr("fn containing pc 0x%lux not found", pc); return -1; } int dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s) { int i; ulong aoff, len; if(unit >= d->info.len){ werrstr("dwarf unit address 0x%x >= 0x%x out of range", unit, d->info.len); return -1; } memset(s, 0, sizeof *s); memset(&s->b, 0, sizeof s->b); s->b.d = d; s->b.p = d->info.data + unit; s->b.ep = d->info.data + d->info.len; len = dwarfget4(&s->b); s->unit = unit; s->nextunit = unit + 4 + len; s->b.ep = d->info.data + s->nextunit; if(s->b.ep - s->b.p < len){ badheader: 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); return -1; } s->b.ep = s->b.p+len; if((i=dwarfget2(&s->b)) > 4) goto badheader; aoff = dwarfget4(&s->b); s->b.addrsize = dwarfget1(&s->b); if(d->addrsize == 0) d->addrsize = s->b.addrsize; if(s->b.p == nil) goto badheader; s->aoff = aoff; return dwarfnextsym(d, s); } int dwarfnextsym(Dwarf *d, DwarfSym *s) { ulong num; DwarfAbbrev *a; werrstr("sym at %x (left %x)\n", s->b.p - d->info.data, s->b.ep - s->b.p); num = dwarfget128(&s->b); werrstr("abbrev num %x\n", num); s->num = num; if(num == 0){ return -1; } a = dwarfgetabbrev(d, s->aoff, num); werrstr("a %p\n", a); if(a == nil){ werrstr("getabbrev %x %x for %x", s->aoff, num, s->unit); return -1; } if(parseattrs(d, &s->b, s->attrs.tag, s->unit, a, &s->attrs) < 0) { return -1; } if (s->attrs.haskids) { DwarfSym childSkip = { }; s->childoff = s->b.p - d->info.data; werrstr("Set childoff at %x\n", s->childoff); int r = dwarfnextsymat(d, s, &childSkip); while (r == 0) { r = dwarfnextsym(d, &childSkip); } s->b = childSkip.b; } else { s->childoff = 0; } return 0; } int dwarfnextsymat(Dwarf *d, DwarfSym *parent, DwarfSym *child) { uint sib; if (!parent->attrs.haskids || !parent->childoff) return -1; child->unit = parent->unit; child->aoff = parent->aoff; child->depth = parent->depth + 1; if(child->attrs.have.sibling){ sib = child->attrs.sibling; if(sib < d->info.len && d->info.data+sib > child->b.p) child->b.p = d->info.data+sib; else if (sib >= d->info.len) { werrstr("sibling reported as out of bounds %d vs %d", sib, d->info.len); return -1; } else if (d->info.data+sib+parent->unit < child->b.p) { werrstr("subsequent sibling is listed before prev %d vs %d", sib+parent->unit, child->b.p - d->info.data); return -1; } } // Uninitialized if (!child->b.d) { child->b = parent->b; child->b.p = parent->childoff + parent->b.d->info.data; werrstr("Rewound to childoff %x\n", parent->childoff); } return dwarfnextsym(d, child); } typedef struct Parse Parse; struct Parse { const char *namestr; int name; int off; int haveoff; int type; }; #define ATTR(x) (#x)+9, x #define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x) static Parse plist[] = { /* Font Tab 4 */ { ATTR(DwarfAttrAbstractOrigin), OFFSET(abstractorigin), TReference }, { ATTR(DwarfAttrAccessibility), OFFSET(accessibility), TConstant }, { ATTR(DwarfAttrAddrClass), OFFSET(addrclass), TConstant }, { ATTR(DwarfAttrBaseTypes), OFFSET(basetypes), TReference }, { ATTR(DwarfAttrBitOffset), OFFSET(bitoffset), TConstant }, { ATTR(DwarfAttrBitSize), OFFSET(bitsize), TConstant }, { ATTR(DwarfAttrByteSize), OFFSET(bytesize), TConstant }, { ATTR(DwarfAttrCalling), OFFSET(calling), TConstant }, { ATTR(DwarfAttrCommonRef), OFFSET(commonref), TReference }, { ATTR(DwarfAttrCompDir), OFFSET(compdir), TString }, { ATTR(DwarfAttrConstValue), OFFSET(constvalue), TString|TConstant|TBlock }, { ATTR(DwarfAttrContainingType), OFFSET(containingtype), TReference }, { ATTR(DwarfAttrCount), OFFSET(count), TConstant|TReference }, { ATTR(DwarfAttrDataMemberLoc), OFFSET(datamemberloc), TBlock|TConstant|TReference }, { ATTR(DwarfAttrDeclColumn), OFFSET(declcolumn), TConstant }, { ATTR(DwarfAttrDeclFile), OFFSET(declfile), TConstant }, { ATTR(DwarfAttrDeclLine), OFFSET(declline), TConstant }, { ATTR(DwarfAttrDefaultValue), OFFSET(defaultvalue), TReference }, { ATTR(DwarfAttrDiscr), OFFSET(discr), TReference }, { ATTR(DwarfAttrDiscrList), OFFSET(discrlist), TBlock }, { ATTR(DwarfAttrDiscrValue), OFFSET(discrvalue), TConstant }, { ATTR(DwarfAttrEncoding), OFFSET(encoding), TConstant }, { ATTR(DwarfAttrFrameBase), OFFSET(framebase), TBlock|TConstant }, { ATTR(DwarfAttrFriend), OFFSET(friend), TReference }, { ATTR(DwarfAttrHighpc), OFFSET(highpc), TAddress }, { ATTR(DwarfAttrEntrypc), OFFSET(entrypc), TAddress }, { ATTR(DwarfAttrIdentifierCase), OFFSET(identifiercase), TConstant }, { ATTR(DwarfAttrImport), OFFSET(import), TReference }, { ATTR(DwarfAttrInline), OFFSET(inlined), TConstant }, { ATTR(DwarfAttrArtificial), OFFSET(isartificial), TFlag }, { ATTR(DwarfAttrDeclaration), OFFSET(isdeclaration), TFlag }, { ATTR(DwarfAttrExternal), OFFSET(isexternal), TFlag }, { ATTR(DwarfAttrIsOptional), OFFSET(isoptional), TFlag }, { ATTR(DwarfAttrPrototyped), OFFSET(isprototyped), TFlag }, { ATTR(DwarfAttrVarParam), OFFSET(isvarparam), TFlag }, { ATTR(DwarfAttrLanguage), OFFSET(language), TConstant }, { ATTR(DwarfAttrLocation), OFFSET(location), TReference|TBlock }, { ATTR(DwarfAttrLowerBound), OFFSET(lowerbound), TConstant|TReference }, { ATTR(DwarfAttrLowpc), OFFSET(lowpc), TAddress }, { ATTR(DwarfAttrMacroInfo), OFFSET(macroinfo), TConstant }, { ATTR(DwarfAttrName), OFFSET(name), TString }, { ATTR(DwarfAttrNamelistItem), OFFSET(namelistitem), TBlock }, { ATTR(DwarfAttrOrdering), OFFSET(ordering), TConstant }, { ATTR(DwarfAttrPriority), OFFSET(priority), TReference }, { ATTR(DwarfAttrProducer), OFFSET(producer), TString }, { ATTR(DwarfAttrRanges), OFFSET(ranges), TReference }, { ATTR(DwarfAttrReturnAddr), OFFSET(returnaddr), TBlock|TConstant }, { ATTR(DwarfAttrSegment), OFFSET(segment), TBlock|TConstant }, { ATTR(DwarfAttrSibling), OFFSET(sibling), TReference }, { ATTR(DwarfAttrSpecification), OFFSET(specification), TReference }, { ATTR(DwarfAttrStartScope), OFFSET(startscope), TConstant }, { ATTR(DwarfAttrStaticLink), OFFSET(staticlink), TBlock|TConstant }, { ATTR(DwarfAttrStmtList), OFFSET(stmtlist), TConstant }, { ATTR(DwarfAttrStrideSize), OFFSET(stridesize), TConstant }, { ATTR(DwarfAttrStringLength), OFFSET(stringlength), TBlock|TConstant }, { ATTR(DwarfAttrType), OFFSET(type), TReference }, { ATTR(DwarfAttrUpperBound), OFFSET(upperbound), TConstant|TReference }, { ATTR(DwarfAttrUseLocation), OFFSET(uselocation), TBlock|TConstant }, { ATTR(DwarfAttrVirtuality), OFFSET(virtuality), TConstant }, { ATTR(DwarfAttrVisibility), OFFSET(visibility), TConstant }, { ATTR(DwarfAttrVtableElemLoc), OFFSET(vtableelemloc), TBlock|TReference }, { } }; static Parse ptab[DwarfAttrMax]; static int parseattrs(Dwarf *d, DwarfBuf *b, ulong tag, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs) { int i, f, n, got; static int nbad; void *v; /* initialize ptab first time through for quick access */ if(ptab[DwarfAttrName].name != DwarfAttrName) for(i=0; plist[i].name; i++) ptab[plist[i].name] = plist[i]; memset(attrs, 0, sizeof *attrs); attrs->tag = a->tag; attrs->haskids = a->haskids; for(i=0; inattr; i++){ n = a->attr[i].name; f = a->attr[i].form; werrstr("struct: (@%x) n %x f %x (%d %d)\n", b->p - d->info.data, n, f, ptab[n].haveoff, ptab[n].off); if(n < 0 || n >= DwarfAttrMax || ptab[n].name==0) { if (skipform(d, b, f) < 0) { if(++nbad == 1) werrstr("dwarf parse attrs: cannot skip form %d", f); return -1; } continue; } v = (char*)attrs + ptab[n].off; got = 0; if(f == FormIndirect) f = dwarfget128(b); if((ptab[n].type&(TConstant|TReference|TAddress)) && getulong(b, f, unit, v, &got) >= 0) ; else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0) got = TFlag; else if((ptab[n].type&TString) && getstring(d, b, f, v) >= 0) got = TString; else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0) { got = TBlock; } else { werrstr("Skipping form %x\n", f); if(skipform(d, b, f) < 0){ //if(++nbad == 1) werrstr("dwarf parse attrs: cannot skip form %d", f); return -1; } } #if 0 if(got == TBlock && (ptab[n].type&TConstant)) got = constblock(b->d, v, v); #endif *((uchar*)attrs+ptab[n].haveoff) = got; } if (attrs->have.name) werrstr("%s: tag %x kids %d (last %x)\n", attrs->name, attrs->tag, attrs->haskids, b->p - b->d->info.data); return 0; } static int getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type) { static int nbad; uvlong uv; switch(form){ default: return -1; /* addresses */ case FormAddr: *type = TAddress; *u = dwarfgetaddr(b); return 0; /* references */ case FormRefAddr: /* absolute ref in .debug_info */ *type = TReference; *u = dwarfgetaddr(b); return 0; case FormRef1: *u = dwarfget1(b); goto relativeref; case FormRef2: *u = dwarfget2(b); goto relativeref; case FormRef4: *u = dwarfget4(b); goto relativeref; case FormRef8: *u = dwarfget8(b); goto relativeref; case FormRefUdata: *u = dwarfget128(b); relativeref: *u += unit; *type = TReference; return 0; /* constants */ case FormData1: *u = dwarfget1(b); goto constant; case FormData2: *u = dwarfget2(b); goto constant; case FormData4: *u = dwarfget4(b); goto constant; case FormData8: uv = dwarfget8(b); *u = uv; if(uv != *u && ++nbad == 1) werrstr("dwarf: truncating 64-bit attribute constants"); goto constant; case FormSdata: *u = dwarfget128s(b); goto constant; case FormUdata: *u = dwarfget128(b); constant: *type = TConstant; return 0; } } static int getuchar(DwarfBuf *b, int form, uchar *u) { switch(form){ default: return -1; case FormFlag: *u = dwarfget1(b); return 0; } } static int getstring(Dwarf *d, DwarfBuf *b, int form, char **s) { static int nbad; ulong u, x; switch(form){ default: return -1; case FormString: x = b->p - d->info.data; *s = dwarfgetstring(b); for (u = 0; (*s)[u]; u++) { assert(isprint((*s)[u])); } return 0; case FormStrp: u = dwarfget4(b); if(u >= b->d->str.len){ if(++nbad == 1) werrstr("dwarf: bad string pointer 0x%lux in attribute", u); /* don't return error - maybe can proceed */ *s = nil; }else *s = (char*)b->d->str.data + u; return 0; } } static int getblock(DwarfBuf *b, int form, DwarfBlock *bl) { ulong n; switch(form){ default: return -1; case FormDwarfBlock: n = dwarfget128(b); goto copyn; case FormDwarfBlock1: n = dwarfget1(b); goto copyn; case FormDwarfBlock2: n = dwarfget2(b); goto copyn; case FormDwarfBlock4: n = dwarfget4(b); copyn: bl->data = dwarfgetnref(b, n); bl->len = n; if(bl->data == nil) return -1; return 0; } } /* last resort */ static int skipform(Dwarf *d, DwarfBuf *b, int form) { int type; DwarfVal val; if(getulong(b, form, 0, &val.c, &type) < 0 && getuchar(b, form, (uchar*)&val) < 0 && getstring(d, b, form, &val.s) < 0 && getblock(b, form, &val.b) < 0) return -1; return 0; } void stackinit(DwarfStack *stack) { memset(stack, 0, sizeof(*stack)); stack->data = stack->storage; stack->length = 0; stack->max = sizeof(stack->storage) / sizeof(stack->storage[0]); } void stackpush(DwarfStack *stack, ulong value) { if (stack->length == stack->max) { ulong *newstack = malloc(sizeof(ulong)*stack->max*2); memcpy(newstack, stack->data, sizeof(ulong)*stack->length); if (stack->data != stack->storage) free(stack->data); stack->data = newstack; stack->max *= 2; } werrstr("stack[%d] = %x", stack->length, value); stack->data[stack->length++] = value; } ulong stackpop(DwarfStack *stack) { ASSERT(stack->length > 0); ulong val = stack->data[--stack->length]; werrstr("pop stack[%d] -> %x", stack->length, val); return val; } void stackfree(DwarfStack *stack) { if (stack->data != stack->storage) free(stack->data); } // Returns -1 on failure int dwarfgetarg(Dwarf *d, const char *name, DwarfBuf *buf, ulong cfa, PROSSYM_REGISTERS registers, ulong *result) { int ret = 0; DwarfStack stack = { }; stackinit(&stack); stackpush(&stack, cfa); while (buf->p < buf->ep) { int opcode = dwarfget1(buf); werrstr("opcode %x", opcode); switch (opcode) { case 0: buf->p = buf->ep; break; case OpAddr: if (d->addrsize == 4) { stackpush(&stack, dwarfget4(buf)); break; } else { werrstr("%s: we only support 4 byte addrs", name); goto fatal; } case OpConst1s: { signed char c = dwarfget1(buf); stackpush(&stack, c); } break; case OpConst1u: stackpush(&stack, dwarfget1(buf)); break; case OpConst2s: { signed short s = dwarfget2(buf); stackpush(&stack, s); } break; case OpConst2u: stackpush(&stack, dwarfget2(buf)); break; case OpConst4s: { signed int i = dwarfget4(buf); stackpush(&stack, i); } break; case OpConst4u: stackpush(&stack, dwarfget4(buf)); break; case OpConst8s: case OpConst8u: werrstr("const 8 not yet supported"); goto fatal; case OpConsts: stackpush(&stack, dwarfget128s(buf)); break; case OpConstu: stackpush(&stack, dwarfget128(buf)); break; case OpDup: { ulong popped = stackpop(&stack); stackpush(&stack, popped); stackpush(&stack, popped); } break; case OpDrop: stackpop(&stack); break; case OpOver: { if (stack.length < 2) goto fatal; stackpush(&stack, stack.data[stack.length-2]); } break; case OpPick: { ulong arg = dwarfget1(buf); if (arg >= stack.length) goto fatal; arg = stack.data[stack.length-1-arg]; stackpush(&stack, arg); } break; case OpSwap: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b); stackpush(&stack, a); } break; case OpRot: { ulong a = stackpop(&stack), b = stackpop(&stack), c = stackpop(&stack); stackpush(&stack, b); stackpush(&stack, c); stackpush(&stack, a); } break; case OpXderef: case OpXderefSize: werrstr("Xderef not yet supported"); goto fatal; case OpAbs: { long a = stackpop(&stack); stackpush(&stack, a < 0 ? -a : a); } break; case OpAnd: stackpush(&stack, stackpop(&stack) & stackpop(&stack)); break; case OpDiv: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b / a); } break; case OpMinus: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b - a); } break; case OpMod: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b % a); } break; case OpMul: stackpush(&stack, stackpop(&stack) * stackpop(&stack)); break; case OpNeg: stackpush(&stack, -stackpop(&stack)); break; case OpNot: stackpush(&stack, ~stackpop(&stack)); break; case OpOr: stackpush(&stack, stackpop(&stack) | stackpop(&stack)); break; case OpPlus: stackpush(&stack, stackpop(&stack) + stackpop(&stack)); break; case OpPlusUconst: stackpush(&stack, stackpop(&stack) + dwarfget128(buf)); break; case OpShl: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b << a); } break; case OpShr: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b >> a); } break; case OpShra: { ulong a = stackpop(&stack); long b = stackpop(&stack); if (b < 0) b = -(-b >> a); else b = b >> a; stackpush(&stack, b); } break; case OpXor: stackpush(&stack, stackpop(&stack) ^ stackpop(&stack)); break; case OpSkip: buf->p += dwarfget2(buf); break; case OpBra: { ulong a = dwarfget2(buf); if (stackpop(&stack)) buf->p += a; } break; case OpEq: stackpush(&stack, stackpop(&stack) == stackpop(&stack)); break; case OpGe: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b >= a); } break; case OpGt: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b > a); } break; case OpLe: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b <= a); } break; case OpLt: { ulong a = stackpop(&stack), b = stackpop(&stack); stackpush(&stack, b < a); } break; case OpNe: stackpush(&stack, stackpop(&stack) != stackpop(&stack)); break; case OpNop: break; case OpDeref: { ulong val; void* addr = (void*)stackpop(&stack); if (!RosSymCallbacks.MemGetProc (d->pe->fd, &val, addr, d->addrsize)) goto fatal; stackpush(&stack, val); } break; case OpDerefSize: { ulong val, size = dwarfget1(buf); void* addr = (void*)stackpop(&stack); if (!RosSymCallbacks.MemGetProc (d->pe->fd, &val, addr, size)) goto fatal; stackpush(&stack, val); } break; case OpFbreg: { ulong val, offset = dwarfget128s(buf); void* addr = (void*)cfa; werrstr("FBREG cfa %x offset %x", cfa, offset); if (!RosSymCallbacks.MemGetProc (d->pe->fd, &val, (PVOID)((ULONG_PTR)addr+offset), d->addrsize)) goto fatal; stackpush(&stack, val); } break; case OpPiece: werrstr("OpPiece not supported"); goto fatal; default: if (opcode >= OpLit0 && opcode < OpReg0) stackpush(&stack, opcode - OpLit0); else if (opcode >= OpReg0 && opcode < OpBreg0) { ulong reg = opcode - OpReg0; werrstr("REG[%d] value %x", reg, (ulong)registers->Registers[reg]); stackpush(&stack, registers->Registers[reg]); } else if (opcode >= OpBreg0 && opcode < OpRegx) { ulong val, reg = opcode - OpBreg0, offset = dwarfget128s(buf); void* addr = (void*)(ULONG_PTR)registers->Registers[reg]; werrstr("BREG[%d] reg %x offset %x", reg, addr, offset); if (!RosSymCallbacks.MemGetProc ((PVOID)d->pe->fd, &val, (PVOID)((ULONG_PTR)addr + offset), d->addrsize)) goto fatal; stackpush(&stack, val); } else { werrstr("opcode %x not supported", opcode); goto fatal; } break; } } if (stack.length < 1) goto fatal; *result = stackpop(&stack); werrstr("%s: value %x", name, *result); goto finish; fatal: ret = -1; finish: stackfree(&stack); return ret; } int dwarfargvalue(Dwarf *d, DwarfSym *proc, ulong pc, ulong cfa, PROSSYM_REGISTERS registers, DwarfParam *parameter) { int gotarg; DwarfSym unit = { }; if (dwarfenumunit(d, proc->unit, &unit) == -1) return -1; werrstr("lookup in unit %x-%x, pc %x", unit.attrs.lowpc, unit.attrs.highpc, pc); pc -= unit.attrs.lowpc; werrstr("paramblock %s -> unit %x type %x fde %x len %d registers %x", parameter->name, parameter->unit, parameter->type, parameter->fde, parameter->len, registers); // Seek our range in loc DwarfBuf locbuf; DwarfBuf instream = { }; locbuf.d = d; locbuf.addrsize = d->addrsize; if (parameter->loctype == TConstant) { locbuf.p = d->loc.data + parameter->fde; locbuf.ep = d->loc.data + d->loc.len; ulong start, end, len; do { len = 0; start = dwarfget4(&locbuf); end = dwarfget4(&locbuf); if (start && end) { len = dwarfget2(&locbuf); instream = locbuf; instream.ep = instream.p + len; locbuf.p = instream.ep; } werrstr("ip %x s %x e %x (%x bytes)", pc, start, end, len); } while (start && end && (start > pc || end <= pc)); } else if (parameter->loctype == TBlock) { instream = locbuf; instream.p = (void *)parameter->fde; instream.ep = instream.p + parameter->len; } else { werrstr("Wrong block type for parameter %s", parameter->name); return -1; } gotarg = dwarfgetarg(d, parameter->name, &instream, cfa, registers, ¶meter->value); if (gotarg == -1) return -1; return 0; } void dwarfdumpsym(Dwarf *d, DwarfSym *s) { int j; werrstr("tag %x\n", s->attrs.tag); for (j = 0; plist[j].name; j++) { char *have = ((char*)&s->attrs) + plist[j].haveoff; char *attr = ((char*)&s->attrs) + plist[j].off; if (*have == TString) { char *str = *((char **)attr); werrstr("%s: %s\n", plist[j].namestr, str); } else if (*have == TReference) { DwarfVal *val = ((DwarfVal*)attr); werrstr("%s: %x:%x\n", plist[j].namestr, val->b.data, val->b.len); } else if (*have) werrstr("%s: (%x)\n", plist[j].namestr, *have); } } int dwarfgetparams(Dwarf *d, DwarfSym *s, ulong pc, int pnum, DwarfParam *paramblocks) { int ip = 0; DwarfSym param = { }; int res = dwarfnextsymat(d, s, ¶m); while (res == 0 && ip < pnum) { if (param.attrs.tag == TagFormalParameter && param.attrs.have.name && param.attrs.have.location) { paramblocks[ip].name = malloc(strlen(param.attrs.name)+1); strcpy(paramblocks[ip].name, param.attrs.name); paramblocks[ip].unit = param.unit; paramblocks[ip].type = param.attrs.type; paramblocks[ip].loctype = param.attrs.have.location; paramblocks[ip].len = param.attrs.location.b.len; paramblocks[ip].fde = (ulong)param.attrs.location.b.data; werrstr("param[%d] block %s -> type %x loctype %x fde %x len %x", ip, paramblocks[ip].name, paramblocks[ip].type, paramblocks[ip].loctype, paramblocks[ip].fde, paramblocks[ip].len); ip++; } res = dwarfnextsymat(d, s, ¶m); } return ip; }