* handle DW_CFA_offset_extended_sf
* make --trace-cfi=yes work, to assist in debugging this


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3585 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_dwarf.c b/coregrind/vg_dwarf.c
index a47eaf9..859ff58 100644
--- a/coregrind/vg_dwarf.c
+++ b/coregrind/vg_dwarf.c
@@ -933,24 +933,25 @@
 
 enum dwarf_cfa_secondary_ops
   {
-    DW_CFA_nop              = 0x00,
-    DW_CFA_set_loc          = 0x01,
-    DW_CFA_advance_loc1     = 0x02,
-    DW_CFA_advance_loc2     = 0x03,
-    DW_CFA_advance_loc4     = 0x04,
-    DW_CFA_offset_extended  = 0x05,
-    DW_CFA_restore_extended = 0x06,
-    DW_CFA_undefined        = 0x07,
-    DW_CFA_same_value       = 0x08,
-    DW_CFA_register         = 0x09,
-    DW_CFA_remember_state   = 0x0a,
-    DW_CFA_restore_state    = 0x0b,
-    DW_CFA_def_cfa          = 0x0c,
-    DW_CFA_def_cfa_register = 0x0d,
-    DW_CFA_def_cfa_offset   = 0x0e,
-    DW_CFA_lo_user          = 0x1c,
-    DW_CFA_GNU_args_size    = 0x2e,
-    DW_CFA_hi_user          = 0x3f
+    DW_CFA_nop                = 0x00,
+    DW_CFA_set_loc            = 0x01,
+    DW_CFA_advance_loc1       = 0x02,
+    DW_CFA_advance_loc2       = 0x03,
+    DW_CFA_advance_loc4       = 0x04,
+    DW_CFA_offset_extended    = 0x05,
+    DW_CFA_restore_extended   = 0x06,
+    DW_CFA_undefined          = 0x07,
+    DW_CFA_same_value         = 0x08,
+    DW_CFA_register           = 0x09,
+    DW_CFA_remember_state     = 0x0a,
+    DW_CFA_restore_state      = 0x0b,
+    DW_CFA_def_cfa            = 0x0c,
+    DW_CFA_def_cfa_register   = 0x0d,
+    DW_CFA_def_cfa_offset     = 0x0e,
+    DW_CFA_offset_extended_sf = 0x11, /* DWARF3 only */
+    DW_CFA_lo_user            = 0x1c,
+    DW_CFA_GNU_args_size      = 0x2e,
+    DW_CFA_hi_user            = 0x3f
   };
 
 #define DW_EH_PE_absptr		0x00
@@ -1285,7 +1286,7 @@
          vg_assert(0);
    }
 
-   if ((encoding & 0x0f) == 0x00)
+   if ((encoding & 0x07) == 0x00)
       encoding |= default_address_encoding();
 
    switch (encoding & 0x0f) {
@@ -1308,7 +1309,7 @@
          *nbytes += sizeof(Long);
          return base + read_Long(data);
       default:
-         vg_assert(0);
+         vg_assert2(0, "read encoded address %d\n", encoding & 0x0f);
    }
 }
 
@@ -1382,27 +1383,38 @@
          ctx->cfa_offset = off;
          break;
 
-      case DW_CFA_def_cfa_register: {
+      case DW_CFA_offset_extended_sf:
+         reg = read_leb128( &instr[i], &nleb, 0 );
+         i += nleb;
+         off = read_leb128( &instr[i], &nleb, 1 );
+         i += nleb;
+         if (reg < 0 || reg >= N_CFI_REGS) 
+            return 0; /* fail */
+         ctx->reg[reg].tag = RR_CFAoff;
+         ctx->reg[reg].coff = off * ctx->data_a_f;
+         break;         
+
+      case DW_CFA_def_cfa_register:
          reg = read_leb128( &instr[i], &nleb, 0);
          i += nleb;
          if (reg < 0 || reg >= N_CFI_REGS) 
             return 0; /* fail */
          ctx->cfa_reg = reg;
          break;
-      }
-      case DW_CFA_def_cfa_offset: {
+
+      case DW_CFA_def_cfa_offset:
          off = read_leb128( &instr[i], &nleb, 0);
          i += nleb;
          ctx->cfa_offset = off;
          break;
-      }
-      case DW_CFA_GNU_args_size: {
+
+      case DW_CFA_GNU_args_size:
          /* No idea what is supposed to happen.  gdb-6.3 simply
             ignores these. */
          off = read_leb128( &instr[i], &nleb, 0 );
          i += nleb;
          break;
-      }
+
       default: 
          VG_(printf)("Unhandled CFI instruction 0:%d\n", (Int)lo6); 
          i = 0;
@@ -1569,10 +1581,6 @@
    Bool ok;
 
    UChar* current_cie = NULL;
-
-   if (0&& ehframe_sz != 240) return;
-   if (0) VG_(printf)("\n\n\neh_frame %p %d\n", ehframe, ehframe_sz);
-
    UChar* data = ehframe;
 
    UChar* cie_instrs = NULL;
@@ -1580,28 +1588,38 @@
    Bool saw_z_augmentation = False;
    UChar address_encoding = default_address_encoding();
 
+   if (VG_(clo_trace_cfi)) {
+      VG_(printf)("\n-----------------------------------------------\n");
+      VG_(printf)("CFI info: ehframe %p, ehframe_sz %d\n",
+		   ehframe, ehframe_sz );
+      VG_(printf)("CFI info: name %s\n",
+		  si->filename );
+   }
+
    /* Loop over CIEs/FDEs */
 
    while (True) {
 
-     /* Are we done? */
-     if (data == ehframe + ehframe_sz)
-       return;
+      /* Are we done? */
+      if (data == ehframe + ehframe_sz)
+         return;
 
-     /* Overshot the end?  Means something is wrong */
-     if  (data > ehframe + ehframe_sz) {
-       how = "overran the end of .eh_frame";
-       goto bad;
-     }
+      /* Overshot the end?  Means something is wrong */
+      if (data > ehframe + ehframe_sz) {
+         how = "overran the end of .eh_frame";
+         goto bad;
+      }
 
-     /* Ok, we must be looking at the start of a new CIE or FDE.
-        Figure out which it is. */
+      /* Ok, we must be looking at the start of a new CIE or FDE.
+         Figure out which it is. */
 
       UChar* ciefde_start = data;
-      if (0) VG_(printf)("\ncie/fde.start   = %p\n", ciefde_start);
+      if (VG_(clo_trace_cfi)) 
+         VG_(printf)("\ncie/fde.start   = %p\n", ciefde_start);
 
       UInt ciefde_len = read_UInt(data); data += sizeof(UInt);
-      if (0) VG_(printf)("cie/fde.length  = %d\n", ciefde_len);
+      if (VG_(clo_trace_cfi)) 
+         VG_(printf)("cie/fde.length  = %d\n", ciefde_len);
 
       /* Apparently, if the .length field is zero, we are at the end
 	 of the sequence.  ?? Neither the DWARF2 spec not the AMD64
@@ -1614,7 +1632,8 @@
       }
 
       UInt cie_pointer = read_UInt(data); data += sizeof(UInt);
-      if (0) VG_(printf)("cie.pointer     = %d\n", cie_pointer);
+      if (VG_(clo_trace_cfi)) 
+         VG_(printf)("cie.pointer     = %d\n", cie_pointer);
 
       /* If cie_pointer is zero, we've got a CIE; else it's an FDE. */
       if (cie_pointer == 0) {
@@ -1623,12 +1642,21 @@
          current_cie = ciefde_start + sizeof(UInt);
 
          /* --------- CIE --------- */
+	 if (VG_(clo_trace_cfi)) 
+            VG_(printf)("------ new CIE ------\n");
+
          UChar cie_version = read_UChar(data); data += sizeof(UChar);
-         if (0) VG_(printf)("cie.version     = %d\n", (Int)cie_version);
+         if (VG_(clo_trace_cfi))
+            VG_(printf)("cie.version     = %d\n", (Int)cie_version);
+         if (cie_version != 1) {
+            how = "unexpected CIE version (not 1)";
+            goto bad;
+         }
 
          UChar* cie_augmentation = data;
          data += 1 + VG_(strlen)(cie_augmentation);
-         if (0) VG_(printf)("cie.augment     = \"%s\"\n", cie_augmentation);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("cie.augment     = \"%s\"\n", cie_augmentation);
 
          if (cie_augmentation[0] == 'e' && cie_augmentation[1] == 'h') {
             data += sizeof(Addr);
@@ -1637,14 +1665,17 @@
 
          cie_codeaf = read_leb128( data, &nbytes, 0);
          data += nbytes;
-         if (0) VG_(printf)("cie.code_af     = %d\n", cie_codeaf);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("cie.code_af     = %d\n", cie_codeaf);
 
          cie_dataaf = read_leb128( data, &nbytes, 1);
          data += nbytes;
-         if (0) VG_(printf)("cie.data_af     = %d\n", cie_dataaf);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("cie.data_af     = %d\n", cie_dataaf);
 
          UChar cie_rareg = read_UChar(data); data += sizeof(UChar);
-         if (0) VG_(printf)("cie.ra_reg      = %d\n", (Int)cie_rareg);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("cie.ra_reg      = %d\n", (Int)cie_rareg);
 
          saw_z_augmentation = *cie_augmentation == 'z';
          if (saw_z_augmentation) {
@@ -1682,12 +1713,15 @@
 
         done_augmentation:
 
-         if (0) VG_(printf)("cie.encoding    = 0x%x\n", address_encoding);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("cie.encoding    = 0x%x\n", address_encoding);
 
          cie_instrs = data;
          cie_ilen   = ciefde_start + ciefde_len + sizeof(UInt) - data;
-         if (0) VG_(printf)("cie.instrs      = %p\n", cie_instrs);
-         if (0) VG_(printf)("cie.ilen        = %d\n", (Int)cie_ilen);
+         if (VG_(clo_trace_cfi)) {
+            VG_(printf)("cie.instrs      = %p\n", cie_instrs);
+            VG_(printf)("cie.ilen        = %d\n", (Int)cie_ilen);
+	 }
 
          if (cie_ilen < 0 || cie_ilen > ehframe_sz) {
             how = "implausible # cie initial insns";
@@ -1696,7 +1730,8 @@
 
 	 data += cie_ilen;
 
-         if (0) show_CF_instructions(cie_instrs, cie_ilen);
+         if (VG_(clo_trace_cfi)) 
+            show_CF_instructions(cie_instrs, cie_ilen);
 
       } else {
 
@@ -1713,15 +1748,19 @@
             goto bad;
          }
 
-         Addr fde_initloc = read_encoded_address(data, address_encoding,
-                                                 &nbytes, ehframe, ehframe_addr);
+         Addr fde_initloc 
+            = read_encoded_address(data, address_encoding,
+                                   &nbytes, ehframe, ehframe_addr);
          data += nbytes;
-         if (0) VG_(printf)("fde.initloc     = %p\n", (void*)fde_initloc);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("fde.initloc     = %p\n", (void*)fde_initloc);
 
-         UWord fde_arange = read_encoded_address(data, address_encoding & 0xf,
-                                                 &nbytes, ehframe, ehframe_addr);
+         UWord fde_arange 
+            = read_encoded_address(data, address_encoding & 0xf,
+                                   &nbytes, ehframe, ehframe_addr);
          data += nbytes;
-         if (0) VG_(printf)("fde.arangec     = %p\n", (void*)fde_arange);
+         if (VG_(clo_trace_cfi)) 
+            VG_(printf)("fde.arangec     = %p\n", (void*)fde_arange);
 
          if (saw_z_augmentation) {
             data += read_leb128( data, &nbytes, 0);
@@ -1730,16 +1769,19 @@
 
          UChar* fde_instrs = data;
          Int    fde_ilen   = ciefde_start + ciefde_len + sizeof(UInt) - data;
-         if (0) VG_(printf)("fde.instrs      = %p\n", fde_instrs);
-         if (0) VG_(printf)("fde.ilen        = %d\n", (Int)fde_ilen);
+         if (VG_(clo_trace_cfi)) VG_(printf)("fde.instrs      = %p\n", fde_instrs);
+         if (VG_(clo_trace_cfi)) VG_(printf)("fde.ilen        = %d\n", (Int)fde_ilen);
 
          if (fde_ilen < 0 || fde_ilen > ehframe_sz) {
-            how = "implausible # fde initial insns";
+            how = "implausible # fde insns";
             goto bad;
          }
 
 	 data += fde_ilen;
 
+         if (VG_(clo_trace_cfi)) 
+            show_CF_instructions(fde_instrs, fde_ilen);
+
 	 initUnwindContext(&ctx);
          ctx.code_a_f = cie_codeaf;
          ctx.data_a_f = cie_dataaf;