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
This commit is contained in:
parent
c66265e483
commit
ce152ef836
19 changed files with 3031 additions and 672 deletions
116
gcc/ChangeLog
116
gcc/ChangeLog
|
@ -1,3 +1,119 @@
|
|||
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.
|
||||
|
||||
2000-05-24 Richard Henderson <rth@cygnus.com>
|
||||
|
||||
* recog.c (offsettable_address_p): If mode size is zero, assume
|
||||
|
|
|
@ -367,6 +367,9 @@ LIBGCC2_INCLUDES =
|
|||
# Additional target-dependent options for compiling libgcc2.a.
|
||||
TARGET_LIBGCC2_CFLAGS =
|
||||
|
||||
# Addition sources to handle exceptions; overridden by some targets.
|
||||
LIB2ADDEH = $(srcdir)/frame-dwarf2.c
|
||||
|
||||
# libgcc1-test target (must also be overridable for a target)
|
||||
LIBGCC1_TEST = libgcc1-test
|
||||
|
||||
|
@ -951,7 +954,7 @@ libgcc2.ready: $(GCC_PASSES) stmp-int-hdrs $(STMP_FIXPROTO)
|
|||
touch libgcc2.ready; \
|
||||
fi
|
||||
|
||||
LIB2ADD = $(srcdir)/frame.c $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
|
||||
LIB2ADD = $(LIB2ADDEH) $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
|
||||
|
||||
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
||||
objext='$(objext)' \
|
||||
|
|
|
@ -61,10 +61,10 @@ __dso_handle:
|
|||
/* ??? How can we rationally keep this size correct? */
|
||||
.section .bss
|
||||
.type frame_object#,@object
|
||||
.size frame_object#,56
|
||||
.size frame_object#,64
|
||||
.align 8
|
||||
frame_object:
|
||||
.zero 56
|
||||
.zero 64
|
||||
|
||||
/*
|
||||
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
|
||||
|
@ -296,3 +296,38 @@ __do_frame_setup:
|
|||
#endif
|
||||
.weak __deregister_frame_info#
|
||||
.weak __register_frame_info#
|
||||
|
||||
.text
|
||||
.align 16
|
||||
.global __do_frame_setup_aux#
|
||||
.proc __do_frame_setup_aux#
|
||||
__do_frame_setup_aux:
|
||||
/*
|
||||
if (__register_frame_info_aux)
|
||||
__register_frame_info_aux(__EH_FRAME_END__)
|
||||
*/
|
||||
alloc loc0 = ar.pfs, 0, 3, 1, 0
|
||||
addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp
|
||||
mov loc1 = b0
|
||||
;;
|
||||
// r16 contains the address of a pointer to __EH_FRAME_END__.
|
||||
ld8 out0 = [r16]
|
||||
ld8 r15 = [r14]
|
||||
mov loc2 = gp
|
||||
;;
|
||||
cmp.eq p6, p7 = 0, r15
|
||||
(p6) br.cond.dptk 1f
|
||||
ld8 r8 = [r15], 8
|
||||
;;
|
||||
ld8 gp = [r15]
|
||||
mov b6 = r8
|
||||
;;
|
||||
br.call.sptk.many b0 = b6
|
||||
;;
|
||||
1:
|
||||
mov gp = loc2
|
||||
mov ar.pfs = loc0
|
||||
mov b0 = loc1
|
||||
br.ret.sptk.many b0
|
||||
.endp __do_frame_setup#
|
||||
.weak __register_frame_info_aux#
|
||||
|
|
|
@ -110,3 +110,25 @@ __do_global_ctors_aux:
|
|||
;;
|
||||
}
|
||||
.endp __do_global_ctors_aux#
|
||||
|
||||
.section .init,"ax","progbits"
|
||||
{ .mlx
|
||||
// __do_frame_setup_aux is in crtbegin.asm
|
||||
movl r2 = @gprel(__do_frame_setup_aux#)
|
||||
;;
|
||||
}
|
||||
{ .mii
|
||||
nop.m 0
|
||||
add r2 = r2, gp
|
||||
;;
|
||||
mov b6 = r2
|
||||
}
|
||||
{ .mib
|
||||
// __do_frame_setup_aux needs the address of __EH_FRAME_END__,
|
||||
// so we pass it in r16. This is rather evil, but we have no
|
||||
// output registers.
|
||||
addl r16 = @ltoff(__EH_FRAME_END__#), gp
|
||||
br.call.sptk.many b0 = b6
|
||||
;;
|
||||
}
|
||||
|
||||
|
|
1608
gcc/config/ia64/frame-ia64.c
Normal file
1608
gcc/config/ia64/frame-ia64.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2606,6 +2606,8 @@ rtx_needs_barrier (x, flags, pred)
|
|||
break;
|
||||
case 20: /* mov = ar.bsp */
|
||||
break;
|
||||
case 21: /* flushrs */
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
|
@ -3329,6 +3331,12 @@ ia64_init_builtins ()
|
|||
|
||||
def_builtin ("__sync_lock_release_di", void_ftype_pdi, IA64_BUILTIN_LOCK_RELEASE_DI);
|
||||
|
||||
def_builtin ("__builtin_ia64_bsp", build_function_type (ptr_type_node, endlink), IA64_BUILTIN_BSP);
|
||||
|
||||
def_builtin ("__builtin_ia64_flushrs",
|
||||
build_function_type (void_type_node, endlink),
|
||||
IA64_BUILTIN_FLUSHRS);
|
||||
|
||||
/* Add all builtins that are operations on two args. */
|
||||
for (i=0, d = bdesc_2argsi; i < sizeof(bdesc_2argsi) / sizeof *d; i++, d++)
|
||||
def_builtin (d->name, si_ftype_psi_si, d->code);
|
||||
|
@ -3743,6 +3751,19 @@ ia64_expand_builtin (exp, target, subtarget, mode, ignore)
|
|||
emit_insn (gen_movdi (op0, GEN_INT(0)));
|
||||
return 0;
|
||||
|
||||
case IA64_BUILTIN_BSP:
|
||||
{
|
||||
rtx reg = gen_reg_rtx (DImode);
|
||||
emit_insn (gen_bsp_value (reg));
|
||||
return reg;
|
||||
}
|
||||
|
||||
case IA64_BUILTIN_FLUSHRS:
|
||||
{
|
||||
emit_insn (gen_flushrs ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2893,7 +2893,10 @@ enum ia64_builtins
|
|||
|
||||
IA64_BUILTIN_LOCK_TEST_AND_SET_DI,
|
||||
|
||||
IA64_BUILTIN_LOCK_RELEASE_DI
|
||||
IA64_BUILTIN_LOCK_RELEASE_DI,
|
||||
|
||||
IA64_BUILTIN_BSP,
|
||||
IA64_BUILTIN_FLUSHRS
|
||||
};
|
||||
|
||||
/* Codes for expand_compare_and_swap and expand_swap_and_compare. */
|
||||
|
|
|
@ -48,6 +48,10 @@
|
|||
|
||||
;; ??? Add function unit scheduling info for Itanium (TM) processor.
|
||||
|
||||
;; ??? The explicit stop in the flushrs pattern is not ideal. It
|
||||
;; would be better if rtx_needs_barrier took care of this, but this is
|
||||
;; something that can be fixed later.
|
||||
|
||||
;; Unspec usage:
|
||||
;;
|
||||
;; unspec:
|
||||
|
@ -66,6 +70,7 @@
|
|||
;; 18 fetch_and_op
|
||||
;; 19 fetchadd_acq
|
||||
;; 20 bsp_value
|
||||
;; 21 flushrs
|
||||
;;
|
||||
;; unspec_volatile:
|
||||
;; 0 alloc
|
||||
|
@ -3243,6 +3248,12 @@
|
|||
mov ar.rsc=r19\;"
|
||||
[(set_attr "type" "unknown")
|
||||
(set_attr "predicable" "no")])
|
||||
|
||||
(define_insn "flushrs"
|
||||
[(unspec [(const_int 0)] 21)]
|
||||
""
|
||||
";; \; flushrs"
|
||||
[(set_attr "type" "M")])
|
||||
|
||||
;; ::::::::::::::::::::
|
||||
;; ::
|
||||
|
|
|
@ -39,3 +39,5 @@ crtendS.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
|
|||
$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
|
||||
|
||||
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
|
||||
LIB2ADDEH = $(srcdir)/config/ia64/frame-ia64.c
|
||||
|
||||
|
|
121
gcc/except.c
121
gcc/except.c
|
@ -698,6 +698,7 @@ struct func_eh_entry
|
|||
int range_number; /* EH region number from EH NOTE insn's. */
|
||||
rtx rethrow_label; /* Label for rethrow. */
|
||||
int rethrow_ref; /* Is rethrow_label referenced? */
|
||||
int emitted; /* 1 if this entry has been emitted in assembly file. */
|
||||
struct handler_info *handlers;
|
||||
};
|
||||
|
||||
|
@ -739,7 +740,8 @@ new_eh_region_entry (note_eh_region, rethrow)
|
|||
else
|
||||
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
|
||||
function_eh_regions[current_func_eh_entry].handlers = NULL;
|
||||
|
||||
function_eh_regions[current_func_eh_entry].emitted = 0;
|
||||
|
||||
return current_func_eh_entry++;
|
||||
}
|
||||
|
||||
|
@ -2221,40 +2223,44 @@ output_exception_table_entry (file, n)
|
|||
else
|
||||
rethrow = NULL_RTX;
|
||||
|
||||
if (function_eh_regions[index].emitted)
|
||||
return;
|
||||
function_eh_regions[index].emitted = 1;
|
||||
|
||||
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
|
||||
{
|
||||
/* rethrow label should indicate the LAST entry for a region */
|
||||
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
|
||||
assemble_label(buf);
|
||||
assemble_eh_label(buf);
|
||||
rethrow = NULL_RTX;
|
||||
}
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
if (handler == NULL)
|
||||
assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
else
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
|
||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
||||
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
}
|
||||
|
||||
if (flag_new_exceptions)
|
||||
{
|
||||
if (handler == NULL || handler->type_info == NULL)
|
||||
assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
else
|
||||
if (handler->type_info == CATCH_ALL_TYPE)
|
||||
assemble_integer (GEN_INT (CATCH_ALL_TYPE),
|
||||
assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE),
|
||||
POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
else
|
||||
output_constant ((tree)(handler->type_info),
|
||||
|
@ -2288,11 +2294,50 @@ set_exception_version_code (code)
|
|||
version_code = code;
|
||||
}
|
||||
|
||||
/* Free the EH table structures. */
|
||||
void
|
||||
free_exception_table ()
|
||||
{
|
||||
free (eh_table);
|
||||
clear_function_eh_region ();
|
||||
}
|
||||
|
||||
/* Output the common content of an exception table. */
|
||||
void
|
||||
output_exception_table_data ()
|
||||
{
|
||||
int i;
|
||||
char buf[256];
|
||||
extern FILE *asm_out_file;
|
||||
|
||||
if (flag_new_exceptions)
|
||||
{
|
||||
assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME),
|
||||
POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (GEN_INT (language_code), 2 , 1);
|
||||
assemble_eh_integer (GEN_INT (version_code), 2 , 1);
|
||||
|
||||
/* Add enough padding to make sure table aligns on a pointer boundry. */
|
||||
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
|
||||
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
|
||||
;
|
||||
if (i != 0)
|
||||
assemble_eh_integer (const0_rtx, i , 1);
|
||||
|
||||
/* Generate the label for offset calculations on rethrows. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
|
||||
assemble_eh_label(buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < eh_table_size; ++i)
|
||||
output_exception_table_entry (asm_out_file, eh_table[i]);
|
||||
|
||||
}
|
||||
|
||||
/* Output an exception table for the entire compilation unit. */
|
||||
void
|
||||
output_exception_table ()
|
||||
{
|
||||
int i;
|
||||
char buf[256];
|
||||
extern FILE *asm_out_file;
|
||||
|
||||
|
@ -2302,47 +2347,47 @@ output_exception_table ()
|
|||
exception_section ();
|
||||
|
||||
/* Beginning marker for table. */
|
||||
assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
|
||||
assemble_label ("__EXCEPTION_TABLE__");
|
||||
assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
|
||||
assemble_eh_label ("__EXCEPTION_TABLE__");
|
||||
|
||||
if (flag_new_exceptions)
|
||||
{
|
||||
assemble_integer (GEN_INT (NEW_EH_RUNTIME),
|
||||
POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_integer (GEN_INT (language_code), 2 , 1);
|
||||
assemble_integer (GEN_INT (version_code), 2 , 1);
|
||||
|
||||
/* Add enough padding to make sure table aligns on a pointer boundry. */
|
||||
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
|
||||
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
|
||||
;
|
||||
if (i != 0)
|
||||
assemble_integer (const0_rtx, i , 1);
|
||||
|
||||
/* Generate the label for offset calculations on rethrows. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
|
||||
assemble_label(buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < eh_table_size; ++i)
|
||||
output_exception_table_entry (asm_out_file, eh_table[i]);
|
||||
|
||||
free (eh_table);
|
||||
clear_function_eh_region ();
|
||||
output_exception_table_data ();
|
||||
|
||||
/* Ending marker for table. */
|
||||
/* Generate the label for end of table. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
|
||||
assemble_label(buf);
|
||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_label(buf);
|
||||
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
/* For binary compatibility, the old __throw checked the second
|
||||
position for a -1, so we should output at least 2 -1's */
|
||||
if (! flag_new_exceptions)
|
||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
putc ('\n', asm_out_file); /* blank line */
|
||||
}
|
||||
|
||||
/* Used by the ia64 unwind format to output data for an individual
|
||||
function. */
|
||||
void
|
||||
output_function_exception_table ()
|
||||
{
|
||||
extern FILE *asm_out_file;
|
||||
|
||||
if (! doing_eh (0) || ! eh_table)
|
||||
return;
|
||||
|
||||
#ifdef HANDLER_SECTION
|
||||
HANDLER_SECTION;
|
||||
#endif
|
||||
|
||||
output_exception_table_data ();
|
||||
|
||||
/* Ending marker for table. */
|
||||
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||
|
||||
putc ('\n', asm_out_file); /* blank line */
|
||||
}
|
||||
|
||||
|
||||
/* Emit code to get EH context.
|
||||
|
||||
|
|
|
@ -355,6 +355,15 @@ extern int exception_table_p PARAMS ((void));
|
|||
|
||||
extern void output_exception_table PARAMS ((void));
|
||||
|
||||
/* Free the exception table. */
|
||||
|
||||
extern void free_exception_table PARAMS((void));
|
||||
|
||||
/* Used by the ia64 unwind format to output data for an individual
|
||||
function. */
|
||||
|
||||
extern void output_function_exception_table PARAMS((void));
|
||||
|
||||
/* Given a return address in ADDR, determine the address we should use
|
||||
to find the corresponding EH region. */
|
||||
|
||||
|
|
|
@ -1827,6 +1827,10 @@ final_end_function (first, file, optimize)
|
|||
|
||||
bb_func_label_num = -1; /* not in function, nuke label # */
|
||||
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
output_function_exception_table ();
|
||||
#endif
|
||||
|
||||
/* If FUNCTION_EPILOGUE is not defined, then the function body
|
||||
itself contains return instructions wherever needed. */
|
||||
}
|
||||
|
@ -2968,6 +2972,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
|||
if (prescan > 0)
|
||||
break;
|
||||
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
IA64_UNWIND_EMIT (asm_out_file, insn);
|
||||
#endif
|
||||
/* Output assembler code from the template. */
|
||||
|
||||
output_asm_insn (template, recog_data.operand);
|
||||
|
|
663
gcc/frame-dwarf2.c
Normal file
663
gcc/frame-dwarf2.c
Normal file
|
@ -0,0 +1,663 @@
|
|||
/* Subroutines needed for unwinding DWARF 2 format stack frame info
|
||||
for exception handling. */
|
||||
/* Compile this one with gcc. */
|
||||
/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Contributed by Jason Merrill <jason@cygnus.com>.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
GNU CC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
In addition to the permissions in the GNU General Public License, the
|
||||
Free Software Foundation gives you unlimited permission to link the
|
||||
compiled version of this file into combinations with other programs,
|
||||
and to distribute those combinations without any restriction coming
|
||||
from the use of this file. (The General Public License restrictions
|
||||
do apply in other respects; for example, they cover modification of
|
||||
the file, and distribution when not linked into a combine
|
||||
executable.)
|
||||
|
||||
GNU CC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU CC; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* It is incorrect to include config.h here, because this file is being
|
||||
compiled for the target, and hence definitions concerning only the host
|
||||
do not apply. */
|
||||
|
||||
#include "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
|
||||
#include "defaults.h"
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
#include "dwarf2.h"
|
||||
#include "frame.h"
|
||||
#include "gthr.h"
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
|
||||
#else
|
||||
static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
|
||||
/* Don't use `fancy_abort' here even if config.h says to use it. */
|
||||
#ifdef abort
|
||||
#undef abort
|
||||
#endif
|
||||
|
||||
/* Some types used by the DWARF 2 spec. */
|
||||
|
||||
typedef int sword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
|
||||
typedef int saddr __attribute__ ((mode (pointer)));
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
/* Terminology:
|
||||
CIE - Common Information Element
|
||||
FDE - Frame Descriptor Element
|
||||
|
||||
There is one per function, and it describes where the function code
|
||||
is located, and what the register lifetimes and stack layout are
|
||||
within the function.
|
||||
|
||||
The data structures are defined in the DWARF specfication, although
|
||||
not in a very readable way (see LITERATURE).
|
||||
|
||||
Every time an exception is thrown, the code needs to locate the FDE
|
||||
for the current function, and starts to look for exception regions
|
||||
from that FDE. This works in a two-level search:
|
||||
a) in a linear search, find the shared image (i.e. DLL) containing
|
||||
the PC
|
||||
b) using the FDE table for that shared object, locate the FDE using
|
||||
binary search (which requires the sorting). */
|
||||
|
||||
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
|
||||
to distinguish it from a valid FDE. FDEs are aligned to an addressing
|
||||
unit boundary, but the fields within are unaligned. */
|
||||
|
||||
struct dwarf_cie {
|
||||
uword length;
|
||||
sword CIE_id;
|
||||
ubyte version;
|
||||
char augmentation[0];
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
/* The first few fields of an FDE. */
|
||||
|
||||
struct dwarf_fde {
|
||||
uword length;
|
||||
sword CIE_delta;
|
||||
void* pc_begin;
|
||||
uaddr pc_range;
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
typedef struct dwarf_fde fde;
|
||||
|
||||
/* Objects to be searched for frame unwind info. */
|
||||
|
||||
static struct object *objects;
|
||||
|
||||
/* The information we care about from a CIE. */
|
||||
|
||||
struct cie_info {
|
||||
char *augmentation;
|
||||
void *eh_ptr;
|
||||
int code_align;
|
||||
int data_align;
|
||||
unsigned ra_regno;
|
||||
};
|
||||
|
||||
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
|
||||
|
||||
struct frame_state_internal
|
||||
{
|
||||
struct frame_state s;
|
||||
struct frame_state_internal *saved_state;
|
||||
};
|
||||
|
||||
/* This is undefined below if we need it to be an actual function. */
|
||||
#define init_object_mutex_once()
|
||||
|
||||
#if __GTHREADS
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
|
||||
/* Helper for init_object_mutex_once. */
|
||||
|
||||
static void
|
||||
init_object_mutex (void)
|
||||
{
|
||||
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
|
||||
}
|
||||
|
||||
/* Call this to arrange to initialize the object mutex. */
|
||||
|
||||
#undef init_object_mutex_once
|
||||
static void
|
||||
init_object_mutex_once (void)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once (&once, init_object_mutex);
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
|
||||
#endif /* __GTHREADS */
|
||||
|
||||
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_uleb128 (unsigned char *buf, unsigned *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Decode the signed LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_sleb128 (unsigned char *buf, int *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
unsigned byte;
|
||||
|
||||
while (1)
|
||||
{
|
||||
byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
|
||||
result |= - (1 << shift);
|
||||
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read unaligned data from the instruction buffer. */
|
||||
|
||||
union unaligned {
|
||||
void *p;
|
||||
unsigned b2 __attribute__ ((mode (HI)));
|
||||
unsigned b4 __attribute__ ((mode (SI)));
|
||||
unsigned b8 __attribute__ ((mode (DI)));
|
||||
} __attribute__ ((packed));
|
||||
static inline void *
|
||||
read_pointer (void *p)
|
||||
{ union unaligned *up = p; return up->p; }
|
||||
static inline unsigned
|
||||
read_1byte (void *p)
|
||||
{ return *(unsigned char *)p; }
|
||||
static inline unsigned
|
||||
read_2byte (void *p)
|
||||
{ union unaligned *up = p; return up->b2; }
|
||||
static inline unsigned
|
||||
read_4byte (void *p)
|
||||
{ union unaligned *up = p; return up->b4; }
|
||||
static inline unsigned long
|
||||
read_8byte (void *p)
|
||||
{ union unaligned *up = p; return up->b8; }
|
||||
|
||||
/* Ordering function for FDEs. Functions can't overlap, so we just compare
|
||||
their starting addresses. */
|
||||
|
||||
static inline saddr
|
||||
fde_compare (fde *x, fde *y)
|
||||
{
|
||||
return (saddr)x->pc_begin - (saddr)y->pc_begin;
|
||||
}
|
||||
|
||||
/* Return the address of the FDE after P. */
|
||||
|
||||
static inline fde *
|
||||
next_fde (fde *p)
|
||||
{
|
||||
return (fde *)(((char *)p) + p->length + sizeof (p->length));
|
||||
}
|
||||
|
||||
#include "frame.c"
|
||||
|
||||
static size_t
|
||||
count_fdes (fde *this_fde)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
|
||||
{
|
||||
void *pc_begin = *beg_ptr;
|
||||
void *pc_end = *end_ptr;
|
||||
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
fde_insert (accu, this_fde);
|
||||
|
||||
if (this_fde->pc_begin < pc_begin)
|
||||
pc_begin = this_fde->pc_begin;
|
||||
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
|
||||
pc_end = this_fde->pc_begin + this_fde->pc_range;
|
||||
}
|
||||
|
||||
*beg_ptr = pc_begin;
|
||||
*end_ptr = pc_end;
|
||||
}
|
||||
|
||||
/* search this fde table for the one containing the pc */
|
||||
static fde *
|
||||
search_fdes (fde *this_fde, void *pc)
|
||||
{
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
|
||||
return this_fde;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up a sorted array of pointers to FDEs for a loaded object. We
|
||||
count up the entries before allocating the array because it's likely to
|
||||
be faster. We can be called multiple times, should we have failed to
|
||||
allocate a sorted fde array on a previous occasion. */
|
||||
|
||||
static void
|
||||
frame_init (struct object* ob)
|
||||
{
|
||||
size_t count;
|
||||
fde_accumulator accu;
|
||||
void *pc_begin, *pc_end;
|
||||
fde **array;
|
||||
|
||||
if (ob->pc_begin)
|
||||
count = ob->count;
|
||||
else if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (count = 0; *p; ++p)
|
||||
count += count_fdes (*p);
|
||||
}
|
||||
else
|
||||
count = count_fdes (ob->fde_begin);
|
||||
ob->count = count;
|
||||
|
||||
if (!start_fde_sort (&accu, count) && ob->pc_begin)
|
||||
return;
|
||||
|
||||
pc_begin = (void*)(uaddr)-1;
|
||||
pc_end = 0;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (; *p; ++p)
|
||||
add_fdes (*p, &accu, &pc_begin, &pc_end);
|
||||
}
|
||||
else
|
||||
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
|
||||
|
||||
array = end_fde_sort (&accu, count);
|
||||
if (array)
|
||||
ob->fde_array = array;
|
||||
ob->pc_begin = pc_begin;
|
||||
ob->pc_end = pc_end;
|
||||
}
|
||||
|
||||
/* Return a pointer to the FDE for the function containing PC. */
|
||||
|
||||
static fde *
|
||||
find_fde (void *pc)
|
||||
{
|
||||
struct object *ob;
|
||||
size_t lo, hi;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
/* Linear search through the objects, to find the one containing the pc. */
|
||||
for (ob = objects; ob; ob = ob->next)
|
||||
{
|
||||
if (ob->pc_begin == 0)
|
||||
frame_init (ob);
|
||||
if (pc >= ob->pc_begin && pc < ob->pc_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ob == 0)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
|
||||
frame_init (ob);
|
||||
|
||||
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
|
||||
/* Standard binary search algorithm. */
|
||||
for (lo = 0, hi = ob->count; lo < hi; )
|
||||
{
|
||||
size_t i = (lo + hi) / 2;
|
||||
fde *f = ob->fde_array[i];
|
||||
|
||||
if (pc < f->pc_begin)
|
||||
hi = i;
|
||||
else if (pc >= f->pc_begin + f->pc_range)
|
||||
lo = i + 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Long slow labourious linear search, cos we've no memory. */
|
||||
fde *f;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
|
||||
do
|
||||
{
|
||||
f = search_fdes (*p, pc);
|
||||
if (f)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
while (*p);
|
||||
}
|
||||
else
|
||||
f = search_fdes (ob->fde_begin, pc);
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct dwarf_cie *
|
||||
get_cie (fde *f)
|
||||
{
|
||||
return ((void *)&f->CIE_delta) - f->CIE_delta;
|
||||
}
|
||||
|
||||
/* Extract any interesting information from the CIE for the translation
|
||||
unit F belongs to. */
|
||||
|
||||
static void *
|
||||
extract_cie_info (fde *f, struct cie_info *c)
|
||||
{
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
c->augmentation = get_cie (f)->augmentation;
|
||||
|
||||
if (strcmp (c->augmentation, "") != 0
|
||||
&& strcmp (c->augmentation, "eh") != 0
|
||||
&& c->augmentation[0] != 'z')
|
||||
return 0;
|
||||
|
||||
p = c->augmentation + strlen (c->augmentation) + 1;
|
||||
|
||||
if (strcmp (c->augmentation, "eh") == 0)
|
||||
{
|
||||
c->eh_ptr = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
}
|
||||
else
|
||||
c->eh_ptr = 0;
|
||||
|
||||
p = decode_uleb128 (p, &c->code_align);
|
||||
p = decode_sleb128 (p, &c->data_align);
|
||||
c->ra_regno = *(unsigned char *)p++;
|
||||
|
||||
/* If the augmentation starts with 'z', we now see the length of the
|
||||
augmentation fields. */
|
||||
if (c->augmentation[0] == 'z')
|
||||
{
|
||||
p = decode_uleb128 (p, &i);
|
||||
p += i;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Decode one instruction's worth of DWARF 2 call frame information.
|
||||
Used by __frame_state_for. Takes pointers P to the instruction to
|
||||
decode, STATE to the current register unwind information, INFO to the
|
||||
current CIE information, and PC to the current PC value. Returns a
|
||||
pointer to the next instruction. */
|
||||
|
||||
static void *
|
||||
execute_cfa_insn (void *p, struct frame_state_internal *state,
|
||||
struct cie_info *info, void **pc)
|
||||
{
|
||||
unsigned insn = *(unsigned char *)p++;
|
||||
unsigned reg;
|
||||
int offset;
|
||||
|
||||
if (insn & DW_CFA_advance_loc)
|
||||
*pc += ((insn & 0x3f) * info->code_align);
|
||||
else if (insn & DW_CFA_offset)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything about this register; it's only used to
|
||||
reload SP in the epilogue. We don't want to copy in SP
|
||||
values for outer frames; we handle restoring SP specially. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
}
|
||||
else if (insn & DW_CFA_restore)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
}
|
||||
else switch (insn)
|
||||
{
|
||||
case DW_CFA_set_loc:
|
||||
*pc = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
*pc += read_1byte (p);
|
||||
p += 1;
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
*pc += read_2byte (p);
|
||||
p += 2;
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
*pc += read_4byte (p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything; see above. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
break;
|
||||
|
||||
case DW_CFA_undefined:
|
||||
case DW_CFA_same_value:
|
||||
case DW_CFA_nop:
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
{
|
||||
unsigned reg2;
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, ®2);
|
||||
state->s.saved[reg] = REG_SAVED_REG;
|
||||
state->s.reg_or_offset[reg] = reg2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_reg = reg;
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.cfa_reg = reg;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_remember_state:
|
||||
{
|
||||
struct frame_state_internal *save =
|
||||
(struct frame_state_internal *)
|
||||
malloc (sizeof (struct frame_state_internal));
|
||||
memcpy (save, state, sizeof (struct frame_state_internal));
|
||||
state->saved_state = save;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
{
|
||||
struct frame_state_internal *save = state->saved_state;
|
||||
memcpy (state, save, sizeof (struct frame_state_internal));
|
||||
free (save);
|
||||
}
|
||||
break;
|
||||
|
||||
/* FIXME: Hardcoded for SPARC register window configuration. */
|
||||
case DW_CFA_GNU_window_save:
|
||||
for (reg = 16; reg < 32; ++reg)
|
||||
{
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_args_size:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.args_size = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_negative_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = -offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Called from __throw to find the registers to restore for a given
|
||||
PC_TARGET. The caller should allocate a local variable of `struct
|
||||
frame_state' (declared in frame.h) and pass its address to STATE_IN. */
|
||||
|
||||
struct frame_state *
|
||||
__frame_state_for (void *pc_target, struct frame_state *state_in)
|
||||
{
|
||||
fde *f;
|
||||
void *insn, *end, *pc;
|
||||
struct cie_info info;
|
||||
struct frame_state_internal state;
|
||||
|
||||
f = find_fde (pc_target);
|
||||
if (f == 0)
|
||||
return 0;
|
||||
|
||||
insn = extract_cie_info (f, &info);
|
||||
if (insn == 0)
|
||||
return 0;
|
||||
|
||||
memset (&state, 0, sizeof (state));
|
||||
state.s.retaddr_column = info.ra_regno;
|
||||
state.s.eh_ptr = info.eh_ptr;
|
||||
|
||||
/* First decode all the insns in the CIE. */
|
||||
end = next_fde ((fde*) get_cie (f));
|
||||
while (insn < end)
|
||||
insn = execute_cfa_insn (insn, &state, &info, 0);
|
||||
|
||||
insn = ((fde *)f) + 1;
|
||||
|
||||
if (info.augmentation[0] == 'z')
|
||||
{
|
||||
int i;
|
||||
insn = decode_uleb128 (insn, &i);
|
||||
insn += i;
|
||||
}
|
||||
|
||||
/* Then the insns in the FDE up to our target PC. */
|
||||
end = next_fde (f);
|
||||
pc = f->pc_begin;
|
||||
while (insn < end && pc <= pc_target)
|
||||
insn = execute_cfa_insn (insn, &state, &info, &pc);
|
||||
|
||||
memcpy (state_in, &state.s, sizeof (state.s));
|
||||
return state_in;
|
||||
}
|
||||
#endif /* DWARF2_UNWIND_INFO */
|
629
gcc/frame.c
629
gcc/frame.c
|
@ -29,216 +29,6 @@ along with GNU CC; see the file COPYING. If not, write to
|
|||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* It is incorrect to include config.h here, because this file is being
|
||||
compiled for the target, and hence definitions concerning only the host
|
||||
do not apply. */
|
||||
|
||||
#include "tconfig.h"
|
||||
#include "tsystem.h"
|
||||
|
||||
#include "defaults.h"
|
||||
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
#include "dwarf2.h"
|
||||
#include "frame.h"
|
||||
#include "gthr.h"
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
|
||||
#else
|
||||
static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
|
||||
/* Don't use `fancy_abort' here even if config.h says to use it. */
|
||||
#ifdef abort
|
||||
#undef abort
|
||||
#endif
|
||||
|
||||
/* Some types used by the DWARF 2 spec. */
|
||||
|
||||
typedef int sword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uword __attribute__ ((mode (SI)));
|
||||
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
|
||||
typedef int saddr __attribute__ ((mode (pointer)));
|
||||
typedef unsigned char ubyte;
|
||||
|
||||
/* Terminology:
|
||||
CIE - Common Information Element
|
||||
FDE - Frame Descriptor Element
|
||||
|
||||
There is one per function, and it describes where the function code
|
||||
is located, and what the register lifetimes and stack layout are
|
||||
within the function.
|
||||
|
||||
The data structures are defined in the DWARF specfication, although
|
||||
not in a very readable way (see LITERATURE).
|
||||
|
||||
Every time an exception is thrown, the code needs to locate the FDE
|
||||
for the current function, and starts to look for exception regions
|
||||
from that FDE. This works in a two-level search:
|
||||
a) in a linear search, find the shared image (i.e. DLL) containing
|
||||
the PC
|
||||
b) using the FDE table for that shared object, locate the FDE using
|
||||
binary search (which requires the sorting). */
|
||||
|
||||
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
|
||||
to distinguish it from a valid FDE. FDEs are aligned to an addressing
|
||||
unit boundary, but the fields within are unaligned. */
|
||||
|
||||
struct dwarf_cie {
|
||||
uword length;
|
||||
sword CIE_id;
|
||||
ubyte version;
|
||||
char augmentation[0];
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
/* The first few fields of an FDE. */
|
||||
|
||||
struct dwarf_fde {
|
||||
uword length;
|
||||
sword CIE_delta;
|
||||
void* pc_begin;
|
||||
uaddr pc_range;
|
||||
} __attribute__ ((packed, aligned (__alignof__ (void *))));
|
||||
|
||||
typedef struct dwarf_fde fde;
|
||||
|
||||
/* Objects to be searched for frame unwind info. */
|
||||
|
||||
static struct object *objects;
|
||||
|
||||
/* The information we care about from a CIE. */
|
||||
|
||||
struct cie_info {
|
||||
char *augmentation;
|
||||
void *eh_ptr;
|
||||
int code_align;
|
||||
int data_align;
|
||||
unsigned ra_regno;
|
||||
};
|
||||
|
||||
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
|
||||
|
||||
struct frame_state_internal
|
||||
{
|
||||
struct frame_state s;
|
||||
struct frame_state_internal *saved_state;
|
||||
};
|
||||
|
||||
/* This is undefined below if we need it to be an actual function. */
|
||||
#define init_object_mutex_once()
|
||||
|
||||
#if __GTHREADS
|
||||
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
|
||||
|
||||
/* Helper for init_object_mutex_once. */
|
||||
|
||||
static void
|
||||
init_object_mutex (void)
|
||||
{
|
||||
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
|
||||
}
|
||||
|
||||
/* Call this to arrange to initialize the object mutex. */
|
||||
|
||||
#undef init_object_mutex_once
|
||||
static void
|
||||
init_object_mutex_once (void)
|
||||
{
|
||||
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
|
||||
__gthread_once (&once, init_object_mutex);
|
||||
}
|
||||
|
||||
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
|
||||
#endif /* __GTHREADS */
|
||||
|
||||
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_uleb128 (unsigned char *buf, unsigned *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
unsigned byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Decode the signed LEB128 constant at BUF into the variable pointed to
|
||||
by R, and return the new value of BUF. */
|
||||
|
||||
static void *
|
||||
decode_sleb128 (unsigned char *buf, int *r)
|
||||
{
|
||||
unsigned shift = 0;
|
||||
unsigned result = 0;
|
||||
unsigned byte;
|
||||
|
||||
while (1)
|
||||
{
|
||||
byte = *buf++;
|
||||
result |= (byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
|
||||
result |= - (1 << shift);
|
||||
|
||||
*r = result;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Read unaligned data from the instruction buffer. */
|
||||
|
||||
union unaligned {
|
||||
void *p;
|
||||
unsigned b2 __attribute__ ((mode (HI)));
|
||||
unsigned b4 __attribute__ ((mode (SI)));
|
||||
unsigned b8 __attribute__ ((mode (DI)));
|
||||
} __attribute__ ((packed));
|
||||
static inline void *
|
||||
read_pointer (void *p)
|
||||
{ union unaligned *up = p; return up->p; }
|
||||
static inline unsigned
|
||||
read_1byte (void *p)
|
||||
{ return *(unsigned char *)p; }
|
||||
static inline unsigned
|
||||
read_2byte (void *p)
|
||||
{ union unaligned *up = p; return up->b2; }
|
||||
static inline unsigned
|
||||
read_4byte (void *p)
|
||||
{ union unaligned *up = p; return up->b4; }
|
||||
static inline unsigned long
|
||||
read_8byte (void *p)
|
||||
{ union unaligned *up = p; return up->b8; }
|
||||
|
||||
/* Ordering function for FDEs. Functions can't overlap, so we just compare
|
||||
their starting addresses. */
|
||||
|
||||
static inline saddr
|
||||
fde_compare (fde *x, fde *y)
|
||||
{
|
||||
return (saddr)x->pc_begin - (saddr)y->pc_begin;
|
||||
}
|
||||
|
||||
/* Return the address of the FDE after P. */
|
||||
|
||||
static inline fde *
|
||||
next_fde (fde *p)
|
||||
{
|
||||
return (fde *)(((char *)p) + p->length + sizeof (p->length));
|
||||
}
|
||||
|
||||
/* Sorting an array of FDEs by address.
|
||||
(Ideally we would have the linker sort the FDEs so we don't have to do
|
||||
it at run time. But the linkers are not yet prepared for this.) */
|
||||
|
@ -452,377 +242,6 @@ end_fde_sort (fde_accumulator *accu, size_t count)
|
|||
return accu->linear.array;
|
||||
}
|
||||
|
||||
static size_t
|
||||
count_fdes (fde *this_fde)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
|
||||
{
|
||||
void *pc_begin = *beg_ptr;
|
||||
void *pc_end = *end_ptr;
|
||||
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
fde_insert (accu, this_fde);
|
||||
|
||||
if (this_fde->pc_begin < pc_begin)
|
||||
pc_begin = this_fde->pc_begin;
|
||||
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
|
||||
pc_end = this_fde->pc_begin + this_fde->pc_range;
|
||||
}
|
||||
|
||||
*beg_ptr = pc_begin;
|
||||
*end_ptr = pc_end;
|
||||
}
|
||||
|
||||
/* search this fde table for the one containing the pc */
|
||||
static fde *
|
||||
search_fdes (fde *this_fde, void *pc)
|
||||
{
|
||||
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
|
||||
{
|
||||
/* Skip CIEs and linked once FDE entries. */
|
||||
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
|
||||
continue;
|
||||
|
||||
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
|
||||
return this_fde;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up a sorted array of pointers to FDEs for a loaded object. We
|
||||
count up the entries before allocating the array because it's likely to
|
||||
be faster. We can be called multiple times, should we have failed to
|
||||
allocate a sorted fde array on a previous occasion. */
|
||||
|
||||
static void
|
||||
frame_init (struct object* ob)
|
||||
{
|
||||
size_t count;
|
||||
fde_accumulator accu;
|
||||
void *pc_begin, *pc_end;
|
||||
fde **array;
|
||||
|
||||
if (ob->pc_begin)
|
||||
count = ob->count;
|
||||
else if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (count = 0; *p; ++p)
|
||||
count += count_fdes (*p);
|
||||
}
|
||||
else
|
||||
count = count_fdes (ob->fde_begin);
|
||||
ob->count = count;
|
||||
|
||||
if (!start_fde_sort (&accu, count) && ob->pc_begin)
|
||||
return;
|
||||
|
||||
pc_begin = (void*)(uaddr)-1;
|
||||
pc_end = 0;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
for (; *p; ++p)
|
||||
add_fdes (*p, &accu, &pc_begin, &pc_end);
|
||||
}
|
||||
else
|
||||
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
|
||||
|
||||
array = end_fde_sort (&accu, count);
|
||||
if (array)
|
||||
ob->fde_array = array;
|
||||
ob->pc_begin = pc_begin;
|
||||
ob->pc_end = pc_end;
|
||||
}
|
||||
|
||||
/* Return a pointer to the FDE for the function containing PC. */
|
||||
|
||||
static fde *
|
||||
find_fde (void *pc)
|
||||
{
|
||||
struct object *ob;
|
||||
size_t lo, hi;
|
||||
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
|
||||
/* Linear search through the objects, to find the one containing the pc. */
|
||||
for (ob = objects; ob; ob = ob->next)
|
||||
{
|
||||
if (ob->pc_begin == 0)
|
||||
frame_init (ob);
|
||||
if (pc >= ob->pc_begin && pc < ob->pc_end)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ob == 0)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
|
||||
frame_init (ob);
|
||||
|
||||
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
|
||||
{
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
|
||||
/* Standard binary search algorithm. */
|
||||
for (lo = 0, hi = ob->count; lo < hi; )
|
||||
{
|
||||
size_t i = (lo + hi) / 2;
|
||||
fde *f = ob->fde_array[i];
|
||||
|
||||
if (pc < f->pc_begin)
|
||||
hi = i;
|
||||
else if (pc >= f->pc_begin + f->pc_range)
|
||||
lo = i + 1;
|
||||
else
|
||||
return f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Long slow labourious linear search, cos we've no memory. */
|
||||
fde *f;
|
||||
|
||||
if (ob->fde_array)
|
||||
{
|
||||
fde **p = ob->fde_array;
|
||||
|
||||
do
|
||||
{
|
||||
f = search_fdes (*p, pc);
|
||||
if (f)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
while (*p);
|
||||
}
|
||||
else
|
||||
f = search_fdes (ob->fde_begin, pc);
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct dwarf_cie *
|
||||
get_cie (fde *f)
|
||||
{
|
||||
return ((void *)&f->CIE_delta) - f->CIE_delta;
|
||||
}
|
||||
|
||||
/* Extract any interesting information from the CIE for the translation
|
||||
unit F belongs to. */
|
||||
|
||||
static void *
|
||||
extract_cie_info (fde *f, struct cie_info *c)
|
||||
{
|
||||
void *p;
|
||||
int i;
|
||||
|
||||
c->augmentation = get_cie (f)->augmentation;
|
||||
|
||||
if (strcmp (c->augmentation, "") != 0
|
||||
&& strcmp (c->augmentation, "eh") != 0
|
||||
&& c->augmentation[0] != 'z')
|
||||
return 0;
|
||||
|
||||
p = c->augmentation + strlen (c->augmentation) + 1;
|
||||
|
||||
if (strcmp (c->augmentation, "eh") == 0)
|
||||
{
|
||||
c->eh_ptr = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
}
|
||||
else
|
||||
c->eh_ptr = 0;
|
||||
|
||||
p = decode_uleb128 (p, &c->code_align);
|
||||
p = decode_sleb128 (p, &c->data_align);
|
||||
c->ra_regno = *(unsigned char *)p++;
|
||||
|
||||
/* If the augmentation starts with 'z', we now see the length of the
|
||||
augmentation fields. */
|
||||
if (c->augmentation[0] == 'z')
|
||||
{
|
||||
p = decode_uleb128 (p, &i);
|
||||
p += i;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Decode one instruction's worth of DWARF 2 call frame information.
|
||||
Used by __frame_state_for. Takes pointers P to the instruction to
|
||||
decode, STATE to the current register unwind information, INFO to the
|
||||
current CIE information, and PC to the current PC value. Returns a
|
||||
pointer to the next instruction. */
|
||||
|
||||
static void *
|
||||
execute_cfa_insn (void *p, struct frame_state_internal *state,
|
||||
struct cie_info *info, void **pc)
|
||||
{
|
||||
unsigned insn = *(unsigned char *)p++;
|
||||
unsigned reg;
|
||||
int offset;
|
||||
|
||||
if (insn & DW_CFA_advance_loc)
|
||||
*pc += ((insn & 0x3f) * info->code_align);
|
||||
else if (insn & DW_CFA_offset)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything about this register; it's only used to
|
||||
reload SP in the epilogue. We don't want to copy in SP
|
||||
values for outer frames; we handle restoring SP specially. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
}
|
||||
else if (insn & DW_CFA_restore)
|
||||
{
|
||||
reg = (insn & 0x3f);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
}
|
||||
else switch (insn)
|
||||
{
|
||||
case DW_CFA_set_loc:
|
||||
*pc = read_pointer (p);
|
||||
p += sizeof (void *);
|
||||
break;
|
||||
case DW_CFA_advance_loc1:
|
||||
*pc += read_1byte (p);
|
||||
p += 1;
|
||||
break;
|
||||
case DW_CFA_advance_loc2:
|
||||
*pc += read_2byte (p);
|
||||
p += 2;
|
||||
break;
|
||||
case DW_CFA_advance_loc4:
|
||||
*pc += read_4byte (p);
|
||||
p += 4;
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
if (reg == state->s.cfa_reg)
|
||||
/* Don't record anything; see above. */;
|
||||
else
|
||||
{
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = offset;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.saved[reg] = REG_UNSAVED;
|
||||
break;
|
||||
|
||||
case DW_CFA_undefined:
|
||||
case DW_CFA_same_value:
|
||||
case DW_CFA_nop:
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
{
|
||||
unsigned reg2;
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, ®2);
|
||||
state->s.saved[reg] = REG_SAVED_REG;
|
||||
state->s.reg_or_offset[reg] = reg2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_reg = reg;
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
case DW_CFA_def_cfa_register:
|
||||
p = decode_uleb128 (p, ®);
|
||||
state->s.cfa_reg = reg;
|
||||
break;
|
||||
case DW_CFA_def_cfa_offset:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.cfa_offset = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_remember_state:
|
||||
{
|
||||
struct frame_state_internal *save =
|
||||
(struct frame_state_internal *)
|
||||
malloc (sizeof (struct frame_state_internal));
|
||||
memcpy (save, state, sizeof (struct frame_state_internal));
|
||||
state->saved_state = save;
|
||||
}
|
||||
break;
|
||||
case DW_CFA_restore_state:
|
||||
{
|
||||
struct frame_state_internal *save = state->saved_state;
|
||||
memcpy (state, save, sizeof (struct frame_state_internal));
|
||||
free (save);
|
||||
}
|
||||
break;
|
||||
|
||||
/* FIXME: Hardcoded for SPARC register window configuration. */
|
||||
case DW_CFA_GNU_window_save:
|
||||
for (reg = 16; reg < 32; ++reg)
|
||||
{
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_args_size:
|
||||
p = decode_uleb128 (p, &offset);
|
||||
state->s.args_size = offset;
|
||||
break;
|
||||
|
||||
case DW_CFA_GNU_negative_offset_extended:
|
||||
p = decode_uleb128 (p, ®);
|
||||
p = decode_uleb128 (p, &offset);
|
||||
offset *= info->data_align;
|
||||
state->s.saved[reg] = REG_SAVED_OFFSET;
|
||||
state->s.reg_or_offset[reg] = -offset;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
void
|
||||
|
@ -917,51 +336,3 @@ __deregister_frame (void *begin)
|
|||
free (__deregister_frame_info (begin));
|
||||
}
|
||||
|
||||
/* Called from __throw to find the registers to restore for a given
|
||||
PC_TARGET. The caller should allocate a local variable of `struct
|
||||
frame_state' (declared in frame.h) and pass its address to STATE_IN. */
|
||||
|
||||
struct frame_state *
|
||||
__frame_state_for (void *pc_target, struct frame_state *state_in)
|
||||
{
|
||||
fde *f;
|
||||
void *insn, *end, *pc;
|
||||
struct cie_info info;
|
||||
struct frame_state_internal state;
|
||||
|
||||
f = find_fde (pc_target);
|
||||
if (f == 0)
|
||||
return 0;
|
||||
|
||||
insn = extract_cie_info (f, &info);
|
||||
if (insn == 0)
|
||||
return 0;
|
||||
|
||||
memset (&state, 0, sizeof (state));
|
||||
state.s.retaddr_column = info.ra_regno;
|
||||
state.s.eh_ptr = info.eh_ptr;
|
||||
|
||||
/* First decode all the insns in the CIE. */
|
||||
end = next_fde ((fde*) get_cie (f));
|
||||
while (insn < end)
|
||||
insn = execute_cfa_insn (insn, &state, &info, 0);
|
||||
|
||||
insn = ((fde *)f) + 1;
|
||||
|
||||
if (info.augmentation[0] == 'z')
|
||||
{
|
||||
int i;
|
||||
insn = decode_uleb128 (insn, &i);
|
||||
insn += i;
|
||||
}
|
||||
|
||||
/* Then the insns in the FDE up to our target PC. */
|
||||
end = next_fde (f);
|
||||
pc = f->pc_begin;
|
||||
while (insn < end && pc <= pc_target)
|
||||
insn = execute_cfa_insn (insn, &state, &info, &pc);
|
||||
|
||||
memcpy (state_in, &state.s, sizeof (state.s));
|
||||
return state_in;
|
||||
}
|
||||
#endif /* DWARF2_UNWIND_INFO */
|
||||
|
|
187
gcc/frame.h
187
gcc/frame.h
|
@ -50,9 +50,15 @@ typedef struct frame_state
|
|||
keep the copies synchronized! */
|
||||
|
||||
struct object {
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
void *pc_base; /* This field will be set by find_fde. */
|
||||
#endif
|
||||
void *pc_begin;
|
||||
void *pc_end;
|
||||
struct dwarf_fde *fde_begin;
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
struct dwarf_fde *fde_end;
|
||||
#endif
|
||||
struct dwarf_fde **fde_array;
|
||||
size_t count;
|
||||
struct object *next;
|
||||
|
@ -87,3 +93,184 @@ extern void *__deregister_frame_info (void *);
|
|||
Returns NULL on failure, otherwise returns STATE_IN. */
|
||||
|
||||
extern struct frame_state *__frame_state_for (void *, struct frame_state *);
|
||||
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
|
||||
/* This is the information required for unwind records in an ia64
|
||||
object file. This is required by GAS and the compiler runtime. */
|
||||
|
||||
/* These are the starting point masks for the various types of
|
||||
unwind records. To create a record of type R3 for instance, one
|
||||
starts by using the value UNW_R3 and or-ing in any other required values.
|
||||
These values are also unique (in context), so they can be used to identify
|
||||
the various record types as well. UNW_Bx and some UNW_Px do have the
|
||||
same value, but Px can only occur in a prologue context, and Bx in
|
||||
a body context. */
|
||||
|
||||
#define UNW_R1 0x00
|
||||
#define UNW_R2 0x40
|
||||
#define UNW_R3 0x60
|
||||
#define UNW_P1 0x80
|
||||
#define UNW_P2 0xA0
|
||||
#define UNW_P3 0xB0
|
||||
#define UNW_P4 0xB8
|
||||
#define UNW_P5 0xB9
|
||||
#define UNW_P6 0xC0
|
||||
#define UNW_P7 0xE0
|
||||
#define UNW_P8 0xF0
|
||||
#define UNW_P9 0xF1
|
||||
#define UNW_P10 0xFF
|
||||
#define UNW_X1 0xF9
|
||||
#define UNW_X2 0xFA
|
||||
#define UNW_X3 0xFB
|
||||
#define UNW_X4 0xFC
|
||||
#define UNW_B1 0x80
|
||||
#define UNW_B2 0xC0
|
||||
#define UNW_B3 0xE0
|
||||
#define UNW_B4 0xF0
|
||||
|
||||
/* These are all the various types of unwind records. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
prologue, prologue_gr, body, mem_stack_f, mem_stack_v, psp_gr, psp_sprel,
|
||||
rp_when, rp_gr, rp_br, rp_psprel, rp_sprel, pfs_when, pfs_gr, pfs_psprel,
|
||||
pfs_sprel, preds_when, preds_gr, preds_psprel, preds_sprel,
|
||||
fr_mem, frgr_mem, gr_gr, gr_mem, br_mem, br_gr, spill_base, spill_mask,
|
||||
unat_when, unat_gr, unat_psprel, unat_sprel, lc_when, lc_gr, lc_psprel,
|
||||
lc_sprel, fpsr_when, fpsr_gr, fpsr_psprel, fpsr_sprel,
|
||||
priunat_when_gr, priunat_when_mem, priunat_gr, priunat_psprel,
|
||||
priunat_sprel, bsp_when, bsp_gr, bsp_psprel, bsp_sprel, bspstore_when,
|
||||
bspstore_gr, bspstore_psprel, bspstore_sprel, rnat_when, rnat_gr,
|
||||
rnat_psprel, rnat_sprel, epilogue, label_state, copy_state,
|
||||
spill_psprel, spill_sprel, spill_reg, spill_psprel_p, spill_sprel_p,
|
||||
spill_reg_p
|
||||
} unw_record_type;
|
||||
|
||||
|
||||
/* These structures declare the fields that can be used in each of the
|
||||
4 record formats, R, P, B and X. */
|
||||
|
||||
typedef struct unw_r_record
|
||||
{
|
||||
unsigned long rlen;
|
||||
unsigned short mask;
|
||||
unsigned short grsave;
|
||||
} unw_r_record;
|
||||
|
||||
typedef struct unw_p_record
|
||||
{
|
||||
void *imask;
|
||||
unsigned long t;
|
||||
unsigned long size;
|
||||
unsigned long spoff;
|
||||
unsigned long br;
|
||||
unsigned long pspoff;
|
||||
unsigned short gr;
|
||||
unsigned short rmask;
|
||||
unsigned short grmask;
|
||||
unsigned long frmask;
|
||||
unsigned short brmask;
|
||||
} unw_p_record;
|
||||
|
||||
typedef struct unw_b_record
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned long label;
|
||||
unsigned short ecount;
|
||||
} unw_b_record;
|
||||
|
||||
typedef struct unw_x_record
|
||||
{
|
||||
unsigned long t;
|
||||
unsigned long spoff;
|
||||
unsigned long pspoff;
|
||||
unsigned short reg;
|
||||
unsigned short treg;
|
||||
unsigned short qp;
|
||||
unsigned short xy; /* Value of the XY field.. */
|
||||
} unw_x_record;
|
||||
|
||||
/* This structure is used to determine the specific record type and
|
||||
its fields. */
|
||||
typedef struct unwind_record
|
||||
{
|
||||
unw_record_type type;
|
||||
union {
|
||||
unw_r_record r;
|
||||
unw_p_record p;
|
||||
unw_b_record b;
|
||||
unw_x_record x;
|
||||
} record;
|
||||
} unwind_record;
|
||||
|
||||
#define IA64_UNW_LOC_TYPE_NONE 0
|
||||
#define IA64_UNW_LOC_TYPE_MEM 1
|
||||
#define IA64_UNW_LOC_TYPE_GR 2
|
||||
#define IA64_UNW_LOC_TYPE_FR 3
|
||||
#define IA64_UNW_LOC_TYPE_BR 4
|
||||
#define IA64_UNW_LOC_TYPE_SPOFF 5
|
||||
#define IA64_UNW_LOC_TYPE_PSPOFF 6
|
||||
#define IA64_UNW_LOC_TYPE_OFFSET 7
|
||||
#define IA64_UNW_LOC_TYPE_SPILLBASE 8
|
||||
|
||||
typedef struct ia64_reg_loc
|
||||
{
|
||||
long when; /* PC relative offset from start of function. */
|
||||
union { /* In memory or another register? */
|
||||
void *mem;
|
||||
int regno;
|
||||
int offset;
|
||||
} l;
|
||||
short loc_type; /* Where to find value. */
|
||||
short reg_size;
|
||||
} ia64_reg_loc;
|
||||
|
||||
/* Frame information record. */
|
||||
|
||||
typedef struct ia64_frame_state
|
||||
{
|
||||
ia64_reg_loc gr[4]; /* gr4 to gr7. */
|
||||
ia64_reg_loc fr[20]; /* fr2 to fr5, fr16 to fr31. */
|
||||
ia64_reg_loc br[5]; /* br1 to br5. */
|
||||
ia64_reg_loc rp;
|
||||
ia64_reg_loc fpsr;
|
||||
ia64_reg_loc bsp;
|
||||
ia64_reg_loc bspstore;
|
||||
ia64_reg_loc rnat;
|
||||
ia64_reg_loc pfs;
|
||||
ia64_reg_loc unat;
|
||||
ia64_reg_loc lc;
|
||||
ia64_reg_loc pr;
|
||||
ia64_reg_loc priunat;
|
||||
ia64_reg_loc sp;
|
||||
ia64_reg_loc psp;
|
||||
ia64_reg_loc spill_base;
|
||||
void *my_sp;
|
||||
void *my_bsp;
|
||||
} ia64_frame_state;
|
||||
|
||||
/* This structure represents the start of an unwind information pointer.
|
||||
'unwind_descriptors' is the beginninng of the unwind descriptors, which
|
||||
use up 'length' bytes of storage. */
|
||||
|
||||
typedef struct unwind_info_ptr
|
||||
{
|
||||
unsigned short version;
|
||||
unsigned short flags;
|
||||
unsigned int length;
|
||||
unsigned char unwind_descriptors[1];
|
||||
} unwind_info_ptr;
|
||||
|
||||
|
||||
extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *,
|
||||
ia64_frame_state *, void *,
|
||||
void **);
|
||||
extern void *__get_real_reg_value (ia64_reg_loc *);
|
||||
extern void *__get_personality (unwind_info_ptr *);
|
||||
extern void *__get_except_table (unwind_info_ptr *);
|
||||
extern void __set_real_reg_value (ia64_reg_loc *, void *);
|
||||
void *__calc_caller_bsp (long, unsigned char *);
|
||||
void __copy_saved_reg_state (ia64_frame_state *, ia64_frame_state *);
|
||||
#endif /* IA64_UNWIND_INFO */
|
||||
|
||||
|
|
167
gcc/libgcc2.c
167
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
|
||||
|
|
|
@ -292,6 +292,7 @@ extern void assemble_zeros PARAMS ((int));
|
|||
|
||||
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
|
||||
extern void assemble_align PARAMS ((int));
|
||||
extern void assemble_eh_align PARAMS ((int));
|
||||
|
||||
/* Assemble a string constant with the specified C string as contents. */
|
||||
extern void assemble_string PARAMS ((const char *, int));
|
||||
|
@ -306,6 +307,7 @@ extern void assemble_global PARAMS ((const char *));
|
|||
|
||||
/* Assemble a label named NAME. */
|
||||
extern void assemble_label PARAMS ((const char *));
|
||||
extern void assemble_eh_label PARAMS ((const char *));
|
||||
|
||||
/* Output to FILE a reference to the assembler name of a C-level name NAME.
|
||||
If NAME starts with a *, the rest of NAME is output verbatim.
|
||||
|
@ -321,6 +323,7 @@ extern void assemble_name PARAMS ((FILE *, const char *));
|
|||
Return 1 if we were able to output the constant, otherwise 0. If FORCE is
|
||||
non-zero, abort if we can't output the constant. */
|
||||
extern int assemble_integer PARAMS ((rtx, int, int));
|
||||
extern int assemble_eh_integer PARAMS ((rtx, int, int));
|
||||
|
||||
#ifdef EMUSHORT
|
||||
/* Assemble the floating-point constant D into an object of size MODE. */
|
||||
|
|
17
gcc/toplev.c
17
gcc/toplev.c
|
@ -2336,8 +2336,11 @@ compile_file (name)
|
|||
/* Now that all possible functions have been output, we can dump
|
||||
the exception table. */
|
||||
|
||||
#ifndef IA64_UNWIND_INFO
|
||||
output_exception_table ();
|
||||
|
||||
#endif
|
||||
free_exception_table ();
|
||||
|
||||
check_global_declarations (vec, len);
|
||||
|
||||
/* Clean up. */
|
||||
|
@ -4604,11 +4607,23 @@ main (argc, argv)
|
|||
{
|
||||
#ifdef DWARF2_UNWIND_INFO
|
||||
exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
|
||||
#else
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
exceptions_via_longjmp = ! IA64_UNWIND_INFO;
|
||||
#else
|
||||
exceptions_via_longjmp = 1;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Since each function gets its own handler data, we can't support the
|
||||
new model currently, since it depend on a specific rethrow label
|
||||
which is declared at the front of the table, and we can only
|
||||
have one such symbol in a file. */
|
||||
#ifdef IA64_UNWIND_INFO
|
||||
flag_new_exceptions = 0;
|
||||
#endif
|
||||
|
||||
/* Set up the align_*_log variables, defaulting them to 1 if they
|
||||
were still unset. */
|
||||
if (align_loops <= 0) align_loops = 1;
|
||||
|
|
71
gcc/varasm.c
71
gcc/varasm.c
|
@ -4836,3 +4836,74 @@ init_varasm_once ()
|
|||
mark_const_hash_entry);
|
||||
ggc_add_string_root (&in_named_name, 1);
|
||||
}
|
||||
|
||||
/* Extra support for EH values. */
|
||||
void
|
||||
assemble_eh_label (name)
|
||||
const char *name;
|
||||
{
|
||||
#ifdef ASM_OUTPUT_EH_LABEL
|
||||
ASM_OUTPUT_EH_LABEL (asm_out_file, name);
|
||||
#else
|
||||
assemble_label (name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
|
||||
|
||||
void
|
||||
assemble_eh_align (align)
|
||||
int align;
|
||||
{
|
||||
#ifdef ASM_OUTPUT_EH_ALIGN
|
||||
if (align > BITS_PER_UNIT)
|
||||
ASM_OUTPUT_EH_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
|
||||
#else
|
||||
assemble_align (align);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* On some platforms, we may want to specify a special mechansim to
|
||||
output EH data when generating with a function.. */
|
||||
int
|
||||
assemble_eh_integer (x, size, force)
|
||||
rtx x;
|
||||
int size;
|
||||
int force;
|
||||
{
|
||||
|
||||
switch (size)
|
||||
{
|
||||
#ifdef ASM_OUTPUT_EH_CHAR
|
||||
case 1:
|
||||
ASM_OUTPUT_EH_CHAR (asm_out_file, x);
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef ASM_OUTPUT_EH_SHORT
|
||||
case 2:
|
||||
ASM_OUTPUT_EH_SHORT (asm_out_file, x);
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef ASM_OUTPUT_EH_INT
|
||||
case 4:
|
||||
ASM_OUTPUT_EH_INT (asm_out_file, x);
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef ASM_OUTPUT_EH_DOUBLE_INT
|
||||
case 8:
|
||||
ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (assemble_integer (x, size, force));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue