This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

unwind-on-signal support for powerpc-darwin


The attached patch:

- Implements a fallback unwinder for Darwin that can understand
  sigreturn and signal frames.
- Supplies the appropriate libjava stuff to use it.
- Switches on various testcases.  After discussion with rth and zack
  it seems like cleanup-5 should actually work even on hpux,
  and all the cleanup tests should work on all Linux platforms (and
  now on powerpc-darwin).
- Makes the powerpc unwind information be correct.

  The PPC prologue can do things like

  mflr r0  // save lr in r0
  // something that clobbers lr
  lwz r7,0(r3)  // might cause an signal, scheduled up from below
  stw r0,4(r1)  // actually put lr on stack

  and was previously summarising this by just providing unwind
  information for the last instruction.  It had good cause to do this,
  since dwarf2out didn't actually support describing saving a
  register in a register.  However, that won't cut it if you want
  unwind-on-signal to work, and in fact PR 15813 was a case where
  this didn't work on powerpc-linux.

  The PPC prologue can also do things like

  mflr r0  // save lr in r0
  // something that clobbers lr
  lwz r7,0(r3)  // might cause an signal, scheduled up from below
  mtlr r0  // restore lr
  // something that clobbers r0
  // rest of routine

  and so it needs to generate DW_CFA_same_value to express that
  the link register has been restored.

This patch has been tested with a bootstrap on powerpc-darwin, on
both a G4 and G5.  There were no C++ testsuite regressions, and now
all the libjava testsuite passes on both versions.

-- 
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/rs6000-darwin-unwindfallback-5.patch======
Index: gcc/ChangeLog
2004-06-28  Geoffrey Keating  <geoffk@apple.com>
	    Andreas Tobler  <a.tobler@schweiz.ch>

	PR 15813
	* dwarf2out.c (reg_save): Output DW_CFA_same_value when a
	register is saved in itself.
	(initial_return_save): If the return address is a register,
	it's already there, don't bother to mention it in the CFI.
	(struct queued_reg_save): Add field saved_reg.
	(struct reg_saved_in_data): New.
	(regs_saved_in_regs): New.
	(num_regs_saved_in_regs): New.
	(queue_reg_save): Add extra parameter to specify register saved
	in register.  Remove duplicate entries from queue.  Add comment
	for function.
	(flush_queued_reg_saves): Handle registers saved in registers.
	Update regs_saved_in_regs.  Add comment for function.
	(clobbers_queued_reg_save): Add comment for function.  Allow
	for regs_saved_in_regs.
	(reg_saved_in): New.
	(dwarf2out_frame_debug_expr): Handle saving registers in other
	registers.
	(dwarf2out_frame_debug): Reset regs_saved_in_regs.
	* unwind-dw2.c (execute_cfa_program): Correct handling of
	DW_CFA_same_value.  Add FIXME comment about incorrect implementation
	of DW_CFA_restore_extended.
	* config/rs6000/rs6000.c (rs6000_emit_prologue): Let
	dwarf2out_frame_debug_expr see instructions that save registers
	in other registers or save those other registers in memory.

	* unwind-dw2.c (DWARF_FRAME_REGISTERS): Move to unwind-dw2.h.
	(_Unwind_FrameState): Likewise.
	* unwind-dw2.h: New.
	* Makefile.in (LIB2ADDEHDEP): Add unwind-dw2.h.
	* config/rs6000/darwin-fallback.c: New file.
	* config/rs6000/darwin.h (MD_FALLBACK_FRAME_STATE_FOR): Define.
	* config/rs6000/t-darwin (LIB2FUNCS_EXTRA): Add darwin-fallback.o.

Index: gcc/testsuite/ChangeLog
2004-06-26  Geoffrey Keating  <geoffk@apple.com>
	    Andreas Tobler  <a.tobler@schweiz.ch>

	* gcc.dg/cleanup-10.c: Run on all Linux platforms and powerpc-darwin.
	Use SA_RESETHAND rather than SA_ONESHOT.  Trap SIGBUS as well
	as SIGSEGV.
	* gcc.dg/cleanup-11.c: Likewise.
	* gcc.dg/cleanup-8.c: Likewise.
	* gcc.dg/cleanup-9.c: Likewise.
	* gcc.dg/cleanup-5.c: Run on all platforms.

Index: libjava/ChangeLog
2004-06-26  Geoffrey Keating  <geoffk@apple.com>
	    Andreas Tobler  <a.tobler@schweiz.ch>

	* configure.host (powerpc-*-darwin*): New case, define
	can_unwind_signal.
	* configure.in (*-*-darwin*): New case, point to darwin-signal.h.
	* configure: Regenerate.
	* include/darwin-signal.h: New.

Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1309
diff -u -p -u -p -r1.1309 Makefile.in
--- gcc/Makefile.in	28 Jun 2004 18:27:02 -0000	1.1309
+++ gcc/Makefile.in	30 Jun 2004 20:21:50 -0000
@@ -528,7 +528,7 @@ CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(IN
 # Additional sources to handle exceptions; overridden by targets as needed.
 LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \
    $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c
-LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h
+LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h unwind-dw2.h
 
 # nm flags to list global symbols in libgcc object files.
 SHLIB_NM_FLAGS = -pg
Index: gcc/dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.522
diff -u -p -u -p -r1.522 dwarf2out.c
--- gcc/dwarf2out.c	15 Jun 2004 18:02:15 -0000	1.522
+++ gcc/dwarf2out.c	30 Jun 2004 20:21:51 -0000
@@ -359,7 +359,6 @@ static HOST_WIDE_INT stack_adjust_offset
 static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
 static void output_call_frame_info (int);
 static void dwarf2out_stack_adjust (rtx);
-static void queue_reg_save (const char *, rtx, HOST_WIDE_INT);
 static void flush_queued_reg_saves (void);
 static bool clobbers_queued_reg_save (rtx);
 static void dwarf2out_frame_debug_expr (rtx, const char *);
@@ -843,8 +842,7 @@ reg_save (const char *label, unsigned in
       cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
     }
   else if (sreg == reg)
-    /* We could emit a DW_CFA_same_value in this case, but don't bother.  */
-    return;
+    cfi->dw_cfi_opc = DW_CFA_same_value;
   else
     {
       cfi->dw_cfi_opc = DW_CFA_register;
@@ -974,7 +972,8 @@ initial_return_save (rtx rtl)
       abort ();
     }
 
-  reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
+  if (reg != DWARF_FRAME_RETURN_COLUMN)
+    reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
 }
 
 /* Given a SET, calculate the amount of stack adjustment it
@@ -1144,53 +1143,134 @@ struct queued_reg_save GTY(())
   struct queued_reg_save *next;
   rtx reg;
   HOST_WIDE_INT cfa_offset;
+  rtx saved_reg;
 };
 
 static GTY(()) struct queued_reg_save *queued_reg_saves;
 
+/* The caller's ORIG_REG is saved in SAVED_IN_REG.  */
+struct reg_saved_in_data GTY(()) {
+  rtx orig_reg;
+  rtx saved_in_reg;
+};
+
+/* A list of registers saved in other registers.
+   The list intentionally has a small maximum capacity of 4; if your
+   port needs more than that, you might consider implementing a
+   more efficient data structure.  */
+static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
+static GTY(()) size_t num_regs_saved_in_regs;
+  
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 static const char *last_reg_save_label;
 
