summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Baladurin <k.baladurin@partner.samsung.com>2017-10-17 21:27:43 +0300
committerDave Watson <davejwatson@fb.com>2017-10-17 11:27:43 -0700
commit36b46f1921008d2ed64932ab768c1034f8dc6211 (patch)
tree03fa95cdf822534849bd08c8dcbb825c1172c261
parent38fe3bbb97535129c3b71f859f8f387237699868 (diff)
downloadlibunwind-36b46f1921008d2ed64932ab768c1034f8dc6211.tar.gz
dwarf/Gparser: fix crash during unwinding (#46)
We should update locations of the registers after all of them will be restored. Otherwise some locations will be incorrect. For example if function stores ebp, edi, esi and ebx registers on stack in its prologue, compiler can generate following unwind info: DW_CFA_expression: r5 (ebp) (DW_OP_breg5 (ebp): 0) DW_CFA_expression: r7 (edi) (DW_OP_breg5 (ebp): -4) DW_CFA_expression: r6 (esi) (DW_OP_breg5 (ebp): -8) DW_CFA_expression: r3 (ebx) (DW_OP_breg5 (ebp): -12) In this case locations of the ebx and ebp will be calculated using current ebp but locations of the esi and edi will be calculated using previous (restored) one. Due to it their locations will be incorrect and it could lead to crash if we will try to get esi or edi value. This patch fixes this problem.
-rw-r--r--src/dwarf/Gparser.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c
index 9d405e76..70e690f5 100644
--- a/src/dwarf/Gparser.c
+++ b/src/dwarf/Gparser.c
@@ -826,40 +826,45 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
cfa = DWARF_GET_LOC (cfa_loc);
}
+ dwarf_loc_t new_loc[DWARF_NUM_PRESERVED_REGS];
+ memcpy(new_loc, c->loc, sizeof(new_loc));
+
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
{
switch ((dwarf_where_t) rs->reg.where[i])
{
case DWARF_WHERE_UNDEF:
- c->loc[i] = DWARF_NULL_LOC;
+ new_loc[i] = DWARF_NULL_LOC;
break;
case DWARF_WHERE_SAME:
break;
case DWARF_WHERE_CFAREL:
- c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]);
+ new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg.val[i]);
break;
case DWARF_WHERE_REG:
- c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
+ new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg.val[i]));
break;
case DWARF_WHERE_EXPR:
addr = rs->reg.val[i];
- if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+ if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
return ret;
break;
case DWARF_WHERE_VAL_EXPR:
addr = rs->reg.val[i];
- if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
+ if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0)
return ret;
- c->loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (c->loc[i]));
+ new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i]));
break;
}
}
+ memcpy(c->loc, new_loc, sizeof(new_loc));
+
c->cfa = cfa;
/* DWARF spec says undefined return address location means end of stack. */
if (DWARF_IS_NULL_LOC (c->loc[rs->ret_addr_column]))