? gas/autom4te.cache
? gas/doc/as.info
Index: gas/ChangeLog
===================================================================
RCS file: /cvs/src/src/gas/ChangeLog,v
retrieving revision 1.3786
diff -b -B -p -u -r1.3786 ChangeLog
--- gas/ChangeLog
+++ gas/ChangeLog
@@ -1,3 +1,21 @@
+2009-04-15  Roland McGrath  <roland@redhat.com>
+
+	* doc/as.texinfo (CFI directives): Describe new directives
+	.cfi_eh_frame and .cfi_debug_frame.
+	* dw2gencfi.c (struct cie_entry): Add flag field emitted_in.
+	(cfi_pseudo_table): Add .cfi_eh_frame and .cfi_debug_frame.
+	(emit_eh_frame, emit_debug_frame): New static variables.
+	(cfi_parse_section_directive): New function.
+	(dot_cfi_eh_frame, dot_cfi_debug_frame): New functions.
+	(output_cie): Take new EH_FRAME flag argument.  When zero,
+	emit .debug_frame header format.
+	(output_fde): Likewise.
+	(select_cie_for_fde): Take new argument, pass it down.
+	Maintain CIE->emitted_in field and call output_cie for hits
+	that have not been emitted in this pass.
+	(output_cfi): New function, broken out of ...
+	(cfi_finish): ... here.  Call it once for each section enabled.
+
 2009-04-15  Jan Beulich  <jbeulich@novell.com>
 
 	* config/tc-i386.c (process_operands): Print operands in
Index: gas/configure.in
===================================================================
RCS file: /cvs/src/src/gas/configure.in,v
retrieving revision 1.212
diff -b -B -p -u -r1.212 configure.in
Index: gas/dw2gencfi.c
===================================================================
RCS file: /cvs/src/src/gas/dw2gencfi.c,v
retrieving revision 1.40
diff -b -B -p -u -r1.40 dw2gencfi.c
--- gas/dw2gencfi.c
+++ gas/dw2gencfi.c
@@ -1,5 +1,5 @@
 /* dw2gencfi.c - Support for generating Dwarf2 CFI information.
-   Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
    Contributed by Michal Ludvig <mludvig@suse.cz>
 
    This file is part of GAS, the GNU Assembler.
@@ -121,11 +121,18 @@ struct cie_entry
   unsigned int signal_frame;
   unsigned char per_encoding;
   unsigned char lsda_encoding;
+  unsigned int emitted_in:1;
   expressionS personality;
   struct cfi_insn_data *first, *last;
 };
 
 
+/* Which flavor of section will we emit (or both?).
+   Directives can set these to 1 or 0 explicitly.
+   Default settings will be resolved in cfi_finish.  */
+static int emit_eh_frame = 1;
+static int emit_debug_frame;
+
 /* List of FDE entries.  */
 static struct fde_entry *all_fde_data;
 static struct fde_entry **last_fde_data = &all_fde_data;
@@ -386,6 +393,8 @@ 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);
+static void dot_cfi_eh_frame (int);
+static void dot_cfi_debug_frame (int);
 
 /* Fake CFI type; outside the byte range of any real CFI insn.  */
 #define CFI_adjust_cfa_offset	0x100
@@ -418,6 +427,8 @@ const pseudo_typeS cfi_pseudo_table[] =
     { "cfi_personality", dot_cfi_personality, 0 },
     { "cfi_lsda", dot_cfi_lsda, 0 },
     { "cfi_val_encoded_addr", dot_cfi_val_encoded_addr, 0 },
+    { "cfi_eh_frame", dot_cfi_eh_frame, 0 },
+    { "cfi_debug_frame", dot_cfi_debug_frame, 0 },
     { NULL, NULL, 0 }
   };
 
@@ -911,6 +922,34 @@ dot_cfi_endproc (int ignored ATTRIBUTE_U
   demand_empty_rest_of_line ();
 }
 
+static int
+cfi_parse_section_directive (void)
+{
+  expressionS exp;
+  expression_and_evaluate (&exp);
+
+  if (exp.X_op != O_constant)
+    {
+      as_bad (_("bad or irreducible absolute expression"));
+      exp.X_add_number = 0;
+    }
+
+  demand_empty_rest_of_line ();
+
+  return exp.X_add_number != 0;
+}
+
+static void
+dot_cfi_eh_frame (int ignored ATTRIBUTE_UNUSED)
+{
+  emit_eh_frame = cfi_parse_section_directive ();
+}
+
+static void
+dot_cfi_debug_frame (int ignored ATTRIBUTE_UNUSED)
+{
+  emit_debug_frame = cfi_parse_section_directive ();
+}
 
 /* Emit a single byte into the current segment.  */
 
@@ -1189,7 +1228,7 @@ encoding_size (unsigned char encoding)
 }
 
 static void
-output_cie (struct cie_entry *cie)
+output_cie (struct cie_entry *cie, int eh_frame)
 {
   symbolS *after_size_address, *end_address;
   expressionS exp;
@@ -1208,7 +1247,7 @@ output_cie (struct cie_entry *cie)
 
   emit_expr (&exp, 4);				/* Length.  */
   symbol_set_value_now (after_size_address);
-  out_four (0);					/* CIE id.  */
+  out_four (eh_frame ? 0 : 0xffffffffU);	/* CIE id.  */
   out_one (DW_CIE_VERSION);			/* Version.  */
   out_one ('z');				/* Augmentation.  */
   if (cie->per_encoding != DW_EH_PE_omit)
@@ -1280,7 +1319,8 @@ output_cie (struct cie_entry *cie)
 }
 
 static void
-output_fde (struct fde_entry *fde, struct cie_entry *cie,
+output_fde (int eh_frame,
+	    struct fde_entry *fde, struct cie_entry *cie,
 	    struct cfi_insn_data *first, int align)
 {
   symbolS *after_size_address, *end_address;
@@ -1297,11 +1337,21 @@ output_fde (struct fde_entry *fde, struc
   emit_expr (&exp, 4);				/* Length.  */
   symbol_set_value_now (after_size_address);
 
+  if (eh_frame)
+    {
   exp.X_add_symbol = after_size_address;
   exp.X_op_symbol = cie->start_address;
+    }
+  else
+    {
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = cie->start_address;
+      exp.X_op_symbol = NULL;
+    }
   emit_expr (&exp, 4);				/* CIE offset.  */
 
 #if CFI_DIFF_EXPR_OK
+  exp.X_op = O_subtract;
   exp.X_add_symbol = fde->start_address;
   exp.X_op_symbol = symbol_temp_new_now ();
   emit_expr (&exp, DWARF2_FDE_RELOC_SIZE);	/* Code offset.  */
@@ -1351,7 +1401,8 @@ output_fde (struct fde_entry *fde, struc
 }
 
 static struct cie_entry *
-select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst)
+select_cie_for_fde (struct fde_entry *fde, struct cfi_insn_data **pfirst,
+		    int eh_frame)
 {
   struct cfi_insn_data *i, *j;
   struct cie_entry *cie;
@@ -1447,6 +1498,11 @@ select_cie_for_fde (struct fde_entry *fd
 	      || j->insn == CFI_val_encoded_addr))
 	{
 	  *pfirst = j;
+	  if (cie->emitted_in != eh_frame)
+	    {
+	      cie->emitted_in = eh_frame;
+	      output_cie (cie, eh_frame);
+	    }
 	  return cie;
 	}
 
@@ -1473,21 +1529,55 @@ select_cie_for_fde (struct fde_entry *fd
   cie->last = i;
   *pfirst = i;
    
-  output_cie (cie);
+  cie->emitted_in = eh_frame;
+  output_cie (cie, eh_frame);
 
   return cie;
 }
 
+static void
+output_cfi (int eh_frame, int complain)
+{
+  struct fde_entry *fde;
+  int save_flag_traditional_format;
+
+  /* Make sure check_eh_frame doesn't do anything with our output.  */
+  save_flag_traditional_format = flag_traditional_format;
+  flag_traditional_format = 1;
+
+  for (fde = all_fde_data; fde ; fde = fde->next)
+    {
+      struct cfi_insn_data *first;
+      struct cie_entry *cie;
+
+      if (fde->end_address == NULL)
+	{
+	  if (complain)
+	    as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
+	  fde->end_address = fde->start_address;
+	}
+
+      cie = select_cie_for_fde (fde, &first, eh_frame);
+      output_fde (eh_frame,
+		  fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
+    }
+
+  flag_traditional_format = save_flag_traditional_format;
+}
+
 void
 cfi_finish (void)
 {
   segT cfi_seg;
-  struct fde_entry *fde;
-  int save_flag_traditional_format;
 
   if (all_fde_data == 0)
     return;
 
+  if (debug_type == DEBUG_DWARF2)
+    emit_debug_frame = 1;
+
+  if (emit_eh_frame)
+    {
   /* Open .eh_frame section.  */
   cfi_seg = subseg_new (".eh_frame", 0);
   bfd_set_section_flags (stdoutput, cfi_seg,
@@ -1500,26 +1590,19 @@ cfi_finish (void)
   md_fix_up_eh_frame (cfi_seg);
 #endif
 
-  /* Make sure check_eh_frame doesn't do anything with our output.  */
-  save_flag_traditional_format = flag_traditional_format;
-  flag_traditional_format = 1;
-
-  for (fde = all_fde_data; fde ; fde = fde->next)
-    {
-      struct cfi_insn_data *first;
-      struct cie_entry *cie;
+      output_cfi (1, 1);
+    }
 
-      if (fde->end_address == NULL)
+  if (emit_debug_frame)
 	{
-	  as_bad (_("open CFI at the end of file; missing .cfi_endproc directive"));
-	  fde->end_address = fde->start_address;
-	}
+      /* Open .debug_frame section.  */
+      cfi_seg = subseg_new (".debug_frame", 0);
+      bfd_set_section_flags (stdoutput, cfi_seg, SEC_READONLY | SEC_DEBUGGING);
+      subseg_set (cfi_seg, 0);
+      record_alignment (cfi_seg, EH_FRAME_ALIGNMENT);
 
-      cie = select_cie_for_fde (fde, &first);
-      output_fde (fde, cie, first, fde->next == NULL ? EH_FRAME_ALIGNMENT : 2);
+      output_cfi (0, !emit_eh_frame);
     }
-
-  flag_traditional_format = save_flag_traditional_format;
 }
 
 #else /* TARGET_USE_CFIPOP */
Index: gas/doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.199
diff -b -B -p -u -r1.199 as.texinfo
--- gas/doc/as.texinfo
+++ gas/doc/as.texinfo
@@ -4182,6 +4182,23 @@ undefined.
 Each expression is assembled into the next byte.
 
 @node CFI directives
+@section @code{.cfi_eh_frame} @var{enable}, @code{.cfi_debug_frame} @var{enable}
+@cindex @code{cfi_eh_frame} directive
+@cindex @code{cfi_debug_frame} directive
+@code{.cfi_eh_frame} and/or @code{.cfi_debug_frame} can be used anywhere
+in the file to indicate which of the two CFI sections to emit based on all
+the CFI directives in the file.  @var{enable} is a constant expression
+that is nonzero to explicitly request emitting that section.  If both are
+enabled, both the @code{.eh_frame} and @code{.debug_frame} sections are
+emitted.  (@code{.eh_frame} is an allocated section linked into the
+program text so it occupies memory at run-time.  @code{.debug_frame} is a
+nonallocated section for DWARF debugging and does not remain at run-time;
+it is removed by @code{strip -g}, etc.)  The default is to enable
+@code{.eh_frame} and disable @code{.debug_frame}.  If the
+@samp{--gdwarf-2} or @samp{-g} option is used to produce other DWARF
+information, then @code{.debug_frame} is always enabled regardless of
+these directives.
+
 @section @code{.cfi_startproc [simple]}
 @cindex @code{cfi_startproc} directive
 @code{.cfi_startproc} is used at the beginning of each function that
