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:
Andrew MacLeod 2000-05-25 15:21:51 +00:00 committed by Andrew Haley
parent c66265e483
commit ce152ef836
19 changed files with 3031 additions and 672 deletions

View File

@ -1,3 +1,119 @@
2000-05-25 Andrew MacLeod <amacleod@cygnus.com>
Andrew Haley <aph@cygnus.com>
* except.c (func_eh_entry): Add emitted field.
(new_eh_region_entry): Set emitted field to 0;
(output_exception_table_entry): Only emit previously un-emitted data,
and send it to the eh_data section.
(output_exception_table): Break out common parts. Output
exception table for entire compilation unit to eh_data section.
(output_exception_table_data): Common parts of output_exception_table.
Send output to eh_data section.
(output_function_exception_table): Output exception table data for
a single function to eh_data section.
(free_exception_table): New external to free the table.
* except.h (free_exception_table): Add prototype.
(output_function_exception_table): Add prototype.
* final.c (final_end_function): Output function exception table
for IA64_UNWIND_INFO.
(final_scan_insn): Emit any unwind directives for an insn.
* frame-dwarf2.c: New file containing all DWARF 2 specific code
from frame.c.
* frame.c: Remove all DWARF 2 specific code.
* config/ia64/frame-ia64.c: New file.
(gthread_stuff): Make all gthread available with
IA64_UNWIND_INFO.
(dwarf_fde): Define an IA64 struct for dwarf_fde.
(__register_frame_info, __register_frame): Move to common area of file.
(__register_frame_info_table, __register_frame_table): Move to common i
area.
(__deregister_frame_info, __deregister_frame): Move to common area.
(__frame_init, find_fde): New versions for IA64_UNWIND_INFO.
(read_uleb128): New version for ia64.
(get_unwind_record): Read the next IA-64 unwind record.
(read_R_record): Read a region header record.
(process_a_b_reg_code): X record helper.
(read_X_record): Read an X format record.
(read_B_record): Read a B format record.
(P3_record_types): List of record types matching the P3 format.
(P7_record_types): List of record types matching the P7 format.
(P8_record_types): List of record types matching the P8 format.
(read_P_record): Read a P format record.
(init_ia64_reg_loc): Set default fields for a register.
(init_ia64_unwind_frame): Set defaults for all register records.
(execute_one_ia64_descriptor): Execute one descriptor record.
(rse_address_add): Calculate the position of a local reg in memory.
(normalize_reg_loc): Turn a location descriptor into a memory address.
(maybe_normalize_reg_loc): Only normalize a descriptor if it falls
within a specified PC offset range.
(get_real_reg_value): Given a register location, retrieve its value.
(set_real_reg_value): Change the value of a register location.
(copy_reg_value): Copy reg values, if needed.
(copy_saved_reg_state): Copy all registers that need to be copied.
(process_state_between): Normalize all frame register records that
fall within the specified PC range.
(frame_translate): Take a processed frame description, and turn
everything into addresses.
(build_ia64_frame_state ): Find and create frame state record for a PC.
(get_personality): Get the personality routine for a given frame.
(get_except_table): Get the exception table for a given frame.
(record_name): Unwind record names for debugging.
(print_record): Print and unwind record.
(print_all_records): Print an entire unwind image.
(__ia64_backtrace): Print a backtrace.
(ia64_backtrace_helper): New function.
(__register_frame_info_aux): New function.
* config/ia64/crtend.asm (__do_frame_setup_aux): New function.
* frame.h (enum unw_record_type): New unwind record types.
(struct unw_p_record, unw_b_record, unw_x_record) : New unwind records.
(struct unw_r_record, unwind_record): New unwind record structs.
(struct unwind_info_ptr): Unwind information layout.
(IA64_UNW_LOC_TYPE_*): Macros for different types for location
descriptors.
(struct ia64_reg_loc): Register location description.
(struct ia64_frame_state): Location of all registers in a frame.
(struct object): Add pc_base and fde_end for IA64_UNWIND_INFO.
* libgcc2.c (__ia64_personality_v1): Personality routine.
(__calc_caller_bsp): Calculate the bsp register for the caller's
frame.
(ia64_throw_helper): Figure out who to return to and set up the
registers.
(__throw): Throw routine.
* output.h (assemble_eh_align, assemble_eh_label): New functions
to generate EH info where we want it.
(assemble_eh_integer): New function.
* toplev.c (compile_file): Output module level exception table for
non-ia64 targets.
(main): Set exceptions_via_longjump and flag_new_exceptions based
on IA64_UNWIND_INFO too.
* varasm.c (assemble_eh_label): Generate a label via
ASM_OUTPUT_EH_LABEL if it has been specified.
(assemble_eh_align): Generate an alignment directive via
ASM_OUTPUT_EH_ALIGN if it has been specified.
(assemble_eh_label): Generate an integer value via
ASM_OUTPUT_EH_type if they have been specified.
* config/ia64/ia64.c (rtx_needs_barrier): Add flushrs.
(ia64_init_builtins): Add __builtin_ia64_bsp
and __builtin_ia64_flushrs.
(ia64_expand_builtin): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.h (ia64_builtins): Add IA64_BUILTIN_BSP and
IA64_BUILTIN_FLUSHRS.
* config/ia64/ia64.md (flushrs): New insn to flush the register
stack. Add to unspec list.
* config/ia64/crtbegin.asm (frame_object): Change size.
(__do_frame_setup_aux): New function.
* config/ia64/crtend.asm: call __do_frame_setup_aux.
* config/ia64/t-ia64 (LIB2ADDEH): Add.
* Makefile.in (LIB2ADDEH): Add.
(LIB2ADD): Use LIB2ADDEH.
2000-05-24 Richard Henderson <rth@cygnus.com>
* recog.c (offsettable_address_p): If mode size is zero, assume

View File

@ -367,6 +367,9 @@ LIBGCC2_INCLUDES =
# Additional target-dependent options for compiling libgcc2.a.
TARGET_LIBGCC2_CFLAGS =
# Addition sources to handle exceptions; overridden by some targets.
LIB2ADDEH = $(srcdir)/frame-dwarf2.c
# libgcc1-test target (must also be overridable for a target)
LIBGCC1_TEST = libgcc1-test
@ -951,7 +954,7 @@ libgcc2.ready: $(GCC_PASSES) stmp-int-hdrs $(STMP_FIXPROTO)
touch libgcc2.ready; \
fi
LIB2ADD = $(srcdir)/frame.c $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
LIB2ADD = $(LIB2ADDEH) $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) xgcc$(exeext)
objext='$(objext)' \

View File

