#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"
&& DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
{
#define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
- if (! (- ((UDItype) 1 << DF_SIZE) < u
- && u < ((UDItype) 1 << DF_SIZE)))
+ if (! (- ((DItype) 1 << DF_SIZE) < u
+ && u < ((DItype) 1 << DF_SIZE)))
{
if ((USItype) u & (REP_BIT - 1))
u |= REP_BIT;
#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);
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)
/* Jump to a trampoline, loading the static chain address. */
-#if defined(WINNT) && ! defined(__CYGWIN32__)
+#if defined(WINNT) && ! defined(__CYGWIN__)
long getpagesize()
{
#endif /* sony_news */
#endif /* L_trampoline */
\f
-#ifndef __CYGWIN32__
+#ifndef __CYGWIN__
#ifdef L__main
#include "gbl-ctors.h"
#endif /* no HAS_INIT_SECTION or INVOKE__main */
#endif /* L__main */
-#endif /* __CYGWIN32__ */
+#endif /* __CYGWIN__ */
\f
#ifdef L_ctors
_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
/* Shared exception handling support routines. */
+extern void __default_terminate (void) __attribute__ ((__noreturn__));
+
void
__default_terminate ()
{
{
}
\f
-/* EH context structure. */
-
-struct eh_context
-{
- void **dynamic_handler_chain;
- /* This is language dependent part of the eh context. */
- void *info;
-};
-/* This is a safeguard for dynamic handler chain. */
+/* Include definitions of EH context and table layout */
-static void *top_elt[2];
+#include "eh-common.h"
+#ifndef inhibit_libc
+#include <stdio.h>
+#endif
/* Allocate and return a new EH context structure. */
static void *
new_eh_context ()
{
- struct eh_context *eh = (struct eh_context *) malloc (sizeof *eh);
- if (! eh)
+ struct eh_full_context {
+ struct eh_context c;
+ void *top_elt[2];
+ } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+ if (! ehfc)
__terminate ();
- memset (eh, 0, sizeof *eh);
+ memset (ehfc, 0, sizeof *ehfc);
- eh->dynamic_handler_chain = top_elt;
+ ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
- return eh;
+ /* This should optimize out entirely. This should always be true,
+ but just in case it ever isn't, don't allow bogus code to be
+ generated. */
+
+ if ((void*)(&ehfc->c) != (void*)ehfc)
+ __terminate ();
+
+ return &ehfc->c;
}
#if __GTHREADS
static struct eh_context *
eh_context_static ()
{
- static struct eh_context *eh;
- if (! eh)
- eh = new_eh_context ();
- return eh;
+ static struct eh_context eh;
+ static int initialized;
+ static void *top_elt[2];
+
+ if (! initialized)
+ {
+ initialized = 1;
+ memset (&eh, 0, sizeof eh);
+ eh.dynamic_handler_chain = top_elt;
+ }
+ return &eh;
}
#if __GTHREADS
dynamic handler chain, and use longjmp to transfer back to the associated
handler. */
+extern void __sjthrow (void) __attribute__ ((__noreturn__));
+
void
__sjthrow ()
{
/* We must call terminate if we try and rethrow an exception, when
there is no exception currently active and when there are no
handlers left. */
- if (! eh->info || (*dhc) == top_elt)
+ if (! eh->info || (*dhc)[0] == 0)
__terminate ();
/* Find the jmpbuf associated with the top element of the dynamic
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 ()
{
\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. */
#else
-typedef struct exception_table {
- void *start;
- void *end;
- void *exception_handler;
-} exception_table;
+#ifdef DWARF2_UNWIND_INFO
+
+
+/* Return the table version of an exception descriptor */
+
+short
+__get_eh_table_version (exception_descriptor *table)
+{
+ return table->lang.version;
+}
+
+/* Return the originating table language of an exception descriptor */
+
+short
+__get_eh_table_language (exception_descriptor *table)
+{
+ return table->lang.language;
+}
/* This routine takes a PC and a pointer to the exception region TABLE for
its translation unit, and returns the address of the exception handler
an inner block. */
static void *
-find_exception_handler (void *pc, exception_table *table)
+old_find_exception_handler (void *pc, old_exception_table *table)
{
if (table)
{
int best = -1;
/* We can't do a binary search because the table isn't guaranteed
- to be sorted from function to function. */
- for (pos = 0; table[pos].exception_handler != (void *) -1; ++pos)
- {
- if (table[pos].start <= pc && table[pos].end > pc)
- {
- /* This can apply. Make sure it is at least as small as
- the previous best. */
- if (best == -1 || (table[pos].end <= table[best].end
- && table[pos].start >= table[best].start))
- best = pos;
- }
- /* But it is sorted by starting PC within a function. */
- else if (best >= 0 && table[pos].start > pc)
- break;
- }
+ to be sorted from function to function. */
+ for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+ {
+ if (table[pos].start_region <= pc && table[pos].end_region > pc)
+ {
+ /* This can apply. Make sure it is at least as small as
+ the previous best. */
+ if (best == -1 || (table[pos].end_region <= table[best].end_region
+ && table[pos].start_region >= table[best].start_region))
+ best = pos;
+ }
+ /* But it is sorted by starting PC within a function. */
+ else if (best >= 0 && table[pos].start_region > pc)
+ break;
+ }
if (best != -1)
- return table[best].exception_handler;
+ return table[best].exception_handler;
}
return (void *) 0;
}
+
+/* find_exception_handler finds the correct handler, if there is one, to
+ handle an exception.
+ returns a pointer to the handler which controlled should be transferred
+ to, or NULL if there is nothing left.
+ Parameters:
+ PC - pc where the exception originates. If this is a rethrow,
+ then this starts out as a pointer to the exception table
+ entry we wish to rethrow out of.
+ TABLE - exception table for the current module.
+ EH_INFO - eh info pointer for this exception.
+ RETHROW - 1 if this is a rethrow. (see incoming value of PC).
+ CLEANUP - returned flag indicating whether this is a cleanup handler.
+*/
+static void *
+find_exception_handler (void *pc, exception_descriptor *table,
+ __eh_info *eh_info, int rethrow, int *cleanup)
+{
+
+ void *retval = NULL;
+ *cleanup = 1;
+ if (table)
+ {
+ int pos = 0;
+ /* The new model assumed the table is sorted inner-most out so the
+ first region we find which matches is the correct one */
+
+ exception_table *tab = &(table->table[0]);
+
+ /* Subtract 1 from the PC to avoid hitting the next region */
+ if (rethrow)
+ {
+ /* pc is actually the region table entry to rethrow out of */
+ pos = ((exception_table *) pc) - tab;
+ pc = ((exception_table *) pc)->end_region - 1;
+
+ /* The label is always on the LAST handler entry for a region,
+ so we know the next entry is a different region, even if the
+ addresses are the same. Make sure its not end of table tho. */
+ if (tab[pos].start_region != (void *) -1)
+ pos++;
+ }
+ else
+ pc--;
+
+ /* We can't do a binary search because the table is in inner-most
+ to outermost address ranges within functions */
+ for ( ; tab[pos].start_region != (void *) -1; pos++)
+ {
+ if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+ {
+ if (tab[pos].match_info)
+ {
+ __eh_matcher matcher = eh_info->match_function;
+ /* match info but no matcher is NOT a match */
+ if (matcher)
+ {
+ void *ret = (*matcher)((void *) eh_info,
+ tab[pos].match_info, table);
+ if (ret)
+ {
+ if (retval == NULL)
+ retval = tab[pos].exception_handler;
+ *cleanup = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (retval == NULL)
+ retval = tab[pos].exception_handler;
+ }
+ }
+ }
+ }
+ return retval;
+}
+#endif /* DWARF2_UNWIND_INFO */
#endif /* EH_TABLE_LOOKUP */
\f
#ifdef DWARF2_UNWIND_INFO
typedef int ptr_type __attribute__ ((mode (pointer)));
-/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+ window in the previous frame? */
+
+/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
+ to use the macro here. One wonders, though, that perhaps TARGET_FLAT
+ compiled functions won't work with the frame-unwind stuff here.
+ Perhaps the entireity of in_reg_window should be conditional on having
+ seen a DW_CFA_GNU_window_save? */
+#define target_flags 0
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+ if (udata->saved[reg] == REG_SAVED_REG)
+ return INCOMING_REGNO (reg) == reg;
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
+#endif /* INCOMING_REGNO */
+
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
-static void*
-get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
{
+ while (udata->saved[reg] == REG_SAVED_REG)
+ {
+ reg = udata->reg_or_offset[reg];
+ if (in_reg_window (reg, udata))
+ {
+ udata = sub_udata;
+ sub_udata = NULL;
+ }
+ }
if (udata->saved[reg] == REG_SAVED_OFFSET)
- return (void *)(ptr_type)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
- else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
- return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+ return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
else
abort ();
}
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static inline void *
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+ return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+}
+
/* Overwrite the saved value for register REG in frame UDATA with VAL. */
-static void
+static inline void
put_reg (unsigned reg, void *val, frame_state *udata)
{
- if (udata->saved[reg] == REG_SAVED_OFFSET)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
- = (word_type)(ptr_type) val;
- else
- abort ();
+ *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
}
/* Copy the saved value for register REG from frame UDATA to frame
static void
copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
{
- if (udata->saved[reg] == REG_SAVED_OFFSET
- && target_udata->saved[reg] == REG_SAVED_OFFSET)
- memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
- udata->cfa + udata->reg_or_offset[reg],
- __builtin_dwarf_reg_size (reg));
- else
- abort ();
+ word_type *preg = get_reg_addr (reg, udata, NULL);
+ word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+ memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
}
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
- frame called by UDATA or 0. */
+/* Retrieve the return address for frame UDATA. */
static inline void *
get_return_addr (frame_state *udata, frame_state *sub_udata)
return caller_udata;
}
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
- window in the previous frame? */
-
-static int
-in_reg_window (int reg, frame_state *udata)
+/* Hook to call before __terminate if only cleanup handlers remain. */
+void
+__unwinding_cleanup ()
{
- if (udata->saved[reg] != REG_SAVED_OFFSET)
- return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
- return udata->reg_or_offset[reg] > 0;
-#else
- return udata->reg_or_offset[reg] < 0;
-#endif
}
-#endif /* INCOMING_REGNO */
-
-/* We first search for an exception handler, and if we don't find
- it, we call __terminate on the current stack frame so that we may
- use the debugger to walk the stack and understand why no handler
- was found.
-
- If we find one, then we unwind the frames down to the one that
- has the handler and transfer control into the handler. */
-
-void
-__throw ()
-{
- struct eh_context *eh = (*get_eh_context) ();
- void *saved_pc, *pc, *handler, *retaddr;
- frame_state ustruct, ustruct2;
- frame_state *udata = &ustruct;
- frame_state *sub_udata = &ustruct2;
- frame_state my_ustruct, *my_udata = &my_ustruct;
- long args_size;
-
- /* This is required for C++ semantics. We must call terminate if we
- try and rethrow an exception, when there is no exception currently
- active. */
- if (! eh->info)
- __terminate ();
-
- /* Start at our stack frame. */
-label:
- udata = __frame_state_for (&&label, udata);
- if (! udata)
- __terminate ();
-
- /* We need to get the value from the CFA register. At this point in
- compiling __throw we don't know whether or not we will use the frame
- pointer register for the CFA, so we check our unwind info. */
- if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
- udata->cfa = __builtin_fp ();
- else
- udata->cfa = __builtin_sp ();
- udata->cfa += udata->cfa_offset;
-
- memcpy (my_udata, udata, sizeof (*udata));
-
- /* Do any necessary initialization to access arbitrary stack frames.
- On the SPARC, this means flushing the register windows. */
- __builtin_unwind_init ();
- /* Now reset pc to the right throw point. */
- pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
- saved_pc = pc;
+/* throw_helper performs some of the common grunt work for a throw. This
+ routine is called by throw and rethrows. This is pretty much split
+ out from the old __throw routine. An addition has been added which allows
+ for a dummy call to a routine __unwinding_cleanup() when there are nothing
+ but cleanups remaining. This allows a debugger to examine the state
+ at which the throw was executed, before any cleanups, rather than
+ at the terminate point after the stack has been unwound. */
- handler = 0;
+static void *
+throw_helper (eh, pc, my_udata, udata_p)
+ struct eh_context *eh;
+ void *pc;
+ frame_state *my_udata;
+ frame_state **udata_p;
+{
+ frame_state *udata = *udata_p;
+ frame_state ustruct;
+ frame_state *sub_udata = &ustruct;
+ void *saved_pc = pc;
+ void *handler;
+ void *handler_p;
+ void *pc_p;
+ frame_state saved_ustruct;
+ int new_eh_model;
+ int cleanup = 0;
+ int only_cleanup = 0;
+ int rethrow = 0;
+ int saved_state = 0;
+ __eh_info *eh_info = (__eh_info *)eh->info;
+
+ /* Do we find a handler based on a re-throw PC? */
+ if (eh->table_index != (void *) 0)
+ rethrow = 1;
+
+ handler = (void *) 0;
for (;;)
{
frame_state *p = udata;
if (! udata)
break;
- handler = find_exception_handler (pc, udata->eh_ptr);
+ if (udata->eh_ptr == NULL)
+ new_eh_model = 0;
+ else
+ new_eh_model = (((exception_descriptor *)(udata->eh_ptr))->
+ runtime_id_field == NEW_EH_RUNTIME);
- /* If we found one, we can stop searching. */
+ if (rethrow)
+ {
+ rethrow = 0;
+ handler = find_exception_handler (eh->table_index, udata->eh_ptr,
+ eh_info, 1, &cleanup);
+ eh->table_index = (void *)0;
+ }
+ else
+ if (new_eh_model)
+ handler = find_exception_handler (pc, udata->eh_ptr, eh_info,
+ 0, &cleanup);
+ else
+ handler = old_find_exception_handler (pc, udata->eh_ptr);
+
+ /* If we found one, we can stop searching, if its not a cleanup.
+ for cleanups, we save the state, and keep looking. This allows
+ us to call a debug hook if there are nothing but cleanups left. */
if (handler)
- {
- args_size = udata->args_size;
- break;
- }
+ if (cleanup)
+ {
+ if (!saved_state)
+ {
+ saved_ustruct = *udata;
+ handler_p = handler;
+ pc_p = pc;
+ saved_state = 1;
+ only_cleanup = 1;
+ }
+ }
+ else
+ {
+ only_cleanup = 0;
+ break;
+ }
/* Otherwise, we continue searching. We subtract 1 from PC to avoid
hitting the beginning of the next region. */
pc = get_return_addr (udata, sub_udata) - 1;
}
+ if (saved_state)
+ {
+ udata = &saved_ustruct;
+ handler = handler_p;
+ pc = pc_p;
+ if (only_cleanup)
+ __unwinding_cleanup ();
+ }
+
/* If we haven't found a handler by now, this is an unhandled
exception. */
- if (! handler)
- __terminate ();
+ if (! handler)
+ __terminate();
+
+ eh->handler_label = handler;
if (pc == saved_pc)
/* We found a handler in the throw context, no need to unwind. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
if (i != udata->retaddr_column && udata->saved[i])
{
-#ifdef INCOMING_REGNO
/* If you modify the saved value of the return address
register on the SPARC, you modify the return address for
your caller's frame. Don't do that here, as it will
&& udata->saved[udata->retaddr_column] == REG_SAVED_REG
&& udata->reg_or_offset[udata->retaddr_column] == i)
continue;
-#endif
copy_reg (i, udata, my_udata);
}
pc = get_return_addr (udata, sub_udata) - 1;
}
-#ifdef INCOMING_REGNO
/* But we do need to update the saved return address register from
the last frame we unwind, or the handler frame will have the wrong
return address. */
if (in_reg_window (i, udata))
copy_reg (i, udata, my_udata);
}
-#endif
}
/* udata now refers to the frame called by the handler frame. */
- /* Emit the stub to adjust sp and jump to the handler. */
- retaddr = __builtin_eh_stub ();
+ *udata_p = udata;
+ return handler;
+}
+
- /* And then set our return address to point to the stub. */
- if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
- put_return_addr (retaddr, my_udata);
- else
- __builtin_set_return_addr_reg (retaddr);
+/* We first search for an exception handler, and if we don't find
+ it, we call __terminate on the current stack frame so that we may
+ use the debugger to walk the stack and understand why no handler
+ was found.
- /* Set up the registers we use to communicate with the stub.
- We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
- __builtin_set_eh_regs (handler,
+ If we find one, then we unwind the frames down to the one that
+ has the handler and transfer control into the handler. */
+
+/*extern void __throw(void) __attribute__ ((__noreturn__));*/
+
+void
+__throw ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ frame_state ustruct;
+ frame_state *udata = &ustruct;
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* Start at our stack frame. */
+label:
+ udata = __frame_state_for (&&label, udata);
+ if (! udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ udata->cfa = __builtin_dwarf_cfa ();
+
+ memcpy (my_udata, udata, sizeof (*udata));
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &udata);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh,
#ifdef STACK_GROWS_DOWNWARD
- udata->cfa - my_udata->cfa
+ udata->cfa - my_udata->cfa,
#else
- my_udata->cfa - udata->cfa
+ my_udata->cfa - udata->cfa,
#endif
- + args_size
- );
+ handler);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
+}
+
+/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
+
+void
+__rethrow (index)
+ void *index;
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *pc, *handler;
+ frame_state ustruct;
+ frame_state *udata = &ustruct;
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* This is the table index we want to rethrow from. The value of
+ the END_REGION label is used for the PC of the throw, and the
+ search begins with the next table entry. */
+ eh->table_index = index;
+
+ /* Start at our stack frame. */
+label:
+ udata = __frame_state_for (&&label, udata);
+ if (! udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. */
+ udata->cfa = __builtin_dwarf_cfa ();
+
+ memcpy (my_udata, udata, sizeof (*udata));
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+
+ handler = throw_helper (eh, pc, my_udata, &udata);
+
+ /* Now go! */
+
+ __builtin_eh_return ((void *)eh,
+#ifdef STACK_GROWS_DOWNWARD
+ udata->cfa - my_udata->cfa,
+#else
+ my_udata->cfa - udata->cfa,
+#endif
+ handler);
/* Epilogue: restore the handler frame's register values and return
to the stub. */
#endif /* DWARF2_UNWIND_INFO */
#endif /* L_eh */
-
\f
#ifdef L_pure
#ifndef inhibit_libc
#ifndef inhibit_libc
write (2, MESSAGE, sizeof (MESSAGE) - 1);
#endif
- _exit (-1);
+ __terminate ();
}
#endif