summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/dwarf2pdb.cpp80
-rw-r--r--src/readDwarf.cpp381
-rw-r--r--src/readDwarf.h24
3 files changed, 255 insertions, 230 deletions
diff --git a/src/dwarf2pdb.cpp b/src/dwarf2pdb.cpp
index 020c75b..28365ee 100644
--- a/src/dwarf2pdb.cpp
+++ b/src/dwarf2pdb.cpp
@@ -97,8 +97,6 @@ void CV2PDB::appendStackVar(const char* name, int type, Location& loc)
checkUdtSymbolAlloc(100 + kMaxNameLen);
codeview_symbol*cvs = (codeview_symbol*) (udtSymbols + cbUdtSymbols);
- cvs->stack_v2.offset = loc.offset;
- cvs->stack_v2.symtype = type;
CV_X86_REG baseReg = dwarf_to_x86_reg(loc.reg);
if (baseReg == CV_REG_NONE)
@@ -107,6 +105,8 @@ void CV2PDB::appendStackVar(const char* name, int type, Location& loc)
if (baseReg == CV_REG_EBP)
{
cvs->stack_v2.id = v3 ? S_BPREL_V3 : S_BPREL_V2;
+ cvs->stack_v2.offset = loc.off;
+ cvs->stack_v2.symtype = type;
len = cstrcpy_v(v3, (BYTE*)&cvs->stack_v2.p_name, name);
len += (BYTE*)&cvs->stack_v2.p_name - (BYTE*)cvs;
}
@@ -114,6 +114,8 @@ void CV2PDB::appendStackVar(const char* name, int type, Location& loc)
{
cvs->regrel_v3.id = S_REGREL_V3;
cvs->regrel_v3.reg = baseReg;
+ cvs->regrel_v3.offset = loc.off;
+ cvs->regrel_v3.symtype = type;
len = cstrcpy_v(true, (BYTE*)cvs->regrel_v3.name, name);
len += (BYTE*)&cvs->regrel_v3.name - (BYTE*)cvs;
}
@@ -239,14 +241,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
addStackVar("local_var", 0x1001, 8);
#endif
- Location frameBase;
- Location* pframeBase = NULL;
- if(img.debug_loc && procid.frame_base.type == ExprLoc)
- {
- if (decodeLocation(procid.frame_base.expr.ptr, procid.frame_base.expr.len, frameBase))
- pframeBase = &frameBase;
- }
-
+ Location frameBase = decodeLocation(procid.frame_base);
if (cu)
{
@@ -262,9 +257,9 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
{
if (id.name && id.location.type == ExprLoc)
{
- Location param;
- if (decodeLocation(id.location.expr.ptr, id.location.expr.len, param, pframeBase))
- appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), param);
+ Location loc = decodeLocation(id.location, &frameBase);
+ if (loc.is_regrel())
+ appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), loc);
}
}
prev = cursor;
@@ -281,16 +276,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
while (cursor.readSibling(id))
{
- if (id.tag == DW_TAG_variable)
- {
- if (id.name && id.location.type == ExprLoc)
- {
- Location var;
- if (decodeLocation(id.location.expr.ptr, id.location.expr.len, var, pframeBase))
- appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), var);
- }
- }
- else if (id.tag == DW_TAG_lexical_block)
+ if (id.tag == DW_TAG_lexical_block)
{
if (id.hasChild && id.pchi != id.pclo)
{
@@ -299,6 +285,15 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
cursor = cursor.getSubtreeCursor();
}
}
+ else if (id.tag == DW_TAG_variable)
+ {
+ if (id.name && id.location.type == ExprLoc)
+ {
+ Location loc = decodeLocation(id.location, &frameBase);
+ if (loc.is_regrel())
+ appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), loc);
+ }
+ }
}
appendEnd();
}
@@ -348,22 +343,14 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c
int cvid = -1;
if (id.tag == DW_TAG_member && id.name)
{
- printf(" Adding field %s\n", id.name);
+ //printf(" Adding field %s\n", id.name);
int off = 0;
- if(!isunion)
+ if (!isunion)
{
- if (id.member_location.type == ExprLoc)
- {
- Location loc;
- if (decodeLocation(id.member_location.expr.ptr, id.member_location.expr.len, loc) && loc.reg == NoReg)
- {
- off = loc.offset;
- cvid = S_CONSTANT_V2;
- }
- }
- else if (id.member_location.type == Const)
+ Location loc = decodeLocation(id.member_location);
+ if (loc.is_abs())
{
- off = id.member_location.cons;
+ off = loc.off;
cvid = S_CONSTANT_V2;
}
}
@@ -378,12 +365,12 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c
}
else if(id.tag == DW_TAG_inheritance)
{
- Location loc;
int off;
- if (decodeLocation(id.member_location.expr.ptr, id.member_location.expr.len, loc) && loc.reg == NoReg)
+ Location loc = decodeLocation(id.member_location);
+ if (loc.is_abs())
{
cvid = S_CONSTANT_V2;
- off = loc.offset;
+ off = loc.off;
}
if(cvid == S_CONSTANT_V2)
{
@@ -804,16 +791,13 @@ bool CV2PDB::createTypes()
}
else
{
- Location loc;
- if (id.location.type == ExprLoc)
+ Location loc = decodeLocation(id.location);
+ if (loc.is_abs())
{
- if (decodeLocation(id.location.expr.ptr, id.location.expr.len, loc) && loc.reg == NoReg)
- {
- segOff = loc.offset;
- seg = img.findSection(segOff);
- if (seg >= 0)
- segOff -= img.getImageBase() + img.getSection(seg).VirtualAddress;
- }
+ segOff = loc.off;
+ seg = img.findSection(segOff);
+ if (seg >= 0)
+ segOff -= img.getImageBase() + img.getSection(seg).VirtualAddress;
}
}
if (seg >= 0)
diff --git a/src/readDwarf.cpp b/src/readDwarf.cpp
index 5827ea0..5e6faeb 100644
--- a/src/readDwarf.cpp
+++ b/src/readDwarf.cpp
@@ -11,21 +11,48 @@ extern "C" {
#include "mscvpdb.h"
}
-Location makeLoc(int r, int o)
+static Location mkInReg(unsigned reg)
{
- Location e = { r, o };
- return e;
+ Location l;
+ l.type = Location::InReg;
+ l.reg = reg;
+ return l;
}
-bool decodeLocation(byte* loc, long len, Location& result, Location* frameBase)
+static Location mkAbs(int off)
{
- byte* p = loc;
+ Location l;
+ l.type = Location::Abs;
+ l.off = off;
+ return l;
+}
+
+static Location mkRegRel(int reg, int off)
+{
+ Location l;
+ l.type = Location::RegRel;
+ l.reg = reg;
+ l.off = off;
+ return l;
+}
+
+Location decodeLocation(const DWARF_Attribute& attr, const Location* frameBase)
+{
+ static Location invalid = { Location::Invalid };
+
+ if (attr.type == Const)
+ return mkAbs(attr.cons);
+
+ if (attr.type != ExprLoc)
+ return invalid;
+
+ byte* p = attr.expr.ptr;
Location stack[256];
int stackDepth = 0;
for (;;)
{
- if (p >= loc + len)
+ if (p >= attr.expr.ptr + attr.expr.len)
break;
int op = *p++;
@@ -34,38 +61,42 @@ bool decodeLocation(byte* loc, long len, Location& result, Location* frameBase)
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_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++] = mkInReg(op - DW_OP_reg0);
+ break;
case DW_OP_regx:
- stack[stackDepth++] = makeLoc(LEB128(p), 0);
+ stack[stackDepth++] = mkInReg(LEB128(p));
+ break;
+
+ case DW_OP_const1u: stack[stackDepth++] = mkAbs(*p); break;
+ case DW_OP_const2u: stack[stackDepth++] = mkAbs(RD2(p)); break;
+ case DW_OP_const4u: stack[stackDepth++] = mkAbs(RD4(p)); break;
+ case DW_OP_const1s: stack[stackDepth++] = mkAbs((char)*p); break;
+ case DW_OP_const2s: stack[stackDepth++] = mkAbs((short)RD2(p)); break;
+ case DW_OP_const4s: stack[stackDepth++] = mkAbs((int)RD4(p)); break;
+ case DW_OP_constu: stack[stackDepth++] = mkAbs(LEB128(p)); break;
+ case DW_OP_consts: stack[stackDepth++] = mkAbs(SLEB128(p)); break;
+
+ case DW_OP_plus_uconst:
+ if (stack[stackDepth - 1].is_inreg())
+ return invalid;
+ stack[stackDepth - 1].off += 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++] = mkAbs(op - DW_OP_lit0);
break;
case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
@@ -76,169 +107,164 @@ bool decodeLocation(byte* loc, long len, Location& result, Location* frameBase)
case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:
- stack[stackDepth++] = makeLoc(op - DW_OP_breg0, SLEB128(p));
+ stack[stackDepth++] = mkRegRel(op - DW_OP_breg0, SLEB128(p));
break;
- case DW_OP_bregx:
+ case DW_OP_bregx:
{
unsigned reg = LEB128(p);
- stack[stackDepth++] = makeLoc(reg, SLEB128(p));
+ stack[stackDepth++] = mkRegRel(reg, 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.is_abs())
+ return invalid;
+ switch (op)
+ {
+ case DW_OP_abs: op1 = mkAbs(abs(op1.off)); break;
+ case DW_OP_neg: op1 = mkAbs(-op1.off); break;
+ case DW_OP_not: op1 = mkAbs(~op1.off); break;
+ }
+ } break;
+ case DW_OP_plus: // op2 + op1
+ {
+ Location& op1 = stack[stackDepth - 1];
+ Location& op2 = stack[stackDepth - 2];
+ // Can add only two offsets or a regrel and an offset.
+ if (op2.is_regrel() && op1.is_abs())
+ op2 = mkRegRel(op2.reg, op2.off + op1.off);
+ else if (op2.is_abs() && op1.is_regrel())
+ op2 = mkRegRel(op1.reg, op2.off + op1.off);
+ else if (op2.is_abs() && op1.is_abs())
+ op2 = mkAbs(op2.off + op1.off);
+ else
+ return invalid;
+ --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_minus: // op2 - op1
{
- 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;
+ Location& op1 = stack[stackDepth - 1];
+ Location& op2 = stack[stackDepth - 2];
+ if (op2.is_regrel() && op1.is_regrel() && op2.reg == op1.reg)
+ op2 = mkAbs(0); // X - X == 0
+ else if (op2.is_regrel() && op1.is_abs())
+ op2 = mkRegRel(op2.reg, op2.off - op1.off);
+ else if (op2.is_abs() && op1.is_abs())
+ op2 = mkAbs(op2.off - op1.off);
+ else
+ return invalid;
+ --stackDepth;
+ } 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_mul:
{
- 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;
+ Location& op1 = stack[stackDepth - 1];
+ Location& op2 = stack[stackDepth - 2];
+ if ((op1.is_abs() && op1.off == 0) || (op2.is_abs() && op2.off == 0))
+ op2 = mkAbs(0); // X * 0 == 0
+ else if (op1.is_abs() && op2.is_abs())
+ op2 = mkAbs(op1.off * op2.off);
+ else
+ return invalid;
+ --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_and:
{
- 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;
+ Location& op1 = stack[stackDepth - 1];
+ Location& op2 = stack[stackDepth - 2];
+ if ((op1.is_abs() && op1.off == 0) || (op2.is_abs() && op2.off == 0))
+ op2 = mkAbs(0); // X & 0 == 0
+ else if (op1.is_abs() && op2.is_abs())
+ op2 = mkAbs(op1.off & op2.off);
+ else
+ return invalid;
+ --stackDepth;
+ } break;
- case DW_OP_fbreg:
- if (!frameBase)
- return false;
- stack[stackDepth++] = makeLoc(frameBase->reg, frameBase->offset + SLEB128(p));
- 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:
+ case DW_OP_xor:
+ 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.is_abs() || !op2.is_abs()) // can't combine unless both are constants
+ return invalid;
+ switch (op)
+ {
+ case DW_OP_div: op2.off = op2.off / op1.off; break;
+ case DW_OP_mod: op2.off = op2.off % op1.off; break;
+ case DW_OP_shl: op2.off = op2.off << op1.off; break;
+ case DW_OP_shr: op2.off = op2.off >> op1.off; break;
+ case DW_OP_shra: op2.off = op2.off >> op1.off; break;
+ case DW_OP_or: op2.off = op2.off | op1.off; break;
+ case DW_OP_xor: op2.off = op2.off ^ op1.off; break;
+ case DW_OP_eq: op2.off = op2.off == op1.off; break;
+ case DW_OP_ge: op2.off = op2.off >= op1.off; break;
+ case DW_OP_gt: op2.off = op2.off > op1.off; break;
+ case DW_OP_le: op2.off = op2.off <= op1.off; break;
+ case DW_OP_lt: op2.off = op2.off < op1.off; break;
+ case DW_OP_ne: op2.off = op2.off != op1.off; break;
+ }
+ --stackDepth;
+ } 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_fbreg:
+ {
+ if (!frameBase)
+ return invalid;
+
+ Location loc;
+ if (frameBase->is_inreg()) // ok in frame base specification, per DWARF4 spec #3.3.5
+ loc = mkRegRel(frameBase->reg, SLEB128(p));
+ else if (frameBase->is_regrel())
+ loc = mkRegRel(frameBase->reg, frameBase->off + SLEB128(p));
+ else
+ return invalid;
+ stack[stackDepth++] = loc;
+ } break;
- case DW_OP_addr:
- stack[stackDepth++] = makeLoc(NoReg, RD4(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_skip:
- {
- unsigned off = RD2(p);
- p = p + off;
- } break;
+ case DW_OP_addr:
+ stack[stackDepth++] = mkAbs(RD4(p)); // TODO: 64-bit
+ break;
- case DW_OP_bra:
- {
- Location& op1 = stack[stackDepth - 1];
- if (op1.reg != NoReg)
- return false;
- if (op1.offset != 0)
+ case DW_OP_skip:
{
unsigned off = RD2(p);
p = p + off;
- }
- --stackDepth;
- } break;
+ } break;
+
+ case DW_OP_bra:
+ {
+ Location& op1 = stack[stackDepth - 1];
+ if (!op1.is_abs())
+ return invalid;
+ if (op1.off != 0)
+ {
+ unsigned off = RD2(p);
+ p = p + off;
+ }
+ --stackDepth;
+ } break;
case DW_OP_nop:
break;
+ case DW_OP_deref:
+ case DW_OP_deref_size:
case DW_OP_push_object_address:
case DW_OP_call2:
case DW_OP_call4:
@@ -249,13 +275,12 @@ bool decodeLocation(byte* loc, long len, Location& result, Location* frameBase)
case DW_OP_implicit_value:
case DW_OP_stack_value:
default:
- return false;
+ return invalid;
}
}
assert(stackDepth > 0);
- result = stack[0];
- return true;
+ return stack[0];
}
// declare hasher for pair<T1,T2>
diff --git a/src/readDwarf.h b/src/readDwarf.h
index 4191708..35daa8e 100644
--- a/src/readDwarf.h
+++ b/src/readDwarf.h
@@ -305,15 +305,31 @@ struct DWARF_LineState
///////////////////////////////////////////////////////////////////////////////
-// The actual value is {reg} + offset
+
struct Location
{
+ enum Type
+ {
+ Invalid, // Failed to evaluate the location expression
+ InReg, // In register (reg)
+ Abs, // Absolute address (off)
+ RegRel // Register-relative address ($reg + off)
+ };
+
+ Type type;
int reg;
- int offset;
+ int off;
+
+ bool is_invalid() const { return type == Invalid; }
+ bool is_inreg() const { return type == InReg; }
+ bool is_abs() const { return type == Abs; }
+ bool is_regrel() const { return type == RegRel; }
};
-const int NoReg = -1;
-bool decodeLocation(byte* loc, long len, Location& result, Location* frameBase = 0);
+// Attemots to partially evaluate DWARF location expressions.
+// The only supported expressions are those, whose result may be represented
+// as either an absolute value, a register, or a register-relative address.
+Location decodeLocation(const DWARF_Attribute& attr, const Location* frameBase = 0);
class PEImage;