summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVadim Chugunov <vadimcn@gmail.com>2014-10-18 09:05:33 (GMT)
committerVadim Chugunov <vadimcn@gmail.com>2014-12-05 21:37:21 (GMT)
commitd8441072beed68e3eeb9022fa93829bed7dad367 (patch)
tree00cd3f762b7fcb421bb5c88b817fd779d9b267df /src
parentb5bb7f4c024cdedab46a4967433cdbc1e2af31a9 (diff)
downloadcv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.zip
cv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.tar.gz
cv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.tar.bz2
Revamped DIE reading.
My decodeLocation.
Diffstat (limited to 'src')
-rw-r--r--src/cv2pdb.h6
-rw-r--r--src/dwarf2pdb.cpp77
-rw-r--r--src/readDwarf.cpp380
-rw-r--r--src/readDwarf.h111
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<int, int> mapOffsetToType;
+ std::unordered_map<byte*, int> 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<int,int>::iterator it = mapOffsetToType.find(cuoff + off);
+ std::unordered_map<byte*, int>::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<int, int>(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<T1,T2>
namespace std
{
@@ -156,7 +382,7 @@ namespace std
};
}
-typedef std::unordered_map<std::pair<unsigned, unsigned>, unsigned char*> abbrevMap_t;
+typedef std::unordered_map<std::pair<unsigned, unsigned>, 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 <vector>
#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.