OSDN Git Service

* libgcc2.c (near eh_context_specific): Comment #endif string.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index 34a6c71..ba00312 100644 (file)
@@ -1,6 +1,7 @@
 /* More subroutines needed by GCC output code on some machines.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 1999, 2000
+   Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -31,122 +32,39 @@ Boston, MA 02111-1307, USA.  */
    do not apply.  */
 
 #include "tconfig.h"
+#include "tsystem.h"
+
 #include "machmode.h"
 #include "defaults.h" 
-#ifndef L_trampoline
-#include <stddef.h>
-#endif
 
 /* Don't use `fancy_abort' here even if config.h says to use it.  */
 #ifdef abort
 #undef abort
 #endif
 
-#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
-#define WEAK_ALIAS
-#endif
-
-/* Permit the tm.h file to select the endianness to use just for this
-   file.  This is used when the endianness is determined when the
-   compiler is run.  */
-
-#ifndef LIBGCC2_WORDS_BIG_ENDIAN
-#define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
-#endif
-
-/* In the first part of this file, we are interfacing to calls generated
-   by the compiler itself.  These calls pass values into these routines
-   which have very specific modes (rather than very specific types), and
-   these compiler-generated calls also expect any return values to have
-   very specific modes (rather than very specific types).  Thus, we need
-   to avoid using regular C language type names in this part of the file
-   because the sizes for those types can be configured to be anything.
-   Instead we use the following special type names.  */
-
-typedef unsigned int UQItype   __attribute__ ((mode (QI)));
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef unsigned int UDItype   __attribute__ ((mode (DI)));
-
-typedef        float SFtype    __attribute__ ((mode (SF)));
-typedef                float DFtype    __attribute__ ((mode (DF)));
-
-#if LONG_DOUBLE_TYPE_SIZE == 96
-typedef                float XFtype    __attribute__ ((mode (XF)));
-#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-typedef                float TFtype    __attribute__ ((mode (TF)));
-#endif
-
-typedef int word_type __attribute__ ((mode (__word__)));
-
-/* Make sure that we don't accidentally use any normal C language built-in
-   type names in the first part of this file.  Instead we want to use *only*
-   the type names defined above.  The following macro definitions insure
-   that if we *do* accidentally use some normal C language built-in type name,
-   we will get a syntax error.  */
-
-#define char bogus_type
-#define short bogus_type
-#define int bogus_type
-#define long bogus_type
-#define unsigned bogus_type
-#define float bogus_type
-#define double bogus_type
-
-#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+/* In a cross-compilation situation, default to inhibiting compilation
+   of routines that use libc.  */
 
-/* DIstructs are pairs of SItype values in the order determined by
-   LIBGCC2_WORDS_BIG_ENDIAN.  */
-
-#if LIBGCC2_WORDS_BIG_ENDIAN
-  struct DIstruct {SItype high, low;};
-#else
-  struct DIstruct {SItype low, high;};
+#if defined(CROSS_COMPILE) && !defined(inhibit_libc)
+#define inhibit_libc
 #endif
 
-/* We need this union to unpack/pack DImode values, since we don't have
-   any arithmetic yet.  Incoming DImode parameters are stored into the
-   `ll' field, and the unpacked result is read from the struct `s'.  */
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-#if (defined (L_udivmoddi4) || defined (L_muldi3) || defined (L_udiv_w_sdiv)\
-     || defined (L_divdi3) || defined (L_udivdi3) \
-     || defined (L_moddi3) || defined (L_umoddi3))
-
-#include "longlong.h"
-
-#endif /* udiv or mul */
-
-extern DItype __fixunssfdi (SFtype a);
-extern DItype __fixunsdfdi (DFtype a);
-#if LONG_DOUBLE_TYPE_SIZE == 96
-extern DItype __fixunsxfdi (XFtype a);
-#endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
-extern DItype __fixunstfdi (TFtype a);
-#endif
+#include "libgcc2.h"
 \f
 #if defined (L_negdi2) || defined (L_divdi3) || defined (L_moddi3)
 #if defined (L_divdi3) || defined (L_moddi3)
 static inline
 #endif
-DItype
-__negdi2 (DItype u)
+DWtype
+__negdi2 (DWtype u)
 {
-  DIunion w;
-  DIunion uu;
+  DWunion w;
+  DWunion uu;
 
   uu.ll = u;
 
   w.s.low = -uu.s.low;
-  w.s.high = -uu.s.high - ((USItype) w.s.low > 0);
+  w.s.high = -uu.s.high - ((UWtype) w.s.low > 0);
 
   return w.ll;
 }
@@ -155,29 +73,30 @@ __negdi2 (DItype u)
 /* Unless shift functions are defined whith full ANSI prototypes,
    parameter b will be promoted to int if word_type is smaller than an int.  */
 #ifdef L_lshrdi3
-DItype
-__lshrdi3 (DItype u, word_type b)
+DWtype
+__lshrdi3 (DWtype u, word_type b)
 {
-  DIunion w;
+  DWunion w;
   word_type bm;
-  DIunion uu;
+  DWunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       w.s.high = 0;
-      w.s.low = (USItype)uu.s.high >> -bm;
+      w.s.low = (UWtype) uu.s.high >> -bm;
     }
   else
     {
-      USItype carries = (USItype)uu.s.high << bm;
-      w.s.high = (USItype)uu.s.high >> b;
-      w.s.low = ((USItype)uu.s.low >> b) | carries;
+      UWtype carries = (UWtype) uu.s.high << bm;
+
+      w.s.high = (UWtype) uu.s.high >> b;
+      w.s.low = ((UWtype) uu.s.low >> b) | carries;
     }
 
   return w.ll;
@@ -185,29 +104,30 @@ __lshrdi3 (DItype u, word_type b)
 #endif
 
 #ifdef L_ashldi3
-DItype
-__ashldi3 (DItype u, word_type b)
+DWtype
+__ashldi3 (DWtype u, word_type b)
 {
-  DIunion w;
+  DWunion w;
   word_type bm;
-  DIunion uu;
+  DWunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       w.s.low = 0;
-      w.s.high = (USItype)uu.s.low << -bm;
+      w.s.high = (UWtype) uu.s.low << -bm;
     }
   else
     {
-      USItype carries = (USItype)uu.s.low >> bm;
-      w.s.low = (USItype)uu.s.low << b;
-      w.s.high = ((USItype)uu.s.high << b) | carries;
+      UWtype carries = (UWtype) uu.s.low >> bm;
+
+      w.s.low = (UWtype) uu.s.low << b;
+      w.s.high = ((UWtype) uu.s.high << b) | carries;
     }
 
   return w.ll;
@@ -215,30 +135,31 @@ __ashldi3 (DItype u, word_type b)
 #endif
 
 #ifdef L_ashrdi3
