include/
authorRichard Henderson <rth@redhat.com>
Wed, 24 Sep 2008 23:21:04 +0000 (23:21 +0000)
committerRichard Henderson <rth@redhat.com>
Wed, 24 Sep 2008 23:21:04 +0000 (23:21 +0000)
* elf/dwarf2.h (DW_OP_GNU_encoded_addr): New.
binutils/
* dwarf.c (size_of_encoded_value, get_encoded_value): Move up.
(decode_location_expression): Add section parameter.  Handle
DW_OP_GNU_encoded_addr.
(read_and_display_attr_value): Update decode_location_expression call.
(display_debug_loc, display_debug_frames): Likewise.
gas/
        * dw2gencfi.c (DWARF2_ADDR_SIZE): Provide default.
        (struct cfi_insn_data): Add ea member.
        (CFI_val_encoded_addr, dot_cfi_val_encoded_addr): New.
        (output_cfi_insn): Handle CFI_val_encoded_addr.
        (select_cie_for_fde): Don't match CFI_val_encoded_addr.
        * doc/as.texinfo (.cfi_val_encoded_addr): Document.

binutils/ChangeLog
binutils/dwarf.c
gas/ChangeLog
gas/doc/as.texinfo
gas/dw2gencfi.c
include/ChangeLog
include/elf/dwarf2.h

index e909e7728fe639e4323967cf3538471b5c75f03b..ab1d8f3f0b5281e4abd9d6f34d2e4f5f336d8b7c 100644 (file)
@@ -1,3 +1,11 @@
+2008-09-24  Richard Henderson  <rth@redhat.com>
+
+       * dwarf.c (size_of_encoded_value, get_encoded_value): Move up.
+       (decode_location_expression): Add section parameter.  Handle
+       DW_OP_GNU_encoded_addr.
+       (read_and_display_attr_value): Update decode_location_expression call.
+       (display_debug_loc, display_debug_frames): Likewise.
+
 2008-09-25  Alan Modra  <amodra@bigpond.net.au>
 
        PR 6913
index 42ddd94233217034d7eca9a84380ddf794da5f39..983a3c76a5f093c40795446f41ed19166fa180a5 100644 (file)
@@ -164,6 +164,30 @@ byte_get_signed (unsigned char *field, int size)
     }
 }
 
+static int
+size_of_encoded_value (int encoding)
+{
+  switch (encoding & 0x7)
+    {
+    default:   /* ??? */
+    case 0:    return eh_addr_size;
+    case 2:    return 2;
+    case 3:    return 4;
+    case 4:    return 8;
+    }
+}
+
+static dwarf_vma
+get_encoded_value (unsigned char *data, int encoding)
+{
+  int size = size_of_encoded_value (encoding);
+
+  if (encoding & DW_EH_PE_signed)
+    return byte_get_signed (data, size);
+  else
+    return byte_get (data, size);
+}
+
 /* Print a dwarf_vma value (typically an address, offset or length) in
    hexadecimal format, followed by a space.  The length of the value (and
    hence the precision displayed) is determined by the byte_size parameter.  */
@@ -651,7 +675,8 @@ static int
 decode_location_expression (unsigned char * data,
                            unsigned int pointer_size,
                            unsigned long length,
-                           unsigned long cu_offset)
+                           unsigned long cu_offset,
+                           struct dwarf_section * section)
 {
   unsigned op;
   unsigned int bytes_read;
@@ -989,6 +1014,21 @@ decode_location_expression (unsigned char * data,
          printf ("DW_OP_GNU_uninit");
          /* FIXME: Is there data associated with this OP ?  */
          break;
+       case DW_OP_GNU_encoded_addr:
+         {
+           int encoding;
+           dwarf_vma addr;
+       
+           encoding = *data++;
+           addr = get_encoded_value (data, encoding);
+           if ((encoding & 0x70) == DW_EH_PE_pcrel)
+             addr += section->address + (data - section->start);
+           data += size_of_encoded_value (encoding);
+
+           printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding);
+           print_dwarf_vma (addr, pointer_size);
+         }
+         break;
 
          /* HP extensions.  */
        case DW_OP_HP_is_value:
@@ -1508,7 +1548,7 @@ read_and_display_attr_value (unsigned long attribute,
          need_frame_base = decode_location_expression (block_start,
                                                        pointer_size,
                                                        uvalue,
-                                                       cu_offset);
+                                                       cu_offset, section);
          printf (")");
          if (need_frame_base && !have_frame_base)
            printf (_(" [without DW_AT_frame_base]"));
@@ -3186,7 +3226,7 @@ display_debug_loc (struct dwarf_section *section, void *file)
              need_frame_base = decode_location_expression (start,
                                                            pointer_size,
                                                            length,
-                                                           cu_offset);
+                                                           cu_offset, section);
              putchar (')');
 
              if (need_frame_base && !has_frame_base)
@@ -3756,30 +3796,6 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
   printf ("\n");
 }
 
-static int
-size_of_encoded_value (int encoding)
-{
-  switch (encoding & 0x7)
-    {
-    default:   /* ??? */
-    case 0:    return eh_addr_size;
-    case 2:    return 2;
-    case 3:    return 4;
-    case 4:    return 8;
-    }
-}
-
-static dwarf_vma
-get_encoded_value (unsigned char *data, int encoding)
-{
-  int size = size_of_encoded_value (encoding);
-
-  if (encoding & DW_EH_PE_signed)
-    return byte_get_signed (data, size);
-  else
-    return byte_get (data, size);
-}
-
 #define GET(N) byte_get (start, N); start += N
 #define LEB()  read_leb128 (start, & length_return, 0); start += length_return
 #define SLEB() read_leb128 (start, & length_return, 1); start += length_return
@@ -4379,7 +4395,8 @@ display_debug_frames (struct dwarf_section *section,
              if (! do_debug_frames_interp)
                {
                  printf ("  DW_CFA_def_cfa_expression (");
-                 decode_location_expression (start, eh_addr_size, ul, 0);
+                 decode_location_expression (start, eh_addr_size, ul, 0,
+                                             section);
                  printf (")\n");
                }
              fc->cfa_exp = 1;
@@ -4394,7 +4411,7 @@ display_debug_frames (struct dwarf_section *section,
                  printf ("  DW_CFA_expression: %s (",
                          regname (reg, 0));
                  decode_location_expression (start, eh_addr_size,
-                                             ul, 0);
+                                             ul, 0, section);
                  printf (")\n");
                }
              fc->col_type[reg] = DW_CFA_expression;
@@ -4408,7 +4425,8 @@ display_debug_frames (struct dwarf_section *section,
                {
                  printf ("  DW_CFA_val_expression: %s (",
                          regname (reg, 0));
-                 decode_location_expression (start, eh_addr_size, ul, 0);
+                 decode_location_expression (start, eh_addr_size, ul, 0,
+                                             section);
                  printf (")\n");
                }
              fc->col_type[reg] = DW_CFA_val_expression;
index e305b2e372a8cff88566d52169bda982d1734449..3d023dfc38e443da192fe52455dce902ceddc1ab 100644 (file)
@@ -1,3 +1,12 @@
+2008-09-24  Richard Henderson  <rth@redhat.com>
+
+       * dw2gencfi.c (DWARF2_ADDR_SIZE): Provide default.
+       (struct cfi_insn_data): Add ea member.
+       (CFI_val_encoded_addr, dot_cfi_val_encoded_addr): New.
+       (output_cfi_insn): Handle CFI_val_encoded_addr.
+       (select_cie_for_fde): Don't match CFI_val_encoded_addr.
+       * doc/as.texinfo (.cfi_val_encoded_addr): Document.
+
 2008-09-25  Alan Modra  <amodra@bigpond.net.au>
 
        PR 6913
index 92b4cdec204c8ee9152766ad2df46e3cb6165eb6..c0aef5c96c812046405acfefae6cbfb446210f59 100644 (file)
@@ -4230,6 +4230,17 @@ Allows the user to add arbitrary bytes to the unwind info.  One
 might use this to add OS-specific CFI opcodes, or generic CFI
 opcodes that GAS does not yet support.
 
+@section @code{.cfi_val_encoded_addr @var{register}, @var{encoding}, @var{label}}
+The current value of @var{register} is @var{label}.  The value of @var{label}
+will be encoded in the output file according to @var{encoding}; see the
+description of @code{.cfi_personality} for details on this encoding.
+
+The usefulness of equating a register to a fixed label is probably
+limited to the return address register.  Here, it can be useful to
+mark a code segment that has only one return address which is reached
+by a direct branch and no copy of the return address exists in memory
+or another register.
+
 @node LNS directives
 @section @code{.file @var{fileno} @var{filename}}
 @cindex @code{file} directive
index 49a23ad8106a14bf5ec53b5ecdba9799bd6ff138..3cb5dffb100cbe041481f95cb7618424952e6c24 100644 (file)
 # define tc_cfi_frame_initial_instructions() ((void)0)
 #endif
 
+#ifndef DWARF2_ADDR_SIZE
+# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8)
+#endif
+
 
 struct cfi_insn_data
 {
@@ -86,6 +90,11 @@ struct cfi_insn_data
       struct cfi_escape_data *next;
       expressionS exp;
     } *esc;
+
+    struct {
+      unsigned reg, encoding;
+      expressionS exp;
+    } ea;
   } u;
 };
 