+/* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
+   SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.  */
+
 static void
-queue_reg_save (const char *label, rtx reg, HOST_WIDE_INT offset)
+queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
 {
-  struct queued_reg_save *q = ggc_alloc (sizeof (*q));
+  struct queued_reg_save *q;
+
+  /* Duplicates waste space, but it's also necessary to remove them
+     for correctness, since the queue gets output in reverse
+     order.  */
+  for (q = queued_reg_saves; q != NULL; q = q->next)
+    if (REGNO (q->reg) == REGNO (reg))
+      break;
+
+  if (q == NULL)
+    {
+      q = ggc_alloc (sizeof (*q));
+      q->next = queued_reg_saves;
+      queued_reg_saves = q;
+    }
 
-  q->next = queued_reg_saves;
   q->reg = reg;
   q->cfa_offset = offset;
-  queued_reg_saves = q;
+  q->saved_reg = sreg;
 
   last_reg_save_label = label;
 }
 
+/* Output all the entries in QUEUED_REG_SAVES.  */
+
 static void
 flush_queued_reg_saves (void)
 {
-  struct queued_reg_save *q, *next;
+  struct queued_reg_save *q;
 
-  for (q = queued_reg_saves; q; q = next)
+  for (q = queued_reg_saves; q; q = q->next)
     {
-      dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset);
-      next = q->next;
+      size_t i;
+      for (i = 0; i < num_regs_saved_in_regs; i++)
+	if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
+	  break;
+      if (q->saved_reg && i == num_regs_saved_in_regs)
+	{
+	  if (i == ARRAY_SIZE (regs_saved_in_regs))
+	    abort ();
+	  num_regs_saved_in_regs++;
+	}
+      if (i != num_regs_saved_in_regs)
+	{
+	  regs_saved_in_regs[i].orig_reg = q->reg;
+	  regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
+	}
+
+      reg_save (last_reg_save_label, REGNO (q->reg), 
+		q->saved_reg ? REGNO (q->saved_reg) : -1U, q->cfa_offset);
     }
 
   queued_reg_saves = NULL;
   last_reg_save_label = NULL;
 }
 
+/* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
+   location for?  Or, does it clobber a register which we've previously
+   said that some other register is saved in, and for which we now
+   have a new location for?  */
+
 static bool
 clobbers_queued_reg_save (rtx insn)
 {
   struct queued_reg_save *q;
 
   for (q = queued_reg_saves; q; q = q->next)
-    if (modified_in_p (q->reg, insn))
-      return true;
+    {
+      size_t i;
+      if (modified_in_p (q->reg, insn))
+	return true;
+      for (i = 0; i < num_regs_saved_in_regs; i++)
+	if (REGNO (q->reg) == REGNO (regs_saved_in_regs[i].orig_reg)
+	    && modified_in_p (regs_saved_in_regs[i].saved_in_reg, insn))
+	  return true;
+    }
 
   return false;
 }
 
+/* What register, if any, is currently saved in REG?  */
+
+static rtx
+reg_saved_in (rtx reg)
+{
+  unsigned int regn = REGNO (reg);
+  size_t i;
+  struct queued_reg_save *q;
+  
+  for (q = queued_reg_saves; q; q = q->next)
+    if (q->saved_reg && regn == REGNO (q->saved_reg))
+      return q->reg;
+
+  for (i = 0; i < num_regs_saved_in_regs; i++)
+    if (regs_saved_in_regs[i].saved_in_reg
+	&& regn == REGNO (regs_saved_in_regs[i].saved_in_reg))
+      return regs_saved_in_regs[i].orig_reg;
+
+  return NULL_RTX;
+}
+
 
 /* A temporary register holding an integral value used in adjusting SP
    or setting up the store_reg.  The "offset" field holds the integer
@@ -1199,8 +1279,8 @@ static dw_cfa_location cfa_temp;
 
 /* Record call frame debugging information for an expression EXPR,
    which either sets SP or FP (adjusting how we calculate the frame
-   address) or saves a register to the stack.  LABEL indicates the
-   address of EXPR.
+   address) or saves a register to the stack or another register.
+   LABEL indicates the address of EXPR.
 
    This function encodes a state machine mapping rtxes to actions on
    cfa, cfa_store, and cfa_temp.reg.  We describe these rules so
@@ -1224,12 +1304,20 @@ static dw_cfa_location cfa_temp;
   RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a
   register save, and the register used to calculate the destination
   had better be the one we think we're using for this purpose.
+  It's also assumed that a copy from a call-saved register to another
+  register is saving that register if RTX_FRAME_RELATED_P is set on
+  that instruction.  If the copy is from a call-saved register to
+  the *same* register, that means that the register is now the same
+  value as in the caller.
 
   Except: If the register being saved is the CFA register, and the
   offset is nonzero, we are saving the CFA, so we assume we have to
   use DW_CFA_def_cfa_expression.  If the offset is 0, we assume that
   the intent is to save the value of SP from the previous frame.
 
+  In addition, if a register has previously been saved to a different
+  register, 
+
   Invariants / Summaries of Rules
 
   cfa	       current rule for calculating the CFA.  It usually
@@ -1380,29 +1468,42 @@ dwarf2out_frame_debug_expr (rtx expr, co
   src = SET_SRC (expr);
   dest = SET_DEST (expr);
 
+  if (GET_CODE (src) == REG)
+    {
+      rtx rsi = reg_saved_in (src);
+      if (rsi)
+	src = rsi;
+    }
+
   switch (GET_CODE (dest))
     {
     case REG:
-      /* Rule 1 */
-      /* Update the CFA rule wrt SP or FP.  Make sure src is
-	 relative to the current CFA register.  */
       switch (GET_CODE (src))
 	{
 	  /* Setting FP from SP.  */
 	case REG:
 	  if (cfa.reg == (unsigned) REGNO (src))
-	    /* OK.  */
-	    ;
+	    {
+	      /* Rule 1 */
+	      /* Update the CFA rule wrt SP or FP.  Make sure src is
+		 relative to the current CFA register. 
+
+		 We used to require that dest be either SP or FP, but the
+		 ARM copies SP to a temporary register, and from there to
+		 FP.  So we just rely on the backends to only set
+		 RTX_FRAME_RELATED_P on appropriate insns.  */
+	      cfa.reg = REGNO (dest);
+	      cfa_temp.reg = cfa.reg;
+	      cfa_temp.offset = cfa.offset;
+	    }
+	  else if (call_used_regs [REGNO (dest)] 
+		   && ! fixed_regs [REGNO (dest)])
+	    {
+	      /* Saving a register in a register.  */
+	      queue_reg_save (label, src, dest, 0);
+	    }
 	  else
 	    abort ();
-
-	  /* We used to require that dest be either SP or FP, but the
-	     ARM copies SP to a temporary register, and from there to
-	     FP.  So we just rely on the backends to only set
-	     RTX_FRAME_RELATED_P on appropriate insns.  */
-	  cfa.reg = REGNO (dest);
-	  cfa_temp.reg = cfa.reg;
-	  cfa_temp.offset = cfa.offset;
 	  break;
 
 	case PLUS:
@@ -1642,7 +1743,7 @@ dwarf2out_frame_debug_expr (rtx expr, co
 		 we're saving SP like any other register; this happens
 		 on the ARM.  */
 	      def_cfa_1 (label, &cfa);
-	      queue_reg_save (label, stack_pointer_rtx, offset);
+	      queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset);
 	      break;
 	    }
 	  else
@@ -1665,7 +1766,7 @@ dwarf2out_frame_debug_expr (rtx expr, co
 	}
 
       def_cfa_1 (label, &cfa);
-      queue_reg_save (label, src, offset);
+      queue_reg_save (label, src, NULL_RTX, offset);
       break;
 
     default:
@@ -1685,6 +1786,8 @@ dwarf2out_frame_debug (rtx insn)
 
   if (insn == NULL_RTX)
     {
+      size_t i;
+      
       /* Flush any queued register saves.  */
       flush_queued_reg_saves ();
 
@@ -1697,6 +1800,13 @@ dwarf2out_frame_debug (rtx insn)
       cfa_store = cfa;
       cfa_temp.reg = -1;
       cfa_temp.offset = 0;
+      
+      for (i = 0; i < num_regs_saved_in_regs; i++)
+	{
+	  regs_saved_in_regs[i].orig_reg = NULL_RTX;
+	  regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
+	}
+      num_regs_saved_in_regs = 0;
       return;
     }
 
Index: gcc/unwind-dw2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/unwind-dw2.c,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 unwind-dw2.c
--- gcc/unwind-dw2.c	20 May 2004 22:34:58 -0000	1.41
+++ gcc/unwind-dw2.c	30 Jun 2004 20:21:51 -0000
@@ -40,7 +40,7 @@
 #include "unwind-pe.h"
 #include "unwind-dw2-fde.h"
 #include "gthr.h"
-
+#include "unwind-dw2.h"
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
 
@@ -51,12 +51,6 @@
 #define STACK_GROWS_DOWNWARD 1
 #endif
 
-/* A target can override (perhaps for backward compatibility) how
-   many dwarf2 columns are unwound.  */
-#ifndef DWARF_FRAME_REGISTERS
-#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
-#endif
-
 /* Dwarf frame registers used for pre gcc 3.0 compiled glibc.  */
 #ifndef PRE_GCC3_DWARF_FRAME_REGISTERS
 #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
@@ -88,58 +82,6 @@ struct _Unwind_Context
 static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
 
 
-/* The result of interpreting the frame unwind info for a frame.
-   This is all symbolic at this point, as none of the values can
-   be resolved until the target pc is located.  */
-typedef struct
-{
-  /* Each register save state can be described in terms of a CFA slot,
-     another register, or a location expression.  */
-  struct frame_state_reg_info
-  {
-    struct {
-      union {
-	_Unwind_Word reg;
-	_Unwind_Sword offset;
-	const unsigned char *exp;
-      } loc;
-      enum {
-	REG_UNSAVED,
-	REG_SAVED_OFFSET,
-	REG_SAVED_REG,
-	REG_SAVED_EXP
-      } how;
-    } reg[DWARF_FRAME_REGISTERS+1];
-
-    /* Used to implement DW_CFA_remember_state.  */
-    struct frame_state_reg_info *prev;
-  } regs;
-
-  /* The CFA can be described in terms of a reg+offset or a
-     location expression.  */
-  _Unwind_Sword cfa_offset;
-  _Unwind_Word cfa_reg;
-  const unsigned char *cfa_exp;
-  enum {
-    CFA_UNSET,
-    CFA_REG_OFFSET,
-    CFA_EXP
-  } cfa_how;
-
-  /* The PC described by the current frame state.  */
-  void *pc;
-
-  /* The information we care about from the CIE/FDE.  */
-  _Unwind_Personality_Fn personality;
-  _Unwind_Sword data_align;
-  _Unwind_Word code_align;
-  _Unwind_Word retaddr_column;
-  unsigned char fde_encoding;
-  unsigned char lsda_encoding;
-  unsigned char saw_z;
-  void *eh_ptr;
-} _Unwind_FrameState;
-
 /* Read unaligned data from the instruction buffer.  */
 
 union unaligned
@@ -866,12 +808,15 @@ execute_cfa_program (const unsigned char
 
 	case DW_CFA_restore_extended:
 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  /* FIXME, this is wrong; the CIE might have said that the
+	     register was saved somewhere.  */
 	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
 	  break;
 
 	case DW_CFA_undefined:
 	case DW_CFA_same_value:
 	  insn_ptr = read_uleb128 (insn_ptr, &reg);
+	  fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
 	  break;
 
 	case DW_CFA_nop:
Index: gcc/unwind-dw2.h
===================================================================
RCS file: gcc/unwind-dw2.h
diff -N gcc/unwind-dw2.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/unwind-dw2.h	30 Jun 2004 20:21:51 -0000
@@ -0,0 +1,88 @@
+/* DWARF2 frame unwind data structure.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combined
+   executable.)
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* A target can override (perhaps for backward compatibility) how
+   many dwarf2 columns are unwound.  */
+#ifndef DWARF_FRAME_REGISTERS
+#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
+#endif
+
+/* The result of interpreting the frame unwind info for a frame.
+   This is all symbolic at this point, as none of the values can
+   be resolved until the target pc is located.  */
+typedef struct
+{
+  /* Each register save state can be described in terms of a CFA slot,
+     another register, or a location expression.  */
+  struct frame_state_reg_info
+  {
+    struct {
+      union {
+	_Unwind_Word reg;
+	_Unwind_Sword offset;
+	const unsigned char *exp;
+      } loc;
+      enum {
+	REG_UNSAVED,
+	REG_SAVED_OFFSET,
+	REG_SAVED_REG,
+	REG_SAVED_EXP
+      } how;
+    } reg[DWARF_FRAME_REGISTERS+1];
+
+    /* Used to implement DW_CFA_remember_state.  */
+    struct frame_state_reg_info *prev;
+  } regs;
+
+  /* The CFA can be described in terms of a reg+offset or a
+     location expression.  */
+  _Unwind_Sword cfa_offset;
+  _Unwind_Word cfa_reg;
+  const unsigned char *cfa_exp;
+  enum {
+    CFA_UNSET,
+    CFA_REG_OFFSET,
+    CFA_EXP
+  } cfa_how;
+
+  /* The PC described by the current frame state.  */
+  void *pc;
+
+  /* The information we care about from the CIE/FDE.  */
+  _Unwind_Personality_Fn personality;
+  _Unwind_Sword data_align;
+  _Unwind_Word code_align;
+  _Unwind_Word retaddr_column;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
+  void *eh_ptr;
+} _Unwind_FrameState;
+
Index: gcc/config/rs6000/darwin-fallback.c
===================================================================
RCS file: gcc/config/rs6000/darwin-fallback.c
diff -N gcc/config/rs6000/darwin-fallback.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/config/rs6000/darwin-fallback.c	30 Jun 2004 20:21:52 -0000
@@ -0,0 +1,432 @@
+/* Fallback frame-state unwinder for Darwin.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   In addition to the permissions in the GNU General Public License, the
+   Free Software Foundation gives you unlimited permission to link the
+   compiled version of this file into combinations with other programs,
+   and to distribute those combinations without any restriction coming
+   from the use of this file.  (The General Public License restrictions
+   do apply in other respects; for example, they cover modification of
+   the file, and distribution when not linked into a combined
+   executable.)
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "dwarf2.h"
+#include "unwind.h"
+#include "unwind-dw2.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <ucontext.h>
+
+typedef unsigned long reg_unit;
+
+/* Place in GPRS the parameters to the first 'sc' instruction that would
+   have been executed if we were returning from this CONTEXT, or
+   return false if an unexpected instruction is encountered.  */
+
+static bool
+interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context)
+{
+  uint32_t *pc = (uint32_t *)_Unwind_GetIP (context);
+  uint32_t cr;
+  reg_unit lr = (reg_unit) pc;
+  reg_unit ctr = 0;
+  uint32_t *invalid_address = NULL;
+
+  int i;
+
+  for (i = 0; i < 13; i++)
+    gprs[i] = 1;
+  gprs[1] = _Unwind_GetCFA (context);
+  for (; i < 32; i++)
+    gprs[i] = _Unwind_GetGR (context, i);
+  cr = _Unwind_GetGR (context, CR2_REGNO);
+
+  /* For each supported Libc, we have to track the code flow
+     all the way back into the kernel.
+  
+     This code is believed to support all released Libc/Libsystem builds since
+     Jaguar 6C115, including all the security updates.  To be precise,
+
+     Libc	Libsystem	Build(s)
+     262~1	60~37		6C115
+     262~1	60.2~4		6D52
+     262~1	61~3		6F21-6F22
+     262~1	63~24		6G30-6G37
+     262~1	63~32		6I34-6I35
+     262~1	63~64		6L29-6L60
+     262.4.1~1	63~84		6L123-6R172
+     
+     320~1	71~101		7B85-7D28
+     320~1	71~266		7F54-7F56
+     320~1	71~288		7F112
+     320~1	71~289		7F113
+     320.1.3~1	71.1.1~29	7H60-7H105
+     320.1.3~1	71.1.1~30	7H110-7H113
+     320.1.3~1	71.1.1~31	7H114
+     
+     That's a big table!  It would be insane to try to keep track of
+     every little detail, so we just read the code itself and do what
+     it would do.
+  */
+
+  for (;;)
+    {
+      uint32_t ins = *pc++;
+      
+      if ((ins & 0xFC000003) == 0x48000000)  /* b instruction */
+	{
+	  pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4;
+	  continue;
+	}
+      if ((ins & 0xFC600000) == 0x2C000000)  /* cmpwi */
+	{
+	  int32_t val1 = (int16_t) ins;
+	  int32_t val2 = gprs[ins >> 16 & 0x1F];
+	  /* Only beq and bne instructions are supported, so we only
+	     need to set the EQ bit.  */
+	  uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C);
+	  if (val1 == val2)
+	    cr |= mask;
+	  else
+	    cr &= ~mask;
+	  continue;
+	}
+      if ((ins & 0xFEC38003) == 0x40820000)  /* forwards beq/bne */
+	{
+	  if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1))
+	    pc += (ins & 0x7FFC) / 4 - 1;
+	  continue;
+	}
+      if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */
+	{
+	  gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F] 
+				     | gprs [ins >> 21 & 0x1F]);
+	  continue;
+	}
+      if (ins >> 26 == 0x0E)  /* addi, including li */
+	{
+	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
+	  gprs [ins >> 21 & 0x1F] = src + (int16_t) ins;
+	  continue;
+	}
+      if (ins >> 26 == 0x0F)  /* addis, including lis */
+	{
+	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
+	  gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16);
+	  continue;
+	}
+      if (ins >> 26 == 0x20)  /* lwz */
+	{
+	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
+	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
+	  if (p == invalid_address)
+	    return false;
+	  gprs [ins >> 21 & 0x1F] = *p;
+	  continue;
+	}
+      if (ins >> 26 == 0x21)  /* lwzu */
+	{
+	  uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins);
+	  if (p == invalid_address)
+	    return false;
+	  gprs [ins >> 21 & 0x1F] = *p;
+	  continue;
+	}
+      if (ins >> 26 == 0x24)  /* stw */
+	/* What we hope this is doing is '--in_sigtramp'.  We don't want
+	   to actually store to memory, so just make a note of the
+	   address and refuse to load from it.  */
+	{
+	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
+	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
+	  if (p == NULL || invalid_address != NULL)
+	    return false;
+	  invalid_address = p;
+	  continue;
+	}
+      if (ins >> 26 == 0x2E) /* lmw */
+	{
+	  reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F];
+	  uint32_t *p = (uint32_t *)(src + (int16_t) ins);
+	  int i;
+
+	  for (i = (ins >> 21 & 0x1F); i < 32; i++)
+	    {
+	      if (p == invalid_address)
+		return false;
+	      gprs[i] = *p++;
+	    }
+	  continue;
+	}
+      if ((ins & 0xFC1FFFFF) == 0x7c0803a6)  /* mtlr */
+	{
+	  lr = gprs [ins >> 21 & 0x1F];
+	  continue;
+	}
+      if ((ins & 0xFC1FFFFF) == 0x7c0802a6)  /* mflr */
+	{
+	  gprs [ins >> 21 & 0x1F] = lr;
+	  continue;
+	}
+      if ((ins & 0xFC1FFFFF) == 0x7c0903a6)  /* mtctr */
+	{
+	  ctr = gprs [ins >> 21 & 0x1F];
+	  continue;
+	}
+      /* The PowerPC User's Manual says that bit 11 of the mtcrf
+	 instruction is reserved and should be set to zero, but it
+	 looks like the Darwin assembler doesn't do that... */
+      if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */
+	{
+	  int i;
+	  uint32_t mask = 0;
+	  for (i = 0; i < 8; i++)
+	    mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i;
+	  cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask);
+	  continue;
+	}
+      if (ins == 0x429f0005)  /* bcl- 20,4*cr7+so,.+4, loads pc into LR */
+	{
+	  lr = (reg_unit) pc;
+	  continue;
+	}
+      if (ins == 0x4e800420) /* bctr */
+	{
+	  pc = (uint32_t *) ctr;
+	  continue;
+	}
+      if (ins == 0x44000002) /* sc */
+	return true;
+
+      return false;
+    }
+}
+
+/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c.  */
+#define UC_TRAD                 1
+#define UC_TRAD_VEC             6
+#define UC_TRAD64               20
+#define UC_TRAD64_VEC           25
+#define UC_FLAVOR               30
+#define UC_FLAVOR_VEC           35
+#define UC_FLAVOR64             40
+#define UC_FLAVOR64_VEC         45
+#define UC_DUAL                 50
+#define UC_DUAL_VEC             55
+
+/* These are based on /usr/include/ppc/ucontext.h and
+   /usr/include/mach/ppc/thread_status.h, but rewritten to be more
+   convenient, to compile on Jaguar, and to work around Radar 3712064
+   on Panther, which is that the 'es' field of 'struct mcontext64' has
+   the wrong type (doh!).  */
+
+struct gcc_mcontext64 {
+  uint64_t dar;
+  uint32_t dsisr;
+  uint32_t exception;
+  uint32_t padding1[4];
+  uint64_t srr0;
+  uint64_t srr1;
+  uint32_t gpr[32][2];
+  uint32_t cr;
+  uint32_t xer[2];  /* These are arrays because the original structure has them misaligned.  */
+  uint32_t lr[2];
+  uint32_t ctr[2];
+  uint32_t vrsave;
+  ppc_float_state_t fs;
+  ppc_vector_state_t vs;
+};
+
+#define UC_FLAVOR_SIZE \
+  (sizeof (struct mcontext) - sizeof (ppc_vector_state_t))
+
+#define UC_FLAVOR_VEC_SIZE (sizeof (struct mcontext))
+
+#define UC_FLAVOR64_SIZE \
+  (sizeof (struct gcc_mcontext64) - sizeof (ppc_vector_state_t))
+
+#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64))
+
+/* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS
+   to represent the execution of a signal return; or, if not a signal
+   return, return false.  */
+
+static bool
+handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32],
+		_Unwind_Ptr old_cfa)
+{
+  struct ucontext *uctx;
+  bool is_64, is_vector;
+  ppc_float_state_t *float_state;
+  ppc_vector_state_t *vector_state;
+  _Unwind_Ptr new_cfa;
+  int i;
+  static _Unwind_Ptr return_addr;
+  
+  /* Yay!  We're in a Libc that we understand, and it's made a
+     system call.  It'll be one of two kinds: either a Jaguar-style
+     SYS_sigreturn, or a Panther-style 'syscall' call with 184, which 
+     is also SYS_sigreturn.  */
+  
+  if (gprs[0] == 0x67 /* SYS_SIGRETURN */)
+    {
+      uctx = (struct ucontext *) gprs[3];
+      is_vector = (uctx->uc_mcsize == UC_FLAVOR64_VEC_SIZE
+		   || uctx->uc_mcsize == UC_FLAVOR_VEC_SIZE);
+      is_64 = (uctx->uc_mcsize == UC_FLAVOR64_VEC_SIZE
+	       || uctx->uc_mcsize == UC_FLAVOR64_SIZE);
+    }
+  else if (gprs[0] == 0 && gprs[3] == 184)
+    {
+      int ctxstyle = gprs[5];
+      uctx = (struct ucontext *) gprs[4];
+      is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC
+		   || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC);
+      is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC
+	       || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64);
+    }
+  else
+    return false;
+
+#define set_offset(r, addr)					\
+  (fs->regs.reg[r].how = REG_SAVED_OFFSET,			\
+   fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa)
+
+  /* Restore even the registers that are not call-saved, since they
+     might be being used in the prologue to save other registers,
+     for instance GPR0 is sometimes used to save LR.  */
+
+  /* Handle the GPRs, and produce the information needed to do the rest.  */
+  if (is_64)
+    {
+      /* The context is 64-bit, but it doesn't carry any extra information
+	 for us because only the low 32 bits of the registers are
+	 call-saved.  */
+      struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->uc_mcontext;
+      int i;
+
+      float_state = &m64->fs;
+      vector_state = &m64->vs;
+
+      new_cfa = m64->gpr[1][1];
+      
+      set_offset (CR2_REGNO, &m64->cr);
+      for (i = 0; i < 32; i++)
+	set_offset (i, m64->gpr[i] + 1);
+      set_offset (XER_REGNO, m64->xer + 1);
+      set_offset (LINK_REGISTER_REGNUM, m64->lr + 1);
+      set_offset (COUNT_REGISTER_REGNUM, m64->ctr + 1);
+      if (is_vector)
+	set_offset (VRSAVE_REGNO, &m64->vrsave);
+      
+      /* Sometimes, srr0 points to the instruction that caused the exception,
+	 and sometimes to the next instruction to be executed; we want
+	 the latter.  */
+      if (m64->exception == 3 || m64->exception == 4
+	  || m64->exception == 6
+	  || (m64->exception == 7 && !(m64->srr1 & 0x10000)))
+	return_addr = m64->srr0 + 4;
+      else
+	return_addr = m64->srr0;
+    }
+  else
+    {
+      struct mcontext *m = uctx->uc_mcontext;
+      int i;
+
+      float_state = &m->fs;
+      vector_state = &m->vs;
+      
+      new_cfa = m->ss.r1;
+
+      set_offset (CR2_REGNO, &m->ss.cr);
+      for (i = 0; i < 32; i++)
+	set_offset (i, &m->ss.r0 + i);
+      set_offset (XER_REGNO, &m->ss.xer);
+      set_offset (LINK_REGISTER_REGNUM, &m->ss.lr);
+      set_offset (COUNT_REGISTER_REGNUM, &m->ss.ctr);
+
+      if (is_vector)
+	set_offset (VRSAVE_REGNO, &m->ss.vrsave);
+
+      /* Sometimes, srr0 points to the instruction that caused the exception,
+	 and sometimes to the next instruction to be executed; we want
+	 the latter.  */
+      if (m->es.exception == 3 || m->es.exception == 4
+	  || m->es.exception == 6
+	  || (m->es.exception == 7 && !(m->ss.srr1 & 0x10000)))
+	return_addr = m->ss.srr0 + 4;
+      else
+	return_addr = m->ss.srr0;
+    }
+
+  fs->cfa_how = CFA_REG_OFFSET;
+  fs->cfa_reg = STACK_POINTER_REGNUM;
+  fs->cfa_offset = new_cfa - old_cfa;;
+  
+  /* The choice of column for the return address is somewhat tricky.
+     Fortunately, the actual choice is private to this file, and
+     the space it's reserved from is the GCC register space, not the
+     DWARF2 numbering.  So any free element of the right size is an OK
+     choice.  Thus: */
+  fs->retaddr_column = ARG_POINTER_REGNUM;
+  /* FIXME: this should really be done using a DWARF2 location expression,
+     not using a static variable.  In fact, this entire file should
+     be implemented in DWARF2 expressions.  */
+  set_offset (ARG_POINTER_REGNUM, &return_addr);
+
+  for (i = 0; i < 32; i++)
+    set_offset (32 + i, float_state->fpregs + i);
+  set_offset (SPEFSCR_REGNO, &float_state->fpscr);
+  
+  if (is_vector)
+    {
+      for (i = 0; i < 32; i++)
+	set_offset (FIRST_ALTIVEC_REGNO + i, vector_state->save_vr + i);
+      set_offset (VSCR_REGNO, vector_state->save_vscr);
+    }
+
+  return true;
+}
+
+/* This is also prototyped in rs6000/darwin.h, inside the
+   MD_FALLBACK_FRAME_STATE_FOR macro.  */
+extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
+					      _Unwind_FrameState *fs);
+
+/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro,
+   returning true iff the frame was a sigreturn() frame that we
+   can understand.  */
+
+bool
+_Unwind_fallback_frame_state_for (struct _Unwind_Context *context,
+				  _Unwind_FrameState *fs)
+{
+  reg_unit gprs[32];
+
+  if (!interpret_libc (gprs, context))
+    return false;
+  return handle_syscall (fs, gprs, _Unwind_GetCFA (context));
+}
Index: gcc/config/rs6000/darwin.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/darwin.h,v
retrieving revision 1.53
diff -u -p -u -p -r1.53 darwin.h
--- gcc/config/rs6000/darwin.h	25 Jun 2004 15:41:38 -0000	1.53
+++ gcc/config/rs6000/darwin.h	30 Jun 2004 20:21:52 -0000
@@ -327,3 +327,17 @@ do {									\
 #undef REGISTER_TARGET_PRAGMAS
 #define REGISTER_TARGET_PRAGMAS DARWIN_REGISTER_TARGET_PRAGMAS
 
+#ifdef IN_LIBGCC2
+#include <stdbool.h>
+#endif
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)		\
+  {									\
+    extern bool _Unwind_fallback_frame_state_for			\
+      (struct _Unwind_Context *context, _Unwind_FrameState *fs);	\
+									\
+    if (_Unwind_fallback_frame_state_for (CONTEXT, FS))			\
+      goto SUCCESS;							\
+  }
+
+#define HAS_MD_FALLBACK_FRAME_STATE_FOR 1
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.654
diff -u -p -u -p -r1.654 rs6000.c
--- gcc/config/rs6000/rs6000.c	27 Jun 2004 15:56:34 -0000	1.654
+++ gcc/config/rs6000/rs6000.c	30 Jun 2004 20:21:53 -0000
@@ -12342,14 +12342,31 @@ rs6000_emit_prologue (void)
 
   /* If we use the link register, get it into r0.  */
   if (info->lr_save_p)
-    emit_move_insn (gen_rtx_REG (Pmode, 0),
-		    gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+    {
+      insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+			     gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 
   /* If we need to save CR, put it into r12.  */
   if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
     {
+      rtx set;
+      
       cr_save_rtx = gen_rtx_REG (SImode, 12);
-      emit_insn (gen_movesi_from_cr (cr_save_rtx));
+      insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      /* Now, there's no way that dwarf2out_frame_debug_expr is going
+	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
+	 But that's OK.  All we have to do is specify that _one_ condition
+	 code register is saved in this stack slot.  The thrower's epilogue
+	 will then restore all the call-saved registers.
+	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
+      set = gen_rtx_SET (VOIDmode, cr_save_rtx,
+			 gen_rtx_REG (SImode, CR2_REGNO));
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+					    set,
+					    REG_NOTES (insn));
     }
 
   /* Do any required saving of fpr's.  If only one or two to save, do
@@ -12525,7 +12542,7 @@ rs6000_emit_prologue (void)
       
       insn = emit_move_insn (mem, reg);
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-			    reg, gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+			    NULL_RTX, NULL_RTX);
     }
 
   /* Save CR if we use any that must be preserved.  */
@@ -12534,6 +12551,8 @@ rs6000_emit_prologue (void)
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
 			       GEN_INT (info->cr_save_offset + sp_offset));
       rtx mem = gen_rtx_MEM (SImode, addr);
+      /* See the large comment above about why CR2_REGNO is used.  */
+      rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
 
       set_mem_alias_set (mem, rs6000_sr_alias_set);
 
@@ -12541,19 +12560,21 @@ rs6000_emit_prologue (void)
 	 that it's free.  */
       if (REGNO (frame_reg_rtx) == 12)
 	{
+	  rtx set;
+
 	  cr_save_rtx = gen_rtx_REG (SImode, 0);
-	  emit_insn (gen_movesi_from_cr (cr_save_rtx));
+	  insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
+	  RTX_FRAME_RELATED_P (insn) = 1;
+	  set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg);
+	  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+						set,
+						REG_NOTES (insn));
+	  
 	}
       insn = emit_move_insn (mem, cr_save_rtx);
 
