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
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>
|
2000-05-24 Richard Henderson <rth@cygnus.com>
|
||||||
|
|
||||||
* recog.c (offsettable_address_p): If mode size is zero, assume
|
* 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.
|
# Additional target-dependent options for compiling libgcc2.a.
|
||||||
TARGET_LIBGCC2_CFLAGS =
|
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 target (must also be overridable for a target)
|
||||||
LIBGCC1_TEST = libgcc1-test
|
LIBGCC1_TEST = libgcc1-test
|
||||||
|
|
||||||
|
@ -951,7 +954,7 @@ libgcc2.ready: $(GCC_PASSES) stmp-int-hdrs $(STMP_FIXPROTO)
|
||||||
touch libgcc2.ready; \
|
touch libgcc2.ready; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LIB2ADD = $(srcdir)/frame.c $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
|
LIB2ADD = $(LIB2ADDEH) $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
|
||||||
|
|
||||||
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
|
||||||
objext='$(objext)' \
|
objext='$(objext)' \
|
||||||
|
|
|
@ -61,10 +61,10 @@ __dso_handle:
|
||||||
/* ??? How can we rationally keep this size correct? */
|
/* ??? How can we rationally keep this size correct? */
|
||||||
.section .bss
|
.section .bss
|
||||||
.type frame_object#,@object
|
.type frame_object#,@object
|
||||||
.size frame_object#,56
|
.size frame_object#,64
|
||||||
.align 8
|
.align 8
|
||||||
frame_object:
|
frame_object:
|
||||||
.zero 56
|
.zero 64
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
|
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
|
||||||
|
@ -296,3 +296,38 @@ __do_frame_setup:
|
||||||
#endif
|
#endif
|
||||||
.weak __deregister_frame_info#
|
.weak __deregister_frame_info#
|
||||||
.weak __register_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#
|
.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
|
||||||
|
;;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2606,6 +2606,8 @@ rtx_needs_barrier (x, flags, pred)
|
||||||
break;
|
break;
|
||||||
case 20: /* mov = ar.bsp */
|
case 20: /* mov = ar.bsp */
|
||||||
break;
|
break;
|
||||||
|
case 21: /* flushrs */
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
|
@ -3329,6 +3331,12 @@ ia64_init_builtins ()
|
||||||
|
|
||||||
def_builtin ("__sync_lock_release_di", void_ftype_pdi, IA64_BUILTIN_LOCK_RELEASE_DI);
|
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. */
|
/* Add all builtins that are operations on two args. */
|
||||||
for (i=0, d = bdesc_2argsi; i < sizeof(bdesc_2argsi) / sizeof *d; i++, d++)
|
for (i=0, d = bdesc_2argsi; i < sizeof(bdesc_2argsi) / sizeof *d; i++, d++)
|
||||||
def_builtin (d->name, si_ftype_psi_si, d->code);
|
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)));
|
emit_insn (gen_movdi (op0, GEN_INT(0)));
|
||||||
return 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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2893,7 +2893,10 @@ enum ia64_builtins
|
||||||
|
|
||||||
IA64_BUILTIN_LOCK_TEST_AND_SET_DI,
|
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. */
|
/* Codes for expand_compare_and_swap and expand_swap_and_compare. */
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
|
|
||||||
;; ??? Add function unit scheduling info for Itanium (TM) processor.
|
;; ??? 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 usage:
|
||||||
;;
|
;;
|
||||||
;; unspec:
|
;; unspec:
|
||||||
|
@ -66,6 +70,7 @@
|
||||||
;; 18 fetch_and_op
|
;; 18 fetch_and_op
|
||||||
;; 19 fetchadd_acq
|
;; 19 fetchadd_acq
|
||||||
;; 20 bsp_value
|
;; 20 bsp_value
|
||||||
|
;; 21 flushrs
|
||||||
;;
|
;;
|
||||||
;; unspec_volatile:
|
;; unspec_volatile:
|
||||||
;; 0 alloc
|
;; 0 alloc
|
||||||
|
@ -3243,6 +3248,12 @@
|
||||||
mov ar.rsc=r19\;"
|
mov ar.rsc=r19\;"
|
||||||
[(set_attr "type" "unknown")
|
[(set_attr "type" "unknown")
|
||||||
(set_attr "predicable" "no")])
|
(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
|
$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
|
||||||
|
|
||||||
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
|
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
|
||||||
|
LIB2ADDEH = $(srcdir)/config/ia64/frame-ia64.c
|
||||||
|
|
||||||
|
|
119
gcc/except.c
119
gcc/except.c
|
@ -698,6 +698,7 @@ struct func_eh_entry
|
||||||
int range_number; /* EH region number from EH NOTE insn's. */
|
int range_number; /* EH region number from EH NOTE insn's. */
|
||||||
rtx rethrow_label; /* Label for rethrow. */
|
rtx rethrow_label; /* Label for rethrow. */
|
||||||
int rethrow_ref; /* Is rethrow_label referenced? */
|
int rethrow_ref; /* Is rethrow_label referenced? */
|
||||||
|
int emitted; /* 1 if this entry has been emitted in assembly file. */
|
||||||
struct handler_info *handlers;
|
struct handler_info *handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -739,6 +740,7 @@ new_eh_region_entry (note_eh_region, rethrow)
|
||||||
else
|
else
|
||||||
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
|
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].handlers = NULL;
|
||||||
|
function_eh_regions[current_func_eh_entry].emitted = 0;
|
||||||
|
|
||||||
return current_func_eh_entry++;
|
return current_func_eh_entry++;
|
||||||
}
|
}
|
||||||
|
@ -2221,40 +2223,44 @@ output_exception_table_entry (file, n)
|
||||||
else
|
else
|
||||||
rethrow = NULL_RTX;
|
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)
|
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
|
||||||
{
|
{
|
||||||
/* rethrow label should indicate the LAST entry for a region */
|
/* rethrow label should indicate the LAST entry for a region */
|
||||||
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
|
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
|
||||||
{
|
{
|
||||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
|
||||||
assemble_label(buf);
|
assemble_eh_label(buf);
|
||||||
rethrow = NULL_RTX;
|
rethrow = NULL_RTX;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
|
||||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
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);
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
|
||||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
|
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
|
||||||
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
|
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 (flag_new_exceptions)
|
||||||
{
|
{
|
||||||
if (handler == NULL || handler->type_info == NULL)
|
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
|
else
|
||||||
if (handler->type_info == CATCH_ALL_TYPE)
|
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);
|
POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||||
else
|
else
|
||||||
output_constant ((tree)(handler->type_info),
|
output_constant ((tree)(handler->type_info),
|
||||||
|
@ -2288,11 +2294,50 @@ set_exception_version_code (code)
|
||||||
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
|
void
|
||||||
output_exception_table ()
|
output_exception_table ()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
extern FILE *asm_out_file;
|
extern FILE *asm_out_file;
|
||||||
|
|
||||||
|
@ -2302,47 +2347,47 @@ output_exception_table ()
|
||||||
exception_section ();
|
exception_section ();
|
||||||
|
|
||||||
/* Beginning marker for table. */
|
/* Beginning marker for table. */
|
||||||
assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
|
assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
|
||||||
assemble_label ("__EXCEPTION_TABLE__");
|
assemble_eh_label ("__EXCEPTION_TABLE__");
|
||||||
|
|
||||||
if (flag_new_exceptions)
|
output_exception_table_data ();
|
||||||
{
|
|
||||||
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 ();
|
|
||||||
|
|
||||||
/* Ending marker for table. */
|
/* Ending marker for table. */
|
||||||
/* Generate the label for end of table. */
|
/* Generate the label for end of table. */
|
||||||
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
|
||||||
assemble_label(buf);
|
assemble_eh_label(buf);
|
||||||
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
|
||||||
|
|
||||||
/* For binary compatibility, the old __throw checked the second
|
/* For binary compatibility, the old __throw checked the second
|
||||||
position for a -1, so we should output at least 2 -1's */
|
position for a -1, so we should output at least 2 -1's */
|
||||||
if (! flag_new_exceptions)
|
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 */
|
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.
|
/* Emit code to get EH context.
|
||||||
|
|
||||||
|
|
|
@ -355,6 +355,15 @@ extern int exception_table_p PARAMS ((void));
|
||||||
|
|
||||||
extern void output_exception_table 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
|
/* Given a return address in ADDR, determine the address we should use
|
||||||
to find the corresponding EH region. */
|
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 # */
|
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
|
/* If FUNCTION_EPILOGUE is not defined, then the function body
|
||||||
itself contains return instructions wherever needed. */
|
itself contains return instructions wherever needed. */
|
||||||
}
|
}
|
||||||
|
@ -2968,6 +2972,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
|
||||||
if (prescan > 0)
|
if (prescan > 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef IA64_UNWIND_INFO
|
||||||
|
IA64_UNWIND_EMIT (asm_out_file, insn);
|
||||||
|
#endif
|
||||||
/* Output assembler code from the template. */
|
/* Output assembler code from the template. */
|
||||||
|
|
||||||
output_asm_insn (template, recog_data.operand);
|
output_asm_insn (template, recog_data.operand);
|
||||||
|
|
|
@ -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,
|
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||||
Boston, MA 02111-1307, USA. */
|
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.
|
/* Sorting an array of FDEs by address.
|
||||||
(Ideally we would have the linker sort the FDEs so we don't have to do
|
(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.) */
|
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;
|
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. */
|
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -917,51 +336,3 @@ __deregister_frame (void *begin)
|
||||||
free (__deregister_frame_info (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! */
|
keep the copies synchronized! */
|
||||||
|
|
||||||
struct object {
|
struct object {
|
||||||
|
#ifdef IA64_UNWIND_INFO
|
||||||
|
void *pc_base; /* This field will be set by find_fde. */
|
||||||
|
#endif
|
||||||
void *pc_begin;
|
void *pc_begin;
|
||||||
void *pc_end;
|
void *pc_end;
|
||||||
struct dwarf_fde *fde_begin;
|
struct dwarf_fde *fde_begin;
|
||||||
|
#ifdef IA64_UNWIND_INFO
|
||||||
|
struct dwarf_fde *fde_end;
|
||||||
|
#endif
|
||||||
struct dwarf_fde **fde_array;
|
struct dwarf_fde **fde_array;
|
||||||
size_t count;
|
size_t count;
|
||||||
struct object *next;
|
struct object *next;
|
||||||
|
@ -87,3 +93,184 @@ extern void *__deregister_frame_info (void *);
|
||||||
Returns NULL on failure, otherwise returns STATE_IN. */
|
Returns NULL on failure, otherwise returns STATE_IN. */
|
||||||
|
|
||||||
extern struct frame_state *__frame_state_for (void *, struct frame_state *);
|
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 */
|
#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 */
|
#endif /* L_eh */
|
||||||
|
|
||||||
#ifdef L_pure
|
#ifdef L_pure
|
||||||
|
|
|
@ -292,6 +292,7 @@ extern void assemble_zeros PARAMS ((int));
|
||||||
|
|
||||||
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
|
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
|
||||||
extern void assemble_align PARAMS ((int));
|
extern void assemble_align PARAMS ((int));
|
||||||
|
extern void assemble_eh_align PARAMS ((int));
|
||||||
|
|
||||||
/* Assemble a string constant with the specified C string as contents. */
|
/* Assemble a string constant with the specified C string as contents. */
|
||||||
extern void assemble_string PARAMS ((const char *, int));
|
extern void assemble_string PARAMS ((const char *, int));
|
||||||
|
@ -306,6 +307,7 @@ extern void assemble_global PARAMS ((const char *));
|
||||||
|
|
||||||
/* Assemble a label named NAME. */
|
/* Assemble a label named NAME. */
|
||||||
extern void assemble_label PARAMS ((const char *));
|
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.
|
/* 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.
|
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
|
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. */
|
non-zero, abort if we can't output the constant. */
|
||||||
extern int assemble_integer PARAMS ((rtx, int, int));
|
extern int assemble_integer PARAMS ((rtx, int, int));
|
||||||
|
extern int assemble_eh_integer PARAMS ((rtx, int, int));
|
||||||
|
|
||||||
#ifdef EMUSHORT
|
#ifdef EMUSHORT
|
||||||
/* Assemble the floating-point constant D into an object of size MODE. */
|
/* Assemble the floating-point constant D into an object of size MODE. */
|
||||||
|
|
15
gcc/toplev.c
15
gcc/toplev.c
|
@ -2336,7 +2336,10 @@ compile_file (name)
|
||||||
/* Now that all possible functions have been output, we can dump
|
/* Now that all possible functions have been output, we can dump
|
||||||
the exception table. */
|
the exception table. */
|
||||||
|
|
||||||
|
#ifndef IA64_UNWIND_INFO
|
||||||
output_exception_table ();
|
output_exception_table ();
|
||||||
|
#endif
|
||||||
|
free_exception_table ();
|
||||||
|
|
||||||
check_global_declarations (vec, len);
|
check_global_declarations (vec, len);
|
||||||
|
|
||||||
|
@ -4604,11 +4607,23 @@ main (argc, argv)
|
||||||
{
|
{
|
||||||
#ifdef DWARF2_UNWIND_INFO
|
#ifdef DWARF2_UNWIND_INFO
|
||||||
exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
|
exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
|
||||||
|
#else
|
||||||
|
#ifdef IA64_UNWIND_INFO
|
||||||
|
exceptions_via_longjmp = ! IA64_UNWIND_INFO;
|
||||||
#else
|
#else
|
||||||
exceptions_via_longjmp = 1;
|
exceptions_via_longjmp = 1;
|
||||||
|
#endif
|
||||||
#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
|
/* Set up the align_*_log variables, defaulting them to 1 if they
|
||||||
were still unset. */
|
were still unset. */
|
||||||
if (align_loops <= 0) align_loops = 1;
|
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);
|
mark_const_hash_entry);
|
||||||
ggc_add_string_root (&in_named_name, 1);
|
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…
Reference in New Issue