OSDN Git Service

Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index 690d6bf..0275525 100644 (file)
@@ -32,9 +32,15 @@ Boston, MA 02111-1307, USA.  */
 
 #include "tconfig.h"
 
+/* We disable this when inhibit_libc, so that gcc can still be built without
+   needing header files first.  */
+/* ??? This is not a good solution, since prototypes may be required in
+   some cases for correct code.  See also frame.c.  */
+#ifndef inhibit_libc
 /* fixproto guarantees these system headers exist. */
 #include <stdlib.h>
 #include <unistd.h>
+#endif
 
 #include "machmode.h"
 #include "defaults.h" 
@@ -1043,8 +1049,8 @@ __floatdisf (DItype u)
       && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
     {
 #define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
-      if (! (- ((UDItype) 1 << DF_SIZE) < u
-            && u < ((UDItype) 1 << DF_SIZE)))
+      if (! (- ((DItype) 1 << DF_SIZE) < u
+            && u < ((DItype) 1 << DF_SIZE)))
        {
          if ((USItype) u & (REP_BIT - 1))
            u |= REP_BIT;
@@ -1397,9 +1403,12 @@ __builtin_saveregs ()
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
 #include <stdio.h>
 /* This is used by the `assert' macro.  */
+extern void __eprintf (const char *, const char *, unsigned int, const char *)
+  __attribute__ ((__noreturn__));
+
 void
 __eprintf (const char *string, const char *expression,
-          int line, const char *filename)
+          unsigned int line, const char *filename)
 {
   fprintf (stderr, string, expression, line, filename);
   fflush (stderr);
@@ -2151,7 +2160,7 @@ __bb_init_prg ()
       bb_hashbuckets = (struct bb_edge **) 
                    malloc (BB_BUCKETS * sizeof (struct bb_edge *));
       if (bb_hashbuckets)
-        bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+        memset (bb_hashbuckets, 0, BB_BUCKETS * sizeof (struct bb_edge *));
     }
 
   if (bb_mode & 12)
@@ -2563,7 +2572,7 @@ __clear_cache (char *beg, char *end)
 
 /* Jump to a trampoline, loading the static chain address.  */
 
-#if defined(WINNT) && ! defined(__CYGWIN32__)
+#if defined(WINNT) && ! defined(__CYGWIN__)
 
 long getpagesize()
 {
@@ -2801,7 +2810,7 @@ cacheflush (char *beg, int size, int flag)
 #endif /* sony_news */
 #endif /* L_trampoline */
 \f
-#ifndef __CYGWIN32__
+#ifndef __CYGWIN__
 #ifdef L__main
 
 #include "gbl-ctors.h"
@@ -2883,7 +2892,7 @@ SYMBOL__MAIN ()
 #endif /* no HAS_INIT_SECTION or INVOKE__main */
 
 #endif /* L__main */
-#endif /* __CYGWIN32__ */
+#endif /* __CYGWIN__ */
 \f
 #ifdef L_ctors
 
@@ -2997,9 +3006,17 @@ exit (int status)
   _exit (status);
 }
 
-#else
+#else /* ON_EXIT defined */
 int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
+
+# ifndef HAVE_ATEXIT
+/* Provide a fake for atexit() using ON_EXIT.  */
+int atexit (func_ptr func)
+{
+  return ON_EXIT (func, NULL);
+}
+# endif /* HAVE_ATEXIT */
+#endif /* ON_EXIT defined */
 
 #endif /* L_exit */
 \f
@@ -3009,6 +3026,8 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
 
 /* Shared exception handling support routines.  */
 
+extern void __default_terminate (void) __attribute__ ((__noreturn__));
+
 void
 __default_terminate ()
 {
@@ -3040,18 +3059,13 @@ __empty ()
 {
 }
 \f
-/* EH context structure. */
-
-struct eh_context
-{
-  void **dynamic_handler_chain;
-  /* This is language dependent part of the eh context. */
-  void *info;
-};
 
-/* This is a safeguard for dynamic handler chain. */
+/* Include definitions of EH context and table layout */
 
-static void *top_elt[2];
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
 
 /* Allocate and return a new EH context structure. */
 
@@ -3060,15 +3074,26 @@ extern void __throw ();
 static void *
 new_eh_context ()
 {
-  struct eh_context *eh = (struct eh_context *) malloc (sizeof *eh);
-  if (! eh)
+  struct eh_full_context {
+    struct eh_context c;
+    void *top_elt[2];
+  } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+  if (! ehfc)
     __terminate ();
 
-  memset (eh, 0, sizeof *eh);
+  memset (ehfc, 0, sizeof *ehfc);
 
-  eh->dynamic_handler_chain = top_elt;
+  ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
 
-  return eh;
+  /* This should optimize out entirely.  This should always be true,
+     but just in case it ever isn't, don't allow bogus code to be
+     generated.  */
+
+  if ((void*)(&ehfc->c) != (void*)ehfc)
+    __terminate ();
+
+  return &ehfc->c;
 }
 
 #if __GTHREADS
@@ -3160,10 +3185,17 @@ eh_context_initialize ()
 static struct eh_context *
 eh_context_static ()
 {
-  static struct eh_context *eh;
-  if (! eh)
-    eh = new_eh_context ();
-  return eh;
+  static struct eh_context eh;
+  static int initialized;
+  static void *top_elt[2];
+
+  if (! initialized)
+    {
+      initialized = 1;
+      memset (&eh, 0, sizeof eh);
+      eh.dynamic_handler_chain = top_elt;
+    }
+  return &eh;
 }
 
 #if __GTHREADS
@@ -3213,6 +3245,8 @@ __get_dynamic_handler_chain ()
    dynamic handler chain, and use longjmp to transfer back to the associated
    handler.  */
 
+extern void __sjthrow (void) __attribute__ ((__noreturn__));
+
 void
 __sjthrow ()
 {
@@ -3265,7 +3299,7 @@ __sjthrow ()
   /* We must call terminate if we try and rethrow an exception, when
      there is no exception currently active and when there are no
      handlers left.  */
-  if (! eh->info || (*dhc) == top_elt)
+  if (! eh->info || (*dhc)[0] == 0)
     __terminate ();
     
   /* Find the jmpbuf associated with the top element of the dynamic
@@ -3289,6 +3323,8 @@ __sjthrow ()
    then throw.  This is used to skip the first handler, and transfer
    control to the next handler in the dynamic handler stack.  */
 
+extern void __sjpopnthrow (void) __attribute__ ((__noreturn__));
+
 void
 __sjpopnthrow ()
 {
@@ -3345,6 +3381,26 @@ __sjpopnthrow ()
 \f
 /* Support code for all exception region-based exception handling.  */
 
+int
+__eh_rtime_match (void *rtime)
+{
+  void *info;
+  __eh_matcher matcher;
+  void *ret;
+
+  info = *(__get_eh_info ());
+  matcher = ((__eh_info *)info)->match_function;
+  if (! matcher)
+    {
+#ifndef inhibit_libc
+      fprintf (stderr, "Internal Compiler Bug: No runtime type matcher.");
+#endif
+      return 0;
+    }
+  ret = (*matcher) (info, rtime, (void *)0);
+  return (ret != NULL);
+}
+
 /* This value identifies the place from which an exception is being
    thrown.  */
 
@@ -3354,11 +3410,24 @@ EH_TABLE_LOOKUP
 
 #else
 
-typedef struct exception_table {
-  void *start;
-  void *end;
-  void *exception_handler;
-} exception_table;
+#ifdef DWARF2_UNWIND_INFO
+
+
+/* Return the table version of an exception descriptor */
+
+short 
+__get_eh_table_version (exception_descriptor *table) 
+{
+  return table->lang.version;
+}
+
+/* Return the originating table language of an exception descriptor */
+
+short 
+__get_eh_table_language (exception_descriptor *table)
+{
+  return table->lang.language;
+}
 
 /* This routine takes a PC and a pointer to the exception region TABLE for
    its translation unit, and returns the address of the exception handler
@@ -3369,7 +3438,7 @@ typedef struct exception_table {
    an inner block.  */
 
 static void *
-find_exception_handler (void *pc, exception_table *table)
+old_find_exception_handler (void *pc, old_exception_table *table)
 {
   if (table)
     {
@@ -3377,27 +3446,106 @@ find_exception_handler (void *pc, exception_table *table)
       int best = -1;
 
       /* We can't do a binary search because the table isn't guaranteed
-        to be sorted from function to function.  */
-      for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
-       {
-         if (table[pos].start <= pc && table[pos].end > pc)
-           {
-             /* This can apply.  Make sure it is at least as small as
-                the previous best.  */
-             if (best == -1 || (table[pos].end <= table[best].end
-                                && table[pos].start >= table[best].start))
-               best = pos;
-           }
-         /* But it is sorted by starting PC within a function.  */
-         else if (best >= 0 && table[pos].start > pc)
-           break;
-       }
+         to be sorted from function to function.  */
+      for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+        {
+          if (table[pos].start_region <= pc && table[pos].end_region > pc)
+            {
+              /* This can apply.  Make sure it is at least as small as
+                 the previous best.  */
+              if (best == -1 || (table[pos].end_region <= table[best].end_region
+                        && table[pos].start_region >= table[best].start_region))
+                best = pos;
+            }
+          /* But it is sorted by starting PC within a function.  */
+          else if (best >= 0 && table[pos].start_region > pc)
+            break;
+        }
       if (best != -1)
-       return table[best].exception_handler;
+        return table[best].exception_handler;
     }
 
   return (void *) 0;
 }
+
+/* find_exception_handler finds the correct handler, if there is one, to
+   handle an exception.
+   returns a pointer to the handler which controlled should be transferred
+   to, or NULL if there is nothing left.
+   Parameters:
+   PC - pc where the exception originates. If this is a rethrow, 
+        then this starts out as a pointer to the exception table
+       entry we wish to rethrow out of.
+   TABLE - exception table for the current module.
+   EH_INFO - eh info pointer for this exception.
+   RETHROW - 1 if this is a rethrow. (see incoming value of PC).
+   CLEANUP - returned flag indicating whether this is a cleanup handler.
+*/
+static void *
+find_exception_handler (void *pc, exception_descriptor *table, 
+                        __eh_info *eh_info, int rethrow, int *cleanup)
+{
+
+  void *retval = NULL;
+  *cleanup = 1;
+  if (table)
+    {
+      int pos = 0;
+      /* The new model assumed the table is sorted inner-most out so the
+         first region we find which matches is the correct one */
+
+      exception_table *tab = &(table->table[0]);
+
+      /* Subtract 1 from the PC to avoid hitting the next region */
+      if (rethrow) 
+        {
+          /* pc is actually the region table entry to rethrow out of */
+          pos = ((exception_table *) pc) - tab;
+          pc = ((exception_table *) pc)->end_region - 1;
+
+          /* The label is always on the LAST handler entry for a region, 
+             so we know the next entry is a different region, even if the
+             addresses are the same. Make sure its not end of table tho. */
+          if (tab[pos].start_region != (void *) -1)
+            pos++;
+        }
+      else
+        pc--;
+      
+      /* We can't do a binary search because the table is in inner-most
+         to outermost address ranges within functions */
+      for ( ; tab[pos].start_region != (void *) -1; pos++)
+        { 
+          if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+            {
+              if (tab[pos].match_info)
+                {
+                  __eh_matcher matcher = eh_info->match_function;
+                  /* match info but no matcher is NOT a match */
+                  if (matcher) 
+                    {
+                      void *ret = (*matcher)((void *) eh_info, 
+                                             tab[pos].match_info, table);
+                      if (ret) 
+                        {
+                          if (retval == NULL)
+                            retval = tab[pos].exception_handler;
+                          *cleanup = 0;
+                          break;
+                        }
+                    }
+                }
+              else
+                {
+                  if (retval == NULL)
+                    retval = tab[pos].exception_handler;
+                }
+            }
+        }
+    }
+  return retval;
+}
+#endif /* DWARF2_UNWIND_INFO */
 #endif /* EH_TABLE_LOOKUP */
 \f
 #ifdef DWARF2_UNWIND_INFO
@@ -3412,31 +3560,71 @@ find_exception_handler (void *pc, exception_table *table)
 
 typedef int ptr_type __attribute__ ((mode (pointer)));
 
-/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+   window in the previous frame?  */
+
+/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT.  This allows us
+   to use the macro here.  One wonders, though, that perhaps TARGET_FLAT
+   compiled functions won't work with the frame-unwind stuff here.  
+   Perhaps the entireity of in_reg_window should be conditional on having
+   seen a DW_CFA_GNU_window_save?  */
+#define target_flags 0
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+  if (udata->saved[reg] == REG_SAVED_REG)
+    return INCOMING_REGNO (reg) == reg;
+  if (udata->saved[reg] != REG_SAVED_OFFSET)
+    return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+  return udata->reg_or_offset[reg] > 0;
+#else
+  return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
+#endif /* INCOMING_REGNO */
+
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
    frame called by UDATA or 0.  */
 
-static void*
-get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
 {
+  while (udata->saved[reg] == REG_SAVED_REG)
+    {
+      reg = udata->reg_or_offset[reg];
+      if (in_reg_window (reg, udata))
+       {
+          udata = sub_udata;
+         sub_udata = NULL;
+       }
+    }
   if (udata->saved[reg] == REG_SAVED_OFFSET)
-    return (void *)(ptr_type)
-      *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
-  else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
-    return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+    return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
   else
     abort ();
 }
 
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+   frame called by UDATA or 0.  */
+
+static inline void *
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+  return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+}
+
 /* Overwrite the saved value for register REG in frame UDATA with VAL.  */
 
-static void
+static inline void
 put_reg (unsigned reg, void *val, frame_state *udata)
 {
-  if (udata->saved[reg] == REG_SAVED_OFFSET)
-    *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
-      = (word_type)(ptr_type) val;
-  else
-    abort ();
+  *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
 }
 
 /* Copy the saved value for register REG from frame UDATA to frame
@@ -3446,17 +3634,13 @@ put_reg (unsigned reg, void *val, frame_state *udata)
 static void
 copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
 {
-  if (udata->saved[reg] == REG_SAVED_OFFSET
-      && target_udata->saved[reg] == REG_SAVED_OFFSET)
-    memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
-           udata->cfa + udata->reg_or_offset[reg],
-           __builtin_dwarf_reg_size (reg));
-  else
-    abort ();
+  word_type *preg = get_reg_addr (reg, udata, NULL);
+  word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+  memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
 }
 
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
-   frame called by UDATA or 0.  */
+/* Retrieve the return address for frame UDATA.  */
 
 static inline void *
 get_return_addr (frame_state *udata, frame_state *sub_udata)
@@ -3496,75 +3680,47 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
   return caller_udata;
 }
 
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
-   window in the previous frame?  */
-
-static int
-in_reg_window (int reg, frame_state *udata)
+/* Hook to call before __terminate if only cleanup handlers remain. */
+void 
+__unwinding_cleanup ()
 {
-  if (udata->saved[reg] != REG_SAVED_OFFSET)
-    return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
-  return udata->reg_or_offset[reg] > 0;
-#else
-  return udata->reg_or_offset[reg] < 0;
-#endif
 }
-#endif /* INCOMING_REGNO */
-
-/* We first search for an exception handler, and if we don't find
-   it, we call __terminate on the current stack frame so that we may
-   use the debugger to walk the stack and understand why no handler
-   was found.
-
-   If we find one, then we unwind the frames down to the one that
-   has the handler and transfer control into the handler.  */
-
-void
-__throw ()
-{
-  struct eh_context *eh = (*get_eh_context) ();
-  void *saved_pc, *pc, *handler, *retaddr;
-  frame_state ustruct, ustruct2;
-  frame_state *udata = &ustruct;
-  frame_state *sub_udata = &ustruct2;
-  frame_state my_ustruct, *my_udata = &my_ustruct;
-  long args_size;
-
-  /* This is required for C++ semantics.  We must call terminate if we
-     try and rethrow an exception, when there is no exception currently
-     active.  */
-  if (! eh->info)
-    __terminate ();
-    
-  /* Start at our stack frame.  */
-label:
-  udata = __frame_state_for (&&label, udata);
-  if (! udata)
-    __terminate ();
-
-  /* We need to get the value from the CFA register.  At this point in
-     compiling __throw we don't know whether or not we will use the frame
-     pointer register for the CFA, so we check our unwind info.  */
-  if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
-    udata->cfa = __builtin_fp ();
-  else
-    udata->cfa = __builtin_sp ();
-  udata->cfa += udata->cfa_offset;
-
-  memcpy (my_udata, udata, sizeof (*udata));
-
-  /* Do any necessary initialization to access arbitrary stack frames.
-     On the SPARC, this means flushing the register windows.  */
-  __builtin_unwind_init ();
 
-  /* Now reset pc to the right throw point.  */
-  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
-  saved_pc = pc;
+/* throw_helper performs some of the common grunt work for a throw. This
+   routine is called by throw and rethrows. This is pretty much split 
+   out from the old __throw routine. An addition has been added which allows
+   for a dummy call to a routine __unwinding_cleanup() when there are nothing
+   but cleanups remaining. This allows a debugger to examine the state
+   at which the throw was executed, before any cleanups, rather than
+   at the terminate point after the stack has been unwound. */
 
-  handler = 0;
+static void *
+throw_helper (eh, pc, my_udata, udata_p)
+     struct eh_context *eh;
+     void *pc;
+     frame_state *my_udata;
+     frame_state **udata_p;
+{
+  frame_state *udata = *udata_p;
+  frame_state ustruct;
+  frame_state *sub_udata = &ustruct;
+  void *saved_pc = pc;
+  void *handler;
+  void *handler_p;
+  void *pc_p;
+  frame_state saved_ustruct;
+  int new_eh_model;
+  int cleanup = 0;
+  int only_cleanup = 0;
+  int rethrow = 0;
+  int saved_state = 0;
+  __eh_info *eh_info = (__eh_info *)eh->info;
+
+  /* Do we find a handler based on a re-throw PC? */
+  if (eh->table_index != (void *) 0)
+    rethrow = 1;
+
+  handler = (void *) 0;
   for (;;)
     { 
       frame_state *p = udata;
@@ -3575,24 +3731,67 @@ label:
       if (! udata)
        break;
 
-      handler = find_exception_handler (pc, udata->eh_ptr);
+      if (udata->eh_ptr == NULL)
+        new_eh_model = 0;
+      else
+        new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
+                                          runtime_id_field == NEW_EH_RUNTIME);
 
-      /* If we found one, we can stop searching.  */
+      if (rethrow) 
+        {
+          rethrow = 0;
+          handler = find_exception_handler (eh->table_index, udata->eh_ptr, 
+                                          eh_info, 1, &cleanup);
+          eh->table_index = (void *)0;
+        }
+      else
+        if (new_eh_model)
+          handler = find_exception_handler (pc, udata->eh_ptr, eh_info, 
+                                            0, &cleanup);
+        else
+          handler = old_find_exception_handler (pc, udata->eh_ptr);
+
+      /* If we found one, we can stop searching, if its not a cleanup. 
+         for cleanups, we save the state, and keep looking. This allows
+         us to call a debug hook if there are nothing but cleanups left. */
       if (handler)
-       {
-         args_size = udata->args_size;
-         break;
-       }
+       if (cleanup)
+         {
+           if (!saved_state)
+             {
+               saved_ustruct = *udata;
+               handler_p = handler;
+               pc_p = pc;
+               saved_state = 1;
+               only_cleanup = 1;
+             }
+         }
+       else
+         {
+           only_cleanup = 0;
+           break;
+         }
 
       /* Otherwise, we continue searching.  We subtract 1 from PC to avoid
         hitting the beginning of the next region.  */
       pc = get_return_addr (udata, sub_udata) - 1;
     }
 
+  if (saved_state) 
+    {
+      udata = &saved_ustruct;
+      handler = handler_p;
+      pc = pc_p;
+      if (only_cleanup)
+        __unwinding_cleanup ();
+    }
+
   /* If we haven't found a handler by now, this is an unhandled
      exception.  */
-  if (! handler)
-    __terminate ();
+  if (! handler) 
+    __terminate();
+
+  eh->handler_label = handler;
 
   if (pc == saved_pc)
     /* We found a handler in the throw context, no need to unwind.  */
@@ -3620,7 +3819,6 @@ label:
          for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
            if (i != udata->retaddr_column && udata->saved[i])
              {
-#ifdef INCOMING_REGNO
                /* If you modify the saved value of the return address
                   register on the SPARC, you modify the return address for
                   your caller's frame.  Don't do that here, as it will
@@ -3629,14 +3827,12 @@ label:
                    && udata->saved[udata->retaddr_column] == REG_SAVED_REG
                    && udata->reg_or_offset[udata->retaddr_column] == i)
                  continue;
-#endif
                copy_reg (i, udata, my_udata);
              }
 
          pc = get_return_addr (udata, sub_udata) - 1;
        }
 
-#ifdef INCOMING_REGNO
       /* But we do need to update the saved return address register from
         the last frame we unwind, or the handler frame will have the wrong
         return address.  */
@@ -3646,29 +3842,125 @@ label:
          if (in_reg_window (i, udata))
            copy_reg (i, udata, my_udata);
        }
-#endif
     }
   /* udata now refers to the frame called by the handler frame.  */
 
-  /* Emit the stub to adjust sp and jump to the handler.  */
-  retaddr = __builtin_eh_stub ();
+  *udata_p = udata;
+  return handler;
+}
+
 
-  /* And then set our return address to point to the stub.  */
-  if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
-    put_return_addr (retaddr, my_udata);
-  else
-    __builtin_set_return_addr_reg (retaddr);
+/* We first search for an exception handler, and if we don't find
+   it, we call __terminate on the current stack frame so that we may
+   use the debugger to walk the stack and understand why no handler
+   was found.
 
-  /* Set up the registers we use to communicate with the stub.
-     We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack.  */
-  __builtin_set_eh_regs (handler,
+   If we find one, then we unwind the frames down to the one that
+   has the handler and transfer control into the handler.  */
+
+/*extern void __throw(void) __attribute__ ((__noreturn__));*/
+
+void
+__throw ()
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  frame_state ustruct;
+  frame_state *udata = &ustruct;
+  frame_state my_ustruct, *my_udata = &my_ustruct;
+
+  /* This is required for C++ semantics.  We must call terminate if we
+     try and rethrow an exception, when there is no exception currently
+     active.  */
+  if (! eh->info)
+    __terminate ();
+    
+  /* Start at our stack frame.  */
+label:
+  udata = __frame_state_for (&&label, udata);
+  if (! udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  udata->cfa = __builtin_dwarf_cfa ();
+
+  memcpy (my_udata, udata, sizeof (*udata));
+
+  /* Do any necessary initialization to access arbitrary stack frames.
+     On the SPARC, this means flushing the register windows.  */
+  __builtin_unwind_init ();
+
+  /* Now reset pc to the right throw point.  */
+  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+  handler = throw_helper (eh, pc, my_udata, &udata);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh,
 #ifdef STACK_GROWS_DOWNWARD
-                        udata->cfa - my_udata->cfa
+                      udata->cfa - my_udata->cfa,
 #else
-                        my_udata->cfa - udata->cfa
+                      my_udata->cfa - udata->cfa,
 #endif
-                        + args_size
-                        );
+                      handler);
+
+  /* Epilogue:  restore the handler frame's register values and return
+     to the stub.  */
+}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (index)
+     void *index;
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  frame_state ustruct;
+  frame_state *udata = &ustruct;
+  frame_state my_ustruct, *my_udata = &my_ustruct;
+
+  /* This is required for C++ semantics.  We must call terminate if we
+     try and rethrow an exception, when there is no exception currently
+     active.  */
+  if (! eh->info)
+    __terminate ();
+
+  /* This is the table index we want to rethrow from. The value of
+     the END_REGION label is used for the PC of the throw, and the
+     search begins with the next table entry. */
+  eh->table_index = index;
+    
+  /* Start at our stack frame.  */
+label:
+  udata = __frame_state_for (&&label, udata);
+  if (! udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  udata->cfa = __builtin_dwarf_cfa ();
+
+  memcpy (my_udata, udata, sizeof (*udata));
+
+  /* Do any necessary initialization to access arbitrary stack frames.
+     On the SPARC, this means flushing the register windows.  */
+  __builtin_unwind_init ();
+
+  /* Now reset pc to the right throw point.  */
+  pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+  handler = throw_helper (eh, pc, my_udata, &udata);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh,
+#ifdef STACK_GROWS_DOWNWARD
+                      udata->cfa - my_udata->cfa,
+#else
+                      my_udata->cfa - udata->cfa,
+#endif
+                      handler);
 
   /* Epilogue:  restore the handler frame's register values and return
      to the stub.  */
@@ -3676,7 +3968,6 @@ label:
 #endif /* DWARF2_UNWIND_INFO */
 
 #endif /* L_eh */
-
 \f
 #ifdef L_pure
 #ifndef inhibit_libc
@@ -3699,6 +3990,6 @@ __pure_virtual ()
 #ifndef inhibit_libc
   write (2, MESSAGE, sizeof (MESSAGE) - 1);
 #endif
-  _exit (-1);
+  __terminate ();
 }
 #endif