summaryrefslogtreecommitdiffstats
path: root/src/readDwarf.cpp
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/readDwarf.cpp
parentb5bb7f4c024cdedab46a4967433cdbc1e2af31a9 (diff)
downloadcv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.zip
cv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.tar.gz
cv2pdb-d8441072beed68e3eeb9022fa93829bed7dad367.tar.bz2
Revamped DIE reading.
My decodeLocation.
Diffstat (limited to 'src/readDwarf.cpp')
-rw-r--r--src/readDwarf.cpp380
1 files changed, 296 insertions, 84 deletions
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);