-      /* Now, there's no way that dwarf2out_frame_debug_expr is going
-	 to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
-	 But that's OK.  All we have to do is specify that _one_ condition
-	 code register is saved in this stack slot.  The thrower's epilogue
-	 will then restore all the call-saved registers.
-	 We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-			    cr_save_rtx, gen_rtx_REG (SImode, CR2_REGNO));
+			    NULL_RTX, NULL_RTX);
     }
 
   /* Update stack and set back pointer unless this is V.4, 
@@ -12587,9 +12608,16 @@ rs6000_emit_prologue (void)
     if (save_LR_around_toc_setup)
       {
 	rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
-	rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
+
+	insn = emit_move_insn (frame_ptr_rtx, lr);
+	rs6000_maybe_dead (insn);
+	RTX_FRAME_RELATED_P (insn) = 1;
+
 	rs6000_emit_load_toc_table (TRUE);
-	rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
+
+	insn = emit_move_insn (lr, frame_ptr_rtx);
+	rs6000_maybe_dead (insn);
+	RTX_FRAME_RELATED_P (insn) = 1;
       }
     else
       rs6000_emit_load_toc_table (TRUE);
@@ -12599,15 +12627,16 @@ rs6000_emit_prologue (void)
   if (DEFAULT_ABI == ABI_DARWIN
       && flag_pic && current_function_uses_pic_offset_table)
     {
-      rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
       const char *picbase = machopic_function_base_name ();
       rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
 
-      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
+      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
 
-      rs6000_maybe_dead (
-	emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
-			gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
+      insn = emit_move_insn (gen_rtx_REG (Pmode, 
+					  RS6000_PIC_OFFSET_TABLE_REGNUM),
+			     lr);
+      rs6000_maybe_dead (insn);
     }
 #endif
 }
Index: gcc/config/rs6000/t-darwin
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/t-darwin,v
retrieving revision 1.12
diff -u -p -u -p -r1.12 t-darwin
--- gcc/config/rs6000/t-darwin	31 Mar 2004 16:06:53 -0000	1.12
+++ gcc/config/rs6000/t-darwin	30 Jun 2004 20:21:53 -0000
@@ -1,6 +1,6 @@
-# Add trampoline and long double support to libgcc.
 LIB2FUNCS_EXTRA = $(srcdir)/config/rs6000/darwin-tramp.asm \
-	$(srcdir)/config/rs6000/darwin-ldouble.c
+	$(srcdir)/config/rs6000/darwin-ldouble.c \
+	$(srcdir)/config/rs6000/darwin-fallback.c
 
 LIB2FUNCS_STATIC_EXTRA = \
 	$(srcdir)/config/rs6000/darwin-fpsave.asm  \
Index: gcc/testsuite/gcc.dg/cleanup-10.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cleanup-10.c,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 cleanup-10.c
--- gcc/testsuite/gcc.dg/cleanup-10.c	19 Dec 2003 14:00:53 -0000	1.1
+++ gcc/testsuite/gcc.dg/cleanup-10.c	30 Jun 2004 20:21:58 -0000
@@ -1,4 +1,4 @@
-/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
+/* { dg-do run { target *-*-linux* powerpc*-*-darwin* } } */
 /* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
 /* Verify that cleanups work with exception handling through signal frames
    on alternate stack.  */