@@ -376,6 +385,7 @@ static void dot_cfi_startproc (int);
 static void dot_cfi_endproc (int);
 static void dot_cfi_personality (int);
 static void dot_cfi_lsda (int);
+static void dot_cfi_val_encoded_addr (int);
 
 /* Fake CFI type; outside the byte range of any real CFI insn.  */
 #define CFI_adjust_cfa_offset  0x100
@@ -383,6 +393,7 @@ static void dot_cfi_lsda (int);
 #define CFI_rel_offset         0x102
 #define CFI_escape             0x103
 #define CFI_signal_frame       0x104
+#define CFI_val_encoded_addr   0x105
 
 const pseudo_typeS cfi_pseudo_table[] =
   {
@@ -406,6 +417,7 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_signal_frame", dot_cfi, CFI_signal_frame },
     { "cfi_personality", dot_cfi_personality, 0 },
     { "cfi_lsda", dot_cfi_lsda, 0 },
+    { "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 },
     { NULL, NULL, 0 }
   };
 
@@ -654,7 +666,7 @@ dot_cfi_personality (int ignored ATTRIBUTE_UNUSED)
     }
 
   fde = frchain_now->frch_cfi_data->cur_fde_data;
-  encoding = get_absolute_expression ();
+  encoding = cfi_parse_const ();
   if (encoding == DW_EH_PE_omit)
     {
       demand_empty_rest_of_line ();
@@ -724,7 +736,7 @@ dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED)
     }
 
   fde = frchain_now->frch_cfi_data->cur_fde_data;
