Handle partial-reset DW_CFA_def_cfa_* operations after DW_CFA_def_cfa_expression.
authorRoland McGrath <roland@redhat.com>
Fri, 23 Apr 2010 04:35:56 +0000 (21:35 -0700)
committerRoland McGrath <roland@redhat.com>
Fri, 23 Apr 2010 04:35:56 +0000 (21:35 -0700)
libdw/ChangeLog
libdw/cfi.c

index aecad8b..5fa7515 100644 (file)
@@ -1,5 +1,9 @@
 2010-04-22  Roland McGrath  <roland@redhat.com>
 
+       * 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.
index 5936659..125a1d6 100644 (file)
@@ -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: