This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Enable CFI for PowerPC, try 3


The last two times that we (Jim B, and then Andreas) tried to enable
PowerPC CFI, we ran into problems with GCC.  It used to emit bogus
unwind tables.  This has since been fixed - see the comment in the
patch below for the gory details - but if you get it wrong it's such a
messy and terrible outcome.  So here's some workarounds.

+  /* GCC releases before 3.4 use GCC internal register numbering in
+     .debug_frame (and .debug_info, et cetera).  The numbering is
+     different from the standard SysV numbering for everything except
+     for GPRs and FPRs.  We can not detect this problem in most cases
+     - to get accurate debug info for variables living in lr, ctr, v0,
+     et cetera, use a newer version of GCC.  But we must detect
+     one important case - lr is in column 65 in .debug_frame output,
+     instead of 108.
+
+     GCC 3.4, and the "hammer" branch, have a related problem.  They
+     record lr register saves in .debug_frame as 108, but still record
+     the return column as 65.  We fix that up too.
+
+     We can do this because 65 is assigned to fpsr, and GCC never
+     generates debug info referring to it.  To add support for
+     handwritten debug info that restores fpsr, we would need to add a
+     producer version check to this.  */

I tested this, before and after, with GCC 3.3.6, 3.4.4, and 4.1.1.  It
fixed 23, 24, and 25 failures respectively - most notably we can now
backtrace out of glibc in tls.exp.  The others may be weaknesses in
the prologue analyzer - I didn't look deeply.

I also verified that with CFI, but without the rest of the workaround,
GCC 3.4.4 is unhappy.

Any comments?  And would anyone else like to try this patch before I
check it in?

-- 
Daniel Jacobowitz
CodeSourcery

2007-03-12  Andreas Schwab  <schwab@suse.de>
	    Daniel Jacobowitz  <dan@codesourcery.com>

	* dwarf2-frame.c (dwarf2_frame_eh_frame_regnum): Rename to...
	(dwarf2_frame_adjust_regnum): ...this.  Make static.  Add eh_frame_p
	argument.  Update all callers.
	(struct dwarf2_frame_ops): Replace eh_frame_regnum with adjust_regnum.
	(dwarf2_frame_set_eh_frame_regnum): Rename to...
	(dwarf2_frame_set_adjust_regnum): ...this.  Update argument type.
	* dwarf2frame.h (dwarf2_frame_set_eh_frame_regnum): Rename to...
	(dwarf2_frame_set_adjust_regnum): ...this.
	(dwarf2_frame_eh_frame_regnum): Delete prototype.
	* rs6000-tdep.c: Include "dwarf2-frame.h".
	(rs6000_adjust_frame_regnum): Define.
	(rs6000_gdbarch_init): Enable use of DWARF CFI frame unwinder.
	Register rs6000_adjust_frame_regnum.

	* Makefile.in (rs6000-tdep.o): Update dependencies.

Index: Makefile.in
===================================================================
RCS file: /home/gcc/repos/src/src/gdb/Makefile.in,v
retrieving revision 1.883
diff -u -p -r1.883 Makefile.in
--- Makefile.in	2 Mar 2007 21:28:18 -0000	1.883
+++ Makefile.in	12 Mar 2007 12:23:24 -0000
@@ -2584,7 +2584,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $
 	$(reggroups_h) $(libbfd_h) $(coff_internal_h) $(libcoff_h) \
 	$(coff_xcoff_h) $(libxcoff_h) $(elf_bfd_h) $(solib_svr4_h) \
 	$(ppc_tdep_h) $(gdb_assert_h) $(dis_asm_h) $(trad_frame_h) \
-	$(frame_unwind_h) $(frame_base_h) $(rs6000_tdep_h)
+	$(frame_unwind_h) $(frame_base_h) $(rs6000_tdep_h) $(dwarf2_frame_h)
 rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(osabi_h) $(rs6000_tdep_h) \
 	$(ppc_tdep_h)
 s390-nat.o: s390-nat.c $(defs_h) $(regcache_h) $(inferior_h) \
Index: dwarf2-frame.c
===================================================================
RCS file: /home/gcc/repos/src/src/gdb/dwarf2-frame.c,v
retrieving revision 1.68
diff -u -p -r1.68 dwarf2-frame.c
--- dwarf2-frame.c	27 Feb 2007 20:17:18 -0000	1.68
+++ dwarf2-frame.c	12 Mar 2007 13:36:31 -0000
@@ -107,6 +107,9 @@ struct dwarf2_fde
 };
 
 static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc);
+
+static int dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum,
+				       int eh_frame_p);
 
 
 /* Structure describing a frame state.  */
@@ -314,8 +317,7 @@ execute_cfa_program (gdb_byte *insn_ptr,
       else if ((insn & 0xc0) == DW_CFA_offset)
 	{
 	  reg = insn & 0x3f;
-	  if (eh_frame_p)
-	    reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	  reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	  insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
 	  offset = utmp * fs->data_align;
 	  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
@@ -326,8 +328,7 @@ execute_cfa_program (gdb_byte *insn_ptr,
 	{
 	  gdb_assert (fs->initial.reg);
 	  reg = insn & 0x3f;
-	  if (eh_frame_p)
-	    reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	  reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	  if (reg < fs->initial.num_regs)
 	    fs->regs.reg[reg] = fs->initial.reg[reg];
@@ -368,8 +369,7 @@ register %s (#%d) at 0x%s"),
 
 	    case DW_CFA_offset_extended:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
 	      offset = utmp * fs->data_align;
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
@@ -380,35 +380,30 @@ register %s (#%d) at 0x%s"),
 	    case DW_CFA_restore_extended:
 	      gdb_assert (fs->initial.reg);
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	      fs->regs.reg[reg] = fs->initial.reg[reg];
 	      break;
 
 	    case DW_CFA_undefined:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED;
 	      break;
 
 	    case DW_CFA_same_value:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE;
 	      break;
 
 	    case DW_CFA_register:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
-	      if (eh_frame_p)
-		utmp = dwarf2_frame_eh_frame_regnum (gdbarch, utmp);
+	      utmp = dwarf2_frame_adjust_regnum (gdbarch, utmp, eh_frame_p);
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
 	      fs->regs.reg[reg].loc.reg = utmp;
@@ -456,9 +451,8 @@ bad CFI data; mismatched DW_CFA_restore_
 
 	    case DW_CFA_def_cfa_register:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
-	      if (eh_frame_p)
-		fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch,
-							    fs->cfa_reg);
+	      fs->cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, fs->cfa_reg,
+							eh_frame_p);
 	      fs->cfa_how = CFA_REG_OFFSET;
 	      break;
 
@@ -484,8 +478,7 @@ bad CFI data; mismatched DW_CFA_restore_
 
 	    case DW_CFA_expression:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
 	      fs->regs.reg[reg].loc.exp = insn_ptr;
@@ -496,8 +489,7 @@ bad CFI data; mismatched DW_CFA_restore_
 
 	    case DW_CFA_offset_extended_sf:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
 	      offset *= fs->data_align;
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
@@ -535,9 +527,8 @@ bad CFI data; mismatched DW_CFA_restore_
 
 	    case DW_CFA_def_cfa_sf:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &fs->cfa_reg);
-	      if (eh_frame_p)
-		fs->cfa_reg = dwarf2_frame_eh_frame_regnum (gdbarch,
-							    fs->cfa_reg);
+	      fs->cfa_reg = dwarf2_frame_adjust_regnum (gdbarch, fs->cfa_reg,
+							eh_frame_p);
 	      insn_ptr = read_sleb128 (insn_ptr, insn_end, &offset);
 	      fs->cfa_offset = offset * fs->data_align;
 	      fs->cfa_how = CFA_REG_OFFSET;
@@ -581,8 +572,7 @@ bad CFI data; mismatched DW_CFA_restore_
 
 	    case DW_CFA_GNU_negative_offset_extended:
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &reg);
-	      if (eh_frame_p)
-		reg = dwarf2_frame_eh_frame_regnum (gdbarch, reg);
+	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = read_uleb128 (insn_ptr, insn_end, &offset);
 	      offset *= fs->data_align;
 	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
@@ -617,8 +607,9 @@ struct dwarf2_frame_ops
      trampoline.  */
   int (*signal_frame_p) (struct gdbarch *, struct frame_info *);
 
-  /* Convert .eh_frame register number to DWARF register number.  */
-  int (*eh_frame_regnum) (struct gdbarch *, int);
+  /* Convert .eh_frame register number to DWARF register number, or
+     adjust .debug_frame register number.  */
+  int (*adjust_regnum) (struct gdbarch *, int, int);
 };
 
 /* Default architecture-specific register state initialization
@@ -726,29 +717,30 @@ dwarf2_frame_signal_frame_p (struct gdba
   return ops->signal_frame_p (gdbarch, next_frame);
 }
 
-/* Set the architecture-specific mapping of .eh_frame register numbers to
-   DWARF register numbers.  */
+/* Set the architecture-specific adjustment of .eh_frame and .debug_frame
+   register numbers.  */
 
 void
-dwarf2_frame_set_eh_frame_regnum (struct gdbarch *gdbarch,
-				  int (*eh_frame_regnum) (struct gdbarch *,
-							  int))
+dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch,
+				int (*adjust_regnum) (struct gdbarch *,
+						      int, int))
 {
   struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
 
-  ops->eh_frame_regnum = eh_frame_regnum;
+  ops->adjust_regnum = adjust_regnum;
 }
 