@ -61,10 +61,10 @@ __dso_handle:
/* ??? How can we rationally keep this size correct? */
.section .bss
.type frame_object#,@object
.size frame_object#,56
.size frame_object#,64
.align 8
frame_object:
.zero 56
.zero 64
/*
* Fragment of the ELF _fini routine that invokes our dtor cleanup.
@ -296,3 +296,38 @@ __do_frame_setup:
#endif
.weak __deregister_frame_info#
.weak __register_frame_info#
.text
.align 16
.global __do_frame_setup_aux#
.proc __do_frame_setup_aux#
__do_frame_setup_aux:
/*
if (__register_frame_info_aux)
__register_frame_info_aux(__EH_FRAME_END__)
*/
alloc loc0 = ar.pfs, 0, 3, 1, 0
addl r14 = @ltoff(@fptr(__register_frame_info_aux#)), gp
mov loc1 = b0
;;
// r16 contains the address of a pointer to __EH_FRAME_END__.
ld8 out0 = [r16]
ld8 r15 = [r14]
mov loc2 = gp
;;
cmp.eq p6, p7 = 0, r15
(p6) br.cond.dptk 1f
ld8 r8 = [r15], 8
;;
ld8 gp = [r15]
mov b6 = r8
;;
br.call.sptk.many b0 = b6
;;
1:
mov gp = loc2
mov ar.pfs = loc0
mov b0 = loc1
br.ret.sptk.many b0
.endp __do_frame_setup#
.weak __register_frame_info_aux#

View File

@ -110,3 +110,25 @@ __do_global_ctors_aux:
;;
}
.endp __do_global_ctors_aux#
.section .init,"ax","progbits"
{ .mlx
// __do_frame_setup_aux is in crtbegin.asm
movl r2 = @gprel(__do_frame_setup_aux#)
;;
}
{ .mii
nop.m 0
add r2 = r2, gp
;;
mov b6 = r2
}
{ .mib
// __do_frame_setup_aux needs the address of __EH_FRAME_END__,
// so we pass it in r16. This is rather evil, but we have no
// output registers.
addl r16 = @ltoff(__EH_FRAME_END__#), gp
br.call.sptk.many b0 = b6
;;
}

1608
gcc/config/ia64/frame-ia64.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2606,6 +2606,8 @@ rtx_needs_barrier (x, flags, pred)
break;
case 20: /* mov = ar.bsp */
break;
case 21: /* flushrs */
break;
default:
abort ();
@ -3329,6 +3331,12 @@ ia64_init_builtins ()
def_builtin ("__sync_lock_release_di", void_ftype_pdi, IA64_BUILTIN_LOCK_RELEASE_DI);
def_builtin ("__builtin_ia64_bsp", build_function_type (ptr_type_node, endlink), IA64_BUILTIN_BSP);
def_builtin ("__builtin_ia64_flushrs",
build_function_type (void_type_node, endlink),
IA64_BUILTIN_FLUSHRS);
/* Add all builtins that are operations on two args. */
for (i=0, d = bdesc_2argsi; i < sizeof(bdesc_2argsi) / sizeof *d; i++, d++)
def_builtin (d->name, si_ftype_psi_si, d->code);
@ -3743,6 +3751,19 @@ ia64_expand_builtin (exp, target, subtarget, mode, ignore)
emit_insn (gen_movdi (op0, GEN_INT(0)));
return 0;
case IA64_BUILTIN_BSP:
{
rtx reg = gen_reg_rtx (DImode);
emit_insn (gen_bsp_value (reg));
return reg;
}
case IA64_BUILTIN_FLUSHRS:
{
emit_insn (gen_flushrs ());
return 0;
}
default:
break;
}

View File

@ -2893,7 +2893,10 @@ enum ia64_builtins
IA64_BUILTIN_LOCK_TEST_AND_SET_DI,
IA64_BUILTIN_LOCK_RELEASE_DI
IA64_BUILTIN_LOCK_RELEASE_DI,
IA64_BUILTIN_BSP,
IA64_BUILTIN_FLUSHRS
};
/* Codes for expand_compare_and_swap and expand_swap_and_compare. */

View File

@ -48,6 +48,10 @@
;; ??? Add function unit scheduling info for Itanium (TM) processor.
;; ??? The explicit stop in the flushrs pattern is not ideal. It
;; would be better if rtx_needs_barrier took care of this, but this is
;; something that can be fixed later.
;; Unspec usage:
;;
;; unspec:
@ -66,6 +70,7 @@
;; 18 fetch_and_op
;; 19 fetchadd_acq
;; 20 bsp_value
;; 21 flushrs
;;
;; unspec_volatile:
;; 0 alloc
@ -3243,6 +3248,12 @@
mov ar.rsc=r19\;"
[(set_attr "type" "unknown")
(set_attr "predicable" "no")])
(define_insn "flushrs"
[(unspec [(const_int 0)] 21)]
""
";; \; flushrs"
[(set_attr "type" "M")])
;; ::::::::::::::::::::
;; ::

View File

@ -39,3 +39,5 @@ crtendS.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
LIB2ADDEH = $(srcdir)/config/ia64/frame-ia64.c

View File

