* dw2gencfi.c (struct fde_entry): Add per_encoding, lsda_encoding,
authorJakub Jelinek <jakub@redhat.com>
Fri, 3 Nov 2006 07:29:37 +0000 (07:29 +0000)
committerJakub Jelinek <jakub@redhat.com>
Fri, 3 Nov 2006 07:29:37 +0000 (07:29 +0000)
personality and lsda.
(struct cie_entry): Add per_encoding, lsda_encoding and personality.
(alloc_fde_entry): Initialize per_encoding and lsda_encoding.
(cfi_pseudo_table): Handle .cfi_personality and .cfi_lsda.
(dot_cfi_personality, dot_cfi_lsda, encoding_size): New functions.
(output_cie): Output personality including its encoding and LSDA encoding.
(output_fde): Output LSDA.
(select_cie_for_fde): Don't share CIE if personality, its encoding or
LSDA encoding are different.  Copy the 3 fields from fde_entry to
cie_entry.
* doc/as.texinfo (.cfi_personality, .cfi_lsda): Document.

* gas/cfi/cfi-common-6.d: New test.
* gas/cfi/cfi-common-6.s: New.
* gas/cfi/cfi.exp: Add cfi-common-6 test.

gas/ChangeLog
gas/doc/as.texinfo
gas/dw2gencfi.c
gas/testsuite/ChangeLog
gas/testsuite/gas/cfi/cfi-common-6.d [new file with mode: 0644]
gas/testsuite/gas/cfi/cfi-common-6.s [new file with mode: 0644]
gas/testsuite/gas/cfi/cfi.exp

index 0a62c21257e6b978ec4aab9963027dcae0daadd8..e1ba472bdb869bfd9077c3a32b43149373e8d891 100644 (file)
@@ -1,5 +1,18 @@
 2006-11-03  Jakub Jelinek  <jakub@redhat.com>
 
+       * dw2gencfi.c (struct fde_entry): Add per_encoding, lsda_encoding,
+       personality and lsda.
+       (struct cie_entry): Add per_encoding, lsda_encoding and personality.
+       (alloc_fde_entry): Initialize per_encoding and lsda_encoding.
+       (cfi_pseudo_table): Handle .cfi_personality and .cfi_lsda.
+       (dot_cfi_personality, dot_cfi_lsda, encoding_size): New functions.
+       (output_cie): Output personality including its encoding and LSDA encoding.
+       (output_fde): Output LSDA.
+       (select_cie_for_fde): Don't share CIE if personality, its encoding or
+       LSDA encoding are different.  Copy the 3 fields from fde_entry to
+       cie_entry.
+       * doc/as.texinfo (.cfi_personality, .cfi_lsda): Document.
+
        * subsegs.h (struct frchain): Add frch_cfi_data field.
        * dw2gencfi.c: Include subsegs.h.
        (cur_fde_data, last_address, cur_cfa_offset, cfa_save_stack): Removed.
index a43b77e4b664e54bbcb6f1520ad91151746a6cd0..be21112c66d7b70d840a9b2e5fd4ec85c1e99695 100644 (file)
@@ -4102,6 +4102,25 @@ Don't forget to close the function by
 unwind entry previously opened by
 @code{.cfi_startproc}, and emits it to @code{.eh_frame}.
 
+@section @code{.cfi_personality @var{encoding} [, @var{exp}]}
+@code{.cfi_personality} defines personality routine and its encoding.
+@var{encoding} must be a constant determining how the personality
+should be encoded.  If it is 255 (@code{DW_EH_PE_omit}), second
+argument is not present, otherwise second argument should be
+a constant or a symbol name.  When using indirect encodings,
+the symbol provided should be the location where personality
+can be loaded from, not the personality routine itself.
+The default after @code{.cfi_startproc} is @code{.cfi_personality 0xff},
+no personality routine.
+
+@section @code{.cfi_lsda @var{encoding} [, @var{exp}]}
+@code{.cfi_lsda} defines LSDA and its encoding.
+@var{encoding} must be a constant determining how the LSDA
+should be encoded.  If it is 255 (@code{DW_EH_PE_omit}), second
+argument is not present, otherwise second argument should be a constant
+or a symbol name.  The default after @code{.cfi_startproc} is @code{.cfi_lsda 0xff},
+no LSDA.
+
 @section @code{.cfi_def_cfa @var{register}, @var{offset}}
 @code{.cfi_def_cfa} defines a rule for computing CFA as: @i{take 
 address from @var{register} and add @var{offset} to it}.
index 4e39ac5a5278b82c984eeb9e4a4fff0bef748c44..97e12377e76b9c8d6347544719c0ff3af4714da0 100644 (file)
@@ -88,6 +88,10 @@ struct fde_entry
   symbolS *end_address;
   struct cfi_insn_data *data;
   struct cfi_insn_data **last;
+  unsigned char per_encoding;
+  unsigned char lsda_encoding;
+  expressionS personality;
+  expressionS lsda;
   unsigned int return_column;
   unsigned int signal_frame;
 };
@@ -98,6 +102,9 @@ struct cie_entry
   symbolS *start_address;
   unsigned int return_column;
   unsigned int signal_frame;
+  unsigned char per_encoding;
+  unsigned char lsda_encoding;
+  expressionS personality;
   struct cfi_insn_data *first, *last;
 };
 
@@ -139,6 +146,8 @@ alloc_fde_entry (void)
 
   fde->last = &fde->data;
   fde->return_column = DWARF2_DEFAULT_RETURN_COLUMN;
+  fde->per_encoding = DW_EH_PE_omit;
+  fde->lsda_encoding = DW_EH_PE_omit;
 
   return fde;
 }
@@ -357,6 +366,8 @@ static void dot_cfi (int);
 static void dot_cfi_escape (int);
 static void dot_cfi_startproc (int);
 static void dot_cfi_endproc (int);
+static void dot_cfi_personality (int);
+static void dot_cfi_lsda (int);
 
 /* Fake CFI type; outside the byte range of any real CFI insn.  */
 #define CFI_adjust_cfa_offset  0x100
@@ -385,6 +396,8 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_window_save", dot_cfi, DW_CFA_GNU_window_save },
     { "cfi_escape", dot_cfi_escape, 0 },
     { "cfi_signal_frame", dot_cfi, CFI_signal_frame },
+    { "cfi_personality", dot_cfi_personality, 0 },
+    { "cfi_lsda", dot_cfi_lsda, 0 },
     { NULL, NULL, 0 }
   };
 
@@ -610,6 +623,148 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
   demand_empty_rest_of_line ();
 }
 
+static void
+dot_cfi_personality (int ignored ATTRIBUTE_UNUSED)
+{
+  struct fde_entry *fde;
+  offsetT encoding;
+
+  if (frchain_now->frch_cfi_data == NULL)
+    {
+      as_bad (_("CFI instruction used without previous .cfi_startproc"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  fde = frchain_now->frch_cfi_data->cur_fde_data;
+  encoding = get_absolute_expression ();
+  if (encoding == DW_EH_PE_omit)
+    {
+      demand_empty_rest_of_line ();
+      fde->per_encoding = encoding;
+      return;
+    }
+
+  if ((encoding & 0xff) != encoding
+      || ((encoding & 0x70) != 0
+#if defined 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_personality"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (*input_line_pointer++ != ',')
+    {
+      as_bad (_(".cfi_personality requires encoding and symbol arguments"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  expression_and_evaluate (&fde->personality);
+  switch (fde->personality.X_op)
+    {
+    case O_symbol:
+      break;
+    case O_constant:
+      if ((encoding & 0x70) == DW_EH_PE_pcrel)
+       encoding = DW_EH_PE_omit;
+      break;
+    default:
+      encoding = DW_EH_PE_omit;
+      break;
+    }
+
+  fde->per_encoding = encoding;
+
+  if (encoding == DW_EH_PE_omit)
+    {
+      as_bad (_("wrong second argument to .cfi_personality"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+dot_cfi_lsda (int ignored ATTRIBUTE_UNUSED)
+{
+  struct fde_entry *fde;
+  offsetT encoding;
+
+  if (frchain_now->frch_cfi_data == NULL)
+    {
+      as_bad (_("CFI instruction used without previous .cfi_startproc"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  fde = frchain_now->frch_cfi_data->cur_fde_data;
+  encoding = get_absolute_expression ();
+  if (encoding == DW_EH_PE_omit)
+    {
+      demand_empty_rest_of_line ();
+      fde->lsda_encoding = encoding;
+      return;
+    }
+
+  if ((encoding & 0xff) != encoding
+      || ((encoding & 0x70) != 0
+#if defined 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"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  if (*input_line_pointer++ != ',')
+    {
+      as_bad (_(".cfi_lsda requires encoding and symbol arguments"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  fde->lsda_encoding = encoding;
+
+  expression_and_evaluate (&fde->lsda);
+  switch (fde->lsda.X_op)
+    {
+    case O_symbol:
+      break;
+    case O_constant:
+      if ((encoding & 0x70) == DW_EH_PE_pcrel)
+       encoding = DW_EH_PE_omit;
+      break;
+    default:
+      encoding = DW_EH_PE_omit;
+      break;
+    }
+
+  fde->lsda_encoding = encoding;
+
+  if (encoding == DW_EH_PE_omit)
+    {
+      as_bad (_("wrong second argument to .cfi_lsda"));
+      ignore_rest_of_line ();
+      return;
+    }
+
+  demand_empty_rest_of_line ();
+}
+
 static void
 dot_cfi_startproc (int ignored ATTRIBUTE_UNUSED)
 {
@@ -725,18 +880,18 @@ output_cfi_insn (struct cfi_insn_data *insn)
              out_one (DW_CFA_advance_loc + scaled);
            else if (delta <= 0xFF)
              {
-               out_one (DW_CFA_advance_loc1);
-               out_one (delta);
+               out_one (DW_CFA_advance_loc1);
+               out_one (delta);
              }
            else if (delta <= 0xFFFF)
              {
-               out_one (DW_CFA_advance_loc2);
-               out_two (delta);
+               out_one (DW_CFA_advance_loc2);
+               out_two (delta);
              }
            else
              {
-               out_one (DW_CFA_advance_loc4);
-               out_four (delta);
+               out_one (DW_CFA_advance_loc4);
+               out_four (delta);
              }
          }
        else
@@ -861,12 +1016,33 @@ output_cfi_insn (struct cfi_insn_data *insn)
     }
 }
 
+static offsetT
+encoding_size (unsigned char encoding)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+  switch (encoding & 0x7)
+    {
+    case 0:
+      return bfd_get_arch_size (stdoutput) == 64 ? 8 : 4;
+    case DW_EH_PE_udata2:
+      return 2;
+    case DW_EH_PE_udata4:
+      return 4;
+    case DW_EH_PE_udata8:
+      return 8;
+    default:
+      abort ();
+    }
+}
+
 static void
 output_cie (struct cie_entry *cie)
 {
   symbolS *after_size_address, *end_address;
   expressionS exp;
   struct cfi_insn_data *i;
+  offsetT augmentation_size;
 
   cie->start_address = symbol_temp_new_now ();
   after_size_address = symbol_temp_make ();
@@ -882,6 +1058,10 @@ output_cie (struct cie_entry *cie)
   out_four (0);                                        /* CIE id.  */
   out_one (DW_CIE_VERSION);                    /* Version.  */
   out_one ('z');                               /* Augmentation.  */
+  if (cie->per_encoding != DW_EH_PE_omit)
+    out_one ('P');
+  if (cie->lsda_encoding != DW_EH_PE_omit)
+    out_one ('L');
   out_one ('R');
   if (cie->signal_frame)
     out_one ('S');
@@ -892,7 +1072,32 @@ output_cie (struct cie_entry *cie)
     out_one (cie->return_column);
   else
     out_uleb128 (cie->return_column);
-  out_uleb128 (1);                             /* Augmentation size.  */
+  augmentation_size = 1 + (cie->lsda_encoding != DW_EH_PE_omit);
+  if (cie->per_encoding != DW_EH_PE_omit)
+    augmentation_size += 1 + encoding_size (cie->per_encoding);
+  out_uleb128 (augmentation_size);             /* Augmentation size.  */
+  if (cie->per_encoding != DW_EH_PE_omit)
+    {
+      offsetT size = encoding_size (cie->per_encoding);
+      out_one (cie->per_encoding);
+      exp = cie->personality;
+      if ((cie->per_encoding & 0x70) == DW_EH_PE_pcrel)
+       {
+#ifdef DIFF_EXPR_OK
+         exp.X_op = O_subtract;
+         exp.X_op_symbol = symbol_temp_new_now ();
+         emit_expr (&exp, size);
+#elif defined (tc_cfi_emit_pcrel_expr)
+         tc_cfi_emit_pcrel_expr (&exp, size);
+#else
+         abort ();
+#endif
+       }
+      else
+       emit_expr (&exp, size);
+    }
+  if (cie->lsda_encoding != DW_EH_PE_omit)
+    out_one (cie->lsda_encoding);
 #if defined DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr
   out_one (DW_EH_PE_pcrel | DW_EH_PE_sdata4);
 #else
@@ -913,6 +1118,7 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
 {
   symbolS *after_size_address, *end_address;
   expressionS exp;
+  offsetT augmentation_size;
 
   after_size_address = symbol_temp_make ();
   end_address = symbol_temp_make ();
@@ -928,7 +1134,7 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
   exp.X_op_symbol = cie->start_address;
   emit_expr (&exp, 4);                         /* CIE offset.  */
 
-#ifdef DIFF_EXPR_OK  
+#ifdef DIFF_EXPR_OK
   exp.X_add_symbol = fde->start_address;
   exp.X_op_symbol = symbol_temp_new_now ();
   emit_expr (&exp, 4);                         /* Code offset.  */
@@ -948,7 +1154,27 @@ output_fde (struct fde_entry *fde, struct cie_entry *cie,
   exp.X_op_symbol = fde->start_address;                /* Code length.  */
   emit_expr (&exp, 4);
 
-  out_uleb128 (0);                             /* Augmentation size.  */
+  augmentation_size = encoding_size (fde->lsda_encoding);
+  out_uleb128 (augmentation_size);             /* Augmentation size.  */
+
+  if (fde->lsda_encoding != DW_EH_PE_omit)
+    {
+      exp = fde->lsda;
+      if ((fde->lsda_encoding & 0x70) == DW_EH_PE_pcrel)
+       {
+#ifdef DIFF_EXPR_OK
+         exp.X_op = O_subtract;
+         exp.X_op_symbol = symbol_temp_new_now ();
+         emit_expr (&exp, augmentation_size);
+#elif defined (tc_cfi_emit_pcrel_expr)
+         tc_cfi_emit_pcrel_expr (&exp, augmentation_size);
+#else
+         abort ();
+#endif
+       }
+      else
+       emit_expr (&exp, augmentation_size);
+    }
 
   for (; first; first = first->next)
     output_cfi_insn (first);
@@ -966,8 +1192,31 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
   for (cie = cie_root; cie; cie = cie->next)
     {
       if (cie->return_column != fde->return_column
-         || cie->signal_frame != fde->signal_frame)
+         || cie->signal_frame != fde->signal_frame
+         || cie->per_encoding != fde->per_encoding
+         || cie->lsda_encoding != fde->lsda_encoding)
        continue;
+      if (cie->per_encoding != DW_EH_PE_omit)
+       {
+         if (cie->personality.X_op != fde->personality.X_op
+             || cie->personality.X_add_number
+                != fde->personality.X_add_number)
+           continue;
+         switch (cie->personality.X_op)
+           {
+           case O_constant:
+             if (cie->personality.X_unsigned != fde->personality.X_unsigned)
+               continue;
+             break;
+           case O_symbol:
+             if (cie->personality.X_add_symbol
+                 != fde->personality.X_add_symbol)
+               continue;
+             break;
+           default:
+             abort ();
+           }
+       }
       for (i = cie->first, j = fde->data;
           i != cie->last && j != NULL;
           i = i->next, j = j->next)
@@ -1040,6 +1289,9 @@ select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
   cie_root = cie;
   cie->return_column = fde->return_column;
   cie->signal_frame = fde->signal_frame;
+  cie->per_encoding = fde->per_encoding;
+  cie->lsda_encoding = fde->lsda_encoding;
+  cie->personality = fde->personality;
   cie->first = fde->data;
 
   for (i = cie->first; i ; i = i->next)
index 0034982ef8bb804ca897a3c54a270e7d070a7bdd..30c77b3fdf3de4ca4c4ff5d2320e90433f599f5a 100644 (file)
@@ -1,5 +1,9 @@
 2006-11-03  Jakub Jelinek  <jakub@redhat.com>
 
+       * gas/cfi/cfi-common-6.d: New test.
+       * gas/cfi/cfi-common-6.s: New.
+       * gas/cfi/cfi.exp: Add cfi-common-6 test.
+
        * gas/cfi/cfi-common-5.d: New test.
        * gas/cfi/cfi-common-5.s: New.
        * gas/cfi/cfi.exp: Add cfi-common-5 test.
diff --git a/gas/testsuite/gas/cfi/cfi-common-6.d b/gas/testsuite/gas/cfi/cfi-common-6.d
new file mode 100644 (file)
index 0000000..dcc7b79
--- /dev/null
@@ -0,0 +1,73 @@
+#readelf: -wf
+#name: CFI common 6
+The section .eh_frame contains:
+
+00000000 00000018 00000000 CIE
+  Version:               1
+  Augmentation:          "zPLR"
+  Code alignment factor: .*
+  Data alignment factor: .*
+  Return address column: .*
+  Augmentation data:     03 .. .. .. .. 0c 1b
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+0000001c 00000018 00000020 FDE cie=00000000 pc=00000000..00000004
+  Augmentation data:     (00 00 00 00 de ad be ef|ef be ad de 00 00 00 00)
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000038 00000010 00000000 CIE
+  Version:               1
+  Augmentation:          "zLR"
+  Code alignment factor: .*
+  Data alignment factor: .*
+  Return address column: .*
+  Augmentation data:     0c 1b
+
+  DW_CFA_nop
+
+0000004c 00000018 00000018 FDE cie=00000038 pc=00000004..00000008
+  Augmentation data:     (00 00 00 00 de ad be ef|ef be ad de 00 00 00 00)
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000068 00000018 0000006c FDE cie=00000000 pc=00000008..0000000c
+  Augmentation data:     (00 00 00 00 be ef de ad|ad de ef be 00 00 00 00)
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+00000084 00000018 00000000 CIE
+  Version:               1
+  Augmentation:          "zPLR"
+  Code alignment factor: .*
+  Data alignment factor: .*
+  Return address column: .*
+  Augmentation data:     1b .. .. .. .. 1b 1b
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+000000a0 00000014 00000020 FDE cie=00000084 pc=0000000c..00000010
+  Augmentation data:     .. .. .. ..
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
+000000b8 00000014 00000038 FDE cie=00000084 pc=00000010..00000014
+  Augmentation data:     .. .. .. ..
+
+  DW_CFA_nop
+  DW_CFA_nop
+  DW_CFA_nop
+
diff --git a/gas/testsuite/gas/cfi/cfi-common-6.s b/gas/testsuite/gas/cfi/cfi-common-6.s
new file mode 100644 (file)
index 0000000..6fa52a5
--- /dev/null
@@ -0,0 +1,40 @@
+       .text
+       .cfi_startproc simple
+       .cfi_personality 3, my_personality_v0
+       .cfi_lsda 12, 0xdeadbeef
+       .long 0
+       .cfi_endproc
+
+       .cfi_startproc simple
+       .cfi_personality 3, my_personality_v0
+       .cfi_lsda 12, 0xdeadbeef
+       .cfi_personality 0xff
+       .long 0
+       .cfi_endproc
+
+       .cfi_startproc simple
+       .cfi_personality 3, my_personality_v0
+       .cfi_lsda 12, 0xbeefdead
+       .long 0
+       .cfi_endproc
+
+       .cfi_startproc simple
+       .cfi_personality (0x10 | 11), my_personality_v1
+       .cfi_lsda 27, 1f
+       .long 0
+       .cfi_endproc
+
+       .cfi_startproc simple
+       .cfi_personality (0x10 | 11), my_personality_v1
+       .cfi_lsda 27, 2f
+       .long 0
+       .cfi_endproc
+
+my_personality_v0:
+       .long 0
+my_personality_v1:
+       .long 0
+1:
+       .long 0
+2:
+       .long 0
index 60b7952a103a5184fef1d6ae77eae54c6e8678c0..da9ef26d470c51aa17f122f1c9e075d429e20c13 100644 (file)
@@ -73,3 +73,4 @@ run_dump_test "cfi-common-2"
 run_dump_test "cfi-common-3"
 run_dump_test "cfi-common-4"
 run_dump_test "cfi-common-5"
+run_dump_test "cfi-common-6"