/* 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-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
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
#define WEAK_ALIAS
#endif
+/* 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
file. This is used when the endianness is determined when the
compiler is run. */
#else
/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
USItype
-__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype 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
__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
__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
__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
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,
&& 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(__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:");
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
#include <stdio.h>
/* This is used by the `assert' macro. */
+extern void __eprintf (const char *, const char *, unsigned int, const char *)
+ __attribute__ ((__noreturn__));
+
void
__eprintf (const char *string, const char *expression,
- int line, const char *filename)
+ unsigned int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
#include "gbl-ctors.h"
#include "gcov-io.h"
+#include <string.h>
static struct bb *bb_head;
if ((da_file = fopen (ptr->filename, "r")) != 0)
{
long n_counts = 0;
- unsigned char tmp;
- int i;
- int ret = 0;
-
if (__read_long (&n_counts, da_file, 8) != 0)
{
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)
{
fprintf (stderr, "arc profiling: Error closing output file %s.\n",
ptr->filename);
}
- if ((da_file = fopen (ptr->filename, "w")) < 0)
+ 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
+ /* ??? 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.
#define MACHINE_STATE_RESTORE(ID)
#endif
-#include <string.h>
-
/* Number of buckets in hashtable of basic block addresses. */
#define BB_BUCKETS 311
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)
{
{
FILE *file = fopen ("bb.out", "a");
struct bb_func *f;
- struct bb_edge *e;
struct bb *b;
if (!file)
{
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++)
{
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);
{
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;
bb_hashbuckets = (struct bb_edge **)
malloc (BB_BUCKETS * sizeof (struct bb_edge *));
if (bb_hashbuckets)
- bzero ((char *) bb_hashbuckets, BB_BUCKETS);
+ memset (bb_hashbuckets, 0, BB_BUCKETS * sizeof (struct bb_edge *));
}
if (bb_mode & 12)
{
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;
{
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;
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++)
{
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;
}
#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,
/* Jump to a trampoline, loading the static chain address. */
-#ifdef WINNT
+#if defined(WINNT) && ! defined(__CYGWIN__)
long getpagesize()
{
#endif
}
-int mprotect(char *addr, int len, int 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 /* __convex__ */
-#ifdef __DOLPHIN__
+#ifdef __sysV88__
/* Modified from the convex -code above. */
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__
#endif /* sony_news */
#endif /* L_trampoline */
\f
+#ifndef __CYGWIN__
#ifdef L__main
#include "gbl-ctors.h"
#endif /* no HAS_INIT_SECTION or INVOKE__main */
#endif /* L__main */
+#endif /* __CYGWIN__ */
\f
#ifdef L_ctors
{
atexit_chain_length += 32;
if (atexit_chain)
- atexit_chain = realloc (atexit_chain,
- atexit_chain_length * sizeof (func_ptr));
+ atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
+ * sizeof (func_ptr));
else
- atexit_chain = malloc (atexit_chain_length * sizeof (func_ptr));
+ atexit_chain = (func_ptr *) malloc (atexit_chain_length
+ * sizeof (func_ptr));
if (! atexit_chain)
{
atexit_chain_length = 0;
#else /* No NEED_ATEXIT */
__do_global_dtors ();
#endif /* No NEED_ATEXIT */
-#endif
+#endif /* !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF) */
+/* In gbl-ctors.h, ON_EXIT is defined if HAVE_ATEXIT is defined. In
+ __bb_init_func and _bb_init_prg, __bb_exit_func is registered with
+ ON_EXIT if ON_EXIT is defined. Thus we must not call __bb_exit_func here
+ if HAVE_ATEXIT is defined. */
+#ifndef HAVE_ATEXIT
#ifndef inhibit_libc
__bb_exit_func ();
#endif
+#endif /* !HAVE_ATEXIT */
#ifdef EXIT_BODY
EXIT_BODY;
#else
_exit (status);
}
-#else
+#else /* ON_EXIT defined */
int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
-#endif
+
+# ifndef HAVE_ATEXIT
+/* Provide a fake for atexit() using ON_EXIT. */
+int atexit (func_ptr func)
+{
+ return ON_EXIT (func, NULL);
+}
+# endif /* HAVE_ATEXIT */
+#endif /* ON_EXIT defined */
#endif /* L_exit */
\f
#ifdef L_eh
-#ifdef EH_TABLE_LOOKUP
+#include "gthr.h"
-EH_TABLE_LOOKUP
+/* Shared exception handling support routines. */
-#else
+extern void __default_terminate (void) __attribute__ ((__noreturn__));
void
__default_terminate ()
(*__terminate_func)();
}
+void *
+__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);
+#endif
+ if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
+ return obj;
+ return 0;
+}
+
+void
+__empty ()
+{
+}
+\f
+
+/* Include definitions of EH context and table layout */
+
+#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;
+ }
+
+#else /* no __GTHREADS */
+
+ /* Use static version of EH context. */
+ get_eh_context = &eh_context_static;
+
+#endif /* no __GTHREADS */
+
+ return (*get_eh_context) ();
+}
+
+/* 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. */
-extern longjmp (void *, int);
-
-extern void *__eh_type;
-
-static void *top_elt[2];
-void **__dynamic_handler_chain = top_elt;
+#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.
-
- TODO: make thread safe. */
+ use for exception handling. */
void ***
__get_dynamic_handler_chain ()
{
- return &__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 (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. */
+ 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__));
void
__sjthrow ()
{
- void ***dhc = __get_dynamic_handler_chain ();
+ struct eh_context *eh = (*get_eh_context) ();
+ void ***dhc = &eh->dynamic_handler_chain;
void *jmpbuf;
void (*func)(void *, int);
void *arg;
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])
/* 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
/* And then we jump to the handler. */
-#ifdef USE_BUILTIN_SETJMP
- __builtin_longjmp (jmpbuf, 1);
-#else
+#ifdef DONT_USE_BUILTIN_SETJMP
longjmp (jmpbuf, 1);
+#else
+ __builtin_longjmp (jmpbuf, 1);
#endif
}
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 ()
{
- 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;
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])
__sjthrow ();
}
+\f
+/* Support code for all exception region-based exception handling. */
-typedef struct {
- void *start;
- void *end;
- void *exception_handler;
-} exception_table;
+int
+__eh_rtime_match (void *rtime)
+{
+ void *info;
+ __eh_matcher matcher;
+ void *ret;
-struct exception_table_node {
- exception_table *table;
- void *start;
- void *end;
- struct exception_table_node *next;
-};
+ 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. */
-static struct exception_table_node *exception_table_list;
+#ifdef EH_TABLE_LOOKUP
-/* 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:
+EH_TABLE_LOOKUP
- 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;
+#else
- Assuming a correctly sorted table (ascending order) this routine should
- return the tightest match...
+#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
+ 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. */
-void *
-__find_first_exception_table_match (void *pc)
+static void *
+old_find_exception_handler (void *pc, old_exception_table *table)
{
- register struct exception_table_node *tnp;
- register exception_table *table;
- int pos;
- int best;
+ if (table)
+ {
+ int pos;
+ int best = -1;
-#if 0
- printf ("find_first_exception_table_match (): pc = %x!\n", pc);
-#endif
+ /* 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;
+}
- for (tnp = exception_table_list; tnp != 0; tnp = tnp->next)
+/* 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)
{
- if (tnp->start > pc || tnp->end <= pc)
- continue;
+ 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 */
- table = tnp->table;
+ exception_table *tab = &(table->table[0]);
- pos = 0;
- best = 0;
-#if 0
- /* We can't do this yet, as we don't know that the table is sorted. */
- do {
- ++pos;
- if (table[pos].start > pc)
- /* found the first table[pos].start > pc, so the previous
- entry better be the one we want! */
- break;
- } while (table[pos].exception_handler != (void *) -1);
-
- --pos;
- if (table[pos].start <= pc && table[pos].end > pc)
- {
-#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 <= pc && table[pos].end > 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
+ /* 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;
+ }
+ }
+ }
}
-
-#if 0
- printf ("find_first_eh_table_match (): else: returning NULL!\n");
-#endif
- return (void *) 0;
+ return retval;
}
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* EH_TABLE_LOOKUP */
+\f
+#ifdef DWARF2_UNWIND_INFO
+/* Support code for exception handling using static unwind information. */
-void
-__register_exceptions (exception_table *table)
+#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)
{
- struct exception_table_node *node;
- exception_table *range = table + 1;
+ if (udata->saved[reg] == REG_SAVED_REG)
+ return INCOMING_REGNO (reg) == reg;
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
- if (range->start == (void *) -1)
- return;
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
+#endif /* INCOMING_REGNO */
- node = (struct exception_table_node *)
- malloc (sizeof (struct exception_table_node));
- node->table = table;
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 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++)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+ while (udata->saved[reg] == REG_SAVED_REG)
{
- if (range->start < node->start)
- node->start = range->start;
- if (range->end > node->end)
- node->end = range->end;
+ 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 ();
+}
- node->next = exception_table_list;
- exception_table_list = node;
+/* 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);
}
-#endif
-void *
-__throw_type_match (void *catch_type, void *throw_type, void *obj)
+/* Overwrite the saved value for register REG in frame UDATA with VAL. */
+
+static inline void
+put_reg (unsigned reg, void *val, frame_state *udata)
{
-#if 0
- 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;
- return 0;
+ *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
}
-/* Throw stub routine.
+/* 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. */
- This is work in progress, but not completed yet. */
+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);
-void
-__throw ()
+ 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)
{
- abort ();
+ return __builtin_extract_return_addr
+ (get_reg (udata->retaddr_column, udata, sub_udata));
}
-/* This value identifies the place from which an exception is being
- thrown. */
+/* Overwrite the return address for frame UDATA with VAL. */
-void *__eh_pc;
+static inline void
+put_return_addr (void *val, frame_state *udata)
+{
+ val = __builtin_frob_return_addr (val);
+ put_reg (udata->retaddr_column, val, udata);
+}
-void
-__empty ()
+/* 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;
}
-#if #machine(i386)
+/* 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. */
+
+static void *
+throw_helper (eh, pc, my_udata, udata_p)
+ struct eh_context *eh;
+ void *pc;
+ frame_state *my_udata;
+ frame_state **udata_p;
+{
+ frame_state *udata = *udata_p;
+ frame_state ustruct;
+ frame_state *sub_udata = &ustruct;
+ void *saved_pc = pc;
+ void *handler;
+ void *handler_p;
+ void *pc_p;
+ frame_state saved_ustruct;
+ int new_eh_model;
+ int cleanup = 0;
+ int only_cleanup = 0;
+ int rethrow = 0;
+ int saved_state = 0;
+ __eh_info *eh_info = (__eh_info *)eh->info;
+
+ /* Do we find a handler based on a re-throw PC? */
+ if (eh->table_index != (void *) 0)
+ rethrow = 1;
+
+ handler = (void *) 0;
+ for (;;)
+ {
+ frame_state *p = udata;
+ 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;
+
+ 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. */
+
+ *udata_p = udata;
+ 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
-__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;
+__throw ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ frame_state ustruct;
+ frame_state *udata = &ustruct;
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* Start at our stack frame. */
+label:
+ udata = __frame_state_for (&&label, udata);
+ if (! udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ udata->cfa = __builtin_dwarf_cfa ();
+
+ memcpy (my_udata, udata, sizeof (*udata));
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &udata);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh,
+#ifdef STACK_GROWS_DOWNWARD
+ udata->cfa - my_udata->cfa,
+#else
+ my_udata->cfa - udata->cfa,
+#endif
+ handler);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (index)
+ void *index;
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ frame_state ustruct;
+ frame_state *udata = &ustruct;
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* This is the table index we want to rethrow from. The value of
+ the END_REGION label is used for the PC of the throw, and the
+ search begins with the next table entry. */
+ eh->table_index = index;
+
+ /* Start at our stack frame. */
+label:
+ udata = __frame_state_for (&&label, udata);
+ if (! udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ udata->cfa = __builtin_dwarf_cfa ();
+
+ memcpy (my_udata, udata, sizeof (*udata));
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &udata);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh,
+#ifdef STACK_GROWS_DOWNWARD
+ udata->cfa - my_udata->cfa,
#else
-__unwind_function(void *ptr)
-{
- abort ();
+ my_udata->cfa - udata->cfa,
+#endif
+ handler);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
}
-#endif /* powerpc */
+#endif /* DWARF2_UNWIND_INFO */
+
#endif /* L_eh */
\f
#ifdef L_pure
#ifndef inhibit_libc
write (2, MESSAGE, sizeof (MESSAGE) - 1);
#endif
- _exit (-1);
+ __terminate ();
}
#endif