-DItype
-__ashrdi3 (DItype u, word_type b)
+DWtype
+__ashrdi3 (DWtype u, word_type b)
 {
-  DIunion w;
+  DWunion w;
   word_type bm;
-  DIunion uu;
+  DWunion uu;
 
   if (b == 0)
     return u;
 
   uu.ll = u;
 
-  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
   if (bm <= 0)
     {
       /* w.s.high = 1..1 or 0..0 */
-      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
+      w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
       w.s.low = uu.s.high >> -bm;
     }
   else
     {
-      USItype carries = (USItype)uu.s.high << bm;
+      UWtype carries = (UWtype) uu.s.high << bm;
+
       w.s.high = uu.s.high >> b;
-      w.s.low = ((USItype)uu.s.low >> b) | carries;
+      w.s.low = ((UWtype) uu.s.low >> b) | carries;
     }
 
   return w.ll;
@@ -246,10 +167,10 @@ __ashrdi3 (DItype u, word_type b)
 #endif
 \f
 #ifdef L_ffsdi2
-DItype
-__ffsdi2 (DItype u)
+DWtype
+__ffsdi2 (DWtype u)
 {
-  DIunion uu, w;
+  DWunion uu, w;
   uu.ll = u;
   w.s.high = 0;
   w.s.low = ffs (uu.s.low);
@@ -258,7 +179,7 @@ __ffsdi2 (DItype u)
   w.s.low = ffs (uu.s.high);
   if (w.s.low != 0)
     {
-      w.s.low += BITS_PER_UNIT * sizeof (SItype);
+      w.s.low += BITS_PER_UNIT * sizeof (Wtype);
       return w.ll;
     }
   return w.ll;
@@ -266,18 +187,18 @@ __ffsdi2 (DItype u)
 #endif
 \f
 #ifdef L_muldi3
-DItype
-__muldi3 (DItype u, DItype v)
+DWtype
+__muldi3 (DWtype u, DWtype v)
 {
-  DIunion w;
-  DIunion uu, vv;
+  DWunion w;
+  DWunion uu, vv;
 
   uu.ll = u,
   vv.ll = v;
 
   w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
+  w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
+              + (UWtype) uu.s.high * (UWtype) vv.s.low);
 
   return w.ll;
 }
@@ -285,15 +206,15 @@ __muldi3 (DItype u, DItype v)
 \f
 #ifdef L_udiv_w_sdiv
 #if defined (sdiv_qrnnd)
-USItype
-__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
+UWtype
+__udiv_w_sdiv (UWtype *rp, UWtype a1, UWtype a0, UWtype d)
 {
-  USItype q, r;
-  USItype c0, c1, b1;
+  UWtype q, r;
+  UWtype c0, c1, b1;
 
-  if ((SItype) d >= 0)
+  if ((Wtype) d >= 0)
     {
-      if (a1 < d - a1 - (a0 >> (SI_TYPE_SIZE - 1)))
+      if (a1 < d - a1 - (a0 >> (W_TYPE_SIZE - 1)))
        {
          /* dividend, divisor, and quotient are nonnegative */
          sdiv_qrnnd (q, r, a1, a0, d);
@@ -301,18 +222,18 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
       else
        {
          /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
-         sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (SI_TYPE_SIZE - 1));
+         sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (W_TYPE_SIZE - 1));
          /* Divide (c1*2^32 + c0) by d */
          sdiv_qrnnd (q, r, c1, c0, d);
          /* Add 2^31 to quotient */
-         q += (USItype) 1 << (SI_TYPE_SIZE - 1);
+         q += (UWtype) 1 << (W_TYPE_SIZE - 1);
        }
     }
   else
     {
       b1 = d >> 1;                     /* d/2, between 2^30 and 2^31 - 1 */
       c1 = a1 >> 1;                    /* A/2 */
-      c0 = (a1 << (SI_TYPE_SIZE - 1)) + (a0 >> 1);
+      c0 = (a1 << (W_TYPE_SIZE - 1)) + (a0 >> 1);
 
       if (a1 < b1)                     /* A < 2^32*b1, so A/2 < 2^31*b1 */
        {
@@ -383,9 +304,14 @@ __udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
 }
 #else
 /* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
-USItype
-__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
-{}
+UWtype
+__udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
+              UWtype a1 __attribute__ ((__unused__)),
+              UWtype a0 __attribute__ ((__unused__)),
+              UWtype d __attribute__ ((__unused__)))
+{
+  return 0;
+}
 #endif
 #endif
 \f
@@ -411,15 +337,15 @@ static const UQItype __clz_tab[] =
      defined (L_umoddi3) || defined (L_moddi3))
 static inline
 #endif
-UDItype
-__udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
+UDWtype
+__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
 {
-  DIunion ww;
-  DIunion nn, dd;
-  DIunion rr;
-  USItype d0, d1, n0, n1, n2;
-  USItype q0, q1;
-  USItype b, bm;
+  DWunion ww;
+  DWunion nn, dd;
+  DWunion rr;
+  UWtype d0, d1, n0, n1, n2;
+  UWtype q0, q1;
+  UWtype b, bm;
 
   nn.ll = n;
   dd.ll = d;
@@ -478,7 +404,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
                 denominator set.  */
 
              d0 = d0 << bm;
-             n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
+             n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
              n0 = n0 << bm;
            }
 
@@ -503,7 +429,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
                 leading quotient digit q1 = 1).
 
                 This special case is necessary, not an optimization.
-                (Shifts counts of SI_TYPE_SIZE are undefined.)  */
+                (Shifts counts of W_TYPE_SIZE are undefined.)  */
 
              n1 -= d0;
              q1 = 1;
@@ -512,7 +438,7 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
            {
              /* Normalize.  */
 
-             b = SI_TYPE_SIZE - bm;
+             b = W_TYPE_SIZE - bm;
 
              d0 = d0 << bm;
              n2 = n1 >> b;
@@ -589,10 +515,10 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
            }
          else
            {
-             USItype m1, m0;
+             UWtype m1, m0;
              /* Normalize.  */
 
-             b = SI_TYPE_SIZE - bm;
+             b = W_TYPE_SIZE - bm;
 
              d1 = (d1 << bm) | (d0 >> b);
              d0 = d0 << bm;
@@ -630,14 +556,12 @@ __udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
 #endif
 
 #ifdef L_divdi3
-UDItype __udivmoddi4 ();
-
-DItype
-__divdi3 (DItype u, DItype v)
+DWtype
+__divdi3 (DWtype u, DWtype v)
 {
   word_type c = 0;
-  DIunion uu, vv;
-  DItype w;
+  DWunion uu, vv;
+  DWtype w;
 
   uu.ll = u;
   vv.ll = v;
@@ -649,7 +573,7 @@ __divdi3 (DItype u, DItype v)
     c = ~c,
     vv.ll = __negdi2 (vv.ll);
 
-  w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0);
+  w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
   if (c)
     w = __negdi2 (w);
 
@@ -658,13 +582,12 @@ __divdi3 (DItype u, DItype v)
 #endif
 
 #ifdef L_moddi3
-UDItype __udivmoddi4 ();
-DItype
-__moddi3 (DItype u, DItype v)
+DWtype
+__moddi3 (DWtype u, DWtype v)
 {
   word_type c = 0;
-  DIunion uu, vv;
-  DItype w;
+  DWunion uu, vv;
+  DWtype w;
 
   uu.ll = u;
   vv.ll = v;
@@ -684,11 +607,10 @@ __moddi3 (DItype u, DItype v)
 #endif
 
 #ifdef L_umoddi3
-UDItype __udivmoddi4 ();
-UDItype
-__umoddi3 (UDItype u, UDItype v)
+UDWtype
+__umoddi3 (UDWtype u, UDWtype v)
 {
-  UDItype w;
+  UDWtype w;
 
   (void) __udivmoddi4 (u, v, &w);
 
@@ -697,19 +619,18 @@ __umoddi3 (UDItype u, UDItype v)
 #endif
 
 #ifdef L_udivdi3
-UDItype __udivmoddi4 ();
-UDItype
-__udivdi3 (UDItype n, UDItype d)
+UDWtype
+__udivdi3 (UDWtype n, UDWtype d)
 {
-  return __udivmoddi4 (n, d, (UDItype *) 0);
+  return __udivmoddi4 (n, d, (UDWtype *) 0);
 }
 #endif
 \f
 #ifdef L_cmpdi2
 word_type
-__cmpdi2 (DItype a, DItype b)
+__cmpdi2 (DWtype a, DWtype b)
 {
-  DIunion au, bu;
+  DWunion au, bu;
 
   au.ll = a, bu.ll = b;
 
@@ -717,9 +638,9 @@ __cmpdi2 (DItype a, DItype b)
     return 0;
   else if (au.s.high > bu.s.high)
     return 2;
-  if ((USItype) au.s.low < (USItype) bu.s.low)
+  if ((UWtype) au.s.low < (UWtype) bu.s.low)
     return 0;
-  else if ((USItype) au.s.low > (USItype) bu.s.low)
+  else if ((UWtype) au.s.low > (UWtype) bu.s.low)
     return 2;
   return 1;
 }
@@ -727,270 +648,258 @@ __cmpdi2 (DItype a, DItype b)
 
 #ifdef L_ucmpdi2
 word_type
-__ucmpdi2 (DItype a, DItype b)
+__ucmpdi2 (DWtype a, DWtype b)
 {
-  DIunion au, bu;
+  DWunion au, bu;
 
   au.ll = a, bu.ll = b;
 
-  if ((USItype) au.s.high < (USItype) bu.s.high)
+  if ((UWtype) au.s.high < (UWtype) bu.s.high)
     return 0;
-  else if ((USItype) au.s.high > (USItype) bu.s.high)
+  else if ((UWtype) au.s.high > (UWtype) bu.s.high)
     return 2;
-  if ((USItype) au.s.low < (USItype) bu.s.low)
+  if ((UWtype) au.s.low < (UWtype) bu.s.low)
     return 0;
-  else if ((USItype) au.s.low > (USItype) bu.s.low)
+  else if ((UWtype) au.s.low > (UWtype) bu.s.low)
     return 2;
   return 1;
 }
 #endif
 \f
-#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
-DItype
-__fixunstfdi (TFtype a)
+DWtype
+__fixunstfDI (TFtype a)
 {
   TFtype b;
-  UDItype v;
+  UDWtype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to DItype!),
+  /* Convert that to fixed (but not to DWtype!),
      and shift it into the high word.  */
-  v = (USItype) b;
+  v = (UWtype) b;
   v <<= WORD_SIZE;
   /* Remove high part from the TFtype, leaving the low part as flonum.  */
   a -= (TFtype)v;
-  /* Convert that to fixed (but not to DItype!) and add it in.
+  /* Convert that to fixed (but not to DWtype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (USItype) (- a);
+    v -= (UWtype) (- a);
   else
-    v += (USItype) a;
+    v += (UWtype) a;
   return v;
 }
 #endif
 
-#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
-DItype
+#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+DWtype
 __fixtfdi (TFtype a)
 {
   if (a < 0)
-    return - __fixunstfdi (-a);
-  return __fixunstfdi (a);
+    return - __fixunstfDI (-a);
+  return __fixunstfDI (a);
 }
 #endif
 
-#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
-DItype
-__fixunsxfdi (XFtype a)
+DWtype
+__fixunsxfDI (XFtype a)
 {
   XFtype b;
-  UDItype v;
+  UDWtype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to DItype!),
+  /* Convert that to fixed (but not to DWtype!),
      and shift it into the high word.  */
-  v = (USItype) b;
+  v = (UWtype) b;
   v <<= WORD_SIZE;
   /* Remove high part from the XFtype, leaving the low part as flonum.  */
   a -= (XFtype)v;
-  /* Convert that to fixed (but not to DItype!) and add it in.
+  /* Convert that to fixed (but not to DWtype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (USItype) (- a);
+    v -= (UWtype) (- a);
   else
-    v += (USItype) a;
+    v += (UWtype) a;
   return v;
 }
 #endif
 
-#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
-DItype
+#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+DWtype
 __fixxfdi (XFtype a)
 {
   if (a < 0)
-    return - __fixunsxfdi (-a);
-  return __fixunsxfdi (a);
+    return - __fixunsxfDI (-a);
+  return __fixunsxfDI (a);
 }
 #endif
 
 #ifdef L_fixunsdfdi
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
-DItype
-__fixunsdfdi (DFtype a)
+DWtype
+__fixunsdfDI (DFtype a)
 {
   DFtype b;
-  UDItype v;
+  UDWtype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to DItype!),
+  /* Convert that to fixed (but not to DWtype!),
      and shift it into the high word.  */
-  v = (USItype) b;
+  v = (UWtype) b;
   v <<= WORD_SIZE;
   /* Remove high part from the DFtype, leaving the low part as flonum.  */
   a -= (DFtype)v;
-  /* Convert that to fixed (but not to DItype!) and add it in.
+  /* Convert that to fixed (but not to DWtype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (USItype) (- a);
+    v -= (UWtype) (- a);
   else
-    v += (USItype) a;
+    v += (UWtype) a;
   return v;
 }
 #endif
 
 #ifdef L_fixdfdi
-DItype
+DWtype
 __fixdfdi (DFtype a)
 {
   if (a < 0)
-    return - __fixunsdfdi (-a);
-  return __fixunsdfdi (a);
+    return - __fixunsdfDI (-a);
+  return __fixunsdfDI (a);
 }
 #endif
 
 #ifdef L_fixunssfdi
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
-DItype
-__fixunssfdi (SFtype original_a)
+DWtype
+__fixunssfDI (SFtype original_a)
 {
   /* Convert the SFtype to a DFtype, because that is surely not going
      to lose any bits.  Some day someone else can write a faster version
      that avoids converting to DFtype, and verify it really works right.  */
   DFtype a = original_a;
   DFtype b;
-  UDItype v;
+  UDWtype v;
 
   if (a < 0)
     return 0;
 
   /* Compute high word of result, as a flonum.  */
   b = (a / HIGH_WORD_COEFF);
-  /* Convert that to fixed (but not to DItype!),
+  /* Convert that to fixed (but not to DWtype!),
      and shift it into the high word.  */
-  v = (USItype) b;
+  v = (UWtype) b;
   v <<= WORD_SIZE;
   /* Remove high part from the DFtype, leaving the low part as flonum.  */
-  a -= (DFtype)v;
-  /* Convert that to fixed (but not to DItype!) and add it in.
+  a -= (DFtype) v;
+  /* Convert that to fixed (but not to DWtype!) and add it in.
      Sometimes A comes out negative.  This is significant, since
      A has more bits than a long int does.  */
   if (a < 0)
-    v -= (USItype) (- a);
+    v -= (UWtype) (- a);
   else
-    v += (USItype) a;
+    v += (UWtype) a;
   return v;
 }
 #endif
 
 #ifdef L_fixsfdi
-DItype
+DWtype
 __fixsfdi (SFtype a)
 {
   if (a < 0)
-    return - __fixunssfdi (-a);
-  return __fixunssfdi (a);
+    return - __fixunssfDI (-a);
+  return __fixunssfDI (a);
 }
 #endif
 
-#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_floatdixf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 XFtype
-__floatdixf (DItype u)
+__floatdixf (DWtype u)
 {
   XFtype d;
-  SItype negate = 0;
 
-  if (u < 0)
-    u = -u, negate = 1;
-
-  d = (USItype) (u >> WORD_SIZE);
+  d = (Wtype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
-  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
-#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#if defined(L_floatditf) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 TFtype
-__floatditf (DItype u)
+__floatditf (DWtype u)
 {
   TFtype d;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
-  d = (USItype) (u >> WORD_SIZE);
+  d = (Wtype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
-  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
 #ifdef L_floatdidf
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
 
 DFtype
-__floatdidf (DItype u)
+__floatdidf (DWtype u)
 {
   DFtype d;
-  SItype negate = 0;
 
-  if (u < 0)
-    u = -u, negate = 1;
-
-  d = (USItype) (u >> WORD_SIZE);
+  d = (Wtype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
-  d += (USItype) (u & (HIGH_WORD_COEFF - 1));
+  d += (UWtype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
 #ifdef L_floatdisf
-#define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
-#define HIGH_HALFWORD_COEFF (((UDItype) 1) << (WORD_SIZE / 2))
-#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
-#define DI_SIZE (sizeof (DItype) * BITS_PER_UNIT)
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_HALFWORD_COEFF (((UDWtype) 1) << (WORD_SIZE / 2))
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
 
 /* Define codes for all the float formats that we know of.  Note
    that this is copied from real.h.  */
@@ -1021,16 +930,12 @@ __floatdidf (DItype u)
 #endif
 
 SFtype
-__floatdisf (DItype u)
+__floatdisf (DWtype u)
 {
   /* Do the calculation in DFmode
      so that we don't lose any of the precision of the high word
      while multiplying it.  */
   DFtype f;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
   /* Protect against double-rounding error.
      Represent any low-order bits, that might be truncated in DFmode,
@@ -1041,23 +946,24 @@ __floatdisf (DItype u)
   if (DF_SIZE < DI_SIZE
       && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
     {
-#define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
-      if (u >= ((UDItype) 1 << DF_SIZE))
+#define REP_BIT ((UDWtype) 1 << (DI_SIZE - DF_SIZE))
+      if (! (- ((DWtype) 1 << DF_SIZE) < u
+            && u < ((DWtype) 1 << DF_SIZE)))
        {
-         if ((USItype) u & (REP_BIT - 1))
+         if ((UDWtype) u & (REP_BIT - 1))
            u |= REP_BIT;
        }
     }
-  f = (USItype) (u >> WORD_SIZE);
+  f = (Wtype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
-  f += (USItype) (u & (HIGH_WORD_COEFF - 1));
+  f += (UWtype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (SFtype) (negate ? -f : f);
+  return (SFtype) f;
 }
 #endif
 
-#if defined(L_fixunsxfsi) && LONG_DOUBLE_TYPE_SIZE == 96
+#if defined(L_fixunsxfsi) && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 /* Reenable the normal types, in case limits.h needs them.  */
 #undef char
 #undef short
@@ -1070,12 +976,12 @@ __floatdisf (DItype u)
 #undef MAX
 #include <limits.h>
 
-USItype
-__fixunsxfsi (XFtype a)
+UWtype
+__fixunsxfSI (XFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
-    return (SItype) (a + LONG_MIN) - LONG_MIN;
-  return (SItype) a;
+    return (Wtype) (a + LONG_MIN) - LONG_MIN;
+  return (Wtype) a;
 }
 #endif
 
@@ -1092,12 +998,12 @@ __fixunsxfsi (XFtype a)
 #undef MAX
 #include <limits.h>
 
-USItype
-__fixunsdfsi (DFtype a)
+UWtype
+__fixunsdfSI (DFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
-    return (SItype) (a + LONG_MIN) - LONG_MIN;
-  return (SItype) a;
+    return (Wtype) (a + LONG_MIN) - LONG_MIN;
+  return (Wtype) a;
 }
 #endif
 
@@ -1114,12 +1020,12 @@ __fixunsdfsi (DFtype a)
 #undef MAX
 #include <limits.h>
 
-USItype
-__fixunssfsi (SFtype a)
+UWtype
+__fixunssfSI (SFtype a)
 {
   if (a >= - (SFtype) LONG_MIN)
-    return (SItype) (a + LONG_MIN) - LONG_MIN;
-  return (SItype) a;
+    return (Wtype) (a + LONG_MIN) - LONG_MIN;
+  return (Wtype) a;
 }
 #endif
 \f
@@ -1131,6 +1037,12 @@ __fixunssfsi (SFtype a)
 #define UDItype bogus_type
 #define SFtype bogus_type
 #define DFtype bogus_type
+#undef Wtype
+#undef UWtype
+#undef HWtype
+#undef UHWtype
+#undef DWtype
+#undef UDWtype
 
 #undef char
 #undef short
@@ -1147,7 +1059,7 @@ __fixunssfsi (SFtype a)
    positive if S1 is greater, 0 if S1 and S2 are equal.  */
 
 int
-__gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size)
+__gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size)
 {
   while (size > 0)
     {
@@ -1163,7 +1075,7 @@ __gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size)
 \f\f
 #ifdef L__dummy
 void
-__dummy () {}
+__dummy (void) {}
 #endif
 
 #ifdef L_varargs
@@ -1364,6 +1276,9 @@ asm ("___builtin_saveregs:");
 #if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
 
   asm ("       .text");
+#ifdef __mips16
+  asm ("       .set nomips16");
+#endif
   asm ("       .ent __builtin_saveregs");
   asm ("       .globl __builtin_saveregs");
   asm ("__builtin_saveregs:");
@@ -1375,8 +1290,8 @@ asm ("___builtin_saveregs:");
   asm ("       .end __builtin_saveregs");
 #else /* not __mips__, etc.  */
 
-void *
-__builtin_saveregs ()
+void * __attribute__ ((__noreturn__))
+__builtin_saveregs (void)
 {
   abort ();
 }
@@ -1394,7 +1309,7 @@ __builtin_saveregs ()
 /* This is used by the `assert' macro.  */
 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);
@@ -1439,9 +1354,16 @@ char *ctime ();
 
 #include "gbl-ctors.h"
 #include "gcov-io.h"
+#include <string.h>
+#ifdef TARGET_HAS_F_SETLKW
+#include <fcntl.h>
+#include <errno.h>
+#endif
 
 static struct bb *bb_head;
 
+static int num_digits (long value, int base) __attribute__ ((const));
+
 /* Return the number of digits needed to print a value */
 /* __inline__ */ static int num_digits (long value, int base)
 {
@@ -1480,17 +1402,64 @@ __bb_exit_func (void)
 
       for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
        {
-         /* If the file exists, and the number of counts in it is the same,
-            then merge them in.  */
-            
-         if ((da_file = fopen (ptr->filename, "r")) != 0)
+         int firstchar;
+
+         /* Make sure the output file exists -
+            but don't clobber exiting data.  */
+         if ((da_file = fopen (ptr->filename, "a")) != 0)
+           fclose (da_file);
+
+         /* Need to re-open in order to be able to write from the start.  */
+         da_file = fopen (ptr->filename, "r+b");
+         /* Some old systems might not allow the 'b' mode modifier.
+            Therefore, try to open without it.  This can lead to a race
+            condition so that when you delete and re-create the file, the
+            file might be opened in text mode, but then, you shouldn't
+            delete the file in the first place.  */
+         if (da_file == 0)
+           da_file = fopen (ptr->filename, "r+");
+         if (da_file == 0)
            {
-             long n_counts = 0;
-             unsigned char tmp;
-             int i;
-             int ret = 0;
+             fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+                      ptr->filename);
+             continue;
+           }
+
+         /* After a fork, another process might try to read and/or write
+            the same file simultanously.  So if we can, lock the file to
+            avoid race conditions.  */
+#if defined (TARGET_HAS_F_SETLKW)
+         {
+           struct flock s_flock;
+
+           s_flock.l_type = F_WRLCK;
+           s_flock.l_whence = SEEK_SET;
+           s_flock.l_start = 0;
+           s_flock.l_len = 1;
+           s_flock.l_pid = getpid ();
 
+           while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+                  && errno == EINTR);
+         }
+#endif
+
+         /* If the file is not empty, and the number of counts in it is the
+            same, then merge them in.  */
+         firstchar = fgetc (da_file);
+         if (firstchar == EOF)
+           {
+             if (ferror (da_file))
+               {
+                 fprintf (stderr, "arc profiling: Can't read output file ");
+                 perror (ptr->filename);
+               }
+           }
+         else
+           {
+             long n_counts = 0;
              
+             if (ungetc (firstchar, da_file) == EOF)
+               rewind (da_file);
              if (__read_long (&n_counts, da_file, 8) != 0)
                {
                  fprintf (stderr, "arc profiling: Can't read output file %s.\n",
@@ -1505,9 +1474,6 @@ __bb_exit_func (void)
                  for (i = 0; i < n_counts; i++)
                    {
                      long v = 0;
-                     unsigned char tmp;
-                     int j;
-                     int ret = 0;
 
                      if (__read_long (&v, da_file, 8) != 0)
                        {
@@ -1519,18 +1485,11 @@ __bb_exit_func (void)
                    }
                }
 
-             if (fclose (da_file) == EOF)
-               fprintf (stderr, "arc profiling: Error closing output file %s.\n",
-                        ptr->filename);
-           }
-         if ((da_file = fopen (ptr->filename, "w")) < 0)
-           {
-             fprintf (stderr, "arc profiling: Can't open output file %s.\n",
-                      ptr->filename);
-             continue;
            }
 
-         /* ??? Should first write a header to the file.  Perferably, a 4 byte
+         rewind (da_file);
+
+         /* ??? Should first write a header to the file.  Preferably, a 4 byte
             magic number, 4 bytes containing the time the program was
             compiled, 4 bytes containing the last modification time of the
             source file, and 4 bytes indicating the compiler options used.
@@ -1597,7 +1556,7 @@ __bb_exit_func (void)
       for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
        {
          int i;
-         int func_p    = (ptr->nwords >= sizeof (struct bb)
+         int func_p    = (ptr->nwords >= (long) sizeof (struct bb)
                           && ptr->nwords <= 1000
                           && ptr->functions);
          int line_p    = (func_p && ptr->line_nums);
@@ -1626,7 +1585,7 @@ __bb_exit_func (void)
              if (cnt_max < ptr->counts[i])
                cnt_max = ptr->counts[i];
 
-             if (addr_p && addr_max < ptr->addresses[i])
+             if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
                addr_max = ptr->addresses[i];
 
              if (line_p && line_max < ptr->line_nums[i])
@@ -1697,11 +1656,9 @@ __bb_init_func (struct bb *blocks)
   if (blocks->zero_word)
     return;
 
-#ifdef ON_EXIT
   /* Initialize destructor.  */
   if (!bb_head)
-    ON_EXIT (__bb_exit_func, 0);
-#endif
+    atexit (__bb_exit_func);
 
   /* Set up linked list.  */
   blocks->zero_word = 1;
@@ -1709,6 +1666,23 @@ __bb_init_func (struct bb *blocks)
   bb_head = blocks;
 }
 
+/* Called before fork or exec - write out profile information gathered so
+   far and reset it to zero.  This avoids duplication or loss of the
+   profile information gathered so far.  */
+void
+__bb_fork_func (void)
+{
+  struct bb *ptr;
+
+  __bb_exit_func ();
+  for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+    {
+      long i;
+      for (i = ptr->ncounts - 1; i >= 0; i--)
+       ptr->counts[i] = 0;
+    }
+}
+
 #ifndef MACHINE_STATE_SAVE
 #define MACHINE_STATE_SAVE(ID)
 #endif
@@ -1716,8 +1690,6 @@ __bb_init_func (struct bb *blocks)
 #define MACHINE_STATE_RESTORE(ID)
 #endif
 
-#include <string.h>
-
 /* Number of buckets in hashtable of basic block addresses.  */
 
 #define BB_BUCKETS 311
@@ -1726,11 +1698,6 @@ __bb_init_func (struct bb *blocks)
 
 #define BBINBUFSIZE 500
 
-/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
-   "BBINBUFSIZE" but want to avoid trouble with preprocessors.  */
-
-#define BBINBUFSIZESTR "499"
-
 struct bb_edge
 {
   struct bb_edge *next;
@@ -1870,11 +1837,10 @@ gclose (FILE *f)
 /* Called once per program.  */
 
 static void
-__bb_exit_trace_func ()
+__bb_exit_trace_func (void)
 {
   FILE *file = fopen ("bb.out", "a");
   struct bb_func *f;
-  struct bb_edge *e;
   struct bb *b;
         
   if (!file)
@@ -1909,7 +1875,7 @@ __bb_exit_trace_func ()
         {
           for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
             {
-              if (!ptr->filename || p->filename != (char *) 0 && strcmp (p->filename, ptr->filename))
+              if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
                 continue;
               for (blk = 0; blk < ptr->ncounts; blk++)
                 {
@@ -2009,8 +1975,8 @@ found:        ;
                struct bb_edge *bucket = bb_hashbuckets[i];
                for ( ; bucket; bucket = bucket->next )
                  {
-                   fprintf (file, "Jump from block 0x%.*lx to "
-                                  "block 0x%.*lx executed %*d time(s)\n", 
+                   fprintf (file,
+       "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n", 
                             addr_len, bucket->src_addr, 
                             addr_len, bucket->dst_addr, 
                             cnt_len, bucket->count);
@@ -2066,25 +2032,27 @@ found:        ;
 /* Called once per program.  */
 
 static void
-__bb_init_prg ()
+__bb_init_prg (void)
 {
-
   FILE *file;
   char buf[BBINBUFSIZE];
   const char *p;
   const char *pos;
   enum bb_func_mode m;
+  int i;
 
-#ifdef ON_EXIT
   /* Initialize destructor.  */
-  ON_EXIT (__bb_exit_func, 0);
-#endif
+  atexit (__bb_exit_func);
 
   if (!(file = fopen ("bb.in", "r")))
     return;
 
-  while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
+  while(fgets (buf, BBINBUFSIZE, file) != 0)
     {
+      i = strlen (buf);
+      if (buf[i] == '\n')
+       buf[i--] = '\0';
+
       p = buf;
       if (*p == '-') 
         { 
@@ -2110,7 +2078,7 @@ __bb_init_prg ()
             {
               unsigned long l;
               f->next = bb_func_head;
-              if (pos = strchr (p, ':'))
+              if ((pos = strchr (p, ':')))
                 {
                   if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
                     continue;
@@ -2155,7 +2123,10 @@ __bb_init_prg ()
       bb_hashbuckets = (struct bb_edge **) 
                    malloc (BB_BUCKETS * sizeof (struct bb_edge *));
       if (bb_hashbuckets)
-        bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+       /* Use a loop here rather than calling bzero to avoid having to
+          conditionalize its existance.  */
+       for (i = 0; i < BB_BUCKETS; i++)
+         bb_hashbuckets[i] = 0;
     }
 
   if (bb_mode & 12)
@@ -2164,17 +2135,14 @@ __bb_init_prg ()
       bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
     }
 
-#ifdef ON_EXIT
-      /* Initialize destructor.  */
-      ON_EXIT (__bb_exit_trace_func, 0);
-#endif
-
+  /* Initialize destructor.  */
+  atexit (__bb_exit_trace_func);
 }
 
 /* Called upon entering a basic block.  */
 
 void
-__bb_trace_func ()
+__bb_trace_func (void)
 {
   struct bb_edge *bucket;
 
@@ -2247,7 +2215,7 @@ skip:
 /* Called when returning from a function and `__bb_showret__' is set.  */
 
 static void
-__bb_trace_func_ret ()
+__bb_trace_func_ret (void)
 {
   struct bb_edge *bucket;
 
@@ -2345,7 +2313,7 @@ __bb_init_file (struct bb *blocks)
 /* Called when exiting from a function.  */
 
 void
-__bb_trace_ret ()
+__bb_trace_ret (void)
 {
 
   MACHINE_STATE_SAVE("2")
@@ -2436,157 +2404,6 @@ stack_overflow:;
 #endif /* not BLOCK_PROFILER_CODE */
 #endif /* L_bb */
 \f
-/* Default free-store management functions for C++, per sections 12.5 and
-   17.3.3 of the Working Paper.  */
-
-#ifdef L_op_new
-/* operator new (size_t), described in 17.3.3.5.  This function is used by
-   C++ programs to allocate a block of memory to hold a single object.  */
-
-typedef void (*vfp)(void);
-extern vfp __new_handler;
-extern void __default_new_handler (void);
-
-#ifdef WEAK_ALIAS
-void * __builtin_new (size_t sz)
-     __attribute__ ((weak, alias ("___builtin_new")));
-void *
-___builtin_new (size_t sz)
-#else
-void *
-__builtin_new (size_t sz)
-#endif
-{
-  void *p;
-  vfp handler = (__new_handler) ? __new_handler : __default_new_handler;
-
-  /* malloc (0) is unpredictable; avoid it.  */
-  if (sz == 0)
-    sz = 1;
-  p = (void *) malloc (sz);
-  while (p == 0)
-    {
-      (*handler) ();
-      p = (void *) malloc (sz);
-    }
-  
-  return p;
-}
-#endif /* L_op_new */
-
-#ifdef L_op_vnew
-/* void * operator new [] (size_t), described in 17.3.3.6.  This function
-   is used by C++ programs to allocate a block of memory for an array.  */
-
-extern void * __builtin_new (size_t);
-
-#ifdef WEAK_ALIAS
-void * __builtin_vec_new (size_t sz)
-     __attribute__ ((weak, alias ("___builtin_vec_new")));
-void *
-___builtin_vec_new (size_t sz)
-#else
-void *
-__builtin_vec_new (size_t sz)
-#endif
-{
-  return __builtin_new (sz);
-}
-#endif /* L_op_vnew */
-
-#ifdef L_new_handler
-/* set_new_handler (fvoid_t *) and the default new handler, described in
-   17.3.3.2 and 17.3.3.5.  These functions define the result of a failure
-   to allocate the amount of memory requested from operator new or new [].  */
-
-#ifndef inhibit_libc
-/* This gets us __GNU_LIBRARY__.  */
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
-#include <stdio.h>
-
-#ifdef __GNU_LIBRARY__
-  /* Avoid forcing the library's meaning of `write' on the user program
-     by using the "internal" name (for use within the library)  */
-#define write(fd, buf, n)      __write((fd), (buf), (n))
-#endif
-#endif /* inhibit_libc */
-
-typedef void (*vfp)(void);
-void __default_new_handler (void);
-
-vfp __new_handler = (vfp) 0;
-
-vfp
-set_new_handler (vfp handler)
-{
-  vfp prev_handler;
-
-  prev_handler = __new_handler;
-  if (handler == 0) handler = __default_new_handler;
-  __new_handler = handler;
-  return prev_handler;
-}
-
-#define MESSAGE "Virtual memory exceeded in `new'\n"
-
-void
-__default_new_handler ()
-{
-#ifndef inhibit_libc
-  /* don't use fprintf (stderr, ...) because it may need to call malloc.  */
-  /* This should really print the name of the program, but that is hard to
-     do.  We need a standard, clean way to get at the name.  */
-  write (2, MESSAGE, sizeof (MESSAGE));
-#endif
-  /* don't call exit () because that may call global destructors which
-     may cause a loop.  */
-  _exit (-1);
-}
-#endif
-
-#ifdef L_op_delete
-/* operator delete (void *), described in 17.3.3.3.  This function is used
-   by C++ programs to return to the free store a block of memory allocated
-   as a single object.  */
-
-#ifdef WEAK_ALIAS
-void __builtin_delete (void *ptr)
-     __attribute__ ((weak, alias ("___builtin_delete")));
-void
-___builtin_delete (void *ptr)
-#else
-void
-__builtin_delete (void *ptr)
-#endif
-{
-  if (ptr)
-    free (ptr);
-}
-#endif
-
-#ifdef L_op_vdel
-/* operator delete [] (void *), described in 17.3.3.4.  This function is
-   used by C++ programs to return to the free store a block of memory
-   allocated as an array.  */
-
-extern void __builtin_delete (void *);
-
-#ifdef WEAK_ALIAS
-void __builtin_vec_delete (void *ptr)
-     __attribute__ ((weak, alias ("___builtin_vec_delete")));
-void
-___builtin_vec_delete (void *ptr)
-#else
-void
-__builtin_vec_delete (void *ptr)
-#endif
-{
-  __builtin_delete (ptr);
-}
-#endif
-
-/* End of C++ free-store management functions */
-\f
 #ifdef L_shtab
 unsigned int __shtab[] = {
     0x00000001, 0x00000002, 0x00000004, 0x00000008,
@@ -2606,7 +2423,8 @@ unsigned int __shtab[] = {
 #define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
 
 void
-__clear_cache (char *beg, char *end)
+__clear_cache (char *beg __attribute__((__unused__)),
+              char *end __attribute__((__unused__)))
 {
 #ifdef CLEAR_INSN_CACHE 
   CLEAR_INSN_CACHE (beg, end);
@@ -2617,7 +2435,7 @@ __clear_cache (char *beg, char *end)
   int offset;
   void *start_addr
   void *end_addr;
-  typedef (*function_ptr) ();
+  typedef (*function_ptr) (void);
 
 #if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16
   /* It's cheaper to clear the whole cache.
@@ -2718,9 +2536,10 @@ __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__) && ! defined (_UWIN)
 
-long getpagesize()
+long
+getpagesize (void)
 {
 #ifdef _ALPHA_
   return 8192;
@@ -2729,7 +2548,7 @@ long getpagesize()
 #endif
 }
 
-#ifdef i386
+#ifdef __i386__
 extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
 #endif
 
@@ -2757,7 +2576,7 @@ mprotect (char *addr, int len, int prot)
     return -1;
 }
 
-#endif
+#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
 
 #ifdef TRANSFER_FROM_TRAMPOLINE 
 TRANSFER_FROM_TRAMPOLINE 
@@ -2809,7 +2628,7 @@ __enable_execute_stack (char *addr)
 #include <machine/machparam.h>
 
 void
-__enable_execute_stack ()
+__enable_execute_stack (void)
 {
   int fp;
   static unsigned lowest = USRSTACK;
@@ -2836,7 +2655,7 @@ __enable_execute_stack ()
 #include <sys/m88kbcs.h>
 
 void
-__enable_execute_stack ()
+__enable_execute_stack (void)
 {
   int save_errno;
   static unsigned long lowest = USRSTACK;
@@ -2859,6 +2678,51 @@ __enable_execute_stack ()
 
 #endif /* __sysV88__ */
 
+#ifdef __sysV68__
+
+#include <sys/signal.h>
+#include <errno.h>
+
+/* Motorola forgot to put memctl.o in the libp version of libc881.a,
+   so define it here, because we need it in __clear_insn_cache below */
+/* On older versions of this OS, no memctl or MCT_TEXT are defined;
+   hence we enable this stuff only if MCT_TEXT is #define'd.  */
+
+#ifdef MCT_TEXT
+asm("\n\
+       global memctl\n\
+memctl:\n\
+       movq &75,%d0\n\
+       trap &0\n\
+       bcc.b noerror\n\
+       jmp cerror%\n\
+noerror:\n\
+       movq &0,%d0\n\
+       rts");
+#endif
+
+/* Clear instruction cache so we can call trampolines on stack.
+   This is called from FINALIZE_TRAMPOLINE in mot3300.h.  */
+
+void
+__clear_insn_cache (void)
+{
+#ifdef MCT_TEXT
+  int save_errno;
+
+  /* Preserve errno, because users would be surprised to have
+  errno changing without explicitly calling any system-call. */
+  save_errno = errno;
+
+  /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache. 
+     No need to use an address derived from _start or %sp, as 0 works also. */
+  memctl(0, 4096, MCT_TEXT);
+  errno = save_errno;
+#endif
+}
+
+#endif /* __sysV68__ */
+
 #ifdef __pyr__
 
 #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
@@ -2872,7 +2736,7 @@ __enable_execute_stack ()
    mremap promises to clear the i-cache.  */
 
 void
-__enable_execute_stack ()
+__enable_execute_stack (void)
 {
   int fp;
   if (mprotect (((unsigned int)&fp/PAGSIZ)*PAGSIZ, PAGSIZ,
@@ -2911,6 +2775,7 @@ cacheflush (char *beg, int size, int flag)
 #endif /* sony_news */
 #endif /* L_trampoline */
 \f
+#ifndef __CYGWIN__
 #ifdef L__main
 
 #include "gbl-ctors.h"
@@ -2929,10 +2794,19 @@ cacheflush (char *beg, int size, int flag)
 #endif
 
 #if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
+
+/* Some ELF crosses use crtstuff.c to provide __CTOR_LIST__, but use this
+   code to run constructors.  In that case, we need to handle EH here, too.  */
+
+#ifdef EH_FRAME_SECTION
+#include "frame.h"
+extern unsigned char __EH_FRAME_BEGIN__[];
+#endif
+
 /* Run all the global destructors on exit from the program.  */
 
 void
-__do_global_dtors ()
+__do_global_dtors (void)
 {
 #ifdef DO_GLOBAL_DTORS_BODY
   DO_GLOBAL_DTORS_BODY;
@@ -2944,28 +2818,33 @@ __do_global_dtors ()
       (*(p-1)) ();
     }
 #endif
+#if defined (EH_FRAME_SECTION) && !defined (HAS_INIT_SECTION)
+  {
+    static int completed = 0;
+    if (! completed)
+      {
+       completed = 1;
+       __deregister_frame_info (__EH_FRAME_BEGIN__);
+      }
+  }
+#endif
 }
 #endif
 
 #ifndef HAS_INIT_SECTION
 /* Run all the global constructors on entry to the program.  */
 
-#ifndef ON_EXIT
-#define ON_EXIT(a, b)
-#else
-/* Make sure the exit routine is pulled in to define the globals as
-   bss symbols, just in case the linker does not automatically pull
-   bss definitions from the library.  */
-
-extern int _exit_dummy_decl;
-int *_exit_dummy_ref = &_exit_dummy_decl;
-#endif /* ON_EXIT */
-
 void
-__do_global_ctors ()
+__do_global_ctors (void)
 {
+#ifdef EH_FRAME_SECTION
+  {
+    static struct object object;
+    __register_frame_info (__EH_FRAME_BEGIN__, &object);
+  }
+#endif
   DO_GLOBAL_CTORS_BODY;
-  ON_EXIT (__do_global_dtors, 0);
+  atexit (__do_global_dtors);
 }
 #endif /* no HAS_INIT_SECTION */
 
@@ -2992,6 +2871,7 @@ SYMBOL__MAIN ()
 #endif /* no HAS_INIT_SECTION or INVOKE__main */
 
 #endif /* L__main */
+#endif /* __CYGWIN__ */
 \f
 #ifdef L_ctors
 
@@ -3003,10 +2883,15 @@ SYMBOL__MAIN ()
    the right values.  */
 
 /* We declare the lists here with two elements each,
-   so that they are valid empty lists if no other definition is loaded.  */
+   so that they are valid empty lists if no other definition is loaded.
+
+   If we are using the old "set" extensions to have the gnu linker
+   collect ctors and dtors, then we __CTOR_LIST__ and __DTOR_LIST__
+   must be in the bss/common section.
+
+   Long term no port should use those extensions.  But many still do.  */
 #if !defined(INIT_SECTION_ASM_OP) && !defined(CTOR_LISTS_DEFINED_EXTERNALLY)
-#if defined(__NeXT__) || defined(_AIX)
-/* After 2.3, try this definition on all systems.  */
+#if defined (ASM_OUTPUT_CONSTRUCTOR) || defined (USE_COLLECT2)
 func_ptr __CTOR_LIST__[2] = {0, 0};
 func_ptr __DTOR_LIST__[2] = {0, 0};
 #else
@@ -3021,22 +2906,17 @@ func_ptr __DTOR_LIST__[2];
 #include "gbl-ctors.h"
 
 #ifdef NEED_ATEXIT
-# ifdef ON_EXIT
-#  undef ON_EXIT
-# endif
-int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
 
 #ifndef ON_EXIT
 
-#ifdef NEED_ATEXIT
 # include <errno.h>
 
 static func_ptr *atexit_chain = 0;
 static long atexit_chain_length = 0;
 static volatile long last_atexit_chain_slot = -1;
 
-int atexit (func_ptr func)
+int
+atexit (func_ptr func)
 {
   if (++last_atexit_chain_slot == atexit_chain_length)
     {
@@ -3058,22 +2938,13 @@ int atexit (func_ptr func)
   atexit_chain[last_atexit_chain_slot] = func;
   return (0);
 }
-#endif /* NEED_ATEXIT */
-
-/* If we have no known way of registering our own __do_global_dtors
-   routine so that it will be invoked at program exit time, then we
-   have to define our own exit routine which will get this to happen.  */
 
-extern void __do_global_dtors ();
-extern void __bb_exit_func ();
-extern void _cleanup ();
-extern void _exit () __attribute__ ((noreturn));
+extern void _cleanup (void);
+extern void _exit (int) __attribute__ ((__noreturn__));
 
 void 
 exit (int status)
 {
-#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
-#ifdef NEED_ATEXIT
   if (atexit_chain)
     {
       for ( ; last_atexit_chain_slot-- >= 0; )
@@ -3084,13 +2955,6 @@ exit (int status)
       free (atexit_chain);
       atexit_chain = 0;
     }
-#else /* No NEED_ATEXIT */
-  __do_global_dtors ();
-#endif /* No NEED_ATEXIT */
-#endif
-#ifndef inhibit_libc
-  __bb_exit_func ();
-#endif
 #ifdef EXIT_BODY
   EXIT_BODY;
 #else
@@ -3099,28 +2963,37 @@ exit (int status)
   _exit (status);
 }
 
-#else
-int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
+#else /* ON_EXIT */
+
+/* Simple; we just need a wrapper for ON_EXIT.  */
+int
+atexit (func_ptr func)
+{
+  return ON_EXIT (func);
+}
+
+#endif /* ON_EXIT */
+#endif /* NEED_ATEXIT */
 
 #endif /* L_exit */
 \f
 #ifdef L_eh
 
-/* Shared exception handling support routines.  */
+#include "gthr.h"
 
-extern void *__eh_type;
+/* Shared exception handling support routines.  */
 
 void
-__default_terminate ()
+__default_terminate (void)
 {
   abort ();
 }
 
-void (*__terminate_func)() = __default_terminate;
+void (*__terminate_func)(void) __attribute__ ((__noreturn__)) =
+  __default_terminate;
 
 void
-__terminate ()
+__terminate (void)
 {
   (*__terminate_func)();
 }
@@ -3138,63 +3011,238 @@ __throw_type_match (void *catch_type, void *throw_type, void *obj)
 }
 
 void
-__empty ()
+__empty (void)
 {
 }
 \f
-/* Support routines for setjmp/longjmp exception handling.  */
 
-/* Calls to __sjthrow are generated by the compiler when an exception
-   is raised when using the setjmp/longjmp exception handling codegen
-   method.  */
+/* Include definitions of EH context and table layout */
 
-extern void longjmp (void *, int);
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
 
-static void *top_elt[2];
-void **__dynamic_handler_chain = top_elt;
+/* Allocate and return a new EH context structure. */
 
-/* Routine to get the head of the current thread's dynamic handler chain
-   use for exception handling.
+#if __GTHREADS
+static void *
+new_eh_context (void)
+{
+  struct eh_full_context {
+    struct eh_context c;
+    void *top_elt[2];
+  } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+  if (! ehfc)
+    __terminate ();
 
-   TODO: make thread safe.  */
+  memset (ehfc, 0, sizeof *ehfc);
 
-void ***
-__get_dynamic_handler_chain ()
+  ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
+
+  /* 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;
+}
+
+static __gthread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
 {
-  return &__dynamic_handler_chain;
+  __gthread_key_dtor (eh_context_key, ptr);
+  if (ptr)
+    free (ptr);
 }
+#endif
 
-/* This is used to throw an exception when the setjmp/longjmp codegen
-   method is used for exception handling.
+/* Pointer to function to return EH context. */
 
-   We call __terminate if there are no handlers left (we know this
-   when the dynamic handler chain is top_elt).  Otherwise we run the
-   cleanup actions off the dynamic cleanup stack, and pop the top of
-   the dynamic handler chain, and use longjmp to transfer back to the
-   associated handler.  */
+static struct eh_context *eh_context_initialize (void);
+static struct eh_context *eh_context_static (void);
+#if __GTHREADS
+static struct eh_context *eh_context_specific (void);
+#endif
 
-void
-__sjthrow ()
-{
-  void ***dhc = __get_dynamic_handler_chain ();
-  void *jmpbuf;
-  void (*func)(void *, int);
-  void *arg;
-  void ***cleanup;
+static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
 
-  /* The cleanup chain is one word into the buffer.  Get the cleanup
-     chain.  */
-  cleanup = (void***)&(*dhc)[1];
+/* Routine to get EH context.
+   This one will simply call the function pointer. */
 
-  /* If there are any cleanups in the chain, run them now.  */
-  if (cleanup[0])
-    {
-      double store[200];
-      void **buf = (void**)store;
-      buf[1] = 0;
-      buf[0] = (*dhc);
+void *
+__get_eh_context (void)
+{
+  return (void *) (*get_eh_context) ();
+}
+
+/* Get and set the language specific info pointer. */
+
+void **
+__get_eh_info (void)
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  return &eh->info;
+}
+\f
+#ifdef DWARF2_UNWIND_INFO
+static int dwarf_reg_size_table_initialized = 0;
+static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
+
+static void
+init_reg_size_table (void)
+{
+  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
+  dwarf_reg_size_table_initialized = 1;
+}
+#endif
+
+#if __GTHREADS
+static void
+eh_threads_initialize (void)
+{
+  /* Try to create the key.  If it fails, revert to static method,
+     otherwise start using thread specific EH contexts. */
+  if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
+    get_eh_context = &eh_context_specific;
+  else
+    get_eh_context = &eh_context_static;
+}
+#endif /* no __GTHREADS */
+
+/* Initialize EH context.
+   This will be called only once, since we change GET_EH_CONTEXT
+   pointer to another routine. */
+
+static struct eh_context *
+eh_context_initialize (void)
+{
+#if __GTHREADS
+
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  /* Make sure that get_eh_context does not point to us anymore.
+     Some systems have dummy thread routines in their libc that
+     return a success (Solaris 2.6 for example). */
+  if (__gthread_once (&once, eh_threads_initialize) != 0
+      || get_eh_context == &eh_context_initialize)
+    {
+      /* Use static version of EH context. */
+      get_eh_context = &eh_context_static;
+    }
+#ifdef DWARF2_UNWIND_INFO
+  {
+    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
+    if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
+       || ! dwarf_reg_size_table_initialized)
+      init_reg_size_table ();
+  }
+#endif
+
+#else /* no __GTHREADS */
+
+  /* Use static version of EH context. */
+  get_eh_context = &eh_context_static;
+
+#ifdef DWARF2_UNWIND_INFO
+  init_reg_size_table ();
+#endif
+
+#endif /* no __GTHREADS */
+
+  return (*get_eh_context) ();
+}
+
+/* Return a static EH context. */
+
+static struct eh_context *
+eh_context_static (void)
+{
+  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
+/* Return a thread specific EH context. */
+
+static struct eh_context *
+eh_context_specific (void)
+{
+  struct eh_context *eh;
+  eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
+  if (! eh)
+    {
+      eh = new_eh_context ();
+      if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
+       __terminate ();
+    }
+
+  return eh;
+}
+#endif /* __GTHREADS */
+\f
+/* Support routines for setjmp/longjmp exception handling.  */
+
+/* Calls to __sjthrow are generated by the compiler when an exception
+   is raised when using the setjmp/longjmp exception handling codegen
+   method.  */
 
-      /* try { */
+#ifdef DONT_USE_BUILTIN_SETJMP
+extern void longjmp (void *, int);
+#endif
+
+/* Routine to get the head of the current thread's dynamic handler chain
+   use for exception handling. */
+
+void ***
+__get_dynamic_handler_chain (void)
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  return &eh->dynamic_handler_chain;
+}
+
+/* This is used to throw an exception when the setjmp/longjmp codegen
+   method is used for exception handling.
+
+   We call __terminate if there are no handlers left.  Otherwise we run the
+   cleanup actions off the dynamic cleanup stack, and pop the top of the
+   dynamic handler chain, and use longjmp to transfer back to the associated
+   handler.  */
+
+void
+__sjthrow (void)
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void ***dhc = &eh->dynamic_handler_chain;
+  void *jmpbuf;
+  void (*func)(void *, int);
+  void *arg;
+  /* The cleanup chain is one word into the buffer.  Get the cleanup chain. */
+  void ***cleanup = (void***)&(*dhc)[1];
+
+  /* If there are any cleanups in the chain, run them now.  */
+  if (cleanup[0])
+    {
+      double store[200];
+      void **buf = (void**)store;
+      buf[1] = 0;
+      buf[0] = (*dhc);
+
+      /* try { */
 #ifdef DONT_USE_BUILTIN_SETJMP
       if (! setjmp (&buf[2]))
 #else
@@ -3224,7 +3272,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_type || (*dhc) == top_elt)
+  if (! eh->info || (*dhc)[0] == 0)
     __terminate ();
     
   /* Find the jmpbuf associated with the top element of the dynamic
@@ -3249,17 +3297,14 @@ __sjthrow ()
    control to the next handler in the dynamic handler stack.  */
 
 void
-__sjpopnthrow ()
+__sjpopnthrow (void)
 {
-  void ***dhc = __get_dynamic_handler_chain ();
-  void *jmpbuf;
+  struct eh_context *eh = (*get_eh_context) ();
+  void ***dhc = &eh->dynamic_handler_chain;
   void (*func)(void *, int);
   void *arg;
-  void ***cleanup;
-
-  /* The cleanup chain is one word into the buffer.  Get the cleanup
-     chain.  */
-  cleanup = (void***)&(*dhc)[1];
+  /* The cleanup chain is one word into the buffer.  Get the cleanup chain. */
+  void ***cleanup = (void***)&(*dhc)[1];
 
   /* If there are any cleanups in the chain, run them now.  */
   if (cleanup[0])
@@ -3304,22 +3349,52 @@ __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.  */
 
-extern void *__eh_pc;
-
 #ifdef EH_TABLE_LOOKUP
 
 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
@@ -3330,7 +3405,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)
     {
@@ -3338,186 +3413,109 @@ 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 && 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;
 }
-#endif /* EH_TABLE_LOOKUP */
-\f
-#ifndef DWARF2_UNWIND_INFO
-/* Support code for exception handling using inline unwinders or
-   __unwind_function.  */
 
-#ifndef EH_TABLE_LOOKUP
-typedef struct exception_table_node {
-  exception_table *table;
-  void *start;
-  void *end;
-  struct exception_table_node *next;
-} exception_table_node;
-
-static struct exception_table_node *exception_table_list;
-
-void *
-__find_first_exception_table_match (void *pc)
+/* 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)
 {
-  register exception_table_node *tnp;
 
-  for (tnp = exception_table_list; tnp != 0; tnp = tnp->next)
+  void *retval = NULL;
+  *cleanup = 1;
+  if (table)
     {
-      if (tnp->start <= pc && tnp->end >= pc)
-       return find_exception_handler (pc, tnp->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 */
 
-  return (void *) 0;
-}
-
-void
-__register_exceptions (exception_table *table)
-{
-  exception_table_node *node;
-  exception_table *range = table + 1;
-
-  if (range->start == (void *) -1)
-    return;
-
-  node = (exception_table_node *) malloc (sizeof (exception_table_node));
-  node->table = table;
+      exception_table *tab = &(table->table[0]);
 
-  /* This look can be optimized away either if the table
-     is sorted, or if we pass in extra parameters.  */
-  node->start = range->start;
-  node->end = range->end;
-  for (range++ ; range->start != (void *) (-1); range++)
-    {
-      if (range->start < node->start)
-       node->start = range->start;
-      if (range->end > node->end)
-       node->end = range->end;
+      /* 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;
+                }
+            }
+        }
     }
-
-  node->next = exception_table_list;
-  exception_table_list = node;
+  return retval;
 }
-#endif /* !EH_TABLE_LOOKUP */
-
-/* Throw stub routine.
-
-   This is work in progress, but not completed yet.  */
-
-void
-__throw ()
-{
-  abort ();
-}
-
-/* See expand_builtin_throw for details.  */
-
-void **__eh_pcnthrow () {
-  static void *buf[2] = {
-    &__eh_pc,
-    &__throw
-  };
-  return buf;
-}
-
-#if #machine(i386)
-void
-__unwind_function(void *ptr)
-{
-  asm("movl 8(%esp),%ecx");
-  /* Undo current frame */
-  asm("movl %ebp,%esp");
-  asm("popl %ebp");
-  /* like ret, but stay here */
-  asm("addl $4,%esp");
-  
-  /* Now, undo previous frame.  */
-  /* This is a test routine, as we have to dynamically probe to find out
-     what to pop for certain, this is just a guess.  */
-  asm("leal -16(%ebp),%esp");
-  asm("pop %ebx");
-  asm("pop %esi");
-  asm("pop %edi");
-  asm("movl %ebp,%esp");
-  asm("popl %ebp");
-
-  asm("movl %ecx,0(%esp)");
-  asm("ret");
-}
-#elif #machine(rs6000) && !defined _ARCH_PPC
-__unwind_function(void *ptr)
-{
-  asm("mr 31,1");
-  asm("l 1,0(1)");
-  asm("l 31,-4(1)");
-  asm("# br");
-
-  asm("mr 31,1");
-  asm("l 1,0(1)");
-  /* use 31 as a scratch register to restore the link register.  */
-  asm("l 31, 8(1);mtlr 31 # l lr,8(1)");
-  asm("l 31,-4(1)");
-  asm("# br");
-  asm("mtctr 3;bctr # b 3");
-}
-#elif (#machine(rs6000) || #machine(powerpc)) && defined _ARCH_PPC
-__unwind_function(void *ptr)
-{
-  asm("mr 31,1");
-  asm("lwz 1,0(1)");
-  asm("lwz 31,-4(1)");
-  asm("# br");
-
-  asm("mr 31,1");
-  asm("lwz 1,0(1)");
-  /* use 31 as a scratch register to restore the link register.  */
-  asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)");
-  asm("lwz 31,-4(1)");
-  asm("# br");
-  asm("mtctr 3;bctr # b 3");
-}
-#elif #machine(vax)
-__unwind_function(void *ptr)
-{
-  __label__ return_again;
-
-  /* Replace our frame's return address with the label below.
-     During execution, we will first return here instead of to
-     caller, then second return takes caller's frame off the stack.
-     Two returns matches two actual calls, so is less likely to
-     confuse debuggers.  `16' corresponds to RETURN_ADDRESS_OFFSET.  */
-  __asm ("movl %0,16(fp)" : : "p" (&& return_again));
-  return;
-
- return_again:
-  return;
-}
-#else
-__unwind_function(void *ptr)
-{
-  abort ();
-}
-#endif /* powerpc */
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* EH_TABLE_LOOKUP */
 \f
-#else /* DWARF2_UNWIND_INFO */
+#ifdef DWARF2_UNWIND_INFO
 /* Support code for exception handling using static unwind information.  */
 
 #include "frame.h"
@@ -3529,35 +3527,92 @@ __unwind_function(void *ptr)
 
 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 __attribute__ ((__unused__)),
+              frame_state *udata __attribute__ ((__unused__)))
+{
+  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;
 }
 
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
-   frame called by UDATA or 0.  */
+/* Copy the saved value for register REG from frame UDATA to frame
+   TARGET_UDATA.  Unlike the previous two functions, this can handle
+   registers that are not one word large.  */
+
+static void
+copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
+{
+  word_type *preg = get_reg_addr (reg, udata, NULL);
+  word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+  memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
+}
+
+/* Retrieve the return address for frame UDATA.  */
 
 static inline void *
 get_return_addr (frame_state *udata, frame_state *sub_udata)
@@ -3597,72 +3652,52 @@ 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 (void)
 {
-  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.
+/* 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.
 
-   If we find one, then we unwind the frames down to the one that
-   has the handler and transfer control into the handler.  */
+   EH is the current eh_context structure.
+   PC is the address of the call to __throw.
+   MY_UDATA is the unwind information for __throw.
+   OFFSET_P is where we return the SP adjustment offset.  */
 
-void
-__throw ()
-{
-  void *pc, *handler, *retaddr;
-  frame_state ustruct, ustruct2;
-  frame_state *udata = &ustruct;
-  frame_state *sub_udata = &ustruct2;
-  frame_state my_ustruct, *my_udata = &my_ustruct;
+static void *
+throw_helper (struct eh_context *eh, void *pc, frame_state *my_udata,
+             long *offset_p)
+{
+  frame_state ustruct2, *udata = &ustruct2;
+  frame_state ustruct;
+  frame_state *sub_udata = &ustruct;
+  void *saved_pc = pc;
+  void *handler;
+  void *handler_p = 0;
+  void *pc_p = 0;
+  frame_state saved_ustruct;
+  int new_eh_model;
+  int cleanup = 0;
+  int only_cleanup = 0;
+  int rethrow = 0;
+  int saved_state = 0;
   long args_size;
+  __eh_info *eh_info = (__eh_info *)eh->info;
 
-  /* 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_type)
-    __terminate ();
-    
-  /* Start at our stack frame.  */
-label:
-  udata = __frame_state_for (&&label, udata);
-  if (! udata)
-    __terminate ();
+  /* Do we find a handler based on a re-throw PC? */
+  if (eh->table_index != (void *) 0)
+    rethrow = 1;
 
-  /* 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 = __eh_pc;
+  memcpy (udata, my_udata, sizeof (*udata));
 
+  handler = (void *) 0;
   for (;;)
     { 
       frame_state *p = udata;
@@ -3673,31 +3708,78 @@ 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.  */
-      pc = get_return_addr (udata, sub_udata);
+      /* 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 == __eh_pc)
+  args_size = udata->args_size;
+
+  if (pc == saved_pc)
     /* We found a handler in the throw context, no need to unwind.  */
     udata = my_udata;
   else
     {
       int i;
-      void *val;
 
       /* Unwind all the frames between this one and the handler by copying
         their saved register values into our register save slots.  */
@@ -3706,7 +3788,7 @@ label:
       void *handler_pc = pc;
 
       /* Start from the throw context again.  */
-      pc = __eh_pc;
+      pc = saved_pc;
       memcpy (udata, my_udata, sizeof (*udata));
 
       while (pc != handler_pc)
@@ -3715,10 +3797,9 @@ label:
          udata = next_stack_level (pc, udata, sub_udata);
          sub_udata = p;
 
-         for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
-           if (udata->saved[i])
+         for (i = 0; i < DWARF_FRAME_REGISTERS; ++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
@@ -3727,15 +3808,12 @@ label:
                    && udata->saved[udata->retaddr_column] == REG_SAVED_REG
                    && udata->reg_or_offset[udata->retaddr_column] == i)
                  continue;
-#endif
-               val = get_reg (i, udata, sub_udata);
-               put_reg (i, val, my_udata);
+               copy_reg (i, udata, my_udata);
              }
 
-         pc = get_return_addr (udata, sub_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.  */
@@ -3743,39 +3821,129 @@ label:
        {
          i = udata->reg_or_offset[udata->retaddr_column];
          if (in_reg_window (i, udata))
-           {
-             val = get_reg (i, udata, sub_udata);
-             put_reg (i, val, my_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 ();
-
-  /* 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);
-
-  /* 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,
+  /* We adjust SP by the difference between __throw's CFA and the CFA for
+     the frame called by the handler frame, because those CFAs correspond
+     to the SP values at the two call sites.  We need to further adjust by
+     the args_size of the handler frame itself to get the handler frame's
+     SP from before the args were pushed for that call.  */
 #ifdef STACK_GROWS_DOWNWARD
-                        udata->cfa - my_udata->cfa
+  *offset_p = udata->cfa - my_udata->cfa + args_size;
 #else
-                        my_udata->cfa - udata->cfa
+  *offset_p = my_udata->cfa - udata->cfa - args_size;
 #endif
-                        + args_size
-                        );
+                      
+  return handler;
+}
+
+
+/* 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.  */
+
+/*extern void __throw(void) __attribute__ ((__noreturn__));*/
+
+void
+__throw (void)
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  long offset;
+
+  /* XXX maybe make my_ustruct static so we don't have to look it up for
+     each throw.  */
+  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:
+  my_udata = __frame_state_for (&&label, my_udata);
+  if (! my_udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  my_udata->cfa = __builtin_dwarf_cfa ();
+
+  /* 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, &offset);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh, offset, handler);
+
+  /* Epilogue:  restore the handler frame's register values and return
+     to the stub.  */
+}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (void *index)
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void *pc, *handler;
+  long offset;
+
+  /* XXX maybe make my_ustruct static so we don't have to look it up for
+     each throw.  */
+  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:
+  my_udata = __frame_state_for (&&label, my_udata);
+  if (! my_udata)
+    __terminate ();
+
+  /* We need to get the value from the CFA register. */
+  my_udata->cfa = __builtin_dwarf_cfa ();
+
+  /* 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, &offset);
+
+  /* Now go!  */
+
+  __builtin_eh_return ((void *)eh, offset, handler);
 
   /* Epilogue:  restore the handler frame's register values and return
      to the stub.  */
 }
-#endif /* !DWARF2_UNWIND_INFO */
+#endif /* DWARF2_UNWIND_INFO */
 
 #endif /* L_eh */
 \f
@@ -3795,11 +3963,11 @@ label:
 #define MESSAGE "pure virtual method called\n"
 
 void
-__pure_virtual ()
+__pure_virtual (void)
 {
 #ifndef inhibit_libc
   write (2, MESSAGE, sizeof (MESSAGE) - 1);
 #endif
-  _exit (-1);
+  __terminate ();
 }
 #endif