Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
ca55abae
Commit
ca55abae
authored
Sep 15, 1997
by
Jason Merrill
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dwarf2 EH support
From-SVN: r15464
parent
5168dcfc
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
853 additions
and
200 deletions
+853
-200
gcc/ChangeLog
+163
-0
gcc/Makefile.in
+8
-12
gcc/configure
+4
-1
gcc/configure.in
+3
-0
gcc/cp/ChangeLog
+8
-0
gcc/cp/decl.c
+5
-1
gcc/emit-rtl.c
+1
-0
gcc/except.c
+288
-79
gcc/expr.c
+28
-0
gcc/libgcc2.c
+345
-107
No files found.
gcc/ChangeLog
View file @
ca55abae
...
...
@@ -12,6 +12,47 @@ Mon Sep 15 15:39:26 1997 Jeffrey A Law (law@cygnus.com)
mode wider than HOST_WIDE_INT, then the high word of a CONST_INT
is derived from the sign bit of the low word.
Mon Sep 15 11:43:38 1997 Jason Merrill <jason@yorick.cygnus.com>
Support dwarf2 unwinding on PUSH_ROUNDING targets like the x86.
* dwarf2.h: Add DW_CFA_GNU_args_size.
* frame.c (execute_cfa_insn): Likewise.
* dwarf2out.c (dwarf_cfi_name, output_cfi): Likewise.
(dwarf2out_args_size, dwarf2out_stack_adjust): New fns.
(dwarf2out_frame_debug): If this isn't a prologue or epilogue
insn, hand it off to dwarf2out_stack_adjust.
(dwarf2out_begin_prologue): Initialize args_size.
* frame.h (struct frame_state): Add args_size.
* libgcc2.c (__throw): Use args_size.
* final.c (final_scan_insn): If we push args, hand off all insns
to dwarf2out_frame_debug.
* defaults.h (DWARF2_UNWIND_INFO): OK for !ACCUMULATE_OUTGOING_ARGS.
* dwarf2out.c dwarf2out_frame_debug): Fix typo.
Handle epilogue restore of SP from FP.
* emit-rtl.c (gen_sequence): Still generate a sequence if the
lone insn has RTX_FRAME_RELATED_P set.
* frame.c (extract_cie_info): Handle "e" augmentation.
* dwarf2out.c (ASM_OUTPUT_DWARF_*): Provide definitions in the
absence of UNALIGNED_*_ASM_OP.
(UNALIGNED_*_ASM_OP): Only provide defaults if OBJECT_FORMAT_ELF.
(output_call_frame_info): Use "e" instead of "z" for augmentation.
Don't emit augmentation fields length.
(dwarf2out_do_frame): Move outside of #ifdefs.
* defaults.h (DWARF2_UNWIND_INFO): Don't require unaligned data
opcodes.
* sparc.h (UNALIGNED_INT_ASM_OP et al): Don't define here after all.
* sparc/sysv4.h (UNALIGNED_INT_ASM_OP): Define here.
* sparc/sunos4.h (DWARF2_UNWIND_INFO): Define to 0.
* sparc/sun4gas.h: New file.
* configure.in: Use sun4gas.h if SunOS 4 --with-gnu-as.
* collect2.c (write_c_file_stat, write_c_file_glob): Declare
__register_frame_table and __deregister_frame.
1997-09-15 Brendan Kehoe <brendan@cygnus.com>
* except.c (find_exception_handler_labels): Use xmalloc instead of
...
...
@@ -45,6 +86,11 @@ Sat Sep 13 12:57:26 1997 Jeffrey A Law (law@cygnus.com)
* haifa-sched.c (add_branch_dependences): Make each insn in
a SCHED_GROUP_P block explicitly depend on the previous insn.
Fri Sep 12 13:49:58 1997 Jason Merrill <jason@yorick.cygnus.com>
* except.h: Prototype dwarf2 hooks.
* expr.c: Adjust.
Thu Sep 11 17:43:55 1997 Jim Wilson <wilson@cygnus.com>
* configure.in (native_prefix): Delete.
...
...
@@ -112,6 +158,95 @@ Wed Sep 10 14:05:08 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
(check-gcc, check-g++): Depend on testsuite/site.exp.
Don't stop for failure.
Wed Sep 10 12:59:57 1997 Jason Merrill <jason@yorick.cygnus.com>
* expr.c (expand_builtin): Only support __builtin_dwarf_fp_regnum()
if DWARF2_UNWIND_INFO.
Wed Sep 10 11:49:20 1997 Jason Merrill <jason@yorick.cygnus.com>
Add support for exception handling using DWARF 2 frame unwind info.
Currently works on SPARC and MIPS, and almost on x86.
* libgcc2.c (get_reg, put_reg, get_return_addr, put_return_addr,
next_stack_level, in_reg_window): Helper fns.
(__throw): Implement for DWARF2_UNWIND_INFO.
* expr.c (expand_builtin): Handle builtins used by __throw.
* tree.h (enum built_in_function): Add builtins used by __throw.
* c-decl.c (init_decl_processing): Declare builtins used by __throw.
* dwarf2out.c (expand_builtin_dwarf_fp_regnum): Used by __throw.
* except.c (expand_builtin_unwind_init): Hook for dwarf2 __throw.
(expand_builtin_extract_return_addr): Likewise.
(expand_builtin_frob_return_addr): Likewise.
(expand_builtin_set_return_addr_reg): Likewise.
(expand_builtin_eh_stub): Likewise.
(expand_builtin_set_eh_regs): Likewise.
(eh_regs): Choose two call-clobbered registers for passing back values.
* frame.c, frame.h: New files for parsing dwarf 2 frame info.
* Makefile.in (LIB2ADD): New variable. Add $(srcdir)/frame.c.
(libgcc2.a): Use it instead of $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
(stmp-multilib): Likewise.
($(T)crtbegin.o, $(T)crtend.o): Add -fno-exceptions.
* except.c: #include "defaults.h".
(exceptions_via_longjmp): Default depends on DWARF2_UNWIND_INFO.
(emit_throw): Don't defeat assemble_external if DWARF2_UNWIND_INFO.
(register_exception_table_p): New fn.
(start_eh_unwinder): Don't do anything if DWARF2_UNWIND_INFO.
(end_eh_unwinder): Likewise.
* crtstuff.c: Wrap .eh_frame section, use EH_FRAME_SECTION_ASM_OP,
call __register_frame and __deregister_frame as needed.
* varasm.c (eh_frame_section): New fn if EH_FRAME_SECTION_ASM_OP.
* dwarf2out.c (EH_FRAME_SECTION): Now a function-like macro. Check
EH_FRAME_SECTION_ASM_OP.
* sparc/sysv4.h (EH_FRAME_SECTION_ASM_OP): Define.
* mips/iris6.h: (EH_FRAME_SECTION_ASM_OP): Define.
(LINK_SPEC): Add __EH_FRAME_BEGIN__ to hidden symbols.
* dwarf2out.c (output_call_frame_info): If no support for
EXCEPTION_SECTION, mark the start of the frame info with a
collectable tag.
* collect2.c (frame_tables): New list.
(is_ctor_dtor): Recognise frame entries.
(scan_prog_file): Likewise.
(main): Pass -fno-exceptions to sub-compile. Also do collection
if there are any frame entries.
(write_c_file_stat): Call __register_frame_table and
__deregister_frame as needed.
(write_c_file_glob): Likewise.
* defaults.h (DWARF2_UNWIND_INFO): Default to 1 if supported.
Also require unaligned reloc support.
* sparc.h (UNALIGNED_SHORT_ASM_OP, UNALIGNED_INT_ASM_OP,
UNALIGNED_DOUBLE_INT_ASM_OP): Define here.
* sparc/sysv4.h: Not here.
* toplev.c (compile_file): Call dwarf2out_frame_{init,finish}.
* dwarf2out.c (dwarf2out_init): Don't call dwarf2out_frame_init.
(dwarf2out_finish): Don't call dwarf2out_frame_finish.
* libgcc2.c (L_eh): Reorganize, moving code shared by different
EH implementations to the top.
(find_exception_handler): Split out. Start from 0. Compare against
end with >=.
(__find_first_exception_table_match): Use it.
* except.c (output_exception_table): Don't do anything if there's
no table. Don't output a first entry of zeroes.
(eh_outer_context): Adjust properly.
(add_eh_table_entry): Use xrealloc.
* toplev.c (compile_file): Just call output_exception_table.
Wed Sep 10 11:30:36 1997 Jason Merrill <jason@cygnus.com>
* i386.c (ix86_prologue): Add dwarf2 support for !do_rtl case.
Wed Sep 10 08:17:10 1997 Torbjorn Granlund <tege@pdc.kth..se>
* except.c (eh_outer_context): Do masking using expand_and.
Wed Sep 10 01:38:30 1997 Doug Evans <dje@cygnus.com>
Add port done awhile ago for the ARC cpu.
...
...
@@ -152,10 +287,38 @@ Tue Sep 9 17:07:36 1997 Stan Cox <coxs@dg-rtp.dg.com>
* m88k.c (m88k_expand_prologue): Set MEM_IN_STRUCT_P of va_list
template.
Tue Sep 9 09:50:02 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* dwarf2out.c (output_call_frame_info): Call named_section.
Tue Sep 9 09:12:17 1997 Jeffrey A Law (law@cygnus.com)
* haifa-sched.c (print_value): Fix last change.
Tue Sep 9 01:30:37 1997 Jason Merrill <jason@yorick.cygnus.com>
* mips.h (DWARF_FRAME_REGNUM): Use the same numbering regardless of
write_symbols.
Mon Sep 8 16:32:43 1997 Jason Merrill <jason@yorick.cygnus.com>
* mips.c (function_prologue): Set up the CFA when ABI_32.
* sparc.c (save_regs): Check dwarf2out_do_frame instead of DWARF2_DEBUG
for dwarf2 unwind info.
(output_function_prologue, sparc_flat_output_function_prologue): Same.
* final.c (final_end_function): Check dwarf2out_do_frame instead
of DWARF2_DEBUG for dwarf2 unwind info.
(final_scan_insn): Likewise.
(final_start_function): Likewise. Initialize dwarf2 frame debug here.
(final): Not here.
* expr.c (expand_builtin_return_addr): Only SETUP_FRAME_ADDRESSES if
count > 0.
* varasm.c (exception_section): Check EXCEPTION_SECTION first.
Mon Sep 8 15:15:11 1997 Nick Clifton <nickc@cygnus.com>
* v850.h (ASM_SPEC): Pass on target processor.
...
...
gcc/Makefile.in
View file @
ca55abae
...
...
@@ -268,7 +268,7 @@ LIBGCC2 = libgcc2.a
# -g1 causes output of debug info only for file-scope entities.
# we use this here because that should be enough, and also
# so that -g1 will be tested.
LIBGCC2_DEBUG_CFLAGS
=
-g
1
LIBGCC2_DEBUG_CFLAGS
=
-g
LIBGCC2_CFLAGS
=
-O2
$(LIBGCC2_INCLUDES)
$(GCC_CFLAGS)
$(TARGET_LIBGCC2_CFLAGS)
$(LIBGCC2_DEBUG_CFLAGS)
-DIN_LIBGCC2
-D__GCC_FLOAT_NOT_NEEDED
# Additional options to use when compiling libgcc2.a.
...
...
@@ -949,8 +949,9 @@ libgcc2.ready: $(GCC_PASSES) $(LIBGCC2_DEPS) stmp-int-hdrs
touch libgcc2.ready
;
\
fi
libgcc2.a
:
libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA)
\
$(LANG_LIB2FUNCS) machmode.h longlong.h gbl-ctors.h config.status
LIB2ADD
=
$(srcdir)
/frame.c
$(LIB2FUNCS_EXTRA)
$(LANG_LIB2FUNCS)
libgcc2.a
:
libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2ADD)
\
machmode.h longlong.h gbl-ctors.h config.status
# Actually build it in tmplibgcc2.a, then rename at end,
# so that libgcc2.a itself remains nonexistent if compilation is aborted.
-rm
-f
tmplibgcc2.a
...
...
@@ -975,9 +976,7 @@ libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \
# We don't use -e here because there are if statements
# that should not make the command give up when the if condition is false.
# Instead, we test for failure after each command where it matters.
for
file
in
..
$(LIB2FUNCS_EXTRA)
$(LANG_LIB2FUNCS);
\
do
\
if
[
x$${file}
!=
x..
]
;
then
\
for
file
in
$(LIB2ADD);
do
\
name
=
`
echo
$$
{
file
}
| sed
-e
's/[.][cSo]$$//'
-e
's/[.]asm$$//'
-e
's/[.]txt$$//'
`
;
\
oname
=
`
echo
$$
{
name
}
| sed
-e
's,.*/,,'
`
;
\
if
[
$$
{
name
}
.txt
=
$$
{
file
}
]
;
then
\
...
...
@@ -1003,8 +1002,6 @@ libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \
$(AR)
$(AR_FLAGS)
tmplibgcc2.a
$$
{
oname
}
$(objext)
;
\
rm
-f
$$
{
name
}
.s
$$
{
oname
}
$(objext)
;
\
fi
;
\
else
true
;
\
fi
;
\
done
mv
tmplibgcc2.a
libgcc2.a
# These lines were deleted from above the mv command
...
...
@@ -1050,8 +1047,7 @@ stamp-mlib: $(srcdir)/genmultilib Makefile
# Build multiple copies of libgcc.a, one for each target switch.
stmp-multilib
:
$(LIBGCC1) libgcc2.c libgcc2.ready $(CONFIG_H)
\
$(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS) machmode.h longlong.h gbl-ctors.h
\
config.status
$(LIB2ADD) machmode.h longlong.h gbl-ctors.h config.status
for
i
in
`
$(GCC_FOR_TARGET)
--print-multi-lib
`
;
do
\
dir
=
`
echo
$$
i | sed
-e
's/;.*$$//'
`
;
\
flags
=
`
echo
$$
i | sed
-e
's/^[^;]*;//'
-e
's/@/ -/g'
`
;
\
...
...
@@ -1121,12 +1117,12 @@ stmp-multilib-sub:
# constructors.
$(T)crtbegin.o
:
crtstuff.c $(GCC_PASSES) $(CONFIG_H) gbl-ctors.h
$(GCC_FOR_TARGET)
$(GCC_CFLAGS)
$(INCLUDES)
$(MULTILIB_CFLAGS)
-g0
\
-finhibit-size-directive
-fno-inline-functions
$(CRTSTUFF_T_CFLAGS)
\
-finhibit-size-directive
-fno-inline-functions
-fno-exceptions
$(CRTSTUFF_T_CFLAGS)
\
-c
$(srcdir)
/crtstuff.c
-DCRT_BEGIN
-o
$(T)
crtbegin
$(objext)
$(T)crtend.o
:
crtstuff.c $(GCC_PASSES) $(CONFIG_H) gbl-ctors.h
$(GCC_FOR_TARGET)
$(GCC_CFLAGS)
$(INCLUDES)
$(MULTILIB_CFLAGS)
-g0
\
-finhibit-size-directive
-fno-inline-functions
$(CRTSTUFF_T_CFLAGS)
\
-finhibit-size-directive
-fno-inline-functions
-fno-exceptions
$(CRTSTUFF_T_CFLAGS)
\
-c
$(srcdir)
/crtstuff.c
-DCRT_END
-o
$(T)
crtend
$(objext)
# On some systems we also want to install versions of these files
...
...
gcc/configure
View file @
ca55abae
...
...
@@ -2313,7 +2313,7 @@ for machine in $build $host $target; do
i[3456]86-
*
-freebsd
*
)
tm_file
=
i386/freebsd.h
xm_file
=
i386/xm-freebsd.h
# On FreeBSD, the headers are already ok, except for math.h
# On FreeBSD, the headers are already ok, except for math.h
.
fixincludes
=
fixinc.math
tmake_file
=
i386/t-freebsd
;;
...
...
@@ -3897,6 +3897,9 @@ for machine in $build $host $target; do
tm_file
=
sparc/sunos4.h
tmake_file
=
sparc/t-sunos41
use_collect2
=
yes
if
[
x
$gas
=
xyes
]
;
then
tm_file
=
"
${
tm_file
}
sparc/sun4gas.h"
fi
;;
sparc-
*
-sunos3
*
)
tm_file
=
sparc/sun4o3.h
...
...
gcc/configure.in
View file @
ca55abae
...
...
@@ -2383,6 +2383,9 @@ for machine in $build $host $target; do
tm_file=sparc/sunos4.h
tmake_file=sparc/t-sunos41
use_collect2=yes
if [[ x$gas = xyes ]]; then
tm_file="${tm_file} sparc/sun4gas.h"
fi
;;
sparc-*-sunos3*)
tm_file=sparc/sun4o3.h
...
...
gcc/cp/ChangeLog
View file @
ca55abae
...
...
@@ -36,6 +36,14 @@ Thu Sep 11 10:08:45 1997 Mark Mitchell <mmitchell@usa.net>
(tsubst): Do constant folding as necessary to make sure that
arguments passed to lookup_template_class really are constants.
Wed Sep 10 11:21:55 1997 Jason Merrill <jason@yorick.cygnus.com>
* except.c (expand_builtin_throw): #ifndef DWARF2_UNWIND_INFO.
* decl2.c (finish_file): Only register exception tables if we
need to.
* decl.c (init_decl_processing): Add __builtin_[fs]p.
Tue Sep 9 19:49:38 1997 Jason Merrill <jason@yorick.cygnus.com>
* pt.c (unify): Just return 0 for a TYPENAME_TYPE.
...
...
gcc/cp/decl.c
View file @
ca55abae
...
...
@@ -4725,7 +4725,7 @@ init_decl_processing ()
tree
string_ftype_ptr_ptr
,
int_ftype_string_string
;
tree
sizetype_endlink
;
tree
ptr_ftype
,
ptr_ftype_unsigned
,
ptr_ftype_sizetype
;
tree
void_ftype
,
void_ftype_int
,
void_ftype_ptr
;
tree
void_ftype
,
void_ftype_int
,
void_ftype_ptr
,
ptr_ftype_void
;
/* Have to make these distinct before we try using them. */
lang_name_cplusplus
=
get_identifier
(
"C++"
);
...
...
@@ -5103,6 +5103,10 @@ init_decl_processing ()
builtin_function
(
"__builtin_frame_address"
,
ptr_ftype_unsigned
,
BUILT_IN_FRAME_ADDRESS
,
NULL_PTR
);
ptr_ftype_void
=
build_function_type
(
ptr_type_node
,
endlink
);
builtin_function
(
"__builtin_fp"
,
ptr_ftype_void
,
BUILT_IN_FP
,
NULL_PTR
);
builtin_function
(
"__builtin_sp"
,
ptr_ftype_void
,
BUILT_IN_SP
,
NULL_PTR
);
builtin_function
(
"__builtin_alloca"
,
ptr_ftype_sizetype
,
BUILT_IN_ALLOCA
,
"alloca"
);
builtin_function
(
"__builtin_ffs"
,
int_ftype_int
,
BUILT_IN_FFS
,
NULL_PTR
);
...
...
gcc/emit-rtl.c
View file @
ca55abae
...
...
@@ -3196,6 +3196,7 @@ gen_sequence ()
(Now that we cache SEQUENCE expressions, it isn't worth special-casing
the case of an empty list.) */
if
(
len
==
1
&&
!
RTX_FRAME_RELATED_P
(
first_insn
)
&&
(
GET_CODE
(
first_insn
)
==
INSN
||
GET_CODE
(
first_insn
)
==
JUMP_INSN
/* Don't discard the call usage field. */
...
...
gcc/except.c
View file @
ca55abae
...
...
@@ -87,34 +87,47 @@ Boston, MA 02111-1307, USA. */
exception region, and the address of the handler designated for
that region.
At program startup each object file invokes a function named
If the target does not use the DWARF 2 frame unwind information, at
program startup each object file invokes a function named
__register_exceptions with the address of its local
__EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c,
and is responsible for recording all of the exception regions into
one list (which is kept in a static variable named exception_table_list).
__EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and
is responsible for recording all of the exception regions into one list
(which is kept in a static variable named exception_table_list).
On targets that support crtstuff.c, the unwind information
is stored in a section named .eh_frame and the information for the
entire shared object or program is registered with a call to
__register_frame. On other targets, the information for each
translation unit is registered separately with a static constructor.
__register_frame is defined in frame.c, and is responsible for
recording all of the unwind regions into one list (which is kept in a
static variable named unwind_table_list).
The function __throw is actually responsible for doing the
throw. In the C++ frontend, __throw is generated on a
throw. On machines that have unwind info support, __throw is generated
by code in libgcc2.c, otherwise __throw is generated on a
per-object-file basis for each source file compiled with
-fexceptions. Before __throw is invoked, the current context
of the throw needs to be placed in the global variable __eh_pc.
-fexceptions by the the C++ frontend. Before __throw is invoked,
the current context of the throw needs to be placed in the global
variable __eh_pc.
__throw attempts to find the appropriate exception handler for the
PC value stored in __eh_pc by calling __find_first_exception_table_match
(which is defined in libgcc2.c). If __find_first_exception_table_match
finds a relevant handler, __throw jumps directly to it.
If a handler for the context being thrown from can't be found,
__throw is responsible for unwinding the stack, determining the
address of the caller of the current function (which will be used
as the new context to throw from), and then restarting the process
of searching for a handler for the new context. __throw may also
call abort if it is unable to unwind the stack, and can also
call an external library function named __terminate if it reaches
the top of the stack without finding an appropriate handler. (By
default __terminate invokes abort, but this behavior can be
changed by the user to perform some sort of cleanup behavior before
exiting).
finds a relevant handler, __throw transfers control directly to it.
If a handler for the context being thrown from can't be found, __throw
walks (see Walking the stack below) the stack up the dynamic call chain to
continue searching for an appropriate exception handler based upon the
caller of the function it last sought a exception handler for. It stops
then either an exception handler is found, or when the top of the
call chain is reached.
If no handler is found, an external library function named
__terminate is called. If a handler is found, then we restart
our search for a handler at the end of the call chain, and repeat
the search process, but instead of just walking up the call chain,
we unwind the call chain as we walk up it.
Internal implementation details:
...
...
@@ -231,40 +244,79 @@ Boston, MA 02111-1307, USA. */
incorrect results is better than halting the program.
Unwind
ing the stack:
Walk
ing the stack:
The details of unwinding the stack to the next frame can be rather
complex. While in many cases a generic __unwind_function routine
can be used by the generated exception handling code to do this, it
is often necessary to generate inline code to do the unwinding.
The stack is walked by starting with a pointer to the current
frame, and finding the pointer to the callers frame. The unwind info
tells __throw how to find it.
Whether or not these inlined unwinders are necessary is
target-specific.
Unwinding the stack:
By default, if the target-specific backend doesn't supply a
definition for __unwind_function, inlined unwinders will be used
instead. The main tradeoff here is in text space utilization.
Obviously, if inline unwinders have to be generated repeatedly,
this uses much more space than if a single routine is used.
When we use the term unwinding the stack, we mean undoing the
effects of the function prologue in a controlled fashion so that we
still have the flow of control. Otherwise, we could just return
(jump to the normal end of function epilogue).
This is done in __throw in libgcc2.c when we know that a handler exists
in a frame higher up the call stack than its immediate caller.
To unwind, we find the unwind data associated with the frame, if any.
If we don't find any, we call the library routine __terminate. If we do
find it, we use the information to copy the saved register values from
that frame into the register save area in the frame for __throw, return
into a stub which updates the stack pointer, and jump to the handler.
The normal function epilogue for __throw handles restoring the saved
values into registers.
When unwinding, we use this method if we know it will
work (if DWARF2_UNWIND_INFO is defined). Otherwise, we know that
an inline unwinder will have been emitted for any function that
__unwind_function cannot unwind. The inline unwinder appears as a
normal exception handler for the entire function, for any function
that we know cannot be unwound by __unwind_function. We inform the
compiler of whether a function can be unwound with
__unwind_function by having DOESNT_NEED_UNWINDER evaluate to true
when the unwinder isn't needed. __unwind_function is used as an
action of last resort. If no other method can be used for
unwinding, __unwind_function is used. If it cannot unwind, it
should call __teminate.
By default, if the target-specific backend doesn't supply a definition
for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
unwinders will be used instead. The main tradeoff here is in text space
utilization. Obviously, if inline unwinders have to be generated
repeatedly, this uses much more space than if a single routine is used.
However, it is simply not possible on some platforms to write a
generalized routine for doing stack unwinding without having some
form of additional data associated with each function. The current
implementation encodes this data in the form of additional machine
instructions. This is clearly not desirable, as it is extremely
inefficient. The next implementation will provide a set of metadata
for each function that will provide the needed information.
implementation can encode this data in the form of additional
machine instructions or as static data in tabular form. The later
is called the unwind data.
The backend macro DOESNT_NEED_UNWINDER is used to conditionalize
whether or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER
is defined and has a non-zero value, a per-function unwinder is
not emitted for the current function.
The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether
or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is
defined and has a non-zero value, a per-function unwinder is not emitted
for the current function. If the static unwind data is supported, then
a per-function unwinder is not emitted.
On some platforms it is possible that neither __unwind_function
nor inlined unwinders are available. For these platforms it is not
possible to throw through a function call, and abort will be
invoked instead of performing the throw.
The reason the unwind data may be needed is that on some platforms
the order and types of data stored on the stack can vary depending
on the type of function, its arguments and returned values, and the
compilation options used (optimization versus non-optimization,
-fomit-frame-pointer, processor variations, etc).
Unfortunately, this also means that throwing through functions that
aren't compiled with exception handling support will still not be
possible on some platforms. This problem is currently being
investigated, but no solutions have been found that do not imply
some unacceptable performance penalties.
Future directions:
Currently __throw makes no differentiation between cleanups and
...
...
@@ -309,28 +361,11 @@ Boston, MA 02111-1307, USA. */
query various state variables to determine what actions are to be
performed next.
Another major problem that is being worked on is the issue with
stack unwinding on various platforms. Currently the only platform
that has support for __unwind_function is the Sparc; all other
ports require per-function unwinders, which causes large amounts of
code bloat.
Ideally it would be possible to store a small set of metadata with
each function that would then make it possible to write a
__unwind_function for every platform. This would eliminate the
need for per-function unwinders.
The main reason the data is needed is that on some platforms the
order and types of data stored on the stack can vary depending on
the type of function, its arguments and returned values, and the
compilation options used (optimization versus non-optimization,
-fomit-frame-pointer, processor variations, etc).
Unfortunately, this also means that throwing through functions that
aren't compiled with exception handling support will still not be
possible on some platforms. This problem is currently being
investigated, but no solutions have been found that do not imply
some unacceptable performance penalties.
Another major problem that is being worked on is the issue with stack
unwinding on various platforms. Currently the only platforms that have
support for the generation of a generic unwinder are the SPARC and MIPS.
All other ports require per-function unwinders, which produce large
amounts of code bloat.
For setjmp/longjmp based exception handling, some of the details
are as above, but there are some additional details. This section
...
...
@@ -354,6 +389,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "defaults.h"
#include <stdio.h>
#include "rtl.h"
#include "tree.h"
...
...
@@ -373,7 +409,11 @@ Boston, MA 02111-1307, USA. */
/* One to use setjmp/longjmp method of generating code for exception
handling. */
#if DWARF2_UNWIND_INFO
int
exceptions_via_longjmp
=
0
;
#else
int
exceptions_via_longjmp
=
1
;
#endif
/* One to enable asynchronous exception support. */
...
...
@@ -645,15 +685,12 @@ eh_outer_context (addr)
{
/* First mask out any unwanted bits. */
#ifdef MASK_RETURN_ADDR
expand_binop
(
Pmode
,
and_optab
,
addr
,
MASK_RETURN_ADDR
,
addr
,
1
,
OPTAB_LIB_WIDEN
);
expand_and
(
addr
,
MASK_RETURN_ADDR
,
addr
);
#endif
/* Then subtract out enough to get into the appropriate region. If
this is defined, assume we don't need to subtract anything as it
is already within the correct region. */
#if ! defined (RETURN_ADDR_OFFSET)
addr
=
plus_constant
(
addr
,
-
1
);
/* Then adjust to find the real return address. */
#if defined (RETURN_ADDR_OFFSET)
addr
=
plus_constant
(
addr
,
RETURN_ADDR_OFFSET
);
#endif
return
addr
;
...
...
@@ -1107,7 +1144,10 @@ emit_throw ()
#ifdef JUMP_TO_THROW
emit_indirect_jump
(
throw_libfunc
);
#else
#ifndef DWARF2_UNWIND_INFO
/* Prevent assemble_external from doing anything with this symbol. */
SYMBOL_REF_USED
(
throw_libfunc
)
=
1
;
#endif
emit_library_call
(
throw_libfunc
,
0
,
VOIDmode
,
0
);
#endif
throw_used
=
1
;
...
...
@@ -1446,10 +1486,8 @@ add_eh_table_entry (n)
if
(
eh_table_max_size
<
0
)
abort
();
if
((
eh_table
=
(
int
*
)
realloc
(
eh_table
,
eh_table_max_size
*
sizeof
(
int
)))
==
0
)
fatal
(
"virtual memory exhausted"
);
eh_table
=
(
int
*
)
xrealloc
(
eh_table
,
eh_table_max_size
*
sizeof
(
int
));
}
else
{
...
...
@@ -1475,6 +1513,18 @@ exception_table_p ()
return
0
;
}
/* 1 if we need a static constructor to register EH table info. */
int
register_exception_table_p
()
{
#if defined (DWARF2_UNWIND_INFO)
return
0
;
#endif
return
exception_table_p
();
}
/* Output the entry of the exception table corresponding to to the
exception region numbered N to file FILE.
...
...
@@ -1512,7 +1562,7 @@ output_exception_table ()
int
i
;
extern
FILE
*
asm_out_file
;
if
(
!
doing_eh
(
0
))
if
(
!
doing_eh
(
0
)
||
!
eh_table
)
return
;
exception_section
();
...
...
@@ -1521,11 +1571,6 @@ output_exception_table ()
assemble_align
(
GET_MODE_ALIGNMENT
(
ptr_mode
));
assemble_label
(
"__EXCEPTION_TABLE__"
);
assemble_integer
(
const0_rtx
,
POINTER_SIZE
/
BITS_PER_UNIT
,
1
);
assemble_integer
(
const0_rtx
,
POINTER_SIZE
/
BITS_PER_UNIT
,
1
);
assemble_integer
(
const0_rtx
,
POINTER_SIZE
/
BITS_PER_UNIT
,
1
);
putc
(
'\n'
,
asm_out_file
);
/* blank line */
for
(
i
=
0
;
i
<
eh_table_size
;
++
i
)
output_exception_table_entry
(
asm_out_file
,
eh_table
[
i
]);
...
...
@@ -1572,6 +1617,10 @@ start_eh_unwinder ()
if
(
exceptions_via_longjmp
)
return
;
#ifdef DWARF2_UNWIND_INFO
return
;
#endif
expand_eh_region_start
();
}
...
...
@@ -1598,6 +1647,10 @@ end_eh_unwinder ()
if
(
exceptions_via_longjmp
)
return
;
#ifdef DWARF2_UNWIND_INFO
return
;
#else
/* DWARF2_UNWIND_INFO */
assemble_external
(
eh_saved_pc
);
expr
=
make_node
(
RTL_EXPR
);
...
...
@@ -1658,6 +1711,7 @@ end_eh_unwinder ()
emit_barrier
();
}
#endif
#endif
/* DWARF2_UNWIND_INFO */
}
/* If necessary, emit insns for the per function unwinder for the
...
...
@@ -2101,3 +2155,158 @@ exception_optimize ()
}
}
}
/* Various hooks for the DWARF 2 __throw routine. */
/* Do any necessary initialization to access arbitrary stack frames.
On the SPARC, this means flushing the register windows. */
void
expand_builtin_unwind_init
()
{
/* Set this so all the registers get saved in our frame; we need to be
able to copy the saved values for any registers from frames we unwind. */
current_function_has_nonlocal_label
=
1
;
#ifdef SETUP_FRAME_ADDRESSES
SETUP_FRAME_ADDRESSES
();
#endif
}
/* Given a value extracted from the return address register or stack slot,
return the actual address encoded in that value. */
rtx
expand_builtin_extract_return_addr
(
addr_tree
)
tree
addr_tree
;
{
rtx
addr
=
expand_expr
(
addr_tree
,
NULL_RTX
,
Pmode
,
0
);
return
eh_outer_context
(
addr
);
}
/* Given an actual address in addr_tree, do any necessary encoding
and return the value to be stored in the return address register or
stack slot so the epilogue will return to that address. */
rtx
expand_builtin_frob_return_addr
(
addr_tree
)
tree
addr_tree
;
{
rtx
addr
=
expand_expr
(
addr_tree
,
NULL_RTX
,
Pmode
,
0
);
#ifdef RETURN_ADDR_OFFSET
addr
=
plus_constant
(
addr
,
-
RETURN_ADDR_OFFSET
);
#endif
return
addr
;
}
/* Given an actual address in addr_tree, set the return address register up
so the epilogue will return to that address. If the return address is
not in a register, do nothing. */
void
expand_builtin_set_return_addr_reg
(
addr_tree
)
tree
addr_tree
;
{
rtx
ra
=
expand_builtin_return_addr
(
BUILT_IN_RETURN_ADDRESS
,
0
,
hard_frame_pointer_rtx
);
if
(
GET_CODE
(
ra
)
!=
REG
||
REGNO
(
ra
)
>=
FIRST_PSEUDO_REGISTER
)
return
;
emit_move_insn
(
ra
,
expand_builtin_frob_return_addr
(
addr_tree
));
}
/* Choose two registers for communication between the main body of
__throw and the stub for adjusting the stack pointer. The first register
is used to pass the address of the exception handler; the second register
is used to pass the stack pointer offset.
For register 1 we use the return value register for a void *.
For register 2 we use the static chain register if it exists and is
different from register 1, otherwise some arbitrary call-clobbered
register. */
static
void
eh_regs
(
r1
,
r2
,
outgoing
)
rtx
*
r1
,
*
r2
;
int
outgoing
;
{
rtx
reg1
,
reg2
;
#ifdef FUNCTION_OUTGOING_VALUE
if
(
outgoing
)
reg1
=
FUNCTION_OUTGOING_VALUE
(
build_pointer_type
(
void_type_node
),
current_function_decl
);
else
#endif
reg1
=
FUNCTION_VALUE
(
build_pointer_type
(
void_type_node
),
current_function_decl
);
#ifdef STATIC_CHAIN_REGNUM
if
(
outgoing
)
reg2
=
static_chain_incoming_rtx
;
else
reg2
=
static_chain_rtx
;
if
(
REGNO
(
reg2
)
==
REGNO
(
reg1
))
#endif
/* STATIC_CHAIN_REGNUM */
reg2
=
NULL_RTX
;
if
(
reg2
==
NULL_RTX
)
{
int
i
;
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
++
i
)
if
(
call_used_regs
[
i
]
&&
!
fixed_regs
[
i
]
&&
i
!=
REGNO
(
reg1
))
{
reg2
=
gen_rtx
(
REG
,
Pmode
,
i
);
break
;
}
if
(
reg2
==
NULL_RTX
)
abort
();
}
*
r1
=
reg1
;
*
r2
=
reg2
;
}
/* Emit inside of __throw a stub which adjusts the stack pointer and jumps
to the exception handler. __throw will set up the necessary values
and then return to the stub. */
rtx
expand_builtin_eh_stub
()
{
rtx
stub_start
=
gen_label_rtx
();
rtx
after_stub
=
gen_label_rtx
();
rtx
handler
,
offset
,
temp
;
emit_jump
(
after_stub
);
emit_label
(
stub_start
);
eh_regs
(
&
handler
,
&
offset
,
0
);
adjust_stack
(
offset
);
emit_indirect_jump
(
handler
);
emit_label
(
after_stub
);
return
gen_rtx
(
LABEL_REF
,
Pmode
,
stub_start
);
}
/* Set up the registers for passing the handler address and stack offset
to the stub above. */
void
expand_builtin_set_eh_regs
(
handler
,
offset
)
tree
handler
,
offset
;
{
rtx
reg1
,
reg2
;
eh_regs
(
&
reg1
,
&
reg2
,
1
);
store_expr
(
offset
,
reg2
,
0
);
store_expr
(
handler
,
reg1
,
0
);
/* These will be used by the stub. */
emit_insn
(
gen_rtx
(
USE
,
VOIDmode
,
reg1
));
emit_insn
(
gen_rtx
(
USE
,
VOIDmode
,
reg2
));
}
gcc/expr.c
View file @
ca55abae
...
...
@@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA. */
#include "recog.h"
#include "output.h"
#include "typeclass.h"
#include "defaults.h"
#include "bytecode.h"
#include "bc-opcode.h"
...
...
@@ -7997,6 +7998,7 @@ expand_builtin_return_addr (fndecl_code, count, tem)
arbitrary frames. For example, on the sparc, we must first flush
all register windows to the stack. */
#ifdef SETUP_FRAME_ADDRESSES
if
(
count
>
0
)
SETUP_FRAME_ADDRESSES
();
#endif
...
...
@@ -9137,6 +9139,32 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return
const0_rtx
;
}
/* Various hooks for the DWARF 2 __throw routine. */
case
BUILT_IN_UNWIND_INIT
:
expand_builtin_unwind_init
();
return
const0_rtx
;
case
BUILT_IN_FP
:
return
frame_pointer_rtx
;
case
BUILT_IN_SP
:
return
stack_pointer_rtx
;
#ifdef DWARF2_UNWIND_INFO
case
BUILT_IN_DWARF_FP_REGNUM
:
return
expand_builtin_dwarf_fp_regnum
();
#endif
case
BUILT_IN_FROB_RETURN_ADDR
:
return
expand_builtin_frob_return_addr
(
TREE_VALUE
(
arglist
));
case
BUILT_IN_EXTRACT_RETURN_ADDR
:
return
expand_builtin_extract_return_addr
(
TREE_VALUE
(
arglist
));
case
BUILT_IN_SET_RETURN_ADDR_REG
:
expand_builtin_set_return_addr_reg
(
TREE_VALUE
(
arglist
));
return
const0_rtx
;
case
BUILT_IN_EH_STUB
:
return
expand_builtin_eh_stub
();
case
BUILT_IN_SET_EH_REGS
:
expand_builtin_set_eh_regs
(
TREE_VALUE
(
arglist
),
TREE_VALUE
(
TREE_CHAIN
(
arglist
)));
return
const0_rtx
;
default
:
/* just do library call, if unknown builtin */
error
(
"built-in function `%s' not currently supported"
,
IDENTIFIER_POINTER
(
DECL_NAME
(
fndecl
)));
...
...
gcc/libgcc2.c
View file @
ca55abae
...
...
@@ -3107,11 +3107,9 @@ int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
#ifdef L_eh
#ifdef EH_TABLE_LOOKUP
EH_TABLE_LOOKUP
/* Shared exception handling support routines. */
#else
extern
void
*
__eh_type
;
void
__default_terminate
()
...
...
@@ -3127,14 +3125,31 @@ __terminate ()
(
*
__terminate_func
)();
}
void
*
__throw_type_match
(
void
*
catch_type
,
void
*
throw_type
,
void
*
obj
)
{
#if 0
printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
catch_type, throw_type);
#endif
if
(
strcmp
((
const
char
*
)
catch_type
,
(
const
char
*
)
throw_type
)
==
0
)
return
obj
;
return
0
;
}
void
__empty
()
{
}
/* Support routines for setjmp/longjmp exception handling. */
/* Calls to __sjthrow are generated by the compiler when an exception
is raised when using the setjmp/longjmp exception handling codegen
method. */
extern
void
longjmp
(
void
*
,
int
);
void
*
__eh_type
;
static
void
*
top_elt
[
2
];
void
**
__dynamic_handler_chain
=
top_elt
;
...
...
@@ -3287,119 +3302,103 @@ __sjpopnthrow ()
__sjthrow
();
}
typedef
struct
{
void
*
start
;
void
*
end
;
void
*
exception_handler
;
}
exception_table
;
/* Support code for all exception region-based exception handling. */
struct
exception_table_node
{
exception_table
*
table
;
void
*
start
;
void
*
end
;
struct
exception_table_node
*
next
;
};
/* This value identifies the place from which an exception is being
thrown. */
static
struct
exception_table_node
*
exception_table_list
;
extern
void
*
__eh_pc
;
/* this routine takes a pc, and the address of the exception handler associated
with the closest exception table handler entry associated with that PC,
or 0 if there are no table entries the PC fits in. The algorithm works
something like this:
#ifdef EH_TABLE_LOOKUP
while(current_entry exists) {
if(current_entry.start < pc )
current_entry = next_entry;
else {
if(prev_entry.start <= pc && prev_entry.end > pc) {
save pointer to prev_entry;
return prev_entry.exception_handler;
}
else return 0;
}
}
return 0;
EH_TABLE_LOOKUP
#else
Assuming a correctly sorted table (ascending order) this routine should
return the tightest match...
typedef
struct
exception_table
{
void
*
start
;
void
*
end
;
void
*
exception_handler
;
}
exception_table
;
/* This routine takes a PC and a pointer to the exception region TABLE for
its translation unit, and returns the address of the exception handler
associated with the closest exception table handler entry associated
with that PC, or 0 if there are no table entries the PC fits in.
In the advent of a tie, we have to give the last entry, as it represents
an inner block. */
void
*
__find_first_exception_table_match
(
void
*
pc
)
static
void
*
find_exception_handler
(
void
*
pc
,
exception_table
*
table
)
{
register
struct
exception_table_node
*
tnp
;
register
exception_table
*
table
;
int
pos
;
int
best
;
#if 0
printf ("find_first_exception_table_match (): pc = %x!\n", pc);
#endif
for
(
tnp
=
exception_table_list
;
tnp
!=
0
;
tnp
=
tnp
->
next
)
if
(
table
)
{
if
(
tnp
->
start
>
pc
||
tnp
->
end
<=
pc
)
continue
;
table
=
tnp
->
table
;
pos
=
0
;
best
=
0
;
#if 0
/* We can't do this yet, as we don't know that the table is sorted. */
do {
++pos;
if (table[pos].start > pc)
/* found the first table[pos].start > pc, so the previous
entry better be the one we want! */
break;
} while (table[pos].exception_handler != (void *) -1);
int
pos
;
int
best
=
0
;
--pos;
if (table[pos].start <= pc && table[pos].end > pc)
/* We can't do a binary search because the table isn't guaranteed
to be sorted from function to function. */
for
(
pos
=
0
;
table
[
pos
].
exception_handler
!=
(
void
*
)
-
1
;
++
pos
)
{
#if 0
printf ("find_first_eh_table_match (): found match: %x\n", table[pos].exception_handler);
#endif
return table[pos].exception_handler;
}
#else
while
(
table
[
++
pos
].
exception_handler
!=
(
void
*
)
-
1
)
{
if
(
table
[
pos
].
start
<=
pc
&&
table
[
pos
].
end
>
pc
)
if
(
table
[
pos
].
start
<=
pc
&&
table
[
pos
].
end
>=
pc
)
{
/* This can apply. Make sure it is better or as good
as
/* This can apply. Make sure it is at least as small
as
the previous best. */
/* The best one ends first. */
if
(
best
==
0
||
(
table
[
pos
].
end
<=
table
[
best
].
end
/* The best one starts last. */
&&
table
[
pos
].
start
>=
table
[
best
].
start
))
best
=
pos
;
}
/* But it is sorted by starting PC within a function. */
else
if
(
best
&&
table
[
pos
].
start
>
pc
)
break
;
}
if
(
best
!=
0
)
return
table
[
best
].
exception_handler
;
#endif
}
#if 0
printf ("find_first_eh_table_match (): else: returning NULL!\n");
#endif
return
(
void
*
)
0
;
}
#endif
/* EH_TABLE_LOOKUP */
#ifndef DWARF2_UNWIND_INFO
/* Support code for exception handling using inline unwinders or
__unwind_function. */
#ifndef EH_TABLE_LOOKUP
typedef
struct
exception_table_node
{
exception_table
*
table
;
void
*
start
;
void
*
end
;
struct
exception_table_node
*
next
;
}
exception_table_node
;
static
struct
exception_table_node
*
exception_table_list
;
void
*
__find_first_exception_table_match
(
void
*
pc
)
{
register
exception_table_node
*
tnp
;
for
(
tnp
=
exception_table_list
;
tnp
!=
0
;
tnp
=
tnp
->
next
)
{
if
(
tnp
->
start
<=
pc
&&
tnp
->
end
>=
pc
)
return
find_exception_handler
(
pc
,
tnp
->
table
);
}
return
(
void
*
)
0
;
}
void
__register_exceptions
(
exception_table
*
table
)
{
struct
exception_table_node
*
node
;
exception_table_node
*
node
;
exception_table
*
range
=
table
+
1
;
if
(
range
->
start
==
(
void
*
)
-
1
)
return
;
node
=
(
struct
exception_table_node
*
)
malloc
(
sizeof
(
struct
exception_table_node
));
node
=
(
exception_table_node
*
)
malloc
(
sizeof
(
exception_table_node
));
node
->
table
=
table
;
/* This look can be optimized away either if the table
...
...
@@ -3417,19 +3416,7 @@ __register_exceptions (exception_table *table)
node
->
next
=
exception_table_list
;
exception_table_list
=
node
;
}
#endif
void
*
__throw_type_match
(
void
*
catch_type
,
void
*
throw_type
,
void
*
obj
)
{
#if 0
printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
catch_type, throw_type);
#endif
if
(
strcmp
((
const
char
*
)
catch_type
,
(
const
char
*
)
throw_type
)
==
0
)
return
obj
;
return
0
;
}
#endif
/* !EH_TABLE_LOOKUP */
/* Throw stub routine.
...
...
@@ -3441,11 +3428,6 @@ __throw ()
abort
();
}
/* This value identifies the place from which an exception is being
thrown. */
void
*
__eh_pc
;
/* See expand_builtin_throw for details. */
void
**
__eh_pcnthrow
()
{
...
...
@@ -3456,11 +3438,6 @@ void **__eh_pcnthrow () {
return
buf
;
}
void
__empty
()
{
}
#if #machine(i386)
void
__unwind_function
(
void
*
ptr
)
...
...
@@ -3539,6 +3516,267 @@ __unwind_function(void *ptr)
abort
();
}
#endif
/* powerpc */
#else
/* DWARF2_UNWIND_INFO */
/* Support code for exception handling using static unwind information. */
#include "frame.h"
/* This type is used in get_reg and put_reg to deal with ABIs where a void*
is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
avoid a warning about casting between int and pointer of different
sizes. */
typedef
int
ptr_type
__attribute__
((
mode
(
pointer
)));
/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
static
void
*
get_reg
(
unsigned
reg
,
frame_state
*
udata
,
frame_state
*
sub_udata
)
{
if
(
udata
->
saved
[
reg
]
==
REG_SAVED_OFFSET
)
return
(
void
*
)(
ptr_type
)
*
(
word_type
*
)(
udata
->
cfa
+
udata
->
reg_or_offset
[
reg
]);
else
if
(
udata
->
saved
[
reg
]
==
REG_SAVED_REG
&&
sub_udata
)
return
get_reg
(
udata
->
reg_or_offset
[
reg
],
sub_udata
,
0
);
else
abort
();
}
/* Overwrite the saved value for register REG in frame UDATA with VAL. */
static
void
put_reg
(
unsigned
reg
,
void
*
val
,
frame_state
*
udata
)
{
if
(
udata
->
saved
[
reg
]
==
REG_SAVED_OFFSET
)
*
(
word_type
*
)(
udata
->
cfa
+
udata
->
reg_or_offset
[
reg
])
=
(
word_type
)(
ptr_type
)
val
;
else
abort
();
}
/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
static
inline
void
*
get_return_addr
(
frame_state
*
udata
,
frame_state
*
sub_udata
)
{
return
__builtin_extract_return_addr
(
get_reg
(
udata
->
retaddr_column
,
udata
,
sub_udata
));
}
/* Overwrite the return address for frame UDATA with VAL. */
static
inline
void
put_return_addr
(
void
*
val
,
frame_state
*
udata
)
{
val
=
__builtin_frob_return_addr
(
val
);
put_reg
(
udata
->
retaddr_column
,
val
,
udata
);
}
/* Given the current frame UDATA and its return address PC, return the
information about the calling frame in CALLER_UDATA. */
static
void
*
next_stack_level
(
void
*
pc
,
frame_state
*
udata
,
frame_state
*
caller_udata
)
{
caller_udata
=
__frame_state_for
(
pc
,
caller_udata
);
if
(
!
caller_udata
)
return
0
;
/* Now go back to our caller's stack frame. If our caller's CFA register
was saved in our stack frame, restore it; otherwise, assume the CFA
register is SP and restore it to our CFA value. */
if
(
udata
->
saved
[
caller_udata
->
cfa_reg
])
caller_udata
->
cfa
=
get_reg
(
caller_udata
->
cfa_reg
,
udata
,
0
);
else
caller_udata
->
cfa
=
udata
->
cfa
;
caller_udata
->
cfa
+=
caller_udata
->
cfa_offset
;
return
caller_udata
;
}
#ifdef INCOMING_REGNO
/* Is the saved value for register REG in frame UDATA stored in a register
window in the previous frame? */
static
int
in_reg_window
(
int
reg
,
frame_state
*
udata
)
{
if
(
udata
->
saved
[
reg
]
!=
REG_SAVED_OFFSET
)
return
0
;
#ifdef STACK_GROWS_DOWNWARD
return
udata
->
reg_or_offset
[
reg
]
>
0
;
#else
return
udata
->
reg_or_offset
[
reg
]
<
0
;
#endif
}
#endif
/* INCOMING_REGNO */
/* We first search for an exception handler, and if we don't find
it, we call __terminate on the current stack frame so that we may
use the debugger to walk the stack and understand why no handler
was found.
If we find one, then we unwind the frames down to the one that
has the handler and transfer control into the handler. */
void
__throw
()
{
void
*
pc
,
*
handler
,
*
retaddr
;
frame_state
ustruct
,
ustruct2
;
frame_state
*
udata
=
&
ustruct
;
frame_state
*
sub_udata
=
&
ustruct2
;
frame_state
my_ustruct
,
*
my_udata
=
&
my_ustruct
;
long
args_size
;
/* 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_type
)
__terminate
();
/* Start at our stack frame. */
label:
udata
=
__frame_state_for
(
&&
label
,
udata
);
if
(
!
udata
)
__terminate
();
/* We need to get the value from the CFA register. At this point in
compiling __throw we don't know whether or not we will use the frame
pointer register for the CFA, so we check our unwind info. */
if
(
udata
->
cfa_reg
==
__builtin_dwarf_fp_regnum
())
udata
->
cfa
=
__builtin_fp
();
else
udata
->
cfa
=
__builtin_sp
();
udata
->
cfa
+=
udata
->
cfa_offset
;
memcpy
(
my_udata
,
udata
,
sizeof
(
*
udata
));
/* Do any necessary initialization to access arbitrary stack frames.
On the SPARC, this means flushing the register windows. */
__builtin_unwind_init
();
/* Now reset pc to the right throw point. */
pc
=
__eh_pc
;
for
(;;)
{
frame_state
*
p
=
udata
;
udata
=
next_stack_level
(
pc
,
udata
,
sub_udata
);
sub_udata
=
p
;
/* If we couldn't find the next frame, we lose. */
if
(
!
udata
)
break
;
handler
=
find_exception_handler
(
pc
,
udata
->
eh_ptr
);
/* If we found one, we can stop searching. */
if
(
handler
)
{
args_size
=
udata
->
args_size
;
break
;
}
/* Otherwise, we continue searching. */
pc
=
get_return_addr
(
udata
,
sub_udata
);
}
/* If we haven't found a handler by now, this is an unhandled
exception. */
if
(
!
handler
)
__terminate
();
if
(
pc
==
__eh_pc
)
/* We found a handler in the throw context, no need to unwind. */
udata
=
my_udata
;
else
{
int
i
;
void
*
val
;
/* Unwind all the frames between this one and the handler by copying
their saved register values into our register save slots. */
/* Remember the PC where we found the handler. */
void
*
handler_pc
=
pc
;
/* Start from the throw context again. */
pc
=
__eh_pc
;
memcpy
(
udata
,
my_udata
,
sizeof
(
*
udata
));
while
(
pc
!=
handler_pc
)
{
frame_state
*
p
=
udata
;
udata
=
next_stack_level
(
pc
,
udata
,
sub_udata
);
sub_udata
=
p
;
for
(
i
=
0
;
i
<
FIRST_PSEUDO_REGISTER
;
++
i
)
if
(
udata
->
saved
[
i
])
{
#ifdef INCOMING_REGNO
/* If you modify the saved value of the return address
register on the SPARC, you modify the return address for
your caller's frame. Don't do that here, as it will
confuse get_return_addr. */
if
(
in_reg_window
(
i
,
udata
)
&&
udata
->
saved
[
udata
->
retaddr_column
]
==
REG_SAVED_REG
&&
udata
->
reg_or_offset
[
udata
->
retaddr_column
]
==
i
)
continue
;
#endif
val
=
get_reg
(
i
,
udata
,
sub_udata
);
put_reg
(
i
,
val
,
my_udata
);
}
pc
=
get_return_addr
(
udata
,
sub_udata
);
}
#ifdef INCOMING_REGNO
/* But we do need to update the saved return address register from
the last frame we unwind, or the handler frame will have the wrong
return address. */
if
(
udata
->
saved
[
udata
->
retaddr_column
]
==
REG_SAVED_REG
)
{
i
=
udata
->
reg_or_offset
[
udata
->
retaddr_column
];
if
(
in_reg_window
(
i
,
udata
))
{
val
=
get_reg
(
i
,
udata
,
sub_udata
);
put_reg
(
i
,
val
,
my_udata
);
}
}
#endif
}
/* udata now refers to the frame called by the handler frame. */
/* Emit the stub to adjust sp and jump to the handler. */
retaddr
=
__builtin_eh_stub
();
/* And then set our return address to point to the stub. */
if
(
my_udata
->
saved
[
my_udata
->
retaddr_column
]
==
REG_SAVED_OFFSET
)
put_return_addr
(
retaddr
,
my_udata
);
else
__builtin_set_return_addr_reg
(
retaddr
);
/* Set up the registers we use to communicate with the stub.
We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
__builtin_set_eh_regs
(
handler
,
#ifdef STACK_GROWS_DOWNWARD
udata
->
cfa
-
my_udata
->
cfa
#else
my_udata
->
cfa
-
udata
->
cfa
#endif
+
args_size
);
/* Epilogue: restore the handler frame's register values and return
to the stub. */
}
#endif
/* !DWARF2_UNWIND_INFO */
#endif
/* L_eh */
#ifdef L_pure
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment