OSDN Git Service

* libgcc2.c (__do_global_ctors): Call atexit with one arg.
[pf3gnuchains/gcc-fork.git] / gcc / libgcc2.c
index b7458ef..a27caa3 100644 (file)
@@ -1,6 +1,6 @@
 /* More subroutines needed by GCC output code on some machines.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -31,6 +31,17 @@ Boston, MA 02111-1307, USA.  */
    do not apply.  */
 
 #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" 
 #ifndef L_trampoline
@@ -42,8 +53,11 @@ Boston, MA 02111-1307, USA.  */
 #undef abort
 #endif
 
-#if (SUPPORTS_WEAK == 1) && defined (ASM_OUTPUT_DEF)
-#define WEAK_ALIAS
+/* In a cross-compilation situation, default to inhibiting compilation
+   of routines that use libc.  */
+
+#if defined(CROSS_COMPILE) && !defined(inhibit_libc)
+#define inhibit_libc
 #endif
 
 /* Permit the tm.h file to select the endianness to use just for this
@@ -54,6 +68,10 @@ Boston, MA 02111-1307, USA.  */
 #define LIBGCC2_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
 #endif
 
+#ifndef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE LONG_DOUBLE_TYPE_SIZE
+#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
@@ -72,10 +90,10 @@ 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
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 typedef                float XFtype    __attribute__ ((mode (XF)));
 #endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 typedef                float TFtype    __attribute__ ((mode (TF)));
 #endif
 
@@ -126,10 +144,10 @@ typedef union
 
 extern DItype __fixunssfdi (SFtype a);
 extern DItype __fixunsdfdi (DFtype a);
-#if LONG_DOUBLE_TYPE_SIZE == 96
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96
 extern DItype __fixunsxfdi (XFtype a);
 #endif
-#if LONG_DOUBLE_TYPE_SIZE == 128
+#if LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128
 extern DItype __fixunstfdi (TFtype a);
 #endif
 \f
@@ -138,8 +156,7 @@ extern DItype __fixunstfdi (TFtype a);
 static inline
 #endif
 DItype
-__negdi2 (u)
-     DItype u;
+__negdi2 (DItype u)
 {
   DIunion w;
   DIunion uu;
@@ -153,11 +170,11 @@ __negdi2 (u)
 }
 #endif
 \f
+/* 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 (u, b)
-     DItype u;
-     word_type b;
+__lshrdi3 (DItype u, word_type b)
 {
   DIunion w;
   word_type bm;
@@ -187,9 +204,7 @@ __lshrdi3 (u, b)
 
 #ifdef L_ashldi3
 DItype
-__ashldi3 (u, b)
-     DItype u;
-     word_type b;
+__ashldi3 (DItype u, word_type b)
 {
   DIunion w;
   word_type bm;
@@ -219,9 +234,7 @@ __ashldi3 (u, b)
 
 #ifdef L_ashrdi3
 DItype
-__ashrdi3 (u, b)
-     DItype u;
-     word_type b;
+__ashrdi3 (DItype u, word_type b)
 {
   DIunion w;
   word_type bm;
@@ -252,8 +265,7 @@ __ashrdi3 (u, b)
 \f
 #ifdef L_ffsdi2
 DItype
-__ffsdi2 (u)
-     DItype u;
+__ffsdi2 (DItype u)
 {
   DIunion uu, w;
   uu.ll = u;
@@ -273,8 +285,7 @@ __ffsdi2 (u)
 \f
 #ifdef L_muldi3
 DItype
-__muldi3 (u, v)
-     DItype u, v;
+__muldi3 (DItype u, DItype v)
 {
   DIunion w;
   DIunion uu, vv;
@@ -293,8 +304,7 @@ __muldi3 (u, v)
 #ifdef L_udiv_w_sdiv
 #if defined (sdiv_qrnnd)
 USItype
-__udiv_w_sdiv (rp, a1, a0, d)
-     USItype *rp, a1, a0, d;
+__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
 {
   USItype q, r;
   USItype c0, c1, b1;
@@ -392,9 +402,13 @@ __udiv_w_sdiv (rp, a1, a0, d)
 #else
 /* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv.  */
 USItype
-__udiv_w_sdiv (rp, a1, a0, d)
-     USItype *rp, a1, a0, d;
-{}
+__udiv_w_sdiv (USItype *rp __attribute__ ((__unused__)),
+              USItype a1 __attribute__ ((__unused__)),
+              USItype a0 __attribute__ ((__unused__)),
+              USItype d __attribute__ ((__unused__)))
+{
+  return 0;
+}
 #endif
 #endif
 \f
@@ -421,9 +435,7 @@ static const UQItype __clz_tab[] =
 static inline
 #endif
 UDItype
-__udivmoddi4 (n, d, rp)
-     UDItype n, d;
-     UDItype *rp;
+__udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
 {
   DIunion ww;
   DIunion nn, dd;
@@ -533,7 +545,7 @@ __udivmoddi4 (n, d, rp)
              udiv_qrnnd (q1, n1, n2, n1, d0);
            }
 
-         /* n1 != d0... */
+         /* n1 != d0...  */
 
          udiv_qrnnd (q0, n0, n1, n0, d0);
 
@@ -644,8 +656,7 @@ __udivmoddi4 (n, d, rp)
 UDItype __udivmoddi4 ();
 
 DItype
