summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2010-04-22 21:35:56 -0700
committerRoland McGrath <[email protected]>2010-04-22 21:35:56 -0700
commit3b2486c20c147b420b37a2f610912547b482ee1d (patch)
tree615a7397fb7016364307def7247d2b93c0f58dff
parent3f9d955d56d62bcca1e6d97eb17649b3b0f38acc (diff)
Handle partial-reset DW_CFA_def_cfa_* operations after DW_CFA_def_cfa_expression.
-rw-r--r--libdw/ChangeLog4
-rw-r--r--libdw/cfi.c38
2 files changed, 30 insertions, 12 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index aecad8b6..5fa75151 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,9 @@
2010-04-22 Roland McGrath <[email protected]>
+ * cfi.c (execute_cfi): Track last-set CFA regno and offset even
+ through DW_CFA_def_cfa_expression so DW_CFA_def_cfa_* can reset
+ to an offset rule and respecify only one or the other.
+
* cfi.c (execute_cfi): Never return without cleanup.
Free FS on failure.
(cie_cache_initial_state): Adjust caller to expect that free.
diff --git a/libdw/cfi.c b/libdw/cfi.c
index 5936659a..125a1d6d 100644
--- a/libdw/cfi.c
+++ b/libdw/cfi.c
@@ -124,6 +124,12 @@ execute_cfi (Dwarf_CFI *cache,
fs->regs[regno].value = (r_value); \
} while (0)
+ /* These are the last-set values from DW_CFA_def_cfa* operations.
+ They are hidden by a DW_CFA_def_cfa_expression operation but can
+ pop out again if DW_CFA_def_cfa_* is used afterwards. */
+ Dwarf_Word last_cfa_regno = -1;
+ Dwarf_Word last_cfa_offset = -1;
+
while (program < end)
{
uint8_t opcode = *program++;
@@ -164,39 +170,47 @@ execute_cfi (Dwarf_CFI *cache,
switch block for the row-copying (LOC-moving) cases above. */
case DW_CFA_def_cfa:
- get_uleb128 (operand, program);
- get_uleb128 (offset, program);
+ get_uleb128 (last_cfa_regno, program);
+ get_uleb128 (last_cfa_offset, program);
def_cfa:
+ cfi_assert (last_cfa_regno != (Dwarf_Word) -1);
+ cfi_assert (last_cfa_offset != (Dwarf_Word) -1);
fs->cfa_rule = cfa_offset;
- fs->cfa_val_reg = operand;
- fs->cfa_val_offset = offset;
+ fs->cfa_val_reg = last_cfa_regno;
+ fs->cfa_val_offset = last_cfa_offset;
/* Prime the rest of the Dwarf_Op so dwarf_frame_cfa can use it. */
fs->cfa_data.offset.atom = DW_OP_bregx;
fs->cfa_data.offset.offset = 0;
continue;
case DW_CFA_def_cfa_register:
- get_uleb128 (regno, program);
- cfi_assert (fs->cfa_rule == cfa_offset);
- fs->cfa_val_reg = regno;
+ get_uleb128 (last_cfa_regno, program);
+ if (fs->cfa_rule == cfa_expr)
+ goto def_cfa;
+ else
+ cfi_assert (fs->cfa_rule == cfa_offset);
+ fs->cfa_val_reg = last_cfa_regno;
continue;
case DW_CFA_def_cfa_sf:
- get_uleb128 (operand, program);
+ get_uleb128 (last_cfa_regno, program);
get_sleb128 (sf_offset, program);
offset = sf_offset * cie->data_alignment_factor;
goto def_cfa;
case DW_CFA_def_cfa_offset:
- get_uleb128 (offset, program);
+ get_uleb128 (last_cfa_offset, program);
def_cfa_offset:
- cfi_assert (fs->cfa_rule == cfa_offset);
- fs->cfa_val_offset = offset;
+ if (fs->cfa_rule == cfa_expr)
+ goto def_cfa;
+ else
+ cfi_assert (fs->cfa_rule == cfa_offset);
+ fs->cfa_val_offset = last_cfa_offset;
continue;
case DW_CFA_def_cfa_offset_sf:
get_sleb128 (sf_offset, program);
- offset = sf_offset * cie->data_alignment_factor;
+ last_cfa_offset = sf_offset * cie->data_alignment_factor;
goto def_cfa_offset;
case DW_CFA_def_cfa_expression: