OSDN Git Service

dwarf2 EH support
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 16 Sep 1997 02:07:50 +0000 (02:07 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 16 Sep 1997 02:07:50 +0000 (02:07 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@15464 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/configure
gcc/configure.in
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/emit-rtl.c
gcc/except.c
gcc/expr.c
gcc/libgcc2.c

index a6daaa8..ca793d5 100644 (file)
@@ -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.
index 30dbf0f..985cbd5 100644 (file)
@@ -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 = -g1
+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,35 +976,31 @@ 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 \
-           name=`echo $${file} | sed -e 's/[.][cSo]$$//' -e 's/[.]asm$$//' -e 's/[.]txt$$//'`; \
-           oname=` echo $${name} | sed -e 's,.*/,,'`; \
-           if [ $${name}.txt = $${file} ]; then \
-             for f in .. `cat $${file}`; do if [ x$${f} != x.. ]; then \
-               $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
-                 AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" \
-                 CFLAGS="$(CFLAGS)" HOST_PREFIX="$(HOST_PREFIX)" \
-                 HOST_PREFIX_1="$(HOST_PREFIX_1)" \
-                 LANGUAGES="$(LANGUAGES)" \
-                 LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $${f}; \
-               if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
-               $(AR) $(AR_FLAGS) tmplibgcc2.a $${f}; \
-               rm -f $${f}; \
-             else true; \
-             fi; done; \
-           else \
-             echo $${name}; \
-             if [ $${name}.asm = $${file} ]; then \
-               cp $${file} $${name}.s || exit 1; file=$${name}.s; \
-             else true; fi; \
-             $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \
+       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 \
+           for f in .. `cat $${file}`; do if [ x$${f} != x.. ]; then \
+             $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
+               AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" \
+               CFLAGS="$(CFLAGS)" HOST_PREFIX="$(HOST_PREFIX)" \
+               HOST_PREFIX_1="$(HOST_PREFIX_1)" \
+               LANGUAGES="$(LANGUAGES)" \
+               LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $${f}; \
              if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
-             $(AR) $(AR_FLAGS) tmplibgcc2.a $${oname}$(objext); \
-             rm -f $${name}.s $${oname}$(objext); \
-           fi; \
-         else true; \
+             $(AR) $(AR_FLAGS) tmplibgcc2.a $${f}; \
+             rm -f $${f}; \
+           else true; \
+           fi; done; \
+         else \
+           echo $${name}; \
+           if [ $${name}.asm = $${file} ]; then \
+             cp $${file} $${name}.s || exit 1; file=$${name}.s; \
+           else true; fi; \
+           $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c $${file}; \
+           if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
+           $(AR) $(AR_FLAGS) tmplibgcc2.a $${oname}$(objext); \
+           rm -f $${name}.s $${oname}$(objext); \
          fi; \
        done
        mv tmplibgcc2.a libgcc2.a
@@ -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
index 9e7f889..1327881 100755 (executable)
@@ -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
index 27d562b..7964949 100644 (file)
@@ -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
index 82cd0b6..4873ed6 100644 (file)
@@ -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.
index 8527080..446befb 100644 (file)
@@ -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);
index cc2834b..234b6f5 100644 (file)
@@ -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.  */
index 1e77fd8..47cae20 100644 (file)
@@ -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.
 
 
-   Unwinding the stack:
+   Walking 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.
+   form of additional data associated with each function.  The current
+   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 ()
        }
     }
 }
+\f
+/* 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));
+}
index 954cce4..640bc8f 100644 (file)
@@ -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,7 +7998,8 @@ 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
-  SETUP_FRAME_ADDRESSES ();
+  if (count > 0)
+    SETUP_FRAME_ADDRESSES ();
 #endif
 
   /* On the sparc, the return address is not in the frame, it is in a
@@ -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)));
index 0e9252e..26a0e05 100644 (file)
@@ -3107,11 +3107,9 @@ int _exit_dummy_decl = 0;        /* prevent compiler & linker warnings */
 \f
 #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 ()
+{
+}
+\f
+/* 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;
 
@@ -3286,120 +3301,104 @@ __sjpopnthrow ()
 
   __sjthrow ();
 }
+\f
+/* Support code for all exception region-based exception handling.  */
+
+/* This value identifies the place from which an exception is being
+   thrown.  */
+
+extern void *__eh_pc;
+
+#ifdef EH_TABLE_LOOKUP
+
+EH_TABLE_LOOKUP
 
-typedef struct {
+#else
+
+typedef struct exception_table {
   void *start;
   void *end;
   void *exception_handler;
 } exception_table;
 
-struct exception_table_node {
+/* 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.  */
+
+static void *
+find_exception_handler (void *pc, exception_table *table)
+{
+  if (table)
+    {
+      int pos;
+      int best = 0;
+
+      /* 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 (table[pos].start <= pc && table[pos].end >= pc)
+           {
+             /* This can apply.  Make sure it is at least as small as
+                the previous best.  */
+             if (best == 0 || (table[pos].end <= table[best].end
+                               && 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;
+    }
+
+  return (void *) 0;
+}
+#endif /* EH_TABLE_LOOKUP */
+\f
+#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;
 
-/* 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:
-
-    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;
-
-   Assuming a correctly sorted table (ascending order) this routine should
-   return the tightest match...
-
-   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)
 {
-  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
+  register exception_table_node *tnp;
 
   for (tnp = exception_table_list; tnp != 0; tnp = tnp->next)
     {
-      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);
-
-      --pos;
-      if (table[pos].start <= pc && table[pos].end > pc)
-       {
-#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)
-         {
-           /* This can apply.  Make sure it is better or as good 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;
-         }
-      }
-      if (best != 0)
-       return table[best].exception_handler;
-#endif
+      if (tnp->start <= pc && tnp->end >= pc)
+       return find_exception_handler (pc, tnp->table);
     }
 
-#if 0
-  printf ("find_first_eh_table_match (): else: returning NULL!\n");
-#endif
   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 */
+\f
+#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 */
 \f
 #ifdef L_pure