@@ -93,8 +93,9 @@ static int __attribute__((noinline)) fn1
 
   sigemptyset (&s.sa_mask);
   s.sa_sigaction = fn4;
-  s.sa_flags = SA_ONESHOT | SA_ONSTACK;
+  s.sa_flags = SA_RESETHAND | SA_ONSTACK;
   sigaction (SIGSEGV, &s, NULL);
+  sigaction (SIGBUS, &s, NULL);
   fn2 ();
   return 0;
 }
Index: gcc/testsuite/gcc.dg/cleanup-11.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cleanup-11.c,v
retrieving revision 1.1
diff -u -p -u -p -r1.1 cleanup-11.c
--- gcc/testsuite/gcc.dg/cleanup-11.c	19 Dec 2003 14:00:53 -0000	1.1
+++ gcc/testsuite/gcc.dg/cleanup-11.c	30 Jun 2004 20:21:58 -0000
@@ -1,4 +1,4 @@
-/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
+/* { dg-do run { target *-*-linux* powerpc*-*-darwin* } } */
 /* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
 /* Verify that cleanups work with exception handling through realtime signal
    frames on alternate stack.  */
@@ -93,8 +93,9 @@ static int __attribute__((noinline)) fn1
 
   sigemptyset (&s.sa_mask);
   s.sa_sigaction = fn4;
-  s.sa_flags = SA_ONESHOT | SA_ONSTACK | SA_SIGINFO;
+  s.sa_flags = SA_RESETHAND | SA_ONSTACK | SA_SIGINFO;
   sigaction (SIGSEGV, &s, NULL);
+  sigaction (SIGBUS, &s, NULL);
   fn2 ();
   return 0;
 }
