diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/dwarf/Gexpr.c | 14 | ||||
-rw-r--r-- | src/dwarf/Gparser.c | 17 |
2 files changed, 21 insertions, 10 deletions
diff --git a/src/dwarf/Gexpr.c b/src/dwarf/Gexpr.c index 709c0c8f..2af45433 100644 --- a/src/dwarf/Gexpr.c +++ b/src/dwarf/Gexpr.c @@ -237,8 +237,8 @@ dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr, } HIDDEN int -dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len, - unw_word_t *valp, int *is_register) +dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_word_t *addr, + unw_word_t len, unw_word_t *valp, int *is_register) { unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr; uint8_t opcode, operands_signature, u8; @@ -287,10 +287,14 @@ do { \ end_addr = *addr + len; *is_register = 0; - Debug (14, "len=%lu, pushing cfa=0x%lx\n", - (unsigned long) len, (unsigned long) c->cfa); + Debug (14, "len=%lu, pushing initial value=0x%lx\n", + (unsigned long) len, (unsigned long) stack_val); - push (c->cfa); /* push current CFA as required by DWARF spec */ + /* The DWARF standard requires the current CFA to be pushed onto the stack */ + /* before evaluating DW_CFA_expression and DW_CFA_val_expression programs. */ + /* DW_CFA_def_cfa_expressions do not take an initial value, but we push on */ + /* a dummy value to keep this logic consistent. */ + push (stack_val); while (*addr < end_addr) { diff --git a/src/dwarf/Gparser.c b/src/dwarf/Gparser.c index 1ce862c2..fe7c5817 100644 --- a/src/dwarf/Gparser.c +++ b/src/dwarf/Gparser.c @@ -734,7 +734,7 @@ create_state_record_for (struct dwarf_cursor *c, dwarf_state_record_t *sr, } static inline int -eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as, +eval_location_expr (struct dwarf_cursor *c, unw_word_t stack_val, unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr, dwarf_loc_t *locp, void *arg) { @@ -746,7 +746,7 @@ eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as, return ret; /* evaluate the expression: */ - if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0) + if ((ret = dwarf_eval_expr (c, stack_val, &addr, len, &val, &is_register)) < 0) return ret; if (is_register) @@ -804,7 +804,10 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) assert (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_EXPR); addr = rs->reg.val[DWARF_CFA_REG_COLUMN]; - if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0) + /* The dwarf standard doesn't specify an initial value to be pushed on */ + /* the stack before DW_CFA_def_cfa_expression evaluation. We push on a */ + /* dummy value (0) to keep the eval_location_expr function consistent. */ + if ((ret = eval_location_expr (c, 0, as, a, addr, &cfa_loc, arg)) < 0) return ret; /* the returned location better be a memory location... */ if (DWARF_IS_REG_LOC (cfa_loc)) @@ -844,13 +847,17 @@ apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs) case DWARF_WHERE_EXPR: addr = rs->reg.val[i]; - if ((ret = eval_location_expr (c, as, a, addr, new_loc + i, arg)) < 0) + /* The dwarf standard requires the current CFA to be pushed on the */ + /* stack before DW_CFA_expression evaluation. */ + if ((ret = eval_location_expr (c, cfa, 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, new_loc + i, arg)) < 0) + /* The dwarf standard requires the current CFA to be pushed on the */ + /* stack before DW_CFA_val_expression evaluation. */ + if ((ret = eval_location_expr (c, cfa, as, a, addr, new_loc + i, arg)) < 0) return ret; new_loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (new_loc[i])); break; |