aboutsummaryrefslogtreecommitdiff
path: root/gcc/libgcc2.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r--gcc/libgcc2.c1218
1 files changed, 0 insertions, 1218 deletions
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 9e7aa99..140f1f7 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -3129,1221 +3129,3 @@ atexit (func_ptr func)
#endif /* NEED_ATEXIT */
#endif /* L_exit */
-
-#ifdef L_eh
-
-#include "gthr.h"
-
-/* Shared exception handling support routines. */
-
-void
-__default_terminate (void)
-{
- abort ();
-}
-
-static __terminate_func_ptr __terminate_func =
- __default_terminate;
-
-void __attribute__((__noreturn__))
-__terminate (void)
-{
- (*__terminate_func)();
-}
-
-__terminate_func_ptr
-__terminate_set_func (__terminate_func_ptr newfunc)
-{
- __terminate_func_ptr oldfunc = __terminate_func;
-
- __terminate_func = newfunc;
- return (oldfunc);
-}
-
-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 (void)
-{
-}
-
-
-/* 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. */
-
-#if __GTHREADS
-static void *
-new_eh_context (void)
-{
- struct eh_full_context {
- struct eh_context c;
- void *top_elt[2];
- } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
-
- if (! ehfc)
- __terminate ();
-
- 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;
-}
-
-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 (void);
-static struct eh_context *eh_context_static (void);
-#if __GTHREADS
-static struct eh_context *eh_context_specific (void);
-#endif
-
-static struct eh_context *(*get_eh_context) (void) = &eh_context_initialize;
-
-/* Routine to get EH context.
- This one will simply call the function pointer. */
-
-void *
-__get_eh_context (void)
-{
- return (void *) (*get_eh_context) ();
-}
-
-/* Get and set the language specific info pointer. */
-
-void **
-__get_eh_info (void)
-{
- struct eh_context *eh = (*get_eh_context) ();
- return &eh->info;
-}
-
-#ifdef DWARF2_UNWIND_INFO
-static int dwarf_reg_size_table_initialized = 0;
-static char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
-
-static void
-init_reg_size_table (void)
-{
- __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
- dwarf_reg_size_table_initialized = 1;
-}
-#endif
-
-#if __GTHREADS
-static void
-eh_threads_initialize (void)
-{
- /* Try to create the key. If it fails, revert to static method,
- otherwise start using thread specific EH contexts. */
- if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
- get_eh_context = &eh_context_specific;
- else
- get_eh_context = &eh_context_static;
-}
-#endif /* no __GTHREADS */
-
-/* Initialize EH context.
- This will be called only once, since we change GET_EH_CONTEXT
- pointer to another routine. */
-
-static struct eh_context *
-eh_context_initialize (void)
-{
-#if __GTHREADS
-
- static __gthread_once_t once = __GTHREAD_ONCE_INIT;
- /* Make sure that get_eh_context does not point to us anymore.
- Some systems have dummy thread routines in their libc that
- return a success (Solaris 2.6 for example). */
- if (__gthread_once (&once, eh_threads_initialize) != 0
- || get_eh_context == &eh_context_initialize)
- {
- /* Use static version of EH context. */
- get_eh_context = &eh_context_static;
- }
-#ifdef DWARF2_UNWIND_INFO
- {
- static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
- if (__gthread_once (&once_regsizes, init_reg_size_table) != 0
- || ! dwarf_reg_size_table_initialized)
- init_reg_size_table ();
- }
-#endif
-
-#else /* no __GTHREADS */
-
- /* Use static version of EH context. */
- get_eh_context = &eh_context_static;
-
-#ifdef DWARF2_UNWIND_INFO
- init_reg_size_table ();
-#endif
-
-#endif /* no __GTHREADS */
-
- return (*get_eh_context) ();
-}
-
-/* Return a static EH context. */
-
-static struct eh_context *
-eh_context_static (void)
-{
- static struct eh_context eh;
- static int initialized;
- static void *top_elt[2];
-
- if (! initialized)
- {
- initialized = 1;
- memset (&eh, 0, sizeof eh);
- eh.dynamic_handler_chain = top_elt;
- }
- return &eh;
-}
-
-#if __GTHREADS
-/* Return a thread specific EH context. */
-
-static struct eh_context *
-eh_context_specific (void)
-{
- struct eh_context *eh;
- eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
- if (! eh)
- {
- eh = new_eh_context ();
- if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
- __terminate ();
- }
-
- return eh;
-}
-#endif /* __GTHREADS */
-
-/* Support routines for alloc/free during exception handling */
-
-/* __eh_alloc and __eh_free attempt allocation using malloc, but fall back to
- the small arena in the eh_context. This is needed because throwing an
- out-of-memory exception would fail otherwise. The emergency space is
- allocated in blocks of size EH_ALLOC_ALIGN, the
- minimum allocation being two blocks. A bitmask indicates which blocks
- have been allocated. To indicate the size of an allocation, the bit for
- the final block is not set. Hence each allocation is a run of 1s followed
- by a zero. */
-void *
-__eh_alloc (size_t size)
-{
- void *p;
-
- if (!size)
- abort();
- p = malloc (size);
- if (p == 0)
- {
- struct eh_context *eh = __get_eh_context ();
- unsigned blocks = (size + EH_ALLOC_ALIGN - 1) / EH_ALLOC_ALIGN;
- unsigned real_mask = eh->alloc_mask | (eh->alloc_mask << 1);
- unsigned our_mask;
- unsigned ix;
-
- if (blocks > EH_ALLOC_SIZE / EH_ALLOC_ALIGN)
- __terminate ();
- blocks += blocks == 1;
- our_mask = (1 << blocks) - 1;
-
- for (ix = EH_ALLOC_SIZE / EH_ALLOC_ALIGN - blocks; ix; ix--)
- if (! ((real_mask >> ix) & our_mask))
- {
- /* found some space */
- p = &eh->alloc_buffer[ix * EH_ALLOC_ALIGN];
- eh->alloc_mask |= (our_mask >> 1) << ix;
- return p;
- }
- __terminate ();
- }
- return p;
-}
-
-/* Free the memory for an cp_eh_info and associated exception, given
- a pointer to the cp_eh_info. */
-void
-__eh_free (void *p)
-{
- struct eh_context *eh = __get_eh_context ();
-
- ptrdiff_t diff = (char *)p - &eh->alloc_buffer[0];
- if (diff >= 0 && diff < EH_ALLOC_SIZE)
- {
- unsigned mask = eh->alloc_mask;
- unsigned bit = 1 << (diff / EH_ALLOC_ALIGN);
-
- do
- {
- mask ^= bit;
- bit <<= 1;
- }
- while (mask & bit);
- eh->alloc_mask = mask;
- }
- else
- free (p);
-}
-
-/* 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 (void)
-{
- struct eh_context *eh = (*get_eh_context) ();
- return &eh->dynamic_handler_chain;
-}
-
-/* This is used to throw an exception when the setjmp/longjmp codegen
- method is used for exception handling.
-
- We call __terminate if there are no handlers left. Otherwise we run the
- cleanup actions off the dynamic cleanup stack, and pop the top of the
- dynamic handler chain, and use longjmp to transfer back to the associated
- handler. */
-
-void
-__sjthrow (void)
-{
- struct eh_context *eh = (*get_eh_context) ();
- void ***dhc = &eh->dynamic_handler_chain;
- void *jmpbuf;
- void (*func)(void *, int);
- void *arg;
- /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
- void ***cleanup = (void***)&(*dhc)[1];
-
- /* If there are any cleanups in the chain, run them now. */
- if (cleanup[0])
- {
- double store[200];
- void **buf = (void**)store;
- buf[1] = 0;
- buf[0] = (*dhc);
-
- /* try { */
-#ifdef DONT_USE_BUILTIN_SETJMP
- if (! setjmp (&buf[2]))
-#else
- 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 ();
- }
- }
-
- /* 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. */
-
-void
-__sjpopnthrow (void)
-{
- struct eh_context *eh = (*get_eh_context) ();
- void ***dhc = &eh->dynamic_handler_chain;
- void (*func)(void *, int);
- void *arg;
- /* The cleanup chain is one word into the buffer. Get the cleanup chain. */
- void ***cleanup = (void***)&(*dhc)[1];
-
- /* If there are any cleanups in the chain, run them now. */
- if (cleanup[0])
- {
- double store[200];
- void **buf = (void**)store;
- buf[1] = 0;
- buf[0] = (*dhc);
-
- /* try { */
-#ifdef DONT_USE_BUILTIN_SETJMP
- if (! setjmp (&buf[2]))
-#else
- 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 ();
-}
-
-/* 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
-
-#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. */
-
-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 */
-
-#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)));
-
-typedef struct
-{
- word_type *reg[DWARF_FRAME_REGISTERS];
-} saved_regs_t;
-
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
- window in the previous frame? */
-
-/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
- to use the macro here. One wonders, though, that perhaps TARGET_FLAT
- compiled functions won't work with the frame-unwind stuff here.
- Perhaps the entireity of in_reg_window should be conditional on having
- seen a DW_CFA_GNU_window_save? */
-#define target_flags 0
-
-static int
-in_reg_window (int reg, frame_state *udata)
-{
- if (udata->saved[reg] == REG_SAVED_REG)
- return INCOMING_REGNO (reg) == reg;
- if (udata->saved[reg] != REG_SAVED_OFFSET)
- return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
- return udata->reg_or_offset[reg] > 0;
-#else
- return udata->reg_or_offset[reg] < 0;
-#endif
-}
-#else
-static inline int
-in_reg_window (int reg __attribute__ ((__unused__)),
- frame_state *udata __attribute__ ((__unused__)))
-{
- return 0;
-}
-#endif /* INCOMING_REGNO */
-
-/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
- frame called by UDATA or 0. */
-
-static 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
- /* We don't have a saved copy of this register. */
- return NULL;
-}
-
-/* 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 PTREG 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, word_type *preg, frame_state *target_udata)
-{
- word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
- memcpy (ptreg, preg, dwarf_reg_size_table [reg]);
-}
-
-/* Retrieve the return address for frame UDATA. */
-
-static inline void *
-get_return_addr (frame_state *udata, frame_state *sub_udata)
-{
- 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 and update the
- register array in SAVED_REGS. */
-
-static void *
-next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata,
- saved_regs_t *saved_regs)
-{
- int i;
- word_type *p;
-
- /* Collect all of the registers for the current frame. */
- for (i = 0; i < DWARF_FRAME_REGISTERS; i++)
- if (udata->saved[i])
- saved_regs->reg[i] = get_reg_addr (i, udata, 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 was
- saved in a register in this stack frame or a previous one, restore it;
- otherwise, assume CFA register is SP and restore it to our CFA value
- (which is defined to be the value of SP in the caller's frame). */
-
- p = saved_regs->reg[caller_udata->cfa_reg];
- if (p)
- caller_udata->cfa = (void *)(ptr_type)*p;
- else
- caller_udata->cfa = udata->cfa;
-
- if (caller_udata->indirect)
- caller_udata->cfa = * (void **) ((unsigned char *)caller_udata->cfa
- + caller_udata->base_offset);
- caller_udata->cfa += caller_udata->cfa_offset;
-
- return caller_udata;
-}
-
-/* Hook to call before __terminate if only cleanup handlers remain. */
-void
-__unwinding_cleanup (void)
-{
-}
-
-/* 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 (struct eh_context *eh, void *pc, frame_state *my_udata,
- long *offset_p)
-{
- frame_state ustruct2, *udata = &ustruct2;
- frame_state ustruct;
- frame_state *sub_udata = &ustruct;
- void *saved_pc = pc;
- void *handler;
- void *handler_p = 0;
- void *pc_p = 0;
- void *callee_cfa = 0;
- frame_state saved_ustruct;
- int new_eh_model;
- int cleanup = 0;
- int only_cleanup = 0;
- int rethrow = 0;
- int saved_state = 0;
- long args_size;
- saved_regs_t saved_regs, cleanup_regs;
- __eh_info *eh_info = (__eh_info *)eh->info;
- int i;
-
- memset (saved_regs.reg, 0, sizeof saved_regs.reg);
- memset (sub_udata->saved, REG_UNSAVED, sizeof sub_udata->saved);
-
- /* 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, &saved_regs);
- 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)
- {
- /* sub_udata now refers to the frame called by the handler frame. */
-
- if (cleanup)
- {
- if (!saved_state)
- {
- saved_ustruct = *udata;
- cleanup_regs = saved_regs;
- handler_p = handler;
- pc_p = pc;
- saved_state = 1;
- only_cleanup = 1;
- /* Save the CFA of the frame called by the handler
- frame. */
- callee_cfa = sub_udata->cfa;
- }
- }
- else
- {
- only_cleanup = 0;
- if (!saved_state)
- callee_cfa = sub_udata->cfa;
- 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;
- saved_regs = cleanup_regs;
- 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;
-
- /* 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 = callee_cfa - my_udata->cfa + args_size;
-#else
- *offset_p = my_udata->cfa - callee_cfa - args_size;
-#endif
-
- /* If we found a handler in the throw context there's no need to
- unwind. */
- if (pc != saved_pc)
- {
- /* Copy saved register values into our register save slots. */
- for (i = 0; i < DWARF_FRAME_REGISTERS; i++)
- if (i != udata->retaddr_column && saved_regs.reg[i])
- copy_reg (i, saved_regs.reg[i], my_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
-__throw (void)
-{
- struct eh_context *eh = (*get_eh_context) ();
- void *pc, *handler;
- long offset;
-
- /* XXX maybe make my_ustruct static so we don't have to look it up for
- each throw. */
- frame_state my_ustruct, *my_udata = &my_ustruct;
-
- /* This is required for C++ semantics. We must call terminate if we
- try and rethrow an exception, when there is no exception currently
- active. */
- if (! eh->info)
- __terminate ();
-
- /* Start at our stack frame. */
-label:
- my_udata = __frame_state_for (&&label, my_udata);
- if (! my_udata)
- __terminate ();
-
- /* We need to get the value from the CFA register. */
- my_udata->cfa = __builtin_dwarf_cfa ();
-
- /* Do any necessary initialization to access arbitrary stack frames.
- On the SPARC, this means flushing the register windows. */
- __builtin_unwind_init ();
-
- /* Now reset pc to the right throw point. The return address points to
- the instruction after the call to __throw; we subtract 1 so that pc
- points into the call insn itself. Since we work with PC ranges (as
- opposed to specific call sites), it isn't important for it to point to
- the very beginning of the call insn, and making it do so would be
- hard on targets with variable length call insns. */
- pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
-
- handler = throw_helper (eh, pc, my_udata, &offset);
-
- /* Now go! */
-
- __builtin_eh_return ((void *)eh, offset, handler);
-
- /* Epilogue: restore the handler frame's register values and return
- to the stub. */
-}
-
-/*extern void __rethrow(void *) __attribute__ ((__noreturn__));*/
-
-void
-__rethrow (void *index)
-{
- struct eh_context *eh = (*get_eh_context) ();
- void *pc, *handler;
- long offset;
-
- /* XXX maybe make my_ustruct static so we don't have to look it up for
- each throw. */
- frame_state my_ustruct, *my_udata = &my_ustruct;
-
- /* This is required for C++ semantics. We must call terminate if we
- try and rethrow an exception, when there is no exception currently
- active. */
- if (! eh->info)
- __terminate ();
-
- /* This is the table index we want to rethrow from. The value of
- the END_REGION label is used for the PC of the throw, and the
- search begins with the next table entry. */
- eh->table_index = index;
-
- /* Start at our stack frame. */
-label:
- my_udata = __frame_state_for (&&label, my_udata);
- if (! my_udata)
- __terminate ();
-
- /* We need to get the value from the CFA register. */
- my_udata->cfa = __builtin_dwarf_cfa ();
-
- /* Do any necessary initialization to access arbitrary stack frames.
- On the SPARC, this means flushing the register windows. */
- __builtin_unwind_init ();
-
- /* Now reset pc to the right throw point. The return address points to
- the instruction after the call to __throw; we subtract 1 so that pc
- points into the call insn itself. Since we work with PC ranges (as
- opposed to specific call sites), it isn't important for it to point to
- the very beginning of the call insn, and making it do so would be
- hard on targets with variable length call insns. */
- 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 */
-
-#ifdef IA64_UNWIND_INFO
-#include "frame.h"
-
-/* Return handler to which we want to transfer control, NULL if we don't
- intend to handle this exception here. */
-void *
-__ia64_personality_v1 (void *pc, old_exception_table *table)
-{
- if (table)
- {
- int pos;
- int best = -1;
-
- 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;
- }
- /* 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;
-}
-
-static void
-ia64_throw_helper (ia64_frame_state *throw_frame, ia64_frame_state *caller,
- void *throw_bsp, void *throw_sp)
-{
- void *throw_pc = __builtin_return_address (0);
- unwind_info_ptr *info;
- void *pc, *handler = NULL;
- void *pc_base;
- int frame_count;
- void *bsp;
-
- __builtin_ia64_flushrs (); /* Make the local register stacks available. */
-
- /* Start at our stack frame, get our state. */
- __build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, throw_sp,
- &pc_base);
-
- /* Now we have to find the proper frame for pc, and see if there
- is a handler for it. if not, we keep going back frames until
- we do find one. Otherwise we call uncaught (). */
-
- frame_count = 0;
- memcpy (caller, throw_frame, sizeof (*caller));
- while (!handler)
- {
- void *(*personality) (void *, old_exception_table *);
- void *eh_table;
-
- frame_count++;
- /* We only care about the RP right now, so we dont need to keep
- any other information about a call frame right now. */
- pc = __get_real_reg_value (&caller->rp) - 1;
- bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
- caller->my_bsp);
- info = __build_ia64_frame_state (pc, caller, bsp, caller->my_psp,
- &pc_base);
-
- /* If we couldn't find the next frame, we lose. */
- if (! info)
- break;
-
- personality = __get_personality (info);
- /* TODO Haven't figured out how to actually load the personality address
- yet, so just always default to the one we expect for now. */
- if (personality != 0)
- personality = __ia64_personality_v1;
- eh_table = __get_except_table (info);
- /* If there is no personality routine, we'll keep unwinding. */
- if (personality)
- /* Pass a segment relative PC address to the personality routine,
- because the unwind_info section uses segrel relocs. */
- handler = personality ((void *)(pc - pc_base), eh_table);
- }
-
- if (!handler)
- __terminate ();
-
- /* Handler is a segment relative address, so we must adjust it here. */
- handler += (long) pc_base;
-
- /* If we found a handler, we need to unwind the stack to that point.
- We do this by copying saved values from previous frames into the
- save slot for the throw_frame saved slots. when __throw returns,
- it'll pickup the correct values. */
-
- /* Start with where __throw saved things, and copy each saved register
- of each previous frame until we get to the one before we're
- throwing back to. */
- memcpy (caller, throw_frame, sizeof (*caller));
- for ( ; frame_count > 0; frame_count--)
- {
- pc = __get_real_reg_value (&caller->rp) - 1;
- bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs),
- caller->my_bsp);
- __build_ia64_frame_state (pc, caller, bsp, caller->my_psp, &pc_base);
- /* Any regs that were saved can be put in the throw frame now. */
- /* We don't want to copy any saved register from the
- target destination, but we do want to load up it's frame. */
- if (frame_count > 1)
- __copy_saved_reg_state (throw_frame, caller);
- }
-
- /* Set return address of the throw frame to the handler. */
- __set_real_reg_value (&throw_frame->rp, handler);
-
- /* TODO, do we need to do anything to make the values we wrote 'stick'? */
- /* DO we need to go through the whole loadrs seqeunce? */
-}
-
-
-void
-__throw ()
-{
- register void *stack_pointer __asm__("r12");
- struct eh_context *eh = (*get_eh_context) ();
- ia64_frame_state my_frame;
- ia64_frame_state originator; /* For the context handler is in. */
- void *bsp, *tmp_bsp;
- long offset;
-
- /* 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 ();
-
- __builtin_unwind_init ();
-
- /* We have to call another routine to actually process the frame
- information, which will force all of __throw's local registers into
- backing store. */
-
- /* Get the value of ar.bsp while we're here. */
-
- bsp = __builtin_ia64_bsp ();
- ia64_throw_helper (&my_frame, &originator, bsp, stack_pointer);
-
- /* Now we have to fudge the bsp by the amount in our (__throw)
- frame marker, since the return is going to adjust it by that much. */
-
- tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
- my_frame.my_bsp);
- offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
- tmp_bsp = (char *)originator.my_bsp + offset;
-
- __builtin_eh_return (tmp_bsp, offset, originator.my_sp);
-
- /* The return address was already set by throw_helper. */
-}
-
-#endif /* IA64_UNWIND_INFO */
-
-#endif /* L_eh */