Index: gcc/testsuite/gcc.dg/cleanup-5.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cleanup-5.c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 cleanup-5.c
--- gcc/testsuite/gcc.dg/cleanup-5.c	2 Feb 2004 20:06:23 -0000	1.3
+++ gcc/testsuite/gcc.dg/cleanup-5.c	30 Jun 2004 20:21:58 -0000
@@ -1,4 +1,4 @@
-/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
+/* { dg-do run } */
 /* { dg-options "-fexceptions" } */
 /* Verify that cleanups work with exception handling.  */
 
Index: gcc/testsuite/gcc.dg/cleanup-8.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cleanup-8.c,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 cleanup-8.c
--- gcc/testsuite/gcc.dg/cleanup-8.c	16 Jul 2003 11:52:55 -0000	1.2
+++ gcc/testsuite/gcc.dg/cleanup-8.c	30 Jun 2004 20:21:58 -0000
@@ -1,4 +1,4 @@
-/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* } } */
+/* { dg-do run { target *-*-linux* powerpc*-*-darwin* } } */
 /* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
 /* Verify that cleanups work with exception handling through signal
    frames.  */
@@ -78,6 +78,7 @@ static int __attribute__((noinline)) fn2
 static int __attribute__((noinline)) fn1 ()
 {
   signal (SIGSEGV, fn4);
+  signal (SIGBUS, fn4);
   fn2 ();
   return 0;
 }
Index: gcc/testsuite/gcc.dg/cleanup-9.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/cleanup-9.c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 cleanup-9.c
--- gcc/testsuite/gcc.dg/cleanup-9.c	15 Oct 2003 22:24:56 -0000	1.3
+++ gcc/testsuite/gcc.dg/cleanup-9.c	30 Jun 2004 20:21:58 -0000
@@ -1,4 +1,4 @@
-/* { dg-do run { target i?86-*-linux* x86_64-*-linux* ia64-*-linux* alpha*-*-linux* powerpc*-*-linux* s390*-*-linux* sparc*-*-linux* mips*-*-linux* } } */
+/* { dg-do run { target *-*-linux* powerpc*-*-darwin* } } */
 /* { dg-options "-fasynchronous-unwind-tables -fexceptions -O2" } */
 /* Verify that cleanups work with exception handling through realtime
    signal frames.  */
@@ -80,8 +80,9 @@ static int __attribute__((noinline)) fn1
   struct sigaction s;
   sigemptyset (&s.sa_mask);
   s.sa_sigaction = fn4;
-  s.sa_flags = SA_ONESHOT | SA_SIGINFO;
+  s.sa_flags = SA_RESETHAND | SA_SIGINFO;
   sigaction (SIGSEGV, &s, NULL);
+  sigaction (SIGBUS, &s, NULL);
   fn2 ();
   return 0;
 }
Index: libjava/configure
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure,v
retrieving revision 1.208
diff -u -p -u -p -r1.208 configure
--- libjava/configure	14 Jun 2004 18:28:56 -0000	1.208
+++ libjava/configure	30 Jun 2004 20:22:01 -0000
@@ -8553,6 +8553,9 @@ case "${host}" in
  mips*-*-linux*)
     SIGNAL_HANDLER=include/mips-signal.h
     ;;
+ *-*-darwin*)
+    SIGNAL_HANDLER=include/darwin-signal.h
+    ;;
  *)
     SIGNAL_HANDLER=include/default-signal.h
     ;;
Index: libjava/configure.host
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure.host,v
retrieving revision 1.57
diff -u -p -u -p -r1.57 configure.host
--- libjava/configure.host	19 Mar 2004 22:39:10 -0000	1.57
+++ libjava/configure.host	30 Jun 2004 20:22:01 -0000
@@ -232,10 +232,10 @@ EOF
 	    ;;
 	esac
 	;;
-  *-*-darwin*)
+  powerpc*-*-darwin*)
 	enable_hash_synchronization_default=no
 	slow_pthread_self=
-	can_unwind_signal=no
+	can_unwind_signal=yes
 	;;
   *-*-freebsd*)
 	slow_pthread_self=
Index: libjava/configure.in
===================================================================
RCS file: /cvs/gcc/gcc/libjava/configure.in,v
retrieving revision 1.185
diff -u -p -u -p -r1.185 configure.in
--- libjava/configure.in	14 Jun 2004 18:29:01 -0000	1.185
+++ libjava/configure.in	30 Jun 2004 20:22:01 -0000
@@ -1205,6 +1205,9 @@ case "${host}" in
  mips*-*-linux*)
     SIGNAL_HANDLER=include/mips-signal.h
     ;;
+ *-*-darwin*)
+    SIGNAL_HANDLER=include/darwin-signal.h
+    ;;
  *)
     SIGNAL_HANDLER=include/default-signal.h
     ;;
Index: libjava/include/darwin-signal.h
===================================================================
RCS file: libjava/include/darwin-signal.h
diff -N libjava/include/darwin-signal.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libjava/include/darwin-signal.h	30 Jun 2004 20:22:01 -0000
@@ -0,0 +1,51 @@
+/* darwin-signal.h - Catch runtime signals and turn them into exceptions,
+   on a Darwin system.  */
+
+/* Copyright (C) 2004  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+/* This file is really more of a specification.  The rest of the system
+   should be arranged so that this Just Works.  */
+
+#ifndef JAVA_SIGNAL_H
+# define JAVA_SIGNAL_H 1
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <signal.h>
+
+typedef void (* SIG_PF)(int);
+
+# define HANDLE_SEGV 1
+# undef HANDLE_FPE
+
+# define SIGNAL_HANDLER(_name)					\
+  static void _name (int _dummy __attribute__ ((unused)))
+
+# define MAKE_THROW_FRAME(_exception)
+
+# define INIT_SEGV				\
+  do {						\
+      struct sigaction sa;			\
+      sa.sa_handler = catch_segv;		\
+      sigemptyset (&sa.sa_mask);		\
+      sa.sa_flags = SA_NODEFER;			\
+      sigaction (SIGBUS, &sa, NULL);		\
+      sigaction (SIGSEGV, &sa, NULL);		\
+    } while (0)
+
+# define INIT_FPE				\
+  do {						\
+      struct sigaction sa;			\
+      sa.sa_handler = catch_fpe;		\
+      sigemptyset (&sa.sa_mask);		\
+      sa.sa_flags = SA_NODEFER;			\
+      sigaction (SIGFPE, &sa, NULL);		\
+    } while (0)
+
+#endif /* JAVA_SIGNAL_H */
============================================================


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