diff options
author | Andrew MacLeod <amacleod@cygnus.com> | 2000-05-25 15:21:51 +0000 |
---|---|---|
committer | Andrew Haley <aph@gcc.gnu.org> | 2000-05-25 15:21:51 +0000 |
commit | ce152ef8360320d27e1aacba9af8fdc4e1649941 (patch) | |
tree | feadfb24e9829d3678b304cad386af16dda71a31 /gcc/libgcc2.c | |
parent | c66265e4833fb9553699839453725586cc248fc3 (diff) | |
download | gcc-ce152ef8360320d27e1aacba9af8fdc4e1649941.zip gcc-ce152ef8360320d27e1aacba9af8fdc4e1649941.tar.gz gcc-ce152ef8360320d27e1aacba9af8fdc4e1649941.tar.bz2 |
except.c (func_eh_entry): Add emitted field.
2000-05-25 Andrew MacLeod <amacleod@cygnus.com>
Andrew Haley <aph@cygnus.com>
* except.c (func_eh_entry): Add emitted field.
(new_eh_region_entry): Set emitted field to 0;
(output_exception_table_entry): Only emit previously un-emitted data,
and send it to the eh_data section.
(output_exception_table): Break out common parts. Output
exception table for entire compilation unit to eh_data section.
(output_exception_table_data): Common parts of output_exception_table.
Send output to eh_data section.
(output_function_exception_table): Output exception table data for
a single function to eh_data section.
(free_exception_table): New external to free the table.
* except.h (free_exception_table): Add prototype.
(output_function_exception_table): Add prototype.
* final.c (final_end_function): Output function exception table
for IA64_UNWIND_INFO.
(final_scan_insn): Emit any unwind directives for an insn.
* frame-dwarf2.c: New file containing all DWARF 2 specific code
from frame.c.
* frame.c: Remove all DWARF 2 specific code.
* config/ia64/frame-ia64.c: New file.
(gthread_stuff): Make all gthread available with
IA64_UNWIND_INFO.
(dwarf_fde): Define an IA64 struct for dwarf_fde.
(__register_frame_info, __register_frame): Move to common area of file.
(__register_frame_info_table, __register_frame_table): Move to common i
area.
(__deregister_frame_info, __deregister_frame): Move to common area.
(__frame_init, find_fde): New versions for IA64_UNWIND_INFO.
(read_uleb128): New version for ia64.
(get_unwind_record): Read the next IA-64 unwind record.
(read_R_record): Read a region header record.
(process_a_b_reg_code): X record helper.
(read_X_record): Read an X format record.
(read_B_record): Read a B format record.
(P3_record_types): List of record types matching the P3 format.
(P7_record_types): List of record types matching the P7 format.
(P8_record_types): List of record types matching the P8 format.
(read_P_record): Read a P format record.
(init_ia64_reg_loc): Set default fields for a register.
(init_ia64_unwind_frame): Set defaults for all register records.
(execute_one_ia64_descriptor): Execute one descriptor record.
(rse_address_add): Calculate the position of a local reg in memory.
(normalize_reg_loc): Turn a location descriptor into a memory address.
(maybe_normalize_reg_loc): Only normalize a descriptor if it falls
within a specified PC offset range.
(get_real_reg_value): Given a register location, retrieve its value.
(set_real_reg_value): Change the value of a register location.
(copy_reg_value): Copy reg values, if needed.
(copy_saved_reg_state): Copy all registers that need to be copied.
(process_state_between): Normalize all frame register records that
fall within the specified PC range.
(frame_translate): Take a processed frame description, and turn
everything into addresses.
(build_ia64_frame_state ): Find and create frame state record for a PC.
(get_personality): Get the personality routine for a given frame.
(get_except_table): Get the exception table for a given frame.
(record_name): Unwind record names for debugging.
(print_record): Print and unwind record.
(print_all_records): Print an entire unwind image.
(__ia64_backtrace): Print a backtrace.
(ia64_backtrace_helper): New function.
(__register_frame_info_aux): New function.
* config/ia64/crtend.asm (__do_frame_setup_aux): New function.
* frame.h (enum unw_record_type): New unwind record types.
(struct unw_p_record, unw_b_record, unw_x_record) : New unwind records.
(struct unw_r_record, unwind_record): New unwind record structs.
(struct unwind_info_ptr): Unwind information layout.
(IA64_UNW_LOC_TYPE_*): Macros for different types for location
descriptors.
(struct ia64_reg_loc): Register location description.
(struct ia64_frame_state): Location of all registers in a frame.
(struct object): Add pc_base and fde_end for IA64_UNWIND_INFO.
* libgcc2.c (__ia64_personality_v1): Personality routine.
(__calc_caller_bsp): Calculate the bsp register for the caller's
frame.
(ia64_throw_helper): Figure out who to return to and set up the
registers.
(__throw): Throw routine.
* output.h (assemble_eh_align, assemble_eh_label): New functions
to generate EH info where we want it.
(assemble_eh_integer): New function.
* toplev.c (compile_file): Output module level exception table for
non-ia64 targets.
(main): Set exceptions_via_longjump and flag_new_exceptions based
on IA64_UNWIND_INFO too.
* varasm.c (assemble_eh_label): Generate a label via
ASM_OUTPUT_EH_LABEL if it has been specified.
(assemble_eh_align): Generate an alignment directive via
ASM_OUTPUT_EH_ALIGN if it has been specified.
(assemble_eh_label): Generate an integer value via
ASM_OUTPUT_EH_type if they have been specified.
* config/ia64/ia64.c (rtx_needs_barrier): Add flushrs.
(ia64_init_builtins): Add __builtin_ia64_bsp
and __builtin_ia64_flushrs.
(ia64_expand_builtin): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.h (ia64_builtins): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.md (flushrs): New insn to flush the register
stack. Add to unspec list.
* config/ia64/crtbegin.asm (frame_object): Change size.
(__do_frame_setup_aux): New function.
* config/ia64/crtend.asm: call __do_frame_setup_aux.
* config/ia64/t-ia64 (LIB2ADDEH): Add.
* Makefile.in (LIB2ADDEH): Add.
(LIB2ADD): Use LIB2ADDEH.
Co-Authored-By: Andrew Haley <aph@cygnus.com>
From-SVN: r34169
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r-- | gcc/libgcc2.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 599842e..822d84e 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -3940,6 +3940,173 @@ label: } #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 (throw_pc, throw_frame, caller, throw_bsp) + void *throw_pc; + ia64_frame_state *throw_frame; + ia64_frame_state *caller; + void *throw_bsp; +{ + 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, &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 *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, &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 (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, &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 () +{ + 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 (); +label_ia64: + /* 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 (&&label_ia64, &my_frame, &originator, bsp); + + /* 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; + + /* A throw handler is trated like a non-local goto, which is architeched + to set the FP (or PSP) in r7 before branching. gr[0-3] map to + r4-r7, so we want gr[3]. */ + __set_real_reg_value (&my_frame.gr[3], __get_real_reg_value (&originator.psp)); + + __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 */ #ifdef L_pure |