-/* Translate a .eh_frame register to DWARF register.  */
+/* Translate a .eh_frame register to DWARF register, or adjust a .debug_frame
+   register.  */
 
-int
-dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum)
+static int
+dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p)
 {
   struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
 
-  if (ops->eh_frame_regnum == NULL)
+  if (ops->adjust_regnum == NULL)
     return regnum;
-  return ops->eh_frame_regnum (gdbarch, regnum);
+  return ops->adjust_regnum (gdbarch, regnum, eh_frame_p);
 }
 
 static void
@@ -1726,10 +1718,10 @@ decode_frame_entry_1 (struct comp_unit *
       else
 	cie->return_address_register = read_unsigned_leb128 (unit->abfd, buf,
 							     &bytes_read);
-      if (eh_frame_p)
-	cie->return_address_register
-	  = dwarf2_frame_eh_frame_regnum (current_gdbarch,
-					  cie->return_address_register);
+      cie->return_address_register
+	= dwarf2_frame_adjust_regnum (current_gdbarch,
+				      cie->return_address_register,
+				      eh_frame_p);
 
       buf += bytes_read;
 
Index: dwarf2-frame.h
===================================================================
RCS file: /home/gcc/repos/src/src/gdb/dwarf2-frame.h,v
retrieving revision 1.14
diff -u -p -r1.14 dwarf2-frame.h
--- dwarf2-frame.h	9 Jan 2007 17:58:50 -0000	1.14
+++ dwarf2-frame.h	12 Mar 2007 13:26:48 -0000
@@ -94,18 +94,13 @@ extern void
 				   int (*signal_frame_p) (struct gdbarch *,
 							  struct frame_info *));
 
-/* Set the architecture-specific mapping of .eh_frame register numbers to
-   DWARF register numbers.  */
+/* Set the architecture-specific adjustment of .eh_frame and .debug_frame
+   register numbers.  */
 
 extern void
-  dwarf2_frame_set_eh_frame_regnum (struct gdbarch *gdbarch,
-				    int (*eh_frame_regnum) (struct gdbarch *,
-							    int));
-
-/* Translate a .eh_frame register to DWARF register.  */
-
-extern int
-  dwarf2_frame_eh_frame_regnum (struct gdbarch *gdbarch, int regnum);
+  dwarf2_frame_set_adjust_regnum (struct gdbarch *gdbarch,
+				  int (*adjust_regnum) (struct gdbarch *,
+							int, int));
 
 /* Return the frame unwind methods for the function that contains PC,
    or NULL if it can't be handled by DWARF CFI frame unwinder.  */
Index: rs6000-tdep.c
===================================================================
RCS file: /home/gcc/repos/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.265
diff -u -p -r1.265 rs6000-tdep.c
--- rs6000-tdep.c	27 Feb 2007 23:04:28 -0000	1.265
+++ rs6000-tdep.c	12 Mar 2007 13:36:01 -0000
@@ -40,6 +40,7 @@
 #include "sim-regno.h"
 #include "gdb/sim-ppc.h"
 #include "reggroups.h"
+#include "dwarf2-frame.h"
 
 #include "libbfd.h"		/* for bfd_default_set_arch_mach */
 #include "coff/internal.h"	/* for libcoff.h */
@@ -2211,6 +2212,70 @@ e500_pseudo_register_read (struct gdbarc
                     gdbarch_register_name (gdbarch, reg_nr), reg_nr);
 }
 
+/* Translate a .eh_frame register to DWARF register, or adjust a
+   .debug_frame register.  */
+
+static int
+rs6000_adjust_frame_regnum (struct gdbarch *gdbarch, int num, int eh_frame_p)
+{
+  /* GCC releases before 3.4 use GCC internal register numbering in
+     .debug_frame (and .debug_info, et cetera).  The numbering is
+     different from the standard SysV numbering for everything except
+     for GPRs and FPRs.  We can not detect this problem in most cases
+     - to get accurate debug info for variables living in lr, ctr, v0,
+     et cetera, use a newer version of GCC.  But we must detect
+     one important case - lr is in column 65 in .debug_frame output,
+     instead of 108.
+
+     GCC 3.4, and the "hammer" branch, have a related problem.  They
+     record lr register saves in .debug_frame as 108, but still record
+     the return column as 65.  We fix that up too.
+
+     We can do this because 65 is assigned to fpsr, and GCC never
+     generates debug info referring to it.  To add support for
+     handwritten debug info that restores fpsr, we would need to add a
+     producer version check to this.  */
+  if (!eh_frame_p)
+    {
+      if (num == 65)
+	return 108;
+      else
+	return num;
+    }
+
+  /* .eh_frame is GCC specific.  For binary compatibility, it uses GCC
+     internal register numbering; translate that to the standard DWARF2
+     register numbering.  */
+  if (0 <= num && num <= 63)	/* r0-r31,fp0-fp31 */
+    return num;
+  else if (68 <= num && num <= 75) /* cr0-cr8 */
+    return num - 68 + 86;
+  else if (77 <= num && num <= 108) /* vr0-vr31 */
+    return num - 77 + 1124;
+  else
+    switch (num)
+      {
+      case 64: /* mq */
+	return 100;
+      case 65: /* lr */
+	return 108;
+      case 66: /* ctr */
+	return 109;
+      case 76: /* xer */
+	return 101;
+      case 109: /* vrsave */
+	return 356;
+      case 110: /* vscr */
+	return 67;
+      case 111: /* spe_acc */
+	return 99;
+      case 112: /* spefscr */
+	return 612;
+      default:
+	return num;
+      }
+}
+
 static void
 e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
 			    int reg_nr, const gdb_byte *buffer)
@@ -3471,6 +3536,10 @@ rs6000_gdbarch_init (struct gdbarch_info
     (gdbarch, rs6000_in_solib_return_trampoline);
   set_gdbarch_skip_trampoline_code (gdbarch, rs6000_skip_trampoline_code);
 
+  /* Hook in the DWARF CFI frame unwinder.  */
+  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+  dwarf2_frame_set_adjust_regnum (gdbarch, rs6000_adjust_frame_regnum);
+
   /* Hook in ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]