1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-25 08:37:38 +01:00

dwarf/Gparser: fix crash during unwinding (#44)

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.
This commit is contained in:
Konstantin Baladurin 2017-10-17 21:27:53 +03:00 committed by Dave Watson
parent 5f354cb7b9
commit ac02808556

View file

@ -776,40 +776,45 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
cfa = DWARF_GET_LOC (cfa_loc); 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) for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
{ {
switch ((dwarf_where_t) rs->reg[i].where) switch ((dwarf_where_t) rs->reg[i].where)
{ {
case DWARF_WHERE_UNDEF: case DWARF_WHERE_UNDEF:
c->loc[i] = DWARF_NULL_LOC; new_loc[i] = DWARF_NULL_LOC;
break; break;
case DWARF_WHERE_SAME: case DWARF_WHERE_SAME:
break; break;
case DWARF_WHERE_CFAREL: case DWARF_WHERE_CFAREL:
c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val); new_loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
break; break;
case DWARF_WHERE_REG: case DWARF_WHERE_REG:
c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val)); new_loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
break; break;
case DWARF_WHERE_EXPR: case DWARF_WHERE_EXPR:
addr = rs->reg[i].val; addr = rs->reg[i].val;
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; return ret;
break; break;
case DWARF_WHERE_VAL_EXPR: case DWARF_WHERE_VAL_EXPR:
addr = rs->reg[i].val; addr = rs->reg[i].val;
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; 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; break;
} }
} }
memcpy(c->loc, new_loc, sizeof(new_loc));
c->cfa = cfa; c->cfa = cfa;
/* DWARF spec says undefined return address location means end of stack. */ /* DWARF spec says undefined return address location means end of stack. */
if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column])) if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column]))