From d8441072beed68e3eeb9022fa93829bed7dad367 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sat, 18 Oct 2014 02:05:33 -0700 Subject: Revamped DIE reading. My decodeLocation. --- src/cv2pdb.h | 6 +- src/dwarf2pdb.cpp | 77 ++++++----- src/readDwarf.cpp | 380 ++++++++++++++++++++++++++++++++++++++++++------------ src/readDwarf.h | 111 +++++++++------- 4 files changed, 402 insertions(+), 172 deletions(-) diff --git a/src/cv2pdb.h b/src/cv2pdb.h index f5b2938..b2f56be 100644 --- a/src/cv2pdb.h +++ b/src/cv2pdb.h @@ -171,8 +171,8 @@ public: int addDWARFStructure(DWARF_InfoData& id, DWARF_CompilationUnit* cu, DIECursor cursor); int addDWARFArray(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, DIECursor cursor); int addDWARFBasicType(const char*name, int encoding, int byte_size); - int getTypeByDWARFOffset(DWARF_CompilationUnit* cu, int off); - int getDWARFTypeSize(DWARF_CompilationUnit* cu, int typeOff); + int getTypeByDWARFPtr(DWARF_CompilationUnit* cu, byte* ptr); + int getDWARFTypeSize(DWARF_CompilationUnit* cu, byte* ptr); int getDWARFArrayBounds(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, DIECursor cursor, int& upperBound); bool mapTypes(); @@ -256,7 +256,7 @@ public: // DWARF int codeSegOff; - std::unordered_map mapOffsetToType; + std::unordered_map mapOffsetToType; }; diff --git a/src/dwarf2pdb.cpp b/src/dwarf2pdb.cpp index 58228ab..0612775 100644 --- a/src/dwarf2pdb.cpp +++ b/src/dwarf2pdb.cpp @@ -187,16 +187,15 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE #endif int frameOff = 8; // assume ebp+8 in fb - if(img.debug_loc && procid.frame_base >= 0) + if(img.debug_loc && procid.frame_base.type == ExprLoc) { - unsigned char* loc = (unsigned char*) (img.debug_loc + procid.frame_base); + int locid; + unsigned char* loc = (unsigned char*)(img.debug_loc + decodeLocation(procid.frame_base.expr.ptr, procid.frame_base.expr.len, false, locid)); int frame_breg = cu->address_size == 8 ? DW_OP_breg6 : DW_OP_breg5; #if 1 - while(RDsize(loc, cu->address_size) != 0 || RDsize(loc + cu->address_size, cu->address_size) != 0) + while(RDsize(loc, cu->address_size) != 0 || RDsize(loc, cu->address_size) != 0) { - loc += 2*cu->address_size; int opsize = RD2(loc); - loc += 2; if(*loc == frame_breg) { unsigned char* p = loc + 1; @@ -208,6 +207,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE #endif } + if (cu) { bool endarg = false; @@ -222,11 +222,11 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE { if (id.name) { - off = decodeLocation(id.location_ptr, id.location_len, false, cvid); + off = decodeLocation(id.location.expr.ptr, id.location.expr.len, false, cvid); if (cvid == S_BPREL_V2) - appendStackVar(id.name, getTypeByDWARFOffset(cu, id.type), off + frameOff, false); + appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), off + frameOff, false); else if (cvid == S_BPREL_XXXX_V3) - appendStackVar(id.name, getTypeByDWARFOffset(cu, id.type), off, true); + appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), off, true); } } prev = cursor; @@ -247,11 +247,11 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE { if (id.name) { - off = decodeLocation(id.location_ptr, id.location_len, false, cvid); + off = decodeLocation(id.location.expr.ptr, id.location.expr.len, false, cvid); if (cvid == S_BPREL_V2) - appendStackVar(id.name, getTypeByDWARFOffset(cu, id.type), off + frameOff, false); + appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), off + frameOff, false); else if (cvid == S_BPREL_XXXX_V3) - appendStackVar(id.name, getTypeByDWARFOffset(cu, id.type), off, true); + appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), off, true); } } else if (id.tag == DW_TAG_lexical_block) @@ -277,7 +277,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* cu, DIECursor cursor) { - printf("Adding struct %s, entryoff %d, abbrev %d\n", structid.name, structid.entryOff, structid.abbrev); + //printf("Adding struct %s, entryoff %d, abbrev %d\n", structid.name, structid.entryOff, structid.abbrev); bool isunion = structid.tag == DW_TAG_union_type; @@ -297,7 +297,7 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c codeview_fieldtype* bc = (codeview_fieldtype*) (dwarfTypes + cbDwarfTypes); bc->bclass_v2.id = LF_BCLASS_V2; bc->bclass_v2.offset = 0; - bc->bclass_v2.type = getTypeByDWARFOffset(cu, structid.containing_type); + bc->bclass_v2.type = getTypeByDWARFPtr(cu, structid.containing_type); bc->bclass_v2.attribute = 3; // public cbDwarfTypes += sizeof(bc->bclass_v2); for (; cbDwarfTypes & 3; cbDwarfTypes++) @@ -316,11 +316,11 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c int off = 0; if(!isunion) { - if(id.member_location_ptr) - off = decodeLocation(id.member_location_ptr, id.member_location_len, true, cvid); + if (id.member_location.type == ExprLoc) + off = decodeLocation(id.member_location.expr.ptr, id.member_location.expr.len, true, cvid); else { - off = id.member_location_data; + off = id.member_location.cons; cvid = S_CONSTANT_V2; } } @@ -328,19 +328,19 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c { checkDWARFTypeAlloc(kMaxNameLen + 100); codeview_fieldtype* dfieldtype = (codeview_fieldtype*) (dwarfTypes + cbDwarfTypes); - cbDwarfTypes += addFieldMember(dfieldtype, 0, off, getTypeByDWARFOffset(cu, id.type), id.name); + cbDwarfTypes += addFieldMember(dfieldtype, 0, off, getTypeByDWARFPtr(cu, id.type), id.name); nfields++; } } else if(id.tag == DW_TAG_inheritance) { - int off = decodeLocation(id.member_location_ptr, id.member_location_len, true, cvid); + int off = decodeLocation(id.member_location.expr.ptr, id.member_location.expr.len, true, cvid); if(cvid == S_CONSTANT_V2) { codeview_fieldtype* bc = (codeview_fieldtype*) (dwarfTypes + cbDwarfTypes); bc->bclass_v2.id = LF_BCLASS_V2; bc->bclass_v2.offset = off; - bc->bclass_v2.type = getTypeByDWARFOffset(cu, id.type); + bc->bclass_v2.type = getTypeByDWARFPtr(cu, id.type); bc->bclass_v2.attribute = 3; // public cbDwarfTypes += sizeof(bc->bclass_v2); for (; cbDwarfTypes & 3; cbDwarfTypes++) @@ -398,7 +398,7 @@ int CV2PDB::addDWARFArray(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, codeview_type* cvt = (codeview_type*) (userTypes + cbUserTypes); cvt->array_v2.id = v3 ? LF_ARRAY_V3 : LF_ARRAY_V2; - cvt->array_v2.elemtype = getTypeByDWARFOffset(cu, arrayid.type); + cvt->array_v2.elemtype = getTypeByDWARFPtr(cu, arrayid.type); cvt->array_v2.idxtype = 0x74; int len = (BYTE*)&cvt->array_v2.arrlen - (BYTE*)cvt; int size = (upperBound - lowerBound + 1) * getDWARFTypeSize(cu, arrayid.type); @@ -539,22 +539,22 @@ int CV2PDB::addDWARFBasicType(const char*name, int encoding, int byte_size) return cvtype; } -int CV2PDB::getTypeByDWARFOffset(DWARF_CompilationUnit* cu, int off) +int CV2PDB::getTypeByDWARFPtr(DWARF_CompilationUnit* cu, byte* ptr) { - int cuoff = (char*) cu - img.debug_info; - std::unordered_map::iterator it = mapOffsetToType.find(cuoff + off); + std::unordered_map::iterator it = mapOffsetToType.find(ptr); if(it == mapOffsetToType.end()) return 0x03; // void return it->second; } -int CV2PDB::getDWARFTypeSize(DWARF_CompilationUnit* cu, int typeOff) +int CV2PDB::getDWARFTypeSize(DWARF_CompilationUnit* cu, byte* typePtr) { DWARF_InfoData id; - DIECursor cursor(cu, typeOff); + DIECursor cursor(cu, typePtr); if (!cursor.readNext(id)) return 0; + if(id.byte_size > 0) return id.byte_size; @@ -585,7 +585,7 @@ bool CV2PDB::mapTypes() { DWARF_CompilationUnit* cu = (DWARF_CompilationUnit*)(img.debug_info + off); - DIECursor cursor(cu, sizeof(DWARF_CompilationUnit)); + DIECursor cursor(cu, (byte*)cu + sizeof(DWARF_CompilationUnit)); DWARF_InfoData id; while (cursor.readNext(id)) { @@ -619,7 +619,7 @@ bool CV2PDB::mapTypes() case DW_TAG_mutable_type: // withdrawn case DW_TAG_shared_type: case DW_TAG_rvalue_reference_type: - mapOffsetToType.insert(std::pair(off + id.entryOff, typeID)); + mapOffsetToType.insert(std::make_pair(id.entryPtr, typeID)); typeID++; } } @@ -642,7 +642,7 @@ bool CV2PDB::createTypes() { DWARF_CompilationUnit* cu = (DWARF_CompilationUnit*)(img.debug_info + off); - DIECursor cursor(cu, sizeof(DWARF_CompilationUnit)); + DIECursor cursor(cu, (byte*)cu + sizeof(DWARF_CompilationUnit)); DWARF_InfoData id; while (cursor.readNext(id)) { @@ -656,17 +656,17 @@ bool CV2PDB::createTypes() cvtype = addDWARFBasicType(id.name, id.encoding, id.byte_size); break; case DW_TAG_typedef: - cvtype = appendModifierType(getTypeByDWARFOffset(cu, id.type), 0); + cvtype = appendModifierType(getTypeByDWARFPtr(cu, id.type), 0); addUdtSymbol(cvtype, id.name); break; case DW_TAG_pointer_type: - cvtype = appendPointerType(getTypeByDWARFOffset(cu, id.type), pointerAttr); + cvtype = appendPointerType(getTypeByDWARFPtr(cu, id.type), pointerAttr); break; case DW_TAG_const_type: - cvtype = appendModifierType(getTypeByDWARFOffset(cu, id.type), 1); + cvtype = appendModifierType(getTypeByDWARFPtr(cu, id.type), 1); break; case DW_TAG_reference_type: - cvtype = appendPointerType(getTypeByDWARFOffset(cu, id.type), pointerAttr | 0x20); + cvtype = appendPointerType(getTypeByDWARFPtr(cu, id.type), pointerAttr | 0x20); break; case DW_TAG_class_type: @@ -715,8 +715,8 @@ bool CV2PDB::createTypes() unsigned char* rend = (unsigned char*)img.debug_ranges + img.debug_ranges_length; while (r < rend) { - unsigned long pclo = RD4(r); r += 4; - unsigned long pchi = RD4(r); r += 4; + unsigned long pclo = RD4(r); + unsigned long pchi = RD4(r); if (pclo == 0 && pchi == 0) break; //printf("%s %s %x - %x\n", dir, name, pclo, pchi); @@ -739,14 +739,14 @@ bool CV2PDB::createTypes() { int seg = -1; unsigned long segOff; - if (id.location_ptr == 0 && id.external && id.linkage_name) + if (id.location.type == Invalid && id.external && id.linkage_name) { seg = img.findSymbol(id.linkage_name, segOff); } else { int cvid; - segOff = decodeLocation(id.location_ptr, id.location_len, false, cvid); + segOff = decodeLocation(id.location.expr.ptr, id.location.expr.len, false, cvid); if (cvid == S_GDATA_V2) seg = img.findSection(segOff); if (seg >= 0) @@ -754,7 +754,7 @@ bool CV2PDB::createTypes() } if (seg >= 0) { - int type = getTypeByDWARFOffset(cu, id.type); + int type = getTypeByDWARFPtr(cu, id.type); appendGlobalVar(id.name, type, seg + 1, segOff); int rc = mod->AddPublic2(id.name, seg + 1, segOff, type); } @@ -773,8 +773,7 @@ bool CV2PDB::createTypes() if (cvtype >= 0) { assert(cvtype == typeID); typeID++; - int x = mapOffsetToType[off + id.entryOff]; - assert(mapOffsetToType[off + id.entryOff] == cvtype); + assert(mapOffsetToType[id.entryPtr] == cvtype); } } diff --git a/src/readDwarf.cpp b/src/readDwarf.cpp index 0d298bb..d8a4e47 100644 --- a/src/readDwarf.cpp +++ b/src/readDwarf.cpp @@ -11,9 +11,233 @@ extern "C" { #include "mscvpdb.h" } -long decodeLocation(unsigned char* loc, long len, bool push0, int &id, int& size) +// The actual value is {reg} + offset +struct Location { - unsigned char* p = loc; + int reg; + int offset; +}; +const int NoReg = -1; + +Location makeLoc(int r, int o) +{ + Location e = { r, o }; + return e; +} + +bool decodeLocation(byte* loc, long len, Location* frameBase) +{ + byte* p = loc; + Location stack[256]; + int stackDepth = 0; + + for (;;) + { + if (p >= loc + len) + return false; + + int op = *p++; + if (op == 0) + { + return true; + } + + switch (op) + { + case DW_OP_const1u: stack[stackDepth++] = makeLoc(NoReg, *p); break; + case DW_OP_const2u: stack[stackDepth++] = makeLoc(NoReg, RD2(p)); break; + case DW_OP_const4u: stack[stackDepth++] = makeLoc(NoReg, RD4(p)); break; + case DW_OP_const1s: stack[stackDepth++] = makeLoc(NoReg, (char)*p); break; + case DW_OP_const2s: stack[stackDepth++] = makeLoc(NoReg, (short)RD2(p)); break; + case DW_OP_const4s: stack[stackDepth++] = makeLoc(NoReg, (int)RD4(p)); break; + case DW_OP_constu: stack[stackDepth++] = makeLoc(NoReg, LEB128(p)); break; + case DW_OP_consts: stack[stackDepth++] = makeLoc(NoReg, SLEB128(p)); break; + + case DW_OP_plus_uconst: stack[stackDepth - 1].offset += LEB128(p); break; + + case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: + case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: + case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: + case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: + case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: + case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: + stack[stackDepth++] = makeLoc(NoReg, op - DW_OP_lit0); + break; + + case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: + case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: + case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: + case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: + case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: + case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: + case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: + case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: + stack[stackDepth++] = makeLoc(op - DW_OP_reg0, 0); + break; + + case DW_OP_bregx: + stack[stackDepth++] = makeLoc(LEB128(p), SLEB128(p)); + break; + + case DW_OP_plus: // op2 + op1 + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg != NoReg && op2.reg != NoReg) // only one of them may be reg-relative + return false; + + op2.reg = (op1.reg != NoReg) ? op1.reg : op2.reg; + op2.offset = op2.offset + op1.offset; + --stackDepth; + } break; + + case DW_OP_minus: // op2 - op1 + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg == op2.reg) + op2 = makeLoc(NoReg, op2.offset - op1.offset); + else if (op1.reg == NoReg) + op2.offset = op2.offset - op1.offset; + else + return false; // cannot subtract reg-relative + --stackDepth; + } break; + + case DW_OP_and: + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if ((op1.reg == NoReg && op1.offset == 0) || (op2.reg == NoReg && op1.offset == 0)) // X & 0 == 0 + op2 = makeLoc(NoReg, 0); + else if (op1.reg == NoReg && op2.reg == NoReg) + op2 = makeLoc(NoReg, op1.offset & op2.offset); + else + return false; + --stackDepth; + } break; + + case DW_OP_xor: + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg == op2.reg && op1.offset == op2.offset) // X ^ X == 0 + op2 = makeLoc(NoReg, 0); + else if (op1.reg == NoReg && op2.reg == NoReg) + op2 = makeLoc(NoReg, op1.offset ^ op2.offset); + else + return false; + --stackDepth; + } break; + + case DW_OP_mul: + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg == NoReg && op1.offset == 0) // X * 0 == 0 + op2 = makeLoc(NoReg, 0); + else if (op1.reg == NoReg && op2.reg == NoReg) + op2 = makeLoc(NoReg, op1.offset * op2.offset); + else + return false; + --stackDepth; + } break; + + + case DW_OP_abs: case DW_OP_neg: case DW_OP_not: + { + Location& op1 = stack[stackDepth - 1]; + if (op1.reg != NoReg) + return false; + switch (op) + { + case DW_OP_abs: op1.offset = abs(op1.offset); break; + case DW_OP_neg: op1.offset = -op1.offset; break; + case DW_OP_not: op1.offset = ~op1.offset; break; + } + } break; + + case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: + case DW_OP_le: case DW_OP_lt: case DW_OP_ne: + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg != op2.reg) // can't compare unless both use the same register (or NoReg) + return false; + switch (op) + { + case DW_OP_eq: op2.offset = op2.offset == op1.offset; break; + case DW_OP_ge: op2.offset = op2.offset >= op1.offset; break; + case DW_OP_gt: op2.offset = op2.offset > op1.offset; break; + case DW_OP_le: op2.offset = op2.offset <= op1.offset; break; + case DW_OP_lt: op2.offset = op2.offset < op1.offset; break; + case DW_OP_ne: op2.offset = op2.offset != op1.offset; break; + } + --stackDepth; + } break; + + case DW_OP_div: case DW_OP_mod: case DW_OP_shl: + case DW_OP_shr: case DW_OP_shra: case DW_OP_or: + { + Location& op1 = stack[stackDepth - 1]; + Location& op2 = stack[stackDepth - 2]; + if (op1.reg != NoReg || op2.reg != NoReg) // can't combine unless both are constants + return false; + switch (op) + { + case DW_OP_div: op2.offset = op2.offset / op1.offset; break; + case DW_OP_mod: op2.offset = op2.offset % op1.offset; break; + case DW_OP_shl: op2.offset = op2.offset << op1.offset; break; + case DW_OP_shr: op2.offset = op2.offset >> op1.offset; break; + case DW_OP_shra: op2.offset = op2.offset >> op1.offset; break; + case DW_OP_or: op2.offset = op2.offset | op1.offset; break; + } + --stackDepth; + } break; + + case DW_OP_fbreg: + if (!frameBase) + return false; + stack[stackDepth++] = makeLoc(frameBase->reg, frameBase->offset + SLEB128(p)); + break; + + case DW_OP_dup: stack[stackDepth] = stack[stackDepth - 1]; stackDepth++; break; + case DW_OP_drop: stackDepth--; break; + case DW_OP_over: stack[stackDepth] = stack[stackDepth - 2]; stackDepth++; break; + case DW_OP_pick: stack[stackDepth++] = stack[*p]; break; + case DW_OP_swap: { Location tmp = stack[stackDepth - 1]; stack[stackDepth - 1] = stack[stackDepth - 2]; stack[stackDepth - 2] = tmp; } break; + case DW_OP_rot: { Location tmp = stack[stackDepth - 1]; stack[stackDepth - 1] = stack[stackDepth - 2]; stack[stackDepth - 2] = stack[stackDepth - 3]; stack[stackDepth - 3] = tmp; } break; + + case DW_OP_addr: + stack[stackDepth++] = makeLoc(NoReg, RD4(p)); + break; + + case DW_OP_skip: + { + unsigned off = RD2(p); + p = p + off; + } break; + + case DW_OP_bra: + { + Location& op1 = stack[stackDepth - 1]; + if (op1.reg != NoReg) + return false; + if (op1.offset != 0) + { + unsigned off = RD2(p); + p = p + off; + } + --stackDepth; + } break; + } + } +} + + +long decodeLocation(byte* loc, long len, bool push0, int &id, int& size) +{ + byte* p = loc; long stack[8] = { 0 }; int stackDepth = push0 ? 1 : 0; long data = 0; @@ -133,16 +357,18 @@ long decodeLocation(unsigned char* loc, long len, bool push0, int &id, int& size case DW_OP_bra: case DW_OP_skip: - size = RD2(p) + 2; + size = RD2(p); + p += size; break; } - p += size; } while (stackDepth > 0); size = p - loc; return stack[0]; } +//decodeLocation(byte* loc, long len) + // declare hasher for pair namespace std { @@ -156,7 +382,7 @@ namespace std }; } -typedef std::unordered_map, unsigned char*> abbrevMap_t; +typedef std::unordered_map, byte*> abbrevMap_t; static PEImage* img; static abbrevMap_t abbrevMap; @@ -168,10 +394,10 @@ void DIECursor::setContext(PEImage* img_) } -DIECursor::DIECursor(DWARF_CompilationUnit* cu_, unsigned long offset) +DIECursor::DIECursor(DWARF_CompilationUnit* cu_, byte* ptr_) { cu = cu_; - ptr = (unsigned char*)cu + offset; + ptr = ptr_; level = 0; hasChild = false; sibling = 0; @@ -183,7 +409,7 @@ bool DIECursor::readSibling(DWARF_InfoData& id) if (sibling) { // use sibling pointer, if available - ptr = (unsigned char*)cu + sibling; + ptr = sibling; hasChild = false; } else if (hasChild) @@ -230,10 +456,10 @@ bool DIECursor::readNext(DWARF_InfoData& id, bool stopAtNull) if (level == -1) return false; // we were already at the end of the subtree - if (ptr >= ((unsigned char*)cu + sizeof(cu->unit_length) + cu->unit_length)) + if (ptr >= ((byte*)cu + sizeof(cu->unit_length) + cu->unit_length)) return false; // root of the tree does not have a null terminator, but we know the length - id.entryOff = ptr - (unsigned char*)cu; + id.entryPtr = ptr; id.code = LEB128(ptr); if (id.code == 0) { @@ -249,7 +475,7 @@ bool DIECursor::readNext(DWARF_InfoData& id, bool stopAtNull) break; } - unsigned char* abbrev = getDWARFAbbrev(cu->debug_abbrev_offset, id.code); + byte* abbrev = getDWARFAbbrev(cu->debug_abbrev_offset, id.code); assert(abbrev); if (!abbrev) return false; @@ -267,83 +493,69 @@ bool DIECursor::readNext(DWARF_InfoData& id, bool stopAtNull) if (attr == 0 && form == 0) break; - const char* str = 0; - int size = 0; - unsigned long addr = 0; - unsigned long data = 0; - unsigned long long lldata = 0; - int locid; - bool isRef = false; + while (form == DW_FORM_indirect) + form = LEB128(ptr); + + DWARF_Attribute a; switch (form) { - case DW_FORM_addr: addr = *(unsigned long *)ptr; size = cu->address_size; break; - case DW_FORM_block2: size = RD2(ptr) + 2; break; - case DW_FORM_block4: size = RD4(ptr) + 4; break; - case DW_FORM_data2: size = 2; lldata = data = RD2(ptr); break; - case DW_FORM_data4: size = 4; lldata = data = RD4(ptr); break; - case DW_FORM_data8: size = 8; lldata = RD8(ptr); data = (unsigned long)lldata; break; - case DW_FORM_string: str = (const char*)ptr; size = strlen(str) + 1; break; - case DW_FORM_block: size = LEB128(ptr); lldata = RDsize(ptr, size); data = (unsigned long)lldata; break; - case DW_FORM_block1: size = *ptr++; lldata = RDsize(ptr, size); data = (unsigned long)lldata; break; - case DW_FORM_data1: size = 1; lldata = data = *ptr; break; - case DW_FORM_flag: size = 1; lldata = data = *ptr; break; - case DW_FORM_sdata: lldata = data = SLEB128(ptr); size = 0; break; - case DW_FORM_strp: size = cu->refSize(); str = (const char*)(img->debug_str + RDsize(ptr, size)); break; - case DW_FORM_udata: lldata = data = LEB128(ptr); size = 0; break; - case DW_FORM_ref_addr: size = cu->address_size; lldata = RDsize(ptr, size); data = (unsigned long)lldata; isRef = true; break; - case DW_FORM_ref1: size = 1; lldata = data = *ptr; isRef = true; break; - case DW_FORM_ref2: size = 2; lldata = data = RD2(ptr); isRef = true; break; - case DW_FORM_ref4: size = 4; lldata = data = RD4(ptr); isRef = true; break; - case DW_FORM_ref8: size = 8; lldata = RD8(ptr); data = (unsigned long)lldata; isRef = true; break; - case DW_FORM_ref_udata: lldata = data = LEB128(ptr); size = 0; isRef = true; break; - case DW_FORM_exprloc: size = LEB128(ptr); lldata = decodeLocation(ptr, size, false, locid); data = (unsigned long)lldata; isRef = true; break; - case DW_FORM_flag_present: size = 0; lldata = data = 1; break; - case DW_FORM_ref_sig8: size = 8; break; - case DW_FORM_sec_offset: size = img->isX64() ? 8 : 4; lldata = RDsize(ptr, size); data = (unsigned long)lldata; isRef = true; break; - case DW_FORM_indirect: - default: assert(false && "Unsupported DWARF attribute form"); return false; + case DW_FORM_addr: a.type = Addr; a.addr = (unsigned long)RDsize(ptr, cu->address_size); break; + case DW_FORM_block: a.type = Block; a.block.len = LEB128(ptr); a.block.ptr = ptr; ptr += a.block.len; break; + case DW_FORM_block1: a.type = Block; a.block.len = *ptr++; a.block.ptr = ptr; ptr += a.block.len; break; + case DW_FORM_block2: a.type = Block; a.block.len = RD2(ptr); a.block.ptr = ptr; ptr += a.block.len; break; + case DW_FORM_block4: a.type = Block; a.block.len = RD4(ptr); a.block.ptr = ptr; ptr += a.block.len; break; + case DW_FORM_data1: a.type = Const; a.cons = *ptr++; break; + case DW_FORM_data2: a.type = Const; a.cons = RD2(ptr); break; + case DW_FORM_data4: a.type = Const; a.cons = RD4(ptr); break; + case DW_FORM_data8: a.type = Const; a.cons = RD8(ptr); break; + case DW_FORM_sdata: a.type = Const; a.cons = SLEB128(ptr); break; + case DW_FORM_udata: a.type = Const; a.cons = LEB128(ptr); break; + case DW_FORM_string: a.type = String; a.string = (const char*)ptr; ptr += strlen(a.string) + 1; break; + case DW_FORM_strp: a.type = String; a.string = (const char*)(img->debug_str + RDsize(ptr, cu->address_size)); break; + case DW_FORM_flag: a.type = Flag; a.flag = (*ptr++ != 0); break; + case DW_FORM_flag_present: a.type = Flag; a.flag = true; break; + case DW_FORM_ref1: a.type = Ref; a.ref = (byte*)cu + *ptr++; break; + case DW_FORM_ref2: a.type = Ref; a.ref = (byte*)cu + RD2(ptr); break; + case DW_FORM_ref4: a.type = Ref; a.ref = (byte*)cu + RD4(ptr); break; + case DW_FORM_ref8: a.type = Ref; a.ref = (byte*)cu + RD8(ptr); break; + case DW_FORM_ref_udata: a.type = Ref; a.ref = (byte*)cu + LEB128(ptr); break; + case DW_FORM_ref_addr: a.type = Ref; a.ref = (byte*)img->debug_info + (cu->isDWARF64() ? RD8(ptr) : RD4(ptr)); break; + case DW_FORM_ref_sig8: a.type = Invalid; ptr += 8; break; + case DW_FORM_exprloc: a.type = ExprLoc; a.expr.len = LEB128(ptr); a.expr.ptr = ptr; ptr += a.expr.len; break; + case DW_FORM_sec_offset: a.type = SecOffset; a.sec_offset = cu->isDWARF64() ? RD8(ptr) : RD4(ptr); break; + case DW_FORM_indirect: + default: assert(false && "Unsupported DWARF attribute form"); return false; } + switch (attr) { - case DW_AT_byte_size: id.byte_size = data; break; - case DW_AT_sibling: id.sibling = data; break; - case DW_AT_encoding: id.encoding = data; break; - case DW_AT_name: id.name = str; break; - case DW_AT_MIPS_linkage_name: id.linkage_name = str; break; - case DW_AT_comp_dir: id.dir = str; break; - case DW_AT_low_pc: id.pclo = addr; break; - case DW_AT_high_pc: - if (form == DW_FORM_addr) - id.pchi = addr; - else - id.pchi = id.pclo + data; - break; - case DW_AT_ranges: id.ranges = data; break; - case DW_AT_type: id.type = data; break; - case DW_AT_inline: id.inlined = data; break; - case DW_AT_external: id.external = data; break; - case DW_AT_upper_bound: id.upper_bound = data; break; - case DW_AT_lower_bound: id.lower_bound = data; break; - case DW_AT_containing_type: id.containing_type = data; break; - case DW_AT_specification: id.specification = data; break; - case DW_AT_data_member_location: - if (form == DW_FORM_block1 || form == DW_FORM_exprloc) - id.member_location_ptr = ptr, id.member_location_len = size; - else - id.member_location_data = data; - break; - case DW_AT_location: - if (form == DW_FORM_block1 || form == DW_FORM_exprloc) - id.location_ptr = ptr, id.location_len = size; - else - id.locationlist = data; - break; - case DW_AT_frame_base: - if (form != DW_FORM_block2 && form != DW_FORM_block4 && form != DW_FORM_block1 && form != DW_FORM_block) - id.frame_base = data; + case DW_AT_byte_size: assert(a.type == Const); id.byte_size = a.cons; break; + case DW_AT_sibling: assert(a.type == Ref); id.sibling = a.ref; break; + case DW_AT_encoding: assert(a.type == Const); id.encoding = a.cons; break; + case DW_AT_name: assert(a.type == String); id.name = a.string; break; + case DW_AT_MIPS_linkage_name: assert(a.type == String); id.linkage_name = a.string; break; + case DW_AT_comp_dir: assert(a.type == String); id.dir = a.string; break; + case DW_AT_low_pc: assert(a.type == Addr); id.pclo = a.addr; break; + case DW_AT_high_pc: + if (a.type == Addr) + id.pchi = a.addr; + else if (a.type == Const) + id.pchi = id.pclo + a.cons; + else + assert(false); break; + case DW_AT_ranges: assert(a.type == SecOffset); id.ranges = a.sec_offset; break; + case DW_AT_type: assert(a.type == Ref); id.type = a.ref; break; + case DW_AT_inline: assert(a.type == Const); id.inlined = a.cons; break; + case DW_AT_external: assert(a.type == Flag); id.external = a.flag; break; + case DW_AT_upper_bound: assert(a.type == Const); id.upper_bound = a.cons; break; + case DW_AT_lower_bound: assert(a.type == Const); id.lower_bound = a.cons; break; + case DW_AT_containing_type: assert(a.type == Ref); id.containing_type = a.ref; break; + case DW_AT_specification: assert(a.type == Ref); id.specification = a.ref; break; + case DW_AT_data_member_location: id.member_location = a; break; + case DW_AT_location: id.location = a; break; + case DW_AT_frame_base: id.frame_base = a; break; } - ptr += size; } hasChild = id.hasChild != 0; @@ -352,7 +564,7 @@ bool DIECursor::readNext(DWARF_InfoData& id, bool stopAtNull) return true; } -unsigned char* DIECursor::getDWARFAbbrev(unsigned off, unsigned findcode) +byte* DIECursor::getDWARFAbbrev(unsigned off, unsigned findcode) { if (!img->debug_abbrev) return 0; @@ -364,8 +576,8 @@ unsigned char* DIECursor::getDWARFAbbrev(unsigned off, unsigned findcode) return it->second; } - unsigned char* p = (unsigned char*)img->debug_abbrev + off; - unsigned char* end = (unsigned char*)img->debug_abbrev + img->debug_abbrev_length; + byte* p = (byte*)img->debug_abbrev + off; + byte* end = (byte*)img->debug_abbrev + img->debug_abbrev_length; while (p < end) { int code = LEB128(p); diff --git a/src/readDwarf.h b/src/readDwarf.h index c0587b4..8c81750 100644 --- a/src/readDwarf.h +++ b/src/readDwarf.h @@ -5,7 +5,9 @@ #include #include "mspdb.h" -inline unsigned int LEB128(unsigned char* &p) +typedef unsigned char byte; + +inline unsigned int LEB128(byte* &p) { unsigned int x = 0; int shift = 0; @@ -20,7 +22,7 @@ inline unsigned int LEB128(unsigned char* &p) return x; } -inline int SLEB128(unsigned char* &p) +inline int SLEB128(byte* &p) { unsigned int x = 0; int shift = 0; @@ -37,14 +39,14 @@ inline int SLEB128(unsigned char* &p) return x; } -inline unsigned int RD2(unsigned char* p) +inline unsigned int RD2(byte* &p) { unsigned int x = *p++; x |= *p++ << 8; return x; } -inline unsigned int RD4(unsigned char* p) +inline unsigned int RD4(byte* &p) { unsigned int x = *p++; x |= *p++ << 8; @@ -53,7 +55,7 @@ inline unsigned int RD4(unsigned char* p) return x; } -inline unsigned long long RD8(unsigned char* p) +inline unsigned long long RD8(byte* &p) { unsigned long long x = *p++; for (int shift = 8; shift < 64; shift += 8) @@ -61,7 +63,7 @@ inline unsigned long long RD8(unsigned char* p) return x; } -inline unsigned long long RDsize(unsigned char* p, int size) +inline unsigned long long RDsize(byte* &p, int size) { if (size > 8) size = 8; @@ -71,6 +73,34 @@ inline unsigned long long RDsize(unsigned char* p, int size) return x; } +enum AttrClass +{ + Invalid, + Addr, + Block, + Const, + String, + Flag, + Ref, + ExprLoc, + SecOffset +}; + +struct DWARF_Attribute +{ + AttrClass type; + union + { + unsigned long addr; + struct { byte* ptr; unsigned len; } block; + unsigned long cons; + const char* string; + bool flag; + byte* ref; + struct { byte* ptr; unsigned len; } expr; + unsigned long sec_offset; + }; +}; /////////////////////////////////////////////////////////////////////////////// @@ -81,7 +111,7 @@ struct DWARF_CompilationUnit unsigned int unit_length; // 12 byte in DWARF-64 unsigned short version; unsigned int debug_abbrev_offset; // 8 byte in DWARF-64 - unsigned char address_size; + byte address_size; bool isDWARF64() const { return unit_length == ~0; } int refSize() const { return unit_length == ~0 ? 8 : 4; } @@ -94,7 +124,7 @@ struct DWARF_FileName unsigned long lastModification; unsigned long fileLength; - void read(unsigned char* &p) + void read(byte* &p) { file_name = (const char*)p; p += strlen((const char*)p) + 1; @@ -106,8 +136,9 @@ struct DWARF_FileName struct DWARF_InfoData { - int entryOff; + byte* entryPtr; int code; + byte* abbrev; int tag; int hasChild; @@ -115,31 +146,27 @@ struct DWARF_InfoData const char* linkage_name; const char* dir; unsigned long byte_size; - unsigned long sibling; + byte* sibling; unsigned long encoding; unsigned long pclo; unsigned long pchi; unsigned long ranges; - unsigned long type; - unsigned long containing_type; - unsigned long specification; + byte* type; + byte* containing_type; + byte* specification; unsigned long inlined; - unsigned long external; - unsigned char*location_ptr; - unsigned long location_len; - unsigned char*member_location_ptr; - unsigned long member_location_len; - unsigned long member_location_data; - unsigned long locationlist; // offset into debug_loc - long frame_base; + bool external; + DWARF_Attribute location; + DWARF_Attribute member_location; + DWARF_Attribute frame_base; long upper_bound; long lower_bound; - unsigned char* abbrev; void clear() { - entryOff = 0; + entryPtr = 0; code = 0; + abbrev = 0; tag = 0; hasChild = 0; @@ -151,22 +178,16 @@ struct DWARF_InfoData encoding = 0; pclo = 0; pchi = 0; - ranges = 0; type = 0; containing_type = 0; specification = 0; inlined = 0; external = 0; - member_location_ptr = 0; - member_location_len = 0; - member_location_data = 0; - location_ptr = 0; - location_len = 0; - locationlist = 0; - frame_base = -1; + member_location.type = Invalid; + location.type = Invalid; + frame_base.type = Invalid; upper_bound = 0; lower_bound = 0; - abbrev = 0; } }; @@ -177,12 +198,12 @@ struct DWARF_LineNumberProgramHeader unsigned int unit_length; // 12 byte in DWARF-64 unsigned short version; unsigned int header_length; // 8 byte in DWARF-64 - unsigned char minimum_instruction_length; - //unsigned char maximum_operations_per_instruction; (// not in DWARF 2 - unsigned char default_is_stmt; + byte minimum_instruction_length; + //byte maximum_operations_per_instruction; (// not in DWARF 2 + byte default_is_stmt; signed char line_base; - unsigned char line_range; - unsigned char opcode_base; + byte line_range; + byte opcode_base; //LEB128 standard_opcode_lengths[opcode_base]; // string include_directories[] // zero byte terminated // DWARF_FileNames file_names[] // zero byte terminated @@ -261,16 +282,14 @@ struct DWARF_LineState /////////////////////////////////////////////////////////////////////////////// +long decodeLocation(byte* loc, long len, bool push0, int &id, int& size); -long decodeLocation(unsigned char* loc, long len, bool push0, int &id, int& size); - -inline long decodeLocation(unsigned char*loc, long len, bool push0, int &id) +inline long decodeLocation(byte*loc, long len, bool push0, int &id) { int size; return decodeLocation(loc, len, push0, id, size); } - class PEImage; // Debug Information Entry Cursor @@ -278,19 +297,19 @@ class DIECursor { public: DWARF_CompilationUnit* cu; - unsigned char* ptr; + byte* ptr; int level; bool hasChild; // indicates whether the last read DIE has children - unsigned int sibling; + byte* sibling; - unsigned char* getDWARFAbbrev(unsigned off, unsigned findcode); + byte* getDWARFAbbrev(unsigned off, unsigned findcode); public: static void setContext(PEImage* img_); - // Create a new DIECursor from compilation unit with offset relative to the CU. - DIECursor(DWARF_CompilationUnit* cu_, unsigned long offset); + // Create a new DIECursor + DIECursor(DWARF_CompilationUnit* cu_, byte* ptr); // Reads next sibling DIE. If the last read DIE had any children, they will be skipped over. // Returns 'false' upon reaching the last sibling on the current level. -- cgit v0.12