-  encoding = get_absolute_expression ();
+  encoding = cfi_parse_const ();
   if (encoding == DW_EH_PE_omit)
     {
       demand_empty_rest_of_line ();
@@ -782,6 +794,71 @@ dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+static void
+dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED)
+{
+  struct cfi_insn_data *insn_ptr;
+  offsetT encoding;
+
+  if (frchain_now->frch_cfi_data == NULL)
+    {
+      as_bad (_("CFI instruction used without previous .cfi_startproc"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  /* If the last address was not at the current PC, advance to current.  */
+  if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now
+      || S_GET_VALUE (frchain_now->frch_cfi_data->last_address)
+        != frag_now_fix ())
+    cfi_add_advance_loc (symbol_temp_new_now ());
+
+  insn_ptr = alloc_cfi_insn_data ();
+  insn_ptr->insn = CFI_val_encoded_addr;
+  
+  insn_ptr->u.ea.reg = cfi_parse_reg ();
+
+  cfi_parse_separator ();
+  encoding = cfi_parse_const ();
+  if ((encoding & 0xff) != encoding
+      || ((encoding & 0x70) != 0
+#if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
+         && (encoding & 0x70) != DW_EH_PE_pcrel
+#endif
+         )
+        /* leb128 can be handled, but does something actually need it?  */
+      || (encoding & 7) == DW_EH_PE_uleb128
+      || (encoding & 7) > DW_EH_PE_udata8)
+    {
+      as_bad (_("invalid or unsupported encoding in .cfi_lsda"));
+      encoding = DW_EH_PE_omit;
+    }
+
+  cfi_parse_separator ();
+  expression_and_evaluate (&insn_ptr->u.ea.exp);
+  switch (insn_ptr->u.ea.exp.X_op)
+    {
+    case O_symbol:
+      break;
+    case O_constant:
+      if ((encoding & 0x70) != DW_EH_PE_pcrel)
+        break;
+    default:
+      encoding = DW_EH_PE_omit;
+      break;
+    }
+
+  insn_ptr->u.ea.encoding = encoding;
+  if (encoding == DW_EH_PE_omit)
+    {
+      as_bad (_("wrong third argument to .cfi_val_encoded_addr"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
 static void
 dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
 {
@@ -1028,6 +1105,64 @@ output_cfi_insn (struct cfi_insn_data *insn)
        break;
       }
 
+    case CFI_val_encoded_addr:
+      {
+        unsigned encoding = insn->u.ea.encoding;
+        offsetT encoding_size;
+
+       if (encoding == DW_EH_PE_omit)
+         break;
+       out_one (DW_CFA_val_expression);
+       out_uleb128 (insn->u.ea.reg);
+
+        switch (encoding & 0x7)
+         {
+         case DW_EH_PE_absptr:
+           encoding_size = DWARF2_ADDR_SIZE (stdoutput);
+           break;
+         case DW_EH_PE_udata2:
+           encoding_size = 2;
+           break;
+         case DW_EH_PE_udata4:
+           encoding_size = 4;
+           break;
+         case DW_EH_PE_udata8:
+           encoding_size = 8;
+           break;
+         default:
+           abort ();
+         }
+
+       /* If the user has requested absolute encoding,
+          then use the smaller DW_OP_addr encoding.  */
+       if (insn->u.ea.encoding == DW_EH_PE_absptr)
+         {
+           out_uleb128 (1 + encoding_size);
+           out_one (DW_OP_addr);
+         }
+       else
+         {
+           out_uleb128 (1 + 1 + encoding_size);
+           out_one (DW_OP_GNU_encoded_addr);
+           out_one (encoding);
+
+           if ((encoding & 0x70) == DW_EH_PE_pcrel)
+             {
+#if CFI_DIFF_EXPR_OK
+               insn->u.ea.exp.X_op = O_subtract;
+               insn->u.ea.exp.X_op_symbol = symbol_temp_new_now ();
+#elif defined (tc_cfi_emit_pcrel_expr)
+               tc_cfi_emit_pcrel_expr (&insn.u.ea.exp, encoding_size);
+               break;
+#else
+               abort ();
+#endif
+             }
+         }
+       emit_expr (&insn->u.ea.exp, encoding_size);
+      }
+      break;
+      
     default:
       abort ();
     }
@@ -1292,6 +1427,7 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
              break;
 
            case CFI_escape:
+           case CFI_val_encoded_addr:
              /* Don't bother matching these for now.  */
              goto fail;
 
@@ -1307,7 +1443,8 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
          && (!j
              || j->insn == DW_CFA_advance_loc
              || j->insn == DW_CFA_remember_state
-             || j->insn == CFI_escape))
+             || j->insn == CFI_escape
+             || j->insn == CFI_val_encoded_addr))
        {
          *pfirst = j;
          return cie;
@@ -1329,7 +1466,8 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
   for (i = cie->first; i ; i = i->next)
     if (i->insn == DW_CFA_advance_loc
        || i->insn == DW_CFA_remember_state
-       || i->insn == CFI_escape)
+       || i->insn == CFI_escape
+       || i->insn == CFI_val_encoded_addr)
       break;
 
   cie->last = i;
index 2acaaf1364794fc3f16d568ddbc456c58b8e620f..e8d9a028cfc86cc56b4fead6b20f93a36167406f 100644 (file)
@@ -1,3 +1,7 @@
+2008-09-24  Richard Henderson  <rth@redhat.com>
+
+       * elf/dwarf2.h (DW_OP_GNU_encoded_addr): New.
+
 2008-09-22 Rafael Espindola  <espindola@google.com>
 
        * plugin-api.h (ld_plugin_status): Remove comma from the last item.
index 648658da365a858e72618673f729e1c359c69845..f8d010b53d782d37128d321a4ff6d1c4a389c066 100644 (file)
@@ -544,6 +544,7 @@ enum dwarf_location_atom
     /* GNU extensions.  */
     DW_OP_GNU_push_tls_address = 0xe0,
     DW_OP_GNU_uninit     = 0xf0,
+    DW_OP_GNU_encoded_addr = 0xf1,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,