@ -698,6 +698,7 @@ struct func_eh_entry
int range_number; /* EH region number from EH NOTE insn's. */
rtx rethrow_label; /* Label for rethrow. */
int rethrow_ref; /* Is rethrow_label referenced? */
int emitted; /* 1 if this entry has been emitted in assembly file. */
struct handler_info *handlers;
};
@ -739,7 +740,8 @@ new_eh_region_entry (note_eh_region, rethrow)
else
function_eh_regions[current_func_eh_entry].rethrow_label = rethrow;
function_eh_regions[current_func_eh_entry].handlers = NULL;
function_eh_regions[current_func_eh_entry].emitted = 0;
return current_func_eh_entry++;
}
@ -2221,40 +2223,44 @@ output_exception_table_entry (file, n)
else
rethrow = NULL_RTX;
if (function_eh_regions[index].emitted)
return;
function_eh_regions[index].emitted = 1;
for ( ; handler != NULL || rethrow != NULL_RTX; handler = handler->next)
{
/* rethrow label should indicate the LAST entry for a region */
if (rethrow != NULL_RTX && (handler == NULL || handler->next == NULL))
{
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", n);
assemble_label(buf);
assemble_eh_label(buf);
rethrow = NULL_RTX;
}
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
if (handler == NULL)
assemble_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (GEN_INT (0), POINTER_SIZE / BITS_PER_UNIT, 1);
else
{
ASM_GENERATE_INTERNAL_LABEL (buf, "L", handler->handler_number);
sym = gen_rtx_SYMBOL_REF (Pmode, buf);
assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
}
if (flag_new_exceptions)
{
if (handler == NULL || handler->type_info == NULL)
assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
else
if (handler->type_info == CATCH_ALL_TYPE)
assemble_integer (GEN_INT (CATCH_ALL_TYPE),
assemble_eh_integer (GEN_INT (CATCH_ALL_TYPE),
POINTER_SIZE / BITS_PER_UNIT, 1);
else
output_constant ((tree)(handler->type_info),
@ -2288,11 +2294,50 @@ set_exception_version_code (code)
version_code = code;
}
/* Free the EH table structures. */
void
free_exception_table ()
{
free (eh_table);
clear_function_eh_region ();
}
/* Output the common content of an exception table. */
void
output_exception_table_data ()
{
int i;
char buf[256];
extern FILE *asm_out_file;
if (flag_new_exceptions)
{
assemble_eh_integer (GEN_INT (NEW_EH_RUNTIME),
POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (GEN_INT (language_code), 2 , 1);
assemble_eh_integer (GEN_INT (version_code), 2 , 1);
/* Add enough padding to make sure table aligns on a pointer boundry. */
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
;
if (i != 0)
assemble_eh_integer (const0_rtx, i , 1);
/* Generate the label for offset calculations on rethrows. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
assemble_eh_label(buf);
}
for (i = 0; i < eh_table_size; ++i)
output_exception_table_entry (asm_out_file, eh_table[i]);
}
/* Output an exception table for the entire compilation unit. */
void
output_exception_table ()
{
int i;
char buf[256];
extern FILE *asm_out_file;
@ -2302,47 +2347,47 @@ output_exception_table ()
exception_section ();
/* Beginning marker for table. */
assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
assemble_label ("__EXCEPTION_TABLE__");
assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
assemble_eh_label ("__EXCEPTION_TABLE__");
if (flag_new_exceptions)
{
assemble_integer (GEN_INT (NEW_EH_RUNTIME),
POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_integer (GEN_INT (language_code), 2 , 1);
assemble_integer (GEN_INT (version_code), 2 , 1);
/* Add enough padding to make sure table aligns on a pointer boundry. */
i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
;
if (i != 0)
assemble_integer (const0_rtx, i , 1);
/* Generate the label for offset calculations on rethrows. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", 0);
assemble_label(buf);
}
for (i = 0; i < eh_table_size; ++i)
output_exception_table_entry (asm_out_file, eh_table[i]);
free (eh_table);
clear_function_eh_region ();
output_exception_table_data ();
/* Ending marker for table. */
/* Generate the label for end of table. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LRTH", CODE_LABEL_NUMBER (final_rethrow));
assemble_label(buf);
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_label(buf);
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
/* For binary compatibility, the old __throw checked the second
position for a -1, so we should output at least 2 -1's */
if (! flag_new_exceptions)
assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
putc ('\n', asm_out_file); /* blank line */
}
/* Used by the ia64 unwind format to output data for an individual
function. */
void
output_function_exception_table ()
{
extern FILE *asm_out_file;
if (! doing_eh (0) || ! eh_table)
return;
#ifdef HANDLER_SECTION
HANDLER_SECTION;
#endif
output_exception_table_data ();
/* Ending marker for table. */
assemble_eh_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
putc ('\n', asm_out_file); /* blank line */
}
/* Emit code to get EH context.

View File

@ -355,6 +355,15 @@ extern int exception_table_p PARAMS ((void));
extern void output_exception_table PARAMS ((void));
/* Free the exception table. */
extern void free_exception_table PARAMS((void));
/* Used by the ia64 unwind format to output data for an individual
function. */
extern void output_function_exception_table PARAMS((void));
/* Given a return address in ADDR, determine the address we should use
to find the corresponding EH region. */

View File

@ -1827,6 +1827,10 @@ final_end_function (first, file, optimize)
bb_func_label_num = -1; /* not in function, nuke label # */
#ifdef IA64_UNWIND_INFO
output_function_exception_table ();
#endif
/* If FUNCTION_EPILOGUE is not defined, then the function body
itself contains return instructions wherever needed. */
}
@ -2968,6 +2972,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (prescan > 0)
break;
#ifdef IA64_UNWIND_INFO
IA64_UNWIND_EMIT (asm_out_file, insn);
#endif
/* Output assembler code from the template. */
output_asm_insn (template, recog_data.operand);

663
gcc/frame-dwarf2.c Normal file
View File

@ -0,0 +1,663 @@
/* Subroutines needed for unwinding DWARF 2 format stack frame info
for exception handling. */
/* Compile this one with gcc. */
/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
Contributed by Jason Merrill <jason@cygnus.com>.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combine
executable.)
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* It is incorrect to include config.h here, because this file is being
compiled for the target, and hence definitions concerning only the host
do not apply. */
#include "tconfig.h"
#include "tsystem.h"
#include "defaults.h"
#ifdef DWARF2_UNWIND_INFO
#include "dwarf2.h"
#include "frame.h"
#include "gthr.h"
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
#else
static __gthread_mutex_t object_mutex;
#endif
/* Don't use `fancy_abort' here even if config.h says to use it. */
#ifdef abort
#undef abort
#endif
/* Some types used by the DWARF 2 spec. */
typedef int sword __attribute__ ((mode (SI)));
typedef unsigned int uword __attribute__ ((mode (SI)));
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
typedef int saddr __attribute__ ((mode (pointer)));
typedef unsigned char ubyte;
/* Terminology:
CIE - Common Information Element
FDE - Frame Descriptor Element
There is one per function, and it describes where the function code
is located, and what the register lifetimes and stack layout are
within the function.
The data structures are defined in the DWARF specfication, although
not in a very readable way (see LITERATURE).
Every time an exception is thrown, the code needs to locate the FDE
for the current function, and starts to look for exception regions
from that FDE. This works in a two-level search:
a) in a linear search, find the shared image (i.e. DLL) containing
the PC
b) using the FDE table for that shared object, locate the FDE using
binary search (which requires the sorting). */
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
to distinguish it from a valid FDE. FDEs are aligned to an addressing
unit boundary, but the fields within are unaligned. */
struct dwarf_cie {
uword length;
sword CIE_id;
ubyte version;
char augmentation[0];
} __attribute__ ((packed, aligned (__alignof__ (void *))));
/* The first few fields of an FDE. */
struct dwarf_fde {
uword length;
sword CIE_delta;
void* pc_begin;
uaddr pc_range;
} __attribute__ ((packed, aligned (__alignof__ (void *))));
typedef struct dwarf_fde fde;
/* Objects to be searched for frame unwind info. */
static struct object *objects;
/* The information we care about from a CIE. */
struct cie_info {
char *augmentation;
void *eh_ptr;
int code_align;
int data_align;
unsigned ra_regno;
};
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
struct frame_state_internal
{
struct frame_state s;
struct frame_state_internal *saved_state;
};
/* This is undefined below if we need it to be an actual function. */
#define init_object_mutex_once()
#if __GTHREADS
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
/* Helper for init_object_mutex_once. */
static void
init_object_mutex (void)
{
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
}
/* Call this to arrange to initialize the object mutex. */
#undef init_object_mutex_once
static void
init_object_mutex_once (void)
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, init_object_mutex);
}
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
#endif /* __GTHREADS */
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static void *
decode_uleb128 (unsigned char *buf, unsigned *r)
{
unsigned shift = 0;
unsigned result = 0;
while (1)
{
unsigned byte = *buf++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*r = result;
return buf;
}
/* Decode the signed LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static void *
decode_sleb128 (unsigned char *buf, int *r)
{
unsigned shift = 0;
unsigned result = 0;
unsigned byte;
while (1)
{
byte = *buf++;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
}
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= - (1 << shift);
*r = result;
return buf;
}
/* Read unaligned data from the instruction buffer. */
union unaligned {
void *p;
unsigned b2 __attribute__ ((mode (HI)));
unsigned b4 __attribute__ ((mode (SI)));
unsigned b8 __attribute__ ((mode (DI)));
} __attribute__ ((packed));
static inline void *
read_pointer (void *p)
{ union unaligned *up = p; return up->p; }
static inline unsigned
read_1byte (void *p)
{ return *(unsigned char *)p; }
static inline unsigned
read_2byte (void *p)
{ union unaligned *up = p; return up->b2; }
static inline unsigned
read_4byte (void *p)
{ union unaligned *up = p; return up->b4; }
static inline unsigned long
read_8byte (void *p)
{ union unaligned *up = p; return up->b8; }
/* Ordering function for FDEs. Functions can't overlap, so we just compare
their starting addresses. */
static inline saddr
fde_compare (fde *x, fde *y)
{
return (saddr)x->pc_begin - (saddr)y->pc_begin;
}
/* Return the address of the FDE after P. */
static inline fde *
next_fde (fde *p)
{
return (fde *)(((char *)p) + p->length + sizeof (p->length));
}
#include "frame.c"
static size_t
count_fdes (fde *this_fde)
{
size_t count;
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
++count;
}
return count;
}
static void
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
{
void *pc_begin = *beg_ptr;
void *pc_end = *end_ptr;
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
fde_insert (accu, this_fde);
if (this_fde->pc_begin < pc_begin)
pc_begin = this_fde->pc_begin;
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
pc_end = this_fde->pc_begin + this_fde->pc_range;
}
*beg_ptr = pc_begin;
*end_ptr = pc_end;
}
/* search this fde table for the one containing the pc */
static fde *
search_fdes (fde *this_fde, void *pc)
{
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
return this_fde;
}
return NULL;
}
/* Set up a sorted array of pointers to FDEs for a loaded object. We
count up the entries before allocating the array because it's likely to
be faster. We can be called multiple times, should we have failed to
allocate a sorted fde array on a previous occasion. */
static void
frame_init (struct object* ob)
{
size_t count;
fde_accumulator accu;
void *pc_begin, *pc_end;
fde **array;
if (ob->pc_begin)
count = ob->count;
else if (ob->fde_array)
{
fde **p = ob->fde_array;
for (count = 0; *p; ++p)
count += count_fdes (*p);
}
else
count = count_fdes (ob->fde_begin);
ob->count = count;
if (!start_fde_sort (&accu, count) && ob->pc_begin)
return;
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (; *p; ++p)
add_fdes (*p, &accu, &pc_begin, &pc_end);
}
else
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
array = end_fde_sort (&accu, count);
if (array)
ob->fde_array = array;
ob->pc_begin = pc_begin;
ob->pc_end = pc_end;
}
/* Return a pointer to the FDE for the function containing PC. */
static fde *
find_fde (void *pc)
{
struct object *ob;
size_t lo, hi;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
/* Linear search through the objects, to find the one containing the pc. */
for (ob = objects; ob; ob = ob->next)
{
if (ob->pc_begin == 0)
frame_init (ob);
if (pc >= ob->pc_begin && pc < ob->pc_end)
break;
}
if (ob == 0)
{
__gthread_mutex_unlock (&object_mutex);
return 0;
}
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
frame_init (ob);
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
{
__gthread_mutex_unlock (&object_mutex);
/* Standard binary search algorithm. */
for (lo = 0, hi = ob->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = ob->fde_array[i];
if (pc < f->pc_begin)
hi = i;
else if (pc >= f->pc_begin + f->pc_range)
lo = i + 1;
else
return f;
}
}
else
{
/* Long slow labourious linear search, cos we've no memory. */
fde *f;
if (ob->fde_array)
{
fde **p = ob->fde_array;
do
{
f = search_fdes (*p, pc);
if (f)
break;
p++;
}
while (*p);
}
else
f = search_fdes (ob->fde_begin, pc);
__gthread_mutex_unlock (&object_mutex);
return f;
}
return 0;
}
static inline struct dwarf_cie *
get_cie (fde *f)
{
return ((void *)&f->CIE_delta) - f->CIE_delta;
}
/* Extract any interesting information from the CIE for the translation
unit F belongs to. */
static void *
extract_cie_info (fde *f, struct cie_info *c)
{
void *p;
int i;
c->augmentation = get_cie (f)->augmentation;
if (strcmp (c->augmentation, "") != 0
&& strcmp (c->augmentation, "eh") != 0
&& c->augmentation[0] != 'z')
return 0;
p = c->augmentation + strlen (c->augmentation) + 1;
if (strcmp (c->augmentation, "eh") == 0)
{
c->eh_ptr = read_pointer (p);
p += sizeof (void *);
}
else
c->eh_ptr = 0;
p = decode_uleb128 (p, &c->code_align);
p = decode_sleb128 (p, &c->data_align);
c->ra_regno = *(unsigned char *)p++;
/* If the augmentation starts with 'z', we now see the length of the
augmentation fields. */
if (c->augmentation[0] == 'z')
{
p = decode_uleb128 (p, &i);
p += i;
}
return p;
}
/* Decode one instruction's worth of DWARF 2 call frame information.
Used by __frame_state_for. Takes pointers P to the instruction to
decode, STATE to the current register unwind information, INFO to the
current CIE information, and PC to the current PC value. Returns a
pointer to the next instruction. */
static void *
execute_cfa_insn (void *p, struct frame_state_internal *state,
struct cie_info *info, void **pc)
{
unsigned insn = *(unsigned char *)p++;
unsigned reg;
int offset;
if (insn & DW_CFA_advance_loc)
*pc += ((insn & 0x3f) * info->code_align);
else if (insn & DW_CFA_offset)
{
reg = (insn & 0x3f);
p = decode_uleb128 (p, &offset);
if (reg == state->s.cfa_reg)
/* Don't record anything about this register; it's only used to
reload SP in the epilogue. We don't want to copy in SP
values for outer frames; we handle restoring SP specially. */;
else
{
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = offset;
}
}
else if (insn & DW_CFA_restore)
{
reg = (insn & 0x3f);
state->s.saved[reg] = REG_UNSAVED;
}
else switch (insn)
{
case DW_CFA_set_loc:
*pc = read_pointer (p);
p += sizeof (void *);
break;
case DW_CFA_advance_loc1:
*pc += read_1byte (p);
p += 1;
break;
case DW_CFA_advance_loc2:
*pc += read_2byte (p);
p += 2;
break;
case DW_CFA_advance_loc4:
*pc += read_4byte (p);
p += 4;
break;
case DW_CFA_offset_extended:
p = decode_uleb128 (p, &reg);
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, &reg);
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, &reg);
p = decode_uleb128 (p, &reg2);
state->s.saved[reg] = REG_SAVED_REG;
state->s.reg_or_offset[reg] = reg2;
}
break;
case DW_CFA_def_cfa:
p = decode_uleb128 (p, &reg);
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, &reg);
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, &reg);
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 */

View File

@ -29,216 +29,6 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* It is incorrect to include config.h here, because this file is being
compiled for the target, and hence definitions concerning only the host
do not apply. */
#include "tconfig.h"
#include "tsystem.h"
#include "defaults.h"
#ifdef DWARF2_UNWIND_INFO
#include "dwarf2.h"
#include "frame.h"
#include "gthr.h"
#ifdef __GTHREAD_MUTEX_INIT
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
#else
static __gthread_mutex_t object_mutex;
#endif
/* Don't use `fancy_abort' here even if config.h says to use it. */
#ifdef abort
#undef abort
#endif
/* Some types used by the DWARF 2 spec. */
typedef int sword __attribute__ ((mode (SI)));
typedef unsigned int uword __attribute__ ((mode (SI)));
typedef unsigned int uaddr __attribute__ ((mode (pointer)));
typedef int saddr __attribute__ ((mode (pointer)));
typedef unsigned char ubyte;
/* Terminology:
CIE - Common Information Element
FDE - Frame Descriptor Element
There is one per function, and it describes where the function code
is located, and what the register lifetimes and stack layout are
within the function.
The data structures are defined in the DWARF specfication, although
not in a very readable way (see LITERATURE).
Every time an exception is thrown, the code needs to locate the FDE
for the current function, and starts to look for exception regions
from that FDE. This works in a two-level search:
a) in a linear search, find the shared image (i.e. DLL) containing
the PC
b) using the FDE table for that shared object, locate the FDE using
binary search (which requires the sorting). */
/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
to distinguish it from a valid FDE. FDEs are aligned to an addressing
unit boundary, but the fields within are unaligned. */
struct dwarf_cie {
uword length;
sword CIE_id;
ubyte version;
char augmentation[0];
} __attribute__ ((packed, aligned (__alignof__ (void *))));
/* The first few fields of an FDE. */
struct dwarf_fde {
uword length;
sword CIE_delta;
void* pc_begin;
uaddr pc_range;
} __attribute__ ((packed, aligned (__alignof__ (void *))));
typedef struct dwarf_fde fde;
/* Objects to be searched for frame unwind info. */
static struct object *objects;
/* The information we care about from a CIE. */
struct cie_info {
char *augmentation;
void *eh_ptr;
int code_align;
int data_align;
unsigned ra_regno;
};
/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
struct frame_state_internal
{
struct frame_state s;
struct frame_state_internal *saved_state;
};
/* This is undefined below if we need it to be an actual function. */
#define init_object_mutex_once()
#if __GTHREADS
#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
/* Helper for init_object_mutex_once. */
static void
init_object_mutex (void)
{
__GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
}
/* Call this to arrange to initialize the object mutex. */
#undef init_object_mutex_once
static void
init_object_mutex_once (void)
{
static __gthread_once_t once = __GTHREAD_ONCE_INIT;
__gthread_once (&once, init_object_mutex);
}
#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
#endif /* __GTHREADS */
/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static void *
decode_uleb128 (unsigned char *buf, unsigned *r)
{
unsigned shift = 0;
unsigned result = 0;
while (1)
{
unsigned byte = *buf++;
result |= (byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
*r = result;
return buf;
}
/* Decode the signed LEB128 constant at BUF into the variable pointed to
by R, and return the new value of BUF. */
static void *
decode_sleb128 (unsigned char *buf, int *r)
{
unsigned shift = 0;
unsigned result = 0;
unsigned byte;
while (1)
{
byte = *buf++;
result |= (byte & 0x7f) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
}
if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
result |= - (1 << shift);
*r = result;
return buf;
}
/* Read unaligned data from the instruction buffer. */
union unaligned {
void *p;
unsigned b2 __attribute__ ((mode (HI)));
unsigned b4 __attribute__ ((mode (SI)));
unsigned b8 __attribute__ ((mode (DI)));
} __attribute__ ((packed));
static inline void *
read_pointer (void *p)
{ union unaligned *up = p; return up->p; }
static inline unsigned
read_1byte (void *p)
{ return *(unsigned char *)p; }
static inline unsigned
read_2byte (void *p)
{ union unaligned *up = p; return up->b2; }
static inline unsigned
read_4byte (void *p)
{ union unaligned *up = p; return up->b4; }
static inline unsigned long
read_8byte (void *p)
{ union unaligned *up = p; return up->b8; }
/* Ordering function for FDEs. Functions can't overlap, so we just compare
their starting addresses. */
static inline saddr
fde_compare (fde *x, fde *y)
{
return (saddr)x->pc_begin - (saddr)y->pc_begin;
}
/* Return the address of the FDE after P. */
static inline fde *
next_fde (fde *p)
{
return (fde *)(((char *)p) + p->length + sizeof (p->length));
}
/* Sorting an array of FDEs by address.
(Ideally we would have the linker sort the FDEs so we don't have to do
it at run time. But the linkers are not yet prepared for this.) */
@ -452,377 +242,6 @@ end_fde_sort (fde_accumulator *accu, size_t count)
return accu->linear.array;
}
static size_t
count_fdes (fde *this_fde)
{
size_t count;
for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
++count;
}
return count;
}
static void
add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
{
void *pc_begin = *beg_ptr;
void *pc_end = *end_ptr;
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
fde_insert (accu, this_fde);
if (this_fde->pc_begin < pc_begin)
pc_begin = this_fde->pc_begin;
if (this_fde->pc_begin + this_fde->pc_range > pc_end)
pc_end = this_fde->pc_begin + this_fde->pc_range;
}
*beg_ptr = pc_begin;
*end_ptr = pc_end;
}
/* search this fde table for the one containing the pc */
static fde *
search_fdes (fde *this_fde, void *pc)
{
for (; this_fde->length != 0; this_fde = next_fde (this_fde))
{
/* Skip CIEs and linked once FDE entries. */
if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
continue;
if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
return this_fde;
}
return NULL;
}
/* Set up a sorted array of pointers to FDEs for a loaded object. We
count up the entries before allocating the array because it's likely to
be faster. We can be called multiple times, should we have failed to
allocate a sorted fde array on a previous occasion. */
static void
frame_init (struct object* ob)
{
size_t count;
fde_accumulator accu;
void *pc_begin, *pc_end;
fde **array;
if (ob->pc_begin)
count = ob->count;
else if (ob->fde_array)
{
fde **p = ob->fde_array;
for (count = 0; *p; ++p)
count += count_fdes (*p);
}
else
count = count_fdes (ob->fde_begin);
ob->count = count;
if (!start_fde_sort (&accu, count) && ob->pc_begin)
return;
pc_begin = (void*)(uaddr)-1;
pc_end = 0;
if (ob->fde_array)
{
fde **p = ob->fde_array;
for (; *p; ++p)
add_fdes (*p, &accu, &pc_begin, &pc_end);
}
else
add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
array = end_fde_sort (&accu, count);
if (array)
ob->fde_array = array;
ob->pc_begin = pc_begin;
ob->pc_end = pc_end;
}
/* Return a pointer to the FDE for the function containing PC. */
static fde *
find_fde (void *pc)
{
struct object *ob;
size_t lo, hi;
init_object_mutex_once ();
__gthread_mutex_lock (&object_mutex);
/* Linear search through the objects, to find the one containing the pc. */
for (ob = objects; ob; ob = ob->next)
{
if (ob->pc_begin == 0)
frame_init (ob);
if (pc >= ob->pc_begin && pc < ob->pc_end)
break;
}
if (ob == 0)
{
__gthread_mutex_unlock (&object_mutex);
return 0;
}
if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
frame_init (ob);
if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
{
__gthread_mutex_unlock (&object_mutex);
/* Standard binary search algorithm. */
for (lo = 0, hi = ob->count; lo < hi; )
{
size_t i = (lo + hi) / 2;
fde *f = ob->fde_array[i];
if (pc < f->pc_begin)
hi = i;
else if (pc >= f->pc_begin + f->pc_range)
lo = i + 1;
else
return f;
}
}
else
{
/* Long slow labourious linear search, cos we've no memory. */
fde *f;
if (ob->fde_array)
{
fde **p = ob->fde_array;
do
{
f = search_fdes (*p, pc);
if (f)
break;
p++;
}
while (*p);
}
else
f = search_fdes (ob->fde_begin, pc);
__gthread_mutex_unlock (&object_mutex);
return f;
}
return 0;
}
static inline struct dwarf_cie *
get_cie (fde *f)
{
return ((void *)&f->CIE_delta) - f->CIE_delta;
}
/* Extract any interesting information from the CIE for the translation
unit F belongs to. */
static void *
extract_cie_info (fde *f, struct cie_info *c)
{
void *p;
int i;
c->augmentation = get_cie (f)->augmentation;
if (strcmp (c->augmentation, "") != 0
&& strcmp (c->augmentation, "eh") != 0
&& c->augmentation[0] != 'z')
return 0;
p = c->augmentation + strlen (c->augmentation) + 1;
if (strcmp (c->augmentation, "eh") == 0)
{
c->eh_ptr = read_pointer (p);
p += sizeof (void *);
}
else
c->eh_ptr = 0;
p = decode_uleb128 (p, &c->code_align);
p = decode_sleb128 (p, &c->data_align);
c->ra_regno = *(unsigned char *)p++;
/* If the augmentation starts with 'z', we now see the length of the
augmentation fields. */
if (c->augmentation[0] == 'z')
{
p = decode_uleb128 (p, &i);
p += i;
}
return p;
}
/* Decode one instruction's worth of DWARF 2 call frame information.
Used by __frame_state_for. Takes pointers P to the instruction to
decode, STATE to the current register unwind information, INFO to the
current CIE information, and PC to the current PC value. Returns a
pointer to the next instruction. */
static void *
execute_cfa_insn (void *p, struct frame_state_internal *state,
struct cie_info *info, void **pc)
{
unsigned insn = *(unsigned char *)p++;
unsigned reg;
int offset;
if (insn & DW_CFA_advance_loc)
*pc += ((insn & 0x3f) * info->code_align);
else if (insn & DW_CFA_offset)
{
reg = (insn & 0x3f);
p = decode_uleb128 (p, &offset);
if (reg == state->s.cfa_reg)
/* Don't record anything about this register; it's only used to
reload SP in the epilogue. We don't want to copy in SP
values for outer frames; we handle restoring SP specially. */;
else
{
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = offset;
}
}
else if (insn & DW_CFA_restore)
{
reg = (insn & 0x3f);
state->s.saved[reg] = REG_UNSAVED;
}
else switch (insn)
{
case DW_CFA_set_loc:
*pc = read_pointer (p);
p += sizeof (void *);
break;
case DW_CFA_advance_loc1:
*pc += read_1byte (p);
p += 1;
break;
case DW_CFA_advance_loc2:
*pc += read_2byte (p);
p += 2;
break;
case DW_CFA_advance_loc4:
*pc += read_4byte (p);
p += 4;
break;
case DW_CFA_offset_extended:
p = decode_uleb128 (p, &reg);
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, &reg);
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, &reg);
p = decode_uleb128 (p, &reg2);
state->s.saved[reg] = REG_SAVED_REG;
state->s.reg_or_offset[reg] = reg2;
}
break;
case DW_CFA_def_cfa:
p = decode_uleb128 (p, &reg);
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, &reg);
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, &reg);
p = decode_uleb128 (p, &offset);
offset *= info->data_align;
state->s.saved[reg] = REG_SAVED_OFFSET;
state->s.reg_or_offset[reg] = -offset;
break;
default:
abort ();
}
return p;
}
/* Called from crtbegin.o to register the unwind info for an object. */
void
@ -917,51 +336,3 @@ __deregister_frame (void *begin)
free (__deregister_frame_info (begin));
}
/* Called from __throw to find the registers to restore for a given
PC_TARGET. The caller should allocate a local variable of `struct
frame_state' (declared in frame.h) and pass its address to STATE_IN. */
struct frame_state *
__frame_state_for (void *pc_target, struct frame_state *state_in)
{
fde *f;
void *insn, *end, *pc;
struct cie_info info;
struct frame_state_internal state;
f = find_fde (pc_target);
if (f == 0)
return 0;
insn = extract_cie_info (f, &info);
if (insn == 0)
return 0;
memset (&state, 0, sizeof (state));
state.s.retaddr_column = info.ra_regno;
state.s.eh_ptr = info.eh_ptr;
/* First decode all the insns in the CIE. */
end = next_fde ((fde*) get_cie (f));
while (insn < end)
insn = execute_cfa_insn (insn, &state, &info, 0);
insn = ((fde *)f) + 1;
if (info.augmentation[0] == 'z')
{
int i;
insn = decode_uleb128 (insn, &i);
insn += i;
}
/* Then the insns in the FDE up to our target PC. */
end = next_fde (f);
pc = f->pc_begin;
while (insn < end && pc <= pc_target)
insn = execute_cfa_insn (insn, &state, &info, &pc);
memcpy (state_in, &state.s, sizeof (state.s));
return state_in;
}
#endif /* DWARF2_UNWIND_INFO */

View File

@ -50,9 +50,15 @@ typedef struct frame_state
keep the copies synchronized! */
struct object {
#ifdef IA64_UNWIND_INFO
void *pc_base; /* This field will be set by find_fde. */
#endif
void *pc_begin;
void *pc_end;
struct dwarf_fde *fde_begin;
#ifdef IA64_UNWIND_INFO
struct dwarf_fde *fde_end;
#endif
struct dwarf_fde **fde_array;
size_t count;
struct object *next;
@ -87,3 +93,184 @@ extern void *__deregister_frame_info (void *);
Returns NULL on failure, otherwise returns STATE_IN. */
extern struct frame_state *__frame_state_for (void *, struct frame_state *);
#ifdef IA64_UNWIND_INFO
/* This is the information required for unwind records in an ia64
object file. This is required by GAS and the compiler runtime. */
/* These are the starting point masks for the various types of
unwind records. To create a record of type R3 for instance, one
starts by using the value UNW_R3 and or-ing in any other required values.
These values are also unique (in context), so they can be used to identify
the various record types as well. UNW_Bx and some UNW_Px do have the
same value, but Px can only occur in a prologue context, and Bx in
a body context. */
#define UNW_R1 0x00
#define UNW_R2 0x40
#define UNW_R3 0x60
#define UNW_P1 0x80
#define UNW_P2 0xA0
#define UNW_P3 0xB0
#define UNW_P4 0xB8
#define UNW_P5 0xB9
#define UNW_P6 0xC0
#define UNW_P7 0xE0
#define UNW_P8 0xF0
#define UNW_P9 0xF1
#define UNW_P10 0xFF
#define UNW_X1 0xF9
#define UNW_X2 0xFA
#define UNW_X3 0xFB
#define UNW_X4 0xFC
#define UNW_B1 0x80
#define UNW_B2 0xC0
#define UNW_B3 0xE0
#define UNW_B4 0xF0
/* These are all the various types of unwind records. */
typedef enum
{
prologue, prologue_gr, body, mem_stack_f, mem_stack_v, psp_gr, psp_sprel,
rp_when, rp_gr, rp_br, rp_psprel, rp_sprel, pfs_when, pfs_gr, pfs_psprel,
pfs_sprel, preds_when, preds_gr, preds_psprel, preds_sprel,
fr_mem, frgr_mem, gr_gr, gr_mem, br_mem, br_gr, spill_base, spill_mask,
unat_when, unat_gr, unat_psprel, unat_sprel, lc_when, lc_gr, lc_psprel,
lc_sprel, fpsr_when, fpsr_gr, fpsr_psprel, fpsr_sprel,
priunat_when_gr, priunat_when_mem, priunat_gr, priunat_psprel,
priunat_sprel, bsp_when, bsp_gr, bsp_psprel, bsp_sprel, bspstore_when,
bspstore_gr, bspstore_psprel, bspstore_sprel, rnat_when, rnat_gr,
rnat_psprel, rnat_sprel, epilogue, label_state, copy_state,
spill_psprel, spill_sprel, spill_reg, spill_psprel_p, spill_sprel_p,
spill_reg_p
} unw_record_type;
/* These structures declare the fields that can be used in each of the
4 record formats, R, P, B and X. */
typedef struct unw_r_record
{
unsigned long rlen;
unsigned short mask;
unsigned short grsave;
} unw_r_record;
typedef struct unw_p_record
{
void *imask;
unsigned long t;
unsigned long size;
unsigned long spoff;
unsigned long br;
unsigned long pspoff;
unsigned short gr;
unsigned short rmask;
unsigned short grmask;
unsigned long frmask;
unsigned short brmask;
} unw_p_record;
typedef struct unw_b_record
{
unsigned long t;
unsigned long label;
unsigned short ecount;
} unw_b_record;
typedef struct unw_x_record
{
unsigned long t;
unsigned long spoff;
unsigned long pspoff;
unsigned short reg;
unsigned short treg;
unsigned short qp;
unsigned short xy; /* Value of the XY field.. */
} unw_x_record;
/* This structure is used to determine the specific record type and
its fields. */
typedef struct unwind_record
{
unw_record_type type;
union {
unw_r_record r;
unw_p_record p;
unw_b_record b;
unw_x_record x;
} record;
} unwind_record;
#define IA64_UNW_LOC_TYPE_NONE 0
#define IA64_UNW_LOC_TYPE_MEM 1
#define IA64_UNW_LOC_TYPE_GR 2
#define IA64_UNW_LOC_TYPE_FR 3
#define IA64_UNW_LOC_TYPE_BR 4
#define IA64_UNW_LOC_TYPE_SPOFF 5
#define IA64_UNW_LOC_TYPE_PSPOFF 6
#define IA64_UNW_LOC_TYPE_OFFSET 7
#define IA64_UNW_LOC_TYPE_SPILLBASE 8
typedef struct ia64_reg_loc
{
long when; /* PC relative offset from start of function. */
union { /* In memory or another register? */
void *mem;
int regno;
int offset;
} l;
short loc_type; /* Where to find value. */
short reg_size;
} ia64_reg_loc;
/* Frame information record. */
typedef struct ia64_frame_state
{
ia64_reg_loc gr[4]; /* gr4 to gr7. */
ia64_reg_loc fr[20]; /* fr2 to fr5, fr16 to fr31. */
ia64_reg_loc br[5]; /* br1 to br5. */
ia64_reg_loc rp;
ia64_reg_loc fpsr;
ia64_reg_loc bsp;
ia64_reg_loc bspstore;
ia64_reg_loc rnat;
ia64_reg_loc pfs;
ia64_reg_loc unat;
ia64_reg_loc lc;
ia64_reg_loc pr;
ia64_reg_loc priunat;
ia64_reg_loc sp;
ia64_reg_loc psp;
ia64_reg_loc spill_base;
void *my_sp;
void *my_bsp;
} ia64_frame_state;
/* This structure represents the start of an unwind information pointer.
'unwind_descriptors' is the beginninng of the unwind descriptors, which
use up 'length' bytes of storage. */
typedef struct unwind_info_ptr
{
unsigned short version;
unsigned short flags;
unsigned int length;
unsigned char unwind_descriptors[1];
} unwind_info_ptr;
extern unwind_info_ptr *__build_ia64_frame_state (unsigned char *,
ia64_frame_state *, void *,
void **);
extern void *__get_real_reg_value (ia64_reg_loc *);
extern void *__get_personality (unwind_info_ptr *);
extern void *__get_except_table (unwind_info_ptr *);
extern void __set_real_reg_value (ia64_reg_loc *, void *);
void *__calc_caller_bsp (long, unsigned char *);
void __copy_saved_reg_state (ia64_frame_state *, ia64_frame_state *);
#endif /* IA64_UNWIND_INFO */

View File

@ -3940,6 +3940,173 @@ label:
}
#endif /* DWARF2_UNWIND_INFO */
#ifdef IA64_UNWIND_INFO
#include "frame.h"
/* Return handler to which we want to transfer control, NULL if we don't
intend to handle this exception here. */
void *
__ia64_personality_v1 (void *pc, old_exception_table *table)
{
if (table)
{
int pos;
int best = -1;
for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
{
if (table[pos].start_region <= pc && table[pos].end_region > pc)
{
/* This can apply. Make sure it is at least as small as
the previous best. */
if (best == -1 || (table[pos].end_region <= table[best].end_region
&& table[pos].start_region >= table[best].start_region))
best = pos;
}
/* It is sorted by starting PC within a function. */
else if (best >= 0 && table[pos].start_region > pc)
break;
}
if (best != -1)
return table[best].exception_handler;
}
return (void *) 0;
}
static void
ia64_throw_helper (throw_pc, throw_frame, caller, throw_bsp)
void *throw_pc;
ia64_frame_state *throw_frame;
ia64_frame_state *caller;
void *throw_bsp;
{
unwind_info_ptr *info;
void *pc, *handler = NULL;
void *pc_base;
int frame_count;
void *bsp;
__builtin_ia64_flushrs (); /* Make the local register stacks available. */
/* Start at our stack frame, get our state. */
__build_ia64_frame_state (throw_pc, throw_frame, throw_bsp, &pc_base);
/* Now we have to find the proper frame for pc, and see if there
is a handler for it. if not, we keep going back frames until
we do find one. Otherwise we call uncaught (). */
frame_count = 0;
memcpy (caller, throw_frame, sizeof (*caller));
while (!handler)
{
void *(*personality) ();
void *eh_table;
frame_count++;
/* We only care about the RP right now, so we dont need to keep
any other information about a call frame right now. */
pc = __get_real_reg_value (&caller->rp) - 1;
bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
info = __build_ia64_frame_state (pc, caller, bsp, &pc_base);
/* If we couldn't find the next frame, we lose. */
if (! info)
break;
personality = __get_personality (info);
/* TODO Haven't figured out how to actually load the personality address
yet, so just always default to the one we expect for now. */
if (personality != 0)
personality = __ia64_personality_v1;
eh_table = __get_except_table (info);
/* If there is no personality routine, we'll keep unwinding. */
if (personality)
/* Pass a segment relative PC address to the personality routine,
because the unwind_info section uses segrel relocs. */
handler = personality (pc - pc_base, eh_table);
}
if (!handler)
__terminate ();
/* Handler is a segment relative address, so we must adjust it here. */
handler += (long) pc_base;
/* If we found a handler, we need to unwind the stack to that point.
We do this by copying saved values from previous frames into the
save slot for the throw_frame saved slots. when __throw returns,
it'll pickup the correct values. */
/* Start with where __throw saved things, and copy each saved register
of each previous frame until we get to the one before we're
throwing back to. */
memcpy (caller, throw_frame, sizeof (*caller));
for ( ; frame_count > 0; frame_count--)
{
pc = __get_real_reg_value (&caller->rp) - 1;
bsp = __calc_caller_bsp ((long)__get_real_reg_value (&caller->pfs), caller->my_bsp);
__build_ia64_frame_state (pc, caller, bsp, &pc_base);
/* Any regs that were saved can be put in the throw frame now. */
/* We don't want to copy any saved register from the
target destination, but we do want to load up it's frame. */
if (frame_count > 1)
__copy_saved_reg_state (throw_frame, caller);
}
/* Set return address of the throw frame to the handler. */
__set_real_reg_value (&throw_frame->rp, handler);
/* TODO, do we need to do anything to make the values we wrote 'stick'? */
/* DO we need to go through the whole loadrs seqeunce? */
}
void
__throw ()
{
struct eh_context *eh = (*get_eh_context) ();
ia64_frame_state my_frame;
ia64_frame_state originator; /* For the context handler is in. */
void *bsp, *tmp_bsp;
long offset;
/* This is required for C++ semantics. We must call terminate if we
try and rethrow an exception, when there is no exception currently
active. */
if (! eh->info)
__terminate ();
__builtin_unwind_init ();
label_ia64:
/* We have to call another routine to actually process the frame
information, which will force all of __throw's local registers into
backing store. */
/* Get the value of ar.bsp while we're here. */
bsp = __builtin_ia64_bsp ();
ia64_throw_helper (&&label_ia64, &my_frame, &originator, bsp);
/* Now we have to fudge the bsp by the amount in our (__throw)
frame marker, since the return is going to adjust it by that much. */
tmp_bsp = __calc_caller_bsp ((long)__get_real_reg_value (&my_frame.pfs),
my_frame.my_bsp);
offset = (char *)my_frame.my_bsp - (char *)tmp_bsp;
tmp_bsp = (char *)originator.my_bsp + offset;
/* A throw handler is trated like a non-local goto, which is architeched
to set the FP (or PSP) in r7 before branching. gr[0-3] map to
r4-r7, so we want gr[3]. */
__set_real_reg_value (&my_frame.gr[3], __get_real_reg_value (&originator.psp));
__builtin_eh_return (tmp_bsp, offset, originator.my_sp);
/* The return address was already set by throw_helper. */
}
#endif /* IA64_UNWIND_INFO */
#endif /* L_eh */
#ifdef L_pure

View File

@ -292,6 +292,7 @@ extern void assemble_zeros PARAMS ((int));
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
extern void assemble_align PARAMS ((int));
extern void assemble_eh_align PARAMS ((int));
/* Assemble a string constant with the specified C string as contents. */
extern void assemble_string PARAMS ((const char *, int));
@ -306,6 +307,7 @@ extern void assemble_global PARAMS ((const char *));
/* Assemble a label named NAME. */
extern void assemble_label PARAMS ((const char *));
extern void assemble_eh_label PARAMS ((const char *));
/* Output to FILE a reference to the assembler name of a C-level name NAME.
If NAME starts with a *, the rest of NAME is output verbatim.
@ -321,6 +323,7 @@ extern void assemble_name PARAMS ((FILE *, const char *));
Return 1 if we were able to output the constant, otherwise 0. If FORCE is
non-zero, abort if we can't output the constant. */
extern int assemble_integer PARAMS ((rtx, int, int));
extern int assemble_eh_integer PARAMS ((rtx, int, int));
#ifdef EMUSHORT
/* Assemble the floating-point constant D into an object of size MODE. */

View File

@ -2336,8 +2336,11 @@ compile_file (name)
/* Now that all possible functions have been output, we can dump
the exception table. */
#ifndef IA64_UNWIND_INFO
output_exception_table ();
#endif
free_exception_table ();
check_global_declarations (vec, len);
/* Clean up. */
@ -4604,11 +4607,23 @@ main (argc, argv)
{
#ifdef DWARF2_UNWIND_INFO
exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
#else
#ifdef IA64_UNWIND_INFO
exceptions_via_longjmp = ! IA64_UNWIND_INFO;
#else
exceptions_via_longjmp = 1;
#endif
#endif
}
/* Since each function gets its own handler data, we can't support the
new model currently, since it depend on a specific rethrow label
which is declared at the front of the table, and we can only
have one such symbol in a file. */
#ifdef IA64_UNWIND_INFO
flag_new_exceptions = 0;
#endif
/* Set up the align_*_log variables, defaulting them to 1 if they
were still unset. */
if (align_loops <= 0) align_loops = 1;

View File

@ -4836,3 +4836,74 @@ init_varasm_once ()
mark_const_hash_entry);
ggc_add_string_root (&in_named_name, 1);
}
/* Extra support for EH values. */
void
assemble_eh_label (name)
const char *name;
{
#ifdef ASM_OUTPUT_EH_LABEL
ASM_OUTPUT_EH_LABEL (asm_out_file, name);
#else
assemble_label (name);
#endif
}
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
void
assemble_eh_align (align)
int align;
{
#ifdef ASM_OUTPUT_EH_ALIGN
if (align > BITS_PER_UNIT)
ASM_OUTPUT_EH_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
#else
assemble_align (align);
#endif
}
/* On some platforms, we may want to specify a special mechansim to
output EH data when generating with a function.. */
int
assemble_eh_integer (x, size, force)
rtx x;
int size;
int force;
{
switch (size)
{
#ifdef ASM_OUTPUT_EH_CHAR
case 1:
ASM_OUTPUT_EH_CHAR (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_SHORT
case 2:
ASM_OUTPUT_EH_SHORT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_INT
case 4:
ASM_OUTPUT_EH_INT (asm_out_file, x);
return 1;
#endif
#ifdef ASM_OUTPUT_EH_DOUBLE_INT
case 8:
ASM_OUTPUT_EH_DOUBLE_INT (asm_out_file, x);
return 1;
#endif
default:
break;
}
return (assemble_integer (x, size, force));
}