-__divdi3 (u, v)
-     DItype u, v;
+__divdi3 (DItype u, DItype v)
 {
   word_type c = 0;
   DIunion uu, vv;
@@ -672,8 +683,7 @@ __divdi3 (u, v)
 #ifdef L_moddi3
 UDItype __udivmoddi4 ();
 DItype
-__moddi3 (u, v)
-     DItype u, v;
+__moddi3 (DItype u, DItype v)
 {
   word_type c = 0;
   DIunion uu, vv;
@@ -699,8 +709,7 @@ __moddi3 (u, v)
 #ifdef L_umoddi3
 UDItype __udivmoddi4 ();
 UDItype
-__umoddi3 (u, v)
-     UDItype u, v;
+__umoddi3 (UDItype u, UDItype v)
 {
   UDItype w;
 
@@ -713,8 +722,7 @@ __umoddi3 (u, v)
 #ifdef L_udivdi3
 UDItype __udivmoddi4 ();
 UDItype
-__udivdi3 (n, d)
-     UDItype n, d;
+__udivdi3 (UDItype n, UDItype d)
 {
   return __udivmoddi4 (n, d, (UDItype *) 0);
 }
@@ -722,8 +730,7 @@ __udivdi3 (n, d)
 \f
 #ifdef L_cmpdi2
 word_type
-__cmpdi2 (a, b)
-     DItype a, b;
+__cmpdi2 (DItype a, DItype b)
 {
   DIunion au, bu;
 
@@ -743,8 +750,7 @@ __cmpdi2 (a, b)
 
 #ifdef L_ucmpdi2
 word_type
-__ucmpdi2 (a, b)
-     DItype a, b;
+__ucmpdi2 (DItype a, DItype b)
 {
   DIunion au, bu;
 
@@ -762,13 +768,12 @@ __ucmpdi2 (a, b)
 }
 #endif
 \f
-#if defined(L_fixunstfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_fixunstfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
 DItype
-__fixunstfdi (a)
-     TFtype a;
+__fixunstfdi (TFtype a)
 {
   TFtype b;
   UDItype v;
@@ -795,10 +800,9 @@ __fixunstfdi (a)
 }
 #endif
 
-#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_fixtfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
 DItype
-__fixtfdi (a)
-     TFtype a;
+__fixtfdi (TFtype a)
 {
   if (a < 0)
     return - __fixunstfdi (-a);
@@ -806,13 +810,12 @@ __fixtfdi (a)
 }
 #endif
 
-#if defined(L_fixunsxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_fixunsxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
 #define WORD_SIZE (sizeof (SItype) * BITS_PER_UNIT)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
 DItype
-__fixunsxfdi (a)
-     XFtype a;
+__fixunsxfdi (XFtype a)
 {
   XFtype b;
   UDItype v;
@@ -839,10 +842,9 @@ __fixunsxfdi (a)
 }
 #endif
 
-#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_fixxfdi) && (LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 96)
 DItype
-__fixxfdi (a)
-     XFtype a;
+__fixxfdi (XFtype a)
 {
   if (a < 0)
     return - __fixunsxfdi (-a);
@@ -855,8 +857,7 @@ __fixxfdi (a)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
 DItype
-__fixunsdfdi (a)
-     DFtype a;
+__fixunsdfdi (DFtype a)
 {
   DFtype b;
   UDItype v;
@@ -885,8 +886,7 @@ __fixunsdfdi (a)
 
 #ifdef L_fixdfdi
 DItype
-__fixdfdi (a)
-     DFtype a;
+__fixdfdi (DFtype a)
 {
   if (a < 0)
     return - __fixunsdfdi (-a);
@@ -940,51 +940,41 @@ __fixsfdi (SFtype a)
 }
 #endif
 
-#if defined(L_floatdixf) && (LONG_DOUBLE_TYPE_SIZE == 96)
+#if defined(L_floatdixf) && (LIBGCC2_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)
 
 XFtype
-__floatdixf (u)
-     DItype u;
+__floatdixf (DItype u)
 {
   XFtype d;
-  SItype negate = 0;
 
-  if (u < 0)
-    u = -u, negate = 1;
-
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
-#if defined(L_floatditf) && (LONG_DOUBLE_TYPE_SIZE == 128)
+#if defined(L_floatditf) && (LIBGCC2_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)
 
 TFtype
-__floatditf (u)
-     DItype u;
+__floatditf (DItype u)
 {
   TFtype d;
-  SItype negate = 0;
-
-  if (u < 0)
-    u = -u, negate = 1;
 
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
@@ -994,21 +984,16 @@ __floatditf (u)
 #define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
 
 DFtype
-__floatdidf (u)
-     DItype u;
+__floatdidf (DItype u)
 {
   DFtype d;
-  SItype negate = 0;
 
-  if (u < 0)
-    u = -u, negate = 1;
-
-  d = (USItype) (u >> WORD_SIZE);
+  d = (SItype) (u >> WORD_SIZE);
   d *= HIGH_HALFWORD_COEFF;
   d *= HIGH_HALFWORD_COEFF;
   d += (USItype) (u & (HIGH_WORD_COEFF - 1));
 
-  return (negate ? -d : d);
+  return d;
 }
 #endif
 
@@ -1047,17 +1032,12 @@ __floatdidf (u)
 #endif
 
 SFtype
-__floatdisf (u)
-     DItype u;
+__floatdisf (DItype 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,
@@ -1069,22 +1049,23 @@ __floatdisf (u)
       && DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
     {
 #define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
-      if (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;
        }
     }
-  f = (USItype) (u >> WORD_SIZE);
+  f = (SItype) (u >> WORD_SIZE);
   f *= HIGH_HALFWORD_COEFF;
   f *= HIGH_HALFWORD_COEFF;
   f += (USItype) (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
@@ -1098,8 +1079,7 @@ __floatdisf (u)
 #include <limits.h>
 
 USItype
-__fixunsxfsi (a)
-     XFtype a;
+__fixunsxfsi (XFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
     return (SItype) (a + LONG_MIN) - LONG_MIN;
@@ -1121,8 +1101,7 @@ __fixunsxfsi (a)
 #include <limits.h>
 
 USItype
-__fixunsdfsi (a)
-     DFtype a;
+__fixunsdfsi (DFtype a)
 {
   if (a >= - (DFtype) LONG_MIN)
     return (SItype) (a + LONG_MIN) - LONG_MIN;
@@ -1176,9 +1155,7 @@ __fixunssfsi (SFtype a)
    positive if S1 is greater, 0 if S1 and S2 are equal.  */
 
 int
-__gcc_bcmp (s1, s2, size)
-     unsigned char *s1, *s2;
-     size_t size;
+__gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size)
 {
   while (size > 0)
     {
@@ -1192,6 +1169,11 @@ __gcc_bcmp (s1, s2, size)
 
 #endif
 \f\f
+#ifdef L__dummy
+void
+__dummy () {}
+#endif
+
 #ifdef L_varargs
 #ifdef __i860__
 #if defined(__svr4__) || defined(__alliant__)
@@ -1390,6 +1372,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:");
@@ -1399,7 +1384,7 @@ asm ("___builtin_saveregs:");
   asm ("       sw      $7,12($30)");
   asm ("       j       $31");
   asm ("       .end __builtin_saveregs");
-#else /* not __mips__, etc. */
+#else /* not __mips__, etc.  */
 
 void *
 __builtin_saveregs ()
@@ -1418,12 +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 (string, expression, line, filename)
-     const char *string;
-     const char *expression;
-     int line;
-     const char *filename;
+__eprintf (const char *string, const char *expression,
+          unsigned int line, const char *filename)
 {
   fprintf (stderr, string, expression, line, filename);
   fflush (stderr);
@@ -1466,19 +1451,9 @@ BLOCK_PROFILER_CODE
 #include <stdio.h>
 char *ctime ();
 
-#ifdef HAVE_ATEXIT
-#ifdef WINNT
-extern int atexit (void (*) (void));
-#else
-extern void atexit (void (*) (void));
-#endif
-#define ON_EXIT(FUNC,ARG) atexit ((FUNC))
-#else
-#ifdef sun
-extern void on_exit (void*, void*);
-#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))
-#endif
-#endif
+#include "gbl-ctors.h"
+#include "gcov-io.h"
+#include <string.h>
 
 static struct bb *bb_head;
 
@@ -1502,8 +1477,111 @@ static struct bb *bb_head;
 void
 __bb_exit_func (void)
 {
-  FILE *file = fopen ("bb.out", "a");
+  FILE *da_file, *file;
   long time_value;
+  int i;
+
+  if (bb_head == 0)
+    return;
+
+  i = strlen (bb_head->filename) - 3;
+
+  if (!strcmp (bb_head->filename+i, ".da"))
+    {
+      /* Must be -fprofile-arcs not -a.
+        Dump data in a form that gcov expects.  */
+
+      struct bb *ptr;
+
+      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)
+           {
+             long n_counts = 0;
+             
+             if (__read_long (&n_counts, da_file, 8) != 0)
+               {
+                 fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+                          ptr->filename);
+                 continue;
+               }
+
+             if (n_counts == ptr->ncounts)
+               {
+                 int i;
+
+                 for (i = 0; i < n_counts; i++)
+                   {
+                     long v = 0;
+
+                     if (__read_long (&v, da_file, 8) != 0)
+                       {
+                         fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+                                  ptr->filename);
+                         break;
+                       }
+                     ptr->counts[i] += v;
+                   }
+               }
+
+             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.  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.
+
+            That way we can easily verify that the proper source/executable/
+            data file combination is being used from gcov.  */
+
+         if (__write_long (ptr->ncounts, da_file, 8) != 0)
+           {
+             
+             fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+                      ptr->filename);
+           }
+         else
+           {
+             int j;
+             long *count_ptr = ptr->counts;
+             int ret = 0;
+             for (j = ptr->ncounts; j > 0; j--)
+               {
+                 if (__write_long (*count_ptr, da_file, 8) != 0)
+                   {
+                     ret=1;
+                     break;
+                   }
+                 count_ptr++;
+               }
+             if (ret)
+               fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+                        ptr->filename);
+           }
+         
+         if (fclose (da_file) == EOF)
+           fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+                    ptr->filename);
+       }
+
+      return;
+    }
+
+  /* Must be basic block profiling.  Emit a human readable output file.  */
+
+  file = fopen ("bb.out", "a");
 
   if (!file)
     perror ("bb.out");
@@ -1524,12 +1602,15 @@ __bb_exit_func (void)
       /* We check the length field explicitly in order to allow compatibility
         with older GCC's which did not provide it.  */
 
-      for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
+      for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
        {
          int i;
-         int func_p    = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000);
+         int func_p    = (ptr->nwords >= sizeof (struct bb)
+                          && ptr->nwords <= 1000
+                          && ptr->functions);
          int line_p    = (func_p && ptr->line_nums);
          int file_p    = (func_p && ptr->filenames);
+         int addr_p    = (ptr->addresses != 0);
          long ncounts  = ptr->ncounts;
          long cnt_max  = 0;
          long line_max = 0;
@@ -1553,7 +1634,7 @@ __bb_exit_func (void)
              if (cnt_max < ptr->counts[i])
                cnt_max = ptr->counts[i];
 
-             if (addr_max < ptr->addresses[i])
+             if (addr_p && addr_max < ptr->addresses[i])
                addr_max = ptr->addresses[i];
 
              if (line_p && line_max < ptr->line_nums[i])
@@ -1584,10 +1665,13 @@ __bb_exit_func (void)
          for (i = 0; i < ncounts; i++)
            {
              fprintf (file,
-                      "    Block #%*d: executed %*ld time(s) address= 0x%.*lx",
+                      "    Block #%*d: executed %*ld time(s)",
                       blk_len, i+1,
-                      cnt_len, ptr->counts[i],
-                      addr_len, ptr->addresses[i]);
+                      cnt_len, ptr->counts[i]);
+
+             if (addr_p)
+               fprintf (file, " address= 0x%.*lx", addr_len,
+                        ptr->addresses[i]);
 
              if (func_p)
                fprintf (file, " function= %-*s", func_len,
@@ -1616,16 +1700,14 @@ void
 __bb_init_func (struct bb *blocks)
 {
   /* User is supposed to check whether the first word is non-0,
-     but just in case.... */
+     but just in case....  */
 
   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;
@@ -1640,18 +1722,16 @@ __bb_init_func (struct bb *blocks)
 #define MACHINE_STATE_RESTORE(ID)
 #endif
 
-#include <string.h>
-
-/* Number of buckets in hashtable of basic block addresses. */
+/* Number of buckets in hashtable of basic block addresses.  */
 
 #define BB_BUCKETS 311
 
-/* Maximum length of string in file bb.in. */
+/* Maximum length of string in file bb.in.  */
 
 #define BBINBUFSIZE 500
 
 /* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
-   "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
+   "BBINBUFSIZE" but want to avoid trouble with preprocessors.  */
 
 #define BBINBUFSIZESTR "499"
 
@@ -1678,7 +1758,7 @@ struct bb_func
 
 /* This is the connection to the outside world.
    The BLOCK_PROFILER macro must set __bb.blocks
-   and __bb.blockno. */
+   and __bb.blockno.  */
 
 struct {
   unsigned long blockno;
@@ -1686,18 +1766,18 @@ struct {
 } __bb;
 
 /* Vars to store addrs of source and destination basic blocks 
-   of a jump. */
+   of a jump.  */
 
 static unsigned long bb_src = 0;
 static unsigned long bb_dst = 0;
 
-static FILE *bb_tracefile = (FILE*)0;
-static struct bb_edge **bb_hashbuckets = (struct bb_edge**)0;
-static struct bb_func *bb_func_head = (struct bb_func*)0;
+static FILE *bb_tracefile = (FILE *) 0;
+static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
+static struct bb_func *bb_func_head = (struct bb_func *) 0;
 static unsigned long bb_callcount = 0;
 static int bb_mode = 0;
 
-static unsigned long *bb_stack = (unsigned long *)0;
+static unsigned long *bb_stack = (unsigned long *) 0;
 static size_t bb_stacksize = 0;
 
 static int reported = 0;
@@ -1717,40 +1797,38 @@ bb_mode & 8 != 0   :   Insert return instructions in basic block flow.
 #include <sys/stat.h>
 /*#include <malloc.h>*/
 
-/* Commands executed by gopen. */
+/* Commands executed by gopen.  */
 
 #define GOPENDECOMPRESS "gzip -cd "
 #define GOPENCOMPRESS "gzip -c >"
 
 /* Like fopen but pipes through gzip.  mode may only be "r" or "w".
    If it does not compile, simply replace gopen by fopen and delete
-   '.gz' from any first parameter to gopen. */
+   '.gz' from any first parameter to gopen.  */
 
 static FILE *
-gopen (fn, mode)
-     char *fn;
-     char *mode;
+gopen (char *fn, char *mode)
 {
   int use_gzip;
   char *p;
 
   if (mode[1])
-    return (FILE*)0;
+    return (FILE *) 0;
 
   if (mode[0] != 'r' && mode[0] != 'w') 
-    return (FILE*)0;
+    return (FILE *) 0;
 
   p = fn + strlen (fn)-1;
-  use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z')) ||
-              (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
+  use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
+             || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
 
   if (use_gzip)
     {
       if (mode[0]=='r')
         {
           FILE *f;
-          char *s = (char*) malloc (sizeof (char) * strlen (fn)
-                                    + sizeof (GOPENDECOMPRESS));
+          char *s = (char *) malloc (sizeof (char) * strlen (fn)
+                                    + sizeof (GOPENDECOMPRESS));
           strcpy (s, GOPENDECOMPRESS);
           strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
           f = popen (s, mode);
@@ -1761,8 +1839,8 @@ gopen (fn, mode)
       else
         {
           FILE *f;
-          char *s = (char*) malloc (sizeof (char) * strlen (fn)
-                                    + sizeof (GOPENCOMPRESS));
+          char *s = (char *) malloc (sizeof (char) * strlen (fn)
+                                    + sizeof (GOPENCOMPRESS));
           strcpy (s, GOPENCOMPRESS);
           strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
           if (!(f = popen (s, mode)))
@@ -1777,12 +1855,11 @@ gopen (fn, mode)
 }
 
 static int
-gclose (f)
-     FILE *f;
+gclose (FILE *f)
 {
   struct stat buf;
 
-  if (f != NULL)
+  if (f != 0)
     {
       if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
         return pclose (f);
@@ -1794,14 +1871,13 @@ gclose (f)
 
 #endif /* HAVE_POPEN */
 
-/* Called once per program. */
+/* Called once per program.  */
 
 static void
 __bb_exit_trace_func ()
 {
   FILE *file = fopen ("bb.out", "a");
   struct bb_func *f;
-  struct bb_edge *e;
   struct bb *b;
         
   if (!file)
@@ -1819,7 +1895,7 @@ __bb_exit_trace_func ()
 #endif /* HAVE_POPEN */
     }
 
-  /* Check functions in `bb.in'. */
+  /* Check functions in `bb.in'.  */
 
   if (file)
     {
@@ -1829,14 +1905,14 @@ __bb_exit_trace_func ()
       struct bb *ptr;
       long blk;
 
-      /* This is somewhat type incorrect. */
+      /* This is somewhat type incorrect.  */
       time ((void *) &time_value);
 
-      for (p = bb_func_head; p != (struct bb_func *)0; p = p->next)
+      for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
         {
-          for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
+          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++)
                 {
@@ -1901,7 +1977,7 @@ found:        ;
               break;
 
               case 4:
-               /* Print nothing. */
+               /* Print nothing.  */
               break;
 
               case 8:
@@ -1937,7 +2013,7 @@ found:        ;
                for ( ; bucket; bucket = bucket->next )
                  {
                    fprintf (file, "Jump from block 0x%.*lx to "
-                                  "block 0x%.*lx executed %*d time(s)\n", 
+                                  "block 0x%.*lx executed %*lu time(s)\n", 
                             addr_len, bucket->src_addr, 
                             addr_len, bucket->dst_addr, 
                             cnt_len, bucket->count);
@@ -1952,7 +2028,7 @@ found:        ;
    if (file)
      fclose (file);
 
-   /* Free allocated memory. */
+   /* Free allocated memory.  */
 
    f = bb_func_head;
    while (f)
@@ -1990,22 +2066,20 @@ found:        ;
      if (b->flags) free (b->flags);
 }
 
-/* Called once per program. */
+/* Called once per program.  */
 
 static void
 __bb_init_prg ()
 {
-
   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;
@@ -2032,31 +2106,31 @@ __bb_init_prg ()
         bb_mode |= 8;
       else 
         {
-          struct bb_func *f = (struct bb_func*) malloc (sizeof (struct bb_func));
+          struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
           if (f)
             {
               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)))
+                  if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
                     continue;
                   strcpy (f->funcname, pos+1);
                   l = pos-p;
-                  if ((f->filename = (char*) malloc (l+1)))
+                  if ((f->filename = (char *) malloc (l+1)))
                     {
                       strncpy (f->filename, p, l);
                       f->filename[l] = '\0';
                     }
                   else
-                    f->filename = (char*)0;
+                    f->filename = (char *) 0;
                 }
               else
                 {
-                  if (!(f->funcname = (char*) malloc (strlen (p)+1)))
+                  if (!(f->funcname = (char *) malloc (strlen (p)+1)))
                     continue;
                   strcpy (f->funcname, p);
-                  f->filename = (char*)0;
+                  f->filename = (char *) 0;
                 }
               f->mode = m;
               bb_func_head = f;
@@ -2082,7 +2156,10 @@ __bb_init_prg ()
       bb_hashbuckets = (struct bb_edge **) 
                    malloc (BB_BUCKETS * sizeof (struct bb_edge *));
       if (bb_hashbuckets)
-        bzero (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)
@@ -2091,14 +2168,11 @@ __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. */
+/* Called upon entering a basic block.  */
 
 void
 __bb_trace_func ()
@@ -2122,15 +2196,15 @@ __bb_trace_func ()
     {
       struct bb_edge **startbucket, **oldnext;
 
-      oldnext = startbucket =
-          & bb_hashbuckets[ (((int)bb_src*8)^(int)bb_dst) % BB_BUCKETS ];
+      oldnext = startbucket
+       = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
       bucket = *startbucket;
 
       for (bucket = *startbucket; bucket; 
            oldnext = &(bucket->next), bucket = *oldnext)
         {
-          if ( bucket->src_addr == bb_src &&
-               bucket->dst_addr == bb_dst )
+          if (bucket->src_addr == bb_src
+             && bucket->dst_addr == bb_dst)
             {
               bucket->count++;
               *oldnext = bucket->next;
@@ -2171,7 +2245,7 @@ skip:
 
 }
 
-/* Called when returning from a function and `__bb_showret__' is set. */
+/* Called when returning from a function and `__bb_showret__' is set.  */
 
 static void
 __bb_trace_func_ret ()
@@ -2185,15 +2259,15 @@ __bb_trace_func_ret ()
     {
       struct bb_edge **startbucket, **oldnext;
 
-      oldnext = startbucket =
-          & bb_hashbuckets[ (((int)bb_dst*8)^(int)bb_src) % BB_BUCKETS ];
+      oldnext = startbucket
+       = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
       bucket = *startbucket;
 
       for (bucket = *startbucket; bucket; 
            oldnext = &(bucket->next), bucket = *oldnext)
         {
-          if ( bucket->src_addr == bb_dst &&
-               bucket->dst_addr == bb_src )
+          if (bucket->src_addr == bb_dst
+              && bucket->dst_addr == bb_src)
             {
               bucket->count++;
               *oldnext = bucket->next;
@@ -2232,11 +2306,10 @@ skip:
 
 }
 
-/* Called upon entering the first function of a file. */
+/* Called upon entering the first function of a file.  */
 
 static void
-__bb_init_file (blocks)
-     struct bb *blocks;
+__bb_init_file (struct bb *blocks)
 {
 
   const struct bb_func *p;
@@ -2249,8 +2322,8 @@ __bb_init_file (blocks)
   bb_head = blocks;
 
   blocks->flags = 0;
-  if (!bb_func_head ||
-      !(blocks->flags = (char*) malloc (sizeof (char) * blocks->ncounts)))
+  if (!bb_func_head
+      || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
     return;
 
   for (blk = 0; blk < ncounts; blk++)
@@ -2260,8 +2333,8 @@ __bb_init_file (blocks)
     {
       for (p = bb_func_head; p; p = p->next)
         {
-          if (!strcmp (p->funcname, functions[blk]) &&
-              (!p->filename || !strcmp (p->filename, blocks->filename)))
+          if (!strcmp (p->funcname, functions[blk])
+             && (!p->filename || !strcmp (p->filename, blocks->filename)))
             {
               blocks->flags[blk] |= p->mode;
             }
@@ -2270,7 +2343,7 @@ __bb_init_file (blocks)
 
 }
 
-/* Called when exiting from a function. */
+/* Called when exiting from a function.  */
 
 void
 __bb_trace_ret ()
@@ -2294,12 +2367,10 @@ __bb_trace_ret ()
 
 }
 
-/* Called when entering a function. */
+/* Called when entering a function.  */
 
 void
-__bb_init_trace_func (blocks, blockno)
-     struct bb *blocks;
-     unsigned long blockno;
+__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
 {
   static int trace_init = 0;
 
@@ -2366,157 +2437,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,
@@ -2536,8 +2456,7 @@ unsigned int __shtab[] = {
 #define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
 
 void
-__clear_cache (beg, end)
-     char *beg, *end;
+__clear_cache (char *beg, char *end)
 {
 #ifdef CLEAR_INSN_CACHE 
   CLEAR_INSN_CACHE (beg, end);
@@ -2567,7 +2486,7 @@ __clear_cache (beg, end)
            = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
          ptr += INSN_CACHE_LINE_WIDTH;
        }
-      *(INSTRUCTION_TYPE *)(ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
+      *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
 
       initialized = 1;
     }
@@ -2649,7 +2568,7 @@ __clear_cache (beg, end)
 
 /* Jump to a trampoline, loading the static chain address.  */
 
-#ifdef WINNT
+#if defined(WINNT) && ! defined(__CYGWIN__) && ! defined (_UWIN)
 
 long getpagesize()
 {
@@ -2660,27 +2579,35 @@ long getpagesize()
 #endif
 }
 
-int mprotect(addr, len, prot)
-  char *addr;
-  int len, prot;
+#ifdef i386
+extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
+#endif
+
+int
+mprotect (char *addr, int len, int prot)
 {
   int np, op;
 
-  if (prot == 7) np = 0x40;
-  else if (prot == 5) np = 0x20;
-  else if (prot == 4) np = 0x10;
-  else if (prot == 3) np = 0x04;
-  else if (prot == 1) np = 0x02;
-  else if (prot == 0) np = 0x01;
+  if (prot == 7)
+    np = 0x40;
+  else if (prot == 5)
+    np = 0x20;
+  else if (prot == 4)
+    np = 0x10;
+  else if (prot == 3)
+    np = 0x04;
+  else if (prot == 1)
+    np = 0x02;
+  else if (prot == 0)
+    np = 0x01;
 
   if (VirtualProtect (addr, len, np, &op))
     return 0;
   else
     return -1;
-    
 }
 
-#endif
+#endif /* WINNT && ! __CYGWIN__ && ! _UWIN */
 
 #ifdef TRANSFER_FROM_TRAMPOLINE 
 TRANSFER_FROM_TRAMPOLINE 
@@ -2697,8 +2624,7 @@ TRANSFER_FROM_TRAMPOLINE
 #endif
 
 void
-__enable_execute_stack (addr)
-     char *addr;
+__enable_execute_stack (char *addr)
 {
   kern_return_t r;
   char *eaddr = addr + TRAMPOLINE_SIZE;
@@ -2746,14 +2672,14 @@ __enable_execute_stack ()
       lowest = current;
     }
 
-  /* Clear instruction cache in case an old trampoline is in it. */
+  /* Clear instruction cache in case an old trampoline is in it.  */
   asm ("pich");
 }
 #endif /* __convex__ */
 
-#ifdef __DOLPHIN__
+#ifdef __sysV88__
 
-/* Modified from the convex -code above. */
+/* Modified from the convex -code above.  */
 
 #include <sys/param.h>
 #include <errno.h>
@@ -2781,7 +2707,52 @@ __enable_execute_stack ()
   errno=save_errno;
 }
 
-#endif /* __DOLPHIN__ */
+#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 ()
+{
+#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__
 
@@ -2793,7 +2764,7 @@ __enable_execute_stack ()
 #include <sys/vmmac.h>
 
 /* Modified from the convex -code above.
-   mremap promises to clear the i-cache. */
+   mremap promises to clear the i-cache.  */
 
 void
 __enable_execute_stack ()
@@ -2808,21 +2779,61 @@ __enable_execute_stack ()
     }
 }
 #endif /* __pyr__ */
+
+#if defined (sony_news) && defined (SYSTYPE_BSD)
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <syscall.h>
+#include <machine/sysnews.h>
+
+/* cacheflush function for NEWS-OS 4.2.
+   This function is called from trampoline-initialize code
+   defined in config/mips/mips.h.  */
+
+void
+cacheflush (char *beg, int size, int flag)
+{
+  if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
+    {
+      perror ("cache_flush");
+      fflush (stderr);
+      abort ();
+    }
+}
+
+#endif /* sony_news */
 #endif /* L_trampoline */
 \f
+#ifndef __CYGWIN__
 #ifdef L__main
 
 #include "gbl-ctors.h"
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
-   must define both, or neither. */
+   must define both, or neither.  */
 #ifndef NAME__MAIN
 #define NAME__MAIN "__main"
 #define SYMBOL__MAIN __main
 #endif
 
-#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
+#ifdef INIT_SECTION_ASM_OP
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#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
@@ -2831,36 +2842,37 @@ __do_global_dtors ()
 #ifdef DO_GLOBAL_DTORS_BODY
   DO_GLOBAL_DTORS_BODY;
 #else
-  func_ptr *p;
-  for (p = __DTOR_LIST__ + 1; *p; )
-    (*p++) ();
+  static func_ptr *p = __DTOR_LIST__ + 1;
+  while (*p)
+    {
+      p++;
+      (*(p-1)) ();
+    }
+#endif
+#ifdef EH_FRAME_SECTION
+  __deregister_frame_info (__EH_FRAME_BEGIN__);
 #endif
 }
 #endif
 
-#ifndef INIT_SECTION_ASM_OP
+#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 ()
 {
+#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 INIT_SECTION_ASM_OP */
+#endif /* no HAS_INIT_SECTION */
 
-#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
+#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
 /* Subroutine called automatically by `main'.
    Compiling a global function named `main'
    produces an automatic call to this function at the beginning.
@@ -2880,9 +2892,10 @@ SYMBOL__MAIN ()
       __do_global_ctors ();
     }
 }
-#endif /* no INIT_SECTION_ASM_OP or INVOKE__main */
+#endif /* no HAS_INIT_SECTION or INVOKE__main */
 
 #endif /* L__main */
+#endif /* __CYGWIN__ */
 \f
 #ifdef L_ctors
 
@@ -2894,10 +2907,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
@@ -2911,23 +2929,56 @@ func_ptr __DTOR_LIST__[2];
 
 #include "gbl-ctors.h"
 
-#ifndef ON_EXIT
+#ifdef NEED_ATEXIT
+
+#ifndef HAVE_ON_EXIT
+
+# include <errno.h>
 
-/* 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.  */
+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)
+{
+  if (++last_atexit_chain_slot == atexit_chain_length)
+    {
+      atexit_chain_length += 32;
+      if (atexit_chain)
+       atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
+                                            * sizeof (func_ptr));
+      else
+       atexit_chain = (func_ptr *) malloc (atexit_chain_length
+                                           * sizeof (func_ptr));
+      if (! atexit_chain)
+       {
+         atexit_chain_length = 0;
+         last_atexit_chain_slot = -1;
+         errno = ENOMEM;
+         return (-1);
+       }
+    }
+  atexit_chain[last_atexit_chain_slot] = func;
+  return (0);
+}
 
-extern void __do_global_dtors ();
 extern void _cleanup ();
 extern void _exit () __attribute__ ((noreturn));
 
 void 
-exit (status)
-     int status;
+exit (int status)
 {
-#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
-  __do_global_dtors ();
-#endif
+  if (atexit_chain)
+    {
+      for ( ; last_atexit_chain_slot-- >= 0; )
+       {
+         (*atexit_chain[last_atexit_chain_slot + 1]) ();
+         atexit_chain[last_atexit_chain_slot + 1] = 0;
+       }
+      free (atexit_chain);
+      atexit_chain = 0;
+    }
 #ifdef EXIT_BODY
   EXIT_BODY;
 #else
@@ -2936,132 +2987,48 @@ exit (status)
   _exit (status);
 }
 
-#else
-int _exit_dummy_decl = 0;      /* prevent compiler & linker warnings */
-#endif
-
-#endif /* L_exit */
-\f
-#ifdef L_eh
-typedef struct {
-  void *start;
-  void *end;
-  void *exception_handler;
-} exception_table;
-
-struct exception_table_node {
-  exception_table *table;
-  void *start;
-  void *end;
-  struct exception_table_node *next;
-};
-
-static int except_table_pos;
-static void *except_pc;
-static struct exception_table_node *exception_table_list;
+#else /* HAVE_ON_EXIT */
 
-static exception_table *
-find_exception_table (pc)
-     void* pc;
+/* Simple; we just need a wrapper for ON_EXIT.  */
+int
+atexit (func_ptr func)
 {
-  register struct exception_table_node *table = exception_table_list;
-  for ( ; table != 0; table = table->next)
-    {
-      if (table->start <= pc && table->end > pc)
-       return table->table;
-    }
-  return 0;
+  return ON_EXIT (func);
 }
 
-/* this routine takes a pc, and the address of the exception handler associated
-   with the closest exception table handler entry associated with that PC,
-   or 0 if there are no table entries the PC fits in.  The algorithm works
-   something like this:
-
-    while(current_entry exists) {
-        if(current_entry.start < pc )
-            current_entry = next_entry;
-        else {
-            if(prev_entry.start <= pc && prev_entry.end > pc) {
-                save pointer to prev_entry;
-                return prev_entry.exception_handler;
-             }
-            else return 0;
-         }
-     }
-    return 0;
+#endif /* HAVE_ON_EXIT */
+#endif /* NEED_ATEXIT */
 
-   Assuming a correctly sorted table (ascending order) this routine should
-   return the tightest match...
+#endif /* L_exit */
+\f
+#ifdef L_eh
 
-   In the advent of a tie, we have to give the last entry, as it represents
-   an inner block.
- */
+#include "gthr.h"
 
+/* Shared exception handling support routines.  */
 
-void *
-__find_first_exception_table_match(pc)
-void *pc;
-{
-  exception_table *table = find_exception_table (pc);
-  int pos = 0;
-  int best = 0;
-  if (table == 0)
-    return (void*)0;
-#if 0
-  printf("find_first_exception_table_match(): pc = %x!\n",pc);
-#endif
+extern void __default_terminate (void) __attribute__ ((__noreturn__));
 
-  except_pc = pc;
+void
+__default_terminate ()
+{
+  abort ();
+}
 
-#if 0
-  /* We can't do this yet, as we don't know that the table is sorted.  */
-  do {
-    ++pos;
-    if (table[pos].start > except_pc)
-      /* found the first table[pos].start > except_pc, so the previous
-        entry better be the one we want! */
-      break;
-  } while(table[pos].exception_handler != (void*)-1);
-
-  --pos;
-  if (table[pos].start <= except_pc && table[pos].end > except_pc)
-    {
-      except_table_pos = pos;
-#if 0
-      printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
-#endif
-      return table[pos].exception_handler;
-    }
-#else
-  while (table[++pos].exception_handler != (void*)-1) {
-    if (table[pos].start <= except_pc && table[pos].end > except_pc)
-      {
-       /* This can apply.  Make sure it is better or as good as the previous
-          best.  */
-       /* The best one ends first. */
-       if (best == 0 || (table[pos].end <= table[best].end
-                         /* The best one starts last.  */
-                         && table[pos].start >= table[best].start))
-         best = pos;
-      }
-  }
-  if (best != 0)
-    return table[best].exception_handler;
-#endif
+void (*__terminate_func)() = __default_terminate;
 
-#if 0
-  printf("find_first_eh_table_match(): else: returning NULL!\n");
-#endif
-  return (void*)0;
+void
+__terminate ()
+{
+  (*__terminate_func)();
 }
 
 void *
-__throw_type_match (void *catch_type, void *throw_type, voidobj)
+__throw_type_match (void *catch_type, void *throw_type, void *obj)
 {
 #if 0
- printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
-       catch_type, throw_type);
+ printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+        catch_type, throw_type);
 #endif
  if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
    return obj;
@@ -3069,117 +3036,928 @@ __throw_type_match (void *catch_type, void *throw_type, void* obj)
 }
 
 void
-__register_exceptions (exception_table *table)
+__empty ()
 {
-  struct exception_table_node *node;
-  exception_table *range = table + 1;
-
-  if (range->start == (void*)-1)
-    return;
+}
+\f
 
-  node = (struct exception_table_node*)
-    malloc (sizeof (struct exception_table_node));
-  node->table = table;
+/* Include definitions of EH context and table layout */
 
-  /* 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;
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
+
+/* Allocate and return a new EH context structure. */
+
+extern void __throw ();
+
+static void *
+new_eh_context ()
+{
+  struct eh_full_context {
+    struct eh_context c;
+    void *top_elt[2];
+  } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+  if (! ehfc)
+    __terminate ();
+
+  memset (ehfc, 0, sizeof *ehfc);
+
+  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;
+}
+
+#if __GTHREADS
+static __gthread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
+{
+  __gthread_key_dtor (eh_context_key, ptr);
+  if (ptr)
+    free (ptr);
+}
+#endif
+
+/* Pointer to function to return EH context. */
+
+static struct eh_context *eh_context_initialize ();
+static struct eh_context *eh_context_static ();
+#if __GTHREADS
+static struct eh_context *eh_context_specific ();
+#endif
+
+static struct eh_context *(*get_eh_context) () = &eh_context_initialize;
+
+/* Routine to get EH context.
+   This one will simply call the function pointer. */
+
+void *
+__get_eh_context ()
+{
+  return (void *) (*get_eh_context) ();
+}
+
+/* Get and set the language specific info pointer. */
+
+void **
+__get_eh_info ()
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  return &eh->info;
+}
+\f
+#if __GTHREADS
+static void
+eh_threads_initialize ()
+{
+  /* 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 ()
+{
+#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;
     }
 
-  node->next = exception_table_list;
-  exception_table_list = node;
+#else /* no __GTHREADS */
+
+  /* Use static version of EH context. */
+  get_eh_context = &eh_context_static;
+
+#endif /* no __GTHREADS */
+
+  return (*get_eh_context) ();
 }
 
-void
-__empty ()
+/* Return a static EH context. */
+
+static struct eh_context *
+eh_context_static ()
+{
+  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 ()
 {
+  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.  */
+
+#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 ()
+{
+  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.  */
+
+extern void __sjthrow (void) __attribute__ ((__noreturn__));
 
-#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");
+__sjthrow ()
+{
+  struct eh_context *eh = (*get_eh_context) ();
+  void ***dhc = &eh->dynamic_handler_chain;
+  void *jmpbuf;
+  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];
+
+  /* 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
+      if (! __builtin_setjmp (&buf[2]))
+#endif
+       {
+         *dhc = buf;
+         while (cleanup[0])
+           {
+             func = (void(*)(void*, int))cleanup[0][1];
+             arg = (void*)cleanup[0][2];
+
+             /* Update this before running the cleanup.  */
+             cleanup[0] = (void **)cleanup[0][0];
+
+             (*func)(arg, 2);
+           }
+         *dhc = buf[0];
+       }
+      /* catch (...) */
+      else
+       {
+         __terminate ();
+       }
+    }
   
-  /* 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)
-__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(powerpc)
-__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;
+  /* 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)[0] == 0)
+    __terminate ();
+    
+  /* Find the jmpbuf associated with the top element of the dynamic
+     handler chain.  The jumpbuf starts two words into the buffer.  */
+  jmpbuf = &(*dhc)[2];
+
+  /* Then we pop the top element off the dynamic handler chain.  */
+  *dhc = (void**)(*dhc)[0];
+
+  /* And then we jump to the handler.  */
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+  longjmp (jmpbuf, 1);
+#else
+  __builtin_longjmp (jmpbuf, 1);
+#endif
+}
+
+/* Run cleanups on the dynamic cleanup stack for the current dynamic
+   handler, then pop the handler off the dynamic handler stack, and
+   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 ()
+{
+  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];
+
+  /* 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
+      if (! __builtin_setjmp (&buf[2]))
+#endif
+       {
+         *dhc = buf;
+         while (cleanup[0])
+           {
+             func = (void(*)(void*, int))cleanup[0][1];
+             arg = (void*)cleanup[0][2];
+
+             /* Update this before running the cleanup.  */
+             cleanup[0] = (void **)cleanup[0][0];
+
+             (*func)(arg, 2);
+           }
+         *dhc = buf[0];
+       }
+      /* catch (...) */
+      else
+       {
+         __terminate ();
+       }
+    }
+
+  /* Then we pop the top element off the dynamic handler chain.  */
+  *dhc = (void**)(*dhc)[0];
+
+  __sjthrow ();
 }
+\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.  */
+
+#ifdef EH_TABLE_LOOKUP
+
+EH_TABLE_LOOKUP
+
 #else
-__unwind_function(void *ptr)
+
+#ifdef DWARF2_UNWIND_INFO
+
+
+/* Return the table version of an exception descriptor */
+
+short 
+__get_eh_table_version (exception_descriptor *table) 
 {
-  abort ();
+  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
+   associated with the closest exception table handler entry associated
+   with that PC, or 0 if there are no table entries the PC fits in.
+
+   In the advent of a tie, we have to give the last entry, as it represents
+   an inner block.  */
+
+static void *
+old_find_exception_handler (void *pc, old_exception_table *table)
+{
+  if (table)
+    {
+      int pos;
+      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].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 (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
+/* Support code for exception handling using static unwind information.  */
+
+#include "frame.h"
+
+/* This type is used in get_reg and put_reg to deal with ABIs where a void*
+   is smaller than a word, such as the Irix 6 n32 ABI.  We cast twice to
+   avoid a warning about casting between int and pointer of different
+   sizes.  */
+
+typedef int ptr_type __attribute__ ((mode (pointer)));
+
+#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
 }
-#endif /* powerpc */
+#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 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 (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 inline void
+put_reg (unsigned reg, void *val, frame_state *udata)
+{
+  *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
+}
+
+/* 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, __builtin_dwarf_reg_size (reg));
+}
+
+/* Retrieve the return address for frame UDATA.  */
+
+static inline void *
+get_return_addr (frame_state *udata, frame_state *sub_udata)
+{
+  return __builtin_extract_return_addr
+    (get_reg (udata->retaddr_column, udata, sub_udata));
+}
+
+/* Overwrite the return address for frame UDATA with VAL.  */
+
+static inline void
+put_return_addr (void *val, frame_state *udata)
+{
+  val = __builtin_frob_return_addr (val);
+  put_reg (udata->retaddr_column, val, udata);
+}
+
+/* Given the current frame UDATA and its return address PC, return the
+   information about the calling frame in CALLER_UDATA.  */
+
+static void *
+next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
+{
+  caller_udata = __frame_state_for (pc, caller_udata);
+  if (! caller_udata)
+    return 0;
+
+  /* Now go back to our caller's stack frame.  If our caller's CFA register
+     was saved in our stack frame, restore it; otherwise, assume the CFA
+     register is SP and restore it to our CFA value.  */
+  if (udata->saved[caller_udata->cfa_reg])
+    caller_udata->cfa = get_reg (caller_udata->cfa_reg, udata, 0);
+  else
+    caller_udata->cfa = udata->cfa;
+  caller_udata->cfa += caller_udata->cfa_offset;
+
+  return caller_udata;
+}
+
+/* Hook to call before __terminate if only cleanup handlers remain. */
+void 
+__unwinding_cleanup ()
+{
+}
+
+/* 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.
+
+   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.  */
+
+static void *
+throw_helper (eh, pc, my_udata, offset_p)
+     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;
+  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;
+  long args_size;
+  __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;
+
+  memcpy (udata, my_udata, sizeof (*udata));
+
+  handler = (void *) 0;
+  for (;;)
+    { 
+      frame_state *p = udata;
+      udata = next_stack_level (pc, udata, sub_udata);
+      sub_udata = p;
+
+      /* If we couldn't find the next frame, we lose.  */
+      if (! udata)
+       break;
+
+      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 (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)
+       {
+         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();
+
+  eh->handler_label = handler;
+
+  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;
+
+      /* Unwind all the frames between this one and the handler by copying
+        their saved register values into our register save slots.  */
+
+      /* Remember the PC where we found the handler.  */
+      void *handler_pc = pc;
+
+      /* Start from the throw context again.  */
+      pc = saved_pc;
+      memcpy (udata, my_udata, sizeof (*udata));
+
+      while (pc != handler_pc)
+       {
+         frame_state *p = udata;
+         udata = next_stack_level (pc, udata, sub_udata);
+         sub_udata = p;
+
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+           if (i != udata->retaddr_column && udata->saved[i])
+             {
+               /* 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
+                  confuse get_return_addr.  */
+               if (in_reg_window (i, udata)
+                   && udata->saved[udata->retaddr_column] == REG_SAVED_REG
+                   && udata->reg_or_offset[udata->retaddr_column] == i)
+                 continue;
+               copy_reg (i, udata, my_udata);
+             }
+
+         pc = get_return_addr (udata, sub_udata) - 1;
+       }
+
+      /* 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.  */
+      if (udata->saved[udata->retaddr_column] == REG_SAVED_REG)
+       {
+         i = udata->reg_or_offset[udata->retaddr_column];
+         if (in_reg_window (i, udata))
+           copy_reg (i, udata, my_udata);
+       }
+    }
+  /* udata now refers to the frame called by the handler frame.  */
+
+  /* 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
+  *offset_p = udata->cfa - my_udata->cfa + args_size;
+#else
+  *offset_p = my_udata->cfa - udata->cfa - args_size;
+#endif
+                      
+  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 ()
+{
+  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 (index)
+     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 /* L_eh */
 \f
 #ifdef L_pure
@@ -3203,6 +3981,6 @@ __pure_virtual ()
 #ifndef inhibit_libc
   write (2, MESSAGE, sizeof (MESSAGE) - 1);
 #endif
-  _exit (-1);
+  __terminate ();
 }
 #endif