This is the mail archive of the libc-alpha@sources.redhat.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH: The gcc v2/v3 frame unwinder for glibc.


This patch puts the gcc v2/v3 frame unwinder in glibc. It is based
on the patched frame unwinders in gcc 2.9x and 3.0:

http://gcc.gnu.org/ml/gcc/2001-07/msg00577.html
http://gcc.gnu.org/ml/gcc/2001-07/msg00584.html
http://gcc.gnu.org/ml/gcc/2001-07/msg00622.html

I have built glibc with gcc 2.95, gcc 2.96 and gcc 3.0.1. They
seem to work fine with the C++ DSO compiled with gcc 2.96 against
glibc compiled with gcc 2.96:

# nm libbar.so | grep _frame
                 w __deregister_frame_info@@GLIBC_2.0
                 U __frame_state_for@@GLIBC_2.0
                 w __register_frame_info@@GLIBC_2.0

and the C++ DSO compiled with gcc 3.0.1 against glibc compiled with gcc
3.0.1:

# nm libbar.so | grep _frame
                 w __deregister_frame_info@@GLIBC_2.0
                 w __deregister_frame_info_bases@@GCC_3.0
                 w __register_frame_info@@GLIBC_2.0
                 w __register_frame_info_bases@@GCC_3.0


H.J.
----
2001-07-09  H.J. Lu  <hjl@gnu.org>

	* Versions.def (libc): Add GCC_3.0.

	* config.make.in (FRAME-UNWINDER-V2): New. Substitute by
	@libc_cv_frame_unwinder_v2@.
	
	* configure.in (libc_cv_frame_unwinder_v2): Set according to
	the gcc compiler version.
	* configure: Regenerated.

	* sysdeps/unix/sysv/linux/Versions (libc): Add _Unwind_Find_FDE,
	__register_frame_info_bases, __deregister_frame_info_bases and
	__register_frame_info_table_bases to version GCC_3.0.

	* sysdeps/generic/dwarf2.h: New file.
	* sysdeps/generic/frame-dwarf2.c: Likewise.
	* sysdeps/generic/frame.c: Likewise.
	* sysdeps/generic/unwind-dw2-fde.c: Likewise.
	* sysdeps/generic/unwind-dw2-fde.h: Likewise.
	* sysdeps/generic/unwind-dw2.c: Likewise.
	* sysdeps/generic/unwind-pe.h: Likewise.
	* sysdeps/generic/unwind.h: Likewise.
	* sysdeps/alpha/gccframe.h: Likewise.
	* sysdeps/arm/gccframe.h: Likewise.
	* sysdeps/i386/gccframe.h: Likewise.
	* sysdeps/m68k/gccframe.h: Likewise.
	* sysdeps/mips/gccframe.h: Likewise.
	* sysdeps/powerpc/gccframe.h: Likewise.
	* sysdeps/s390/s390-32/gccframe.h: Likewise.
	* sysdeps/sparc/gccframe.h: Likewise.

	* sysdeps/generic/gccframe.h: Updated.

	* sysdeps/unix/sysv/linux/alpha/Makefile (sysdep_routines): Add
	$(FRAME-UNWINDER-V2), unwind-dw2 and unwind-dw2-fde for elf if
	$(build-shared) is yes.
	(shared-only-routines): Likewise.
	* sysdeps/unix/sysv/linux/arm/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/i386/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/mips/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/sparc/Makefile: Likewise.

2001-07-09  H.J. Lu  <hjl@gnu.org>

	* Versions.def (libc): Add GCC_3.0.

	* config.make.in (FRAME-UNWINDER-V2): New. Substitute by
	@libc_cv_frame_unwinder_v2@.
	
	* configure.in (libc_cv_frame_unwinder_v2): Set according to
	the gcc compiler version.
	* configure: Regenerated.

	* sysdeps/unix/sysv/linux/Versions (libc): Add _Unwind_Find_FDE,
	__register_frame_info_bases, __deregister_frame_info_bases and
	__register_frame_info_table_bases to version GCC_3.0.

	* sysdeps/generic/dwarf2.h: New file.
	* sysdeps/generic/frame-dwarf2.c: Likewise.
	* sysdeps/generic/frame.c: Likewise.
	* sysdeps/generic/unwind-dw2-fde.c: Likewise.
	* sysdeps/generic/unwind-dw2-fde.h: Likewise.
	* sysdeps/generic/unwind-dw2.c: Likewise.
	* sysdeps/generic/unwind-pe.h: Likewise.
	* sysdeps/generic/unwind.h: Likewise.
	* sysdeps/alpha/gccframe.h: Likewise.
	* sysdeps/arm/gccframe.h: Likewise.
	* sysdeps/i386/gccframe.h: Likewise.
	* sysdeps/m68k/gccframe.h: Likewise.
	* sysdeps/mips/gccframe.h: Likewise.
	* sysdeps/powerpc/gccframe.h: Likewise.
	* sysdeps/s390/s390-32/gccframe.h: Likewise.
	* sysdeps/sparc/gccframe.h: Likewise.

	* sysdeps/generic/gccframe.h: Updated.

	* sysdeps/unix/sysv/linux/alpha/Makefile (sysdep_routines): Add
	$(FRAME-UNWINDER-V2), unwind-dw2 and unwind-dw2-fde for elf if
	$(build-shared) is yes.
	(shared-only-routines): Likewise.
	* sysdeps/unix/sysv/linux/arm/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/i386/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/m68k/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/mips/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/sparc/Makefile: Likewise.

--- libc/Versions.def.gcc	Fri Jun  1 20:36:08 2001
+++ libc/Versions.def	Fri Jul  6 17:38:55 2001
@@ -16,6 +16,7 @@ libc {
 %ifdef USE_IN_LIBIO
   HURD_CTHREADS_0.3
 %endif
+  GCC_3.0
 }
 libcrypt {
   GLIBC_2.0
--- libc/config.make.in.gcc	Sat Jul  7 16:44:42 2001
+++ libc/config.make.in	Mon Jul  9 09:56:23 2001
@@ -103,3 +103,6 @@ PERL = @PERL@
 LIBGD = @LIBGD@
 
 # More variables may be inserted below by configure.
+
+# The gcc v2 frame unwinder, gcc 2.95 or gcc 2.96.
+FRAME-UNWINDER-V2 = @libc_cv_frame_unwinder_v2@
--- libc/configure.in.gcc	Sat Jul  7 16:44:43 2001
+++ libc/configure.in	Mon Jul  9 10:39:56 2001
@@ -586,8 +586,22 @@ if test -n "$critic_missing"; then
 AC_MSG_ERROR([
 *** These critical programs are missing or too old:$critic_missing
 *** Check the INSTALL file for required versions.])
+else
+  # Check which frame unwinder to use.
+  echo $ac_n "checking the frame unwinder of $CC""... $ac_c" 1>&6
+  ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+  2.96)
+    libc_cv_frame_unwinder_v2=frame-dwarf2
+    ;;
+  *)
+    libc_cv_frame_unwinder_v2=frame
+    ;;
+  esac
+ ac_prog_version="$ac_prog_version, $libc_cv_frame_unwinder_v2.c"
+ echo "$ac_t""$ac_prog_version" 1>&6
+ AC_SUBST(libc_cv_frame_unwinder_v2)
 fi
-
 
 AC_CHECK_PROG_VER(MSGFMT, gnumsgfmt gmsgfmt msgfmt, --version,
   [GNU gettext.* \([0-9]*\.[0-9.]*\)],
--- libc/sysdeps/alpha/gccframe.h.gcc	Wed Jul  4 21:37:33 2001
+++ libc/sysdeps/alpha/gccframe.h	Mon Jul  9 10:24:58 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  Alpha version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 64
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/arm/gccframe.h.gcc	Wed Jul  4 21:37:33 2001
+++ libc/sysdeps/arm/gccframe.h	Mon Jul  9 10:25:13 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  Arm version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 27
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/generic/dwarf2.h.gcc	Wed Jul  4 21:37:33 2001
+++ libc/sysdeps/generic/dwarf2.h	Fri Jul  6 14:40:56 2001
@@ -0,0 +1,561 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 2000 
+   Free Software Foundation, Inc.
+   Contributed by Gary Funck (gary@intrepid.com).  Derived from the
+   DWARF 1 implementation written by Ron Guilmette (rfg@monkeys.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.  */
+
+/* Tag names and codes.  */
+
+enum dwarf_tag
+  {
+    DW_TAG_padding = 0x00,
+    DW_TAG_array_type = 0x01,
+    DW_TAG_class_type = 0x02,
+    DW_TAG_entry_point = 0x03,
+    DW_TAG_enumeration_type = 0x04,
+    DW_TAG_formal_parameter = 0x05,
+    DW_TAG_imported_declaration = 0x08,
+    DW_TAG_label = 0x0a,
+    DW_TAG_lexical_block = 0x0b,
+    DW_TAG_member = 0x0d,
+    DW_TAG_pointer_type = 0x0f,
+    DW_TAG_reference_type = 0x10,
+    DW_TAG_compile_unit = 0x11,
+    DW_TAG_string_type = 0x12,
+    DW_TAG_structure_type = 0x13,
+    DW_TAG_subroutine_type = 0x15,
+    DW_TAG_typedef = 0x16,
+    DW_TAG_union_type = 0x17,
+    DW_TAG_unspecified_parameters = 0x18,
+    DW_TAG_variant = 0x19,
+    DW_TAG_common_block = 0x1a,
+    DW_TAG_common_inclusion = 0x1b,
+    DW_TAG_inheritance = 0x1c,
+    DW_TAG_inlined_subroutine = 0x1d,
+    DW_TAG_module = 0x1e,
+    DW_TAG_ptr_to_member_type = 0x1f,
+    DW_TAG_set_type = 0x20,
+    DW_TAG_subrange_type = 0x21,
+    DW_TAG_with_stmt = 0x22,
+    DW_TAG_access_declaration = 0x23,
+    DW_TAG_base_type = 0x24,
+    DW_TAG_catch_block = 0x25,
+    DW_TAG_const_type = 0x26,
+    DW_TAG_constant = 0x27,
+    DW_TAG_enumerator = 0x28,
+    DW_TAG_file_type = 0x29,
+    DW_TAG_friend = 0x2a,
+    DW_TAG_namelist = 0x2b,
+    DW_TAG_namelist_item = 0x2c,
+    DW_TAG_packed_type = 0x2d,
+    DW_TAG_subprogram = 0x2e,
+    DW_TAG_template_type_param = 0x2f,
+    DW_TAG_template_value_param = 0x30,
+    DW_TAG_thrown_type = 0x31,
+    DW_TAG_try_block = 0x32,
+    DW_TAG_variant_part = 0x33,
+    DW_TAG_variable = 0x34,
+    DW_TAG_volatile_type = 0x35,
+    /* SGI/MIPS Extensions */
+    DW_TAG_MIPS_loop = 0x4081,
+    /* GNU extensions */
+    DW_TAG_format_label = 0x4101,	/* for FORTRAN 77 and Fortran 90 */
+    DW_TAG_function_template = 0x4102,	/* for C++ */
+    DW_TAG_class_template = 0x4103,	/* for C++ */
+    DW_TAG_GNU_BINCL = 0x4104,
+    DW_TAG_GNU_EINCL = 0x4105
+  };
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* flag that tells whether entry has a child or not */
+#define DW_children_no   0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+enum dwarf_form
+  {
+    DW_FORM_addr = 0x01,
+    DW_FORM_block2 = 0x03,
+    DW_FORM_block4 = 0x04,
+    DW_FORM_data2 = 0x05,
+    DW_FORM_data4 = 0x06,
+    DW_FORM_data8 = 0x07,
+    DW_FORM_string = 0x08,
+    DW_FORM_block = 0x09,
+    DW_FORM_block1 = 0x0a,
+    DW_FORM_data1 = 0x0b,
+    DW_FORM_flag = 0x0c,
+    DW_FORM_sdata = 0x0d,
+    DW_FORM_strp = 0x0e,
+    DW_FORM_udata = 0x0f,
+    DW_FORM_ref_addr = 0x10,
+    DW_FORM_ref1 = 0x11,
+    DW_FORM_ref2 = 0x12,
+    DW_FORM_ref4 = 0x13,
+    DW_FORM_ref8 = 0x14,
+    DW_FORM_ref_udata = 0x15,
+    DW_FORM_indirect = 0x16
+  };
+
+/* Attribute names and codes.  */
+
+enum dwarf_attribute
+  {
+    DW_AT_sibling = 0x01,
+    DW_AT_location = 0x02,
+    DW_AT_name = 0x03,
+    DW_AT_ordering = 0x09,
+    DW_AT_subscr_data = 0x0a,
+    DW_AT_byte_size = 0x0b,
+    DW_AT_bit_offset = 0x0c,
+    DW_AT_bit_size = 0x0d,
+    DW_AT_element_list = 0x0f,
+    DW_AT_stmt_list = 0x10,
+    DW_AT_low_pc = 0x11,
+    DW_AT_high_pc = 0x12,
+    DW_AT_language = 0x13,
+    DW_AT_member = 0x14,
+    DW_AT_discr = 0x15,
+    DW_AT_discr_value = 0x16,
+    DW_AT_visibility = 0x17,
+    DW_AT_import = 0x18,
+    DW_AT_string_length = 0x19,
+    DW_AT_common_reference = 0x1a,
+    DW_AT_comp_dir = 0x1b,
+    DW_AT_const_value = 0x1c,
+    DW_AT_containing_type = 0x1d,
+    DW_AT_default_value = 0x1e,
+    DW_AT_inline = 0x20,
+    DW_AT_is_optional = 0x21,
+    DW_AT_lower_bound = 0x22,
+    DW_AT_producer = 0x25,
+    DW_AT_prototyped = 0x27,
+    DW_AT_return_addr = 0x2a,
+    DW_AT_start_scope = 0x2c,
+    DW_AT_stride_size = 0x2e,
+    DW_AT_upper_bound = 0x2f,
+    DW_AT_abstract_origin = 0x31,
+    DW_AT_accessibility = 0x32,
+    DW_AT_address_class = 0x33,
+    DW_AT_artificial = 0x34,
+    DW_AT_base_types = 0x35,
+    DW_AT_calling_convention = 0x36,
+    DW_AT_count = 0x37,
+    DW_AT_data_member_location = 0x38,
+    DW_AT_decl_column = 0x39,
+    DW_AT_decl_file = 0x3a,
+    DW_AT_decl_line = 0x3b,
+    DW_AT_declaration = 0x3c,
+    DW_AT_discr_list = 0x3d,
+    DW_AT_encoding = 0x3e,
+    DW_AT_external = 0x3f,
+    DW_AT_frame_base = 0x40,
+    DW_AT_friend = 0x41,
+    DW_AT_identifier_case = 0x42,
+    DW_AT_macro_info = 0x43,
+    DW_AT_namelist_items = 0x44,
+    DW_AT_priority = 0x45,
+    DW_AT_segment = 0x46,
+    DW_AT_specification = 0x47,
+    DW_AT_static_link = 0x48,
+    DW_AT_type = 0x49,
+    DW_AT_use_location = 0x4a,
+    DW_AT_variable_parameter = 0x4b,
+    DW_AT_virtuality = 0x4c,
+    DW_AT_vtable_elem_location = 0x4d,
+    /* SGI/MIPS Extensions */
+    DW_AT_MIPS_fde = 0x2001,
+    DW_AT_MIPS_loop_begin = 0x2002,
+    DW_AT_MIPS_tail_loop_begin = 0x2003,
+    DW_AT_MIPS_epilog_begin = 0x2004,
+    DW_AT_MIPS_loop_unroll_factor = 0x2005,
+    DW_AT_MIPS_software_pipeline_depth = 0x2006,
+    DW_AT_MIPS_linkage_name = 0x2007,
+    DW_AT_MIPS_stride = 0x2008,
+    DW_AT_MIPS_abstract_name = 0x2009,
+    DW_AT_MIPS_clone_origin = 0x200a,
+    DW_AT_MIPS_has_inlines = 0x200b,
+    /* GNU extensions.  */
+    DW_AT_sf_names = 0x2101,
+    DW_AT_src_info = 0x2102,
+    DW_AT_mac_info = 0x2103,
+    DW_AT_src_coords = 0x2104,
+    DW_AT_body_begin = 0x2105,
+    DW_AT_body_end = 0x2106
+  };
+
+#define DW_AT_lo_user	0x2000	/* implementation-defined range start */
+#define DW_AT_hi_user	0x3ff0	/* implementation-defined range end */
+
+/* Location atom names and codes.  */
+
+enum dwarf_location_atom
+  {
+    DW_OP_addr = 0x03,
+    DW_OP_deref = 0x06,
+    DW_OP_const1u = 0x08,
+    DW_OP_const1s = 0x09,
+    DW_OP_const2u = 0x0a,
+    DW_OP_const2s = 0x0b,
+    DW_OP_const4u = 0x0c,
+    DW_OP_const4s = 0x0d,
+    DW_OP_const8u = 0x0e,
+    DW_OP_const8s = 0x0f,
+    DW_OP_constu = 0x10,
+    DW_OP_consts = 0x11,
+    DW_OP_dup = 0x12,
+    DW_OP_drop = 0x13,
+    DW_OP_over = 0x14,
+    DW_OP_pick = 0x15,
+    DW_OP_swap = 0x16,
+    DW_OP_rot = 0x17,
+    DW_OP_xderef = 0x18,
+    DW_OP_abs = 0x19,
+    DW_OP_and = 0x1a,
+    DW_OP_div = 0x1b,
+    DW_OP_minus = 0x1c,
+    DW_OP_mod = 0x1d,
+    DW_OP_mul = 0x1e,
+    DW_OP_neg = 0x1f,
+    DW_OP_not = 0x20,
+    DW_OP_or = 0x21,
+    DW_OP_plus = 0x22,
+    DW_OP_plus_uconst = 0x23,
+    DW_OP_shl = 0x24,
+    DW_OP_shr = 0x25,
+    DW_OP_shra = 0x26,
+    DW_OP_xor = 0x27,
+    DW_OP_bra = 0x28,
+    DW_OP_eq = 0x29,
+    DW_OP_ge = 0x2a,
+    DW_OP_gt = 0x2b,
+    DW_OP_le = 0x2c,
+    DW_OP_lt = 0x2d,
+    DW_OP_ne = 0x2e,
+    DW_OP_skip = 0x2f,
+    DW_OP_lit0 = 0x30,
+    DW_OP_lit1 = 0x31,
+    DW_OP_lit2 = 0x32,
+    DW_OP_lit3 = 0x33,
+    DW_OP_lit4 = 0x34,
+    DW_OP_lit5 = 0x35,
+    DW_OP_lit6 = 0x36,
+    DW_OP_lit7 = 0x37,
+    DW_OP_lit8 = 0x38,
+    DW_OP_lit9 = 0x39,
+    DW_OP_lit10 = 0x3a,
+    DW_OP_lit11 = 0x3b,
+    DW_OP_lit12 = 0x3c,
+    DW_OP_lit13 = 0x3d,
+    DW_OP_lit14 = 0x3e,
+    DW_OP_lit15 = 0x3f,
+    DW_OP_lit16 = 0x40,
+    DW_OP_lit17 = 0x41,
+    DW_OP_lit18 = 0x42,
+    DW_OP_lit19 = 0x43,
+    DW_OP_lit20 = 0x44,
+    DW_OP_lit21 = 0x45,
+    DW_OP_lit22 = 0x46,
+    DW_OP_lit23 = 0x47,
+    DW_OP_lit24 = 0x48,
+    DW_OP_lit25 = 0x49,
+    DW_OP_lit26 = 0x4a,
+    DW_OP_lit27 = 0x4b,
+    DW_OP_lit28 = 0x4c,
+    DW_OP_lit29 = 0x4d,
+    DW_OP_lit30 = 0x4e,
+    DW_OP_lit31 = 0x4f,
+    DW_OP_reg0 = 0x50,
+    DW_OP_reg1 = 0x51,
+    DW_OP_reg2 = 0x52,
+    DW_OP_reg3 = 0x53,
+    DW_OP_reg4 = 0x54,
+    DW_OP_reg5 = 0x55,
+    DW_OP_reg6 = 0x56,
+    DW_OP_reg7 = 0x57,
+    DW_OP_reg8 = 0x58,
+    DW_OP_reg9 = 0x59,
+    DW_OP_reg10 = 0x5a,
+    DW_OP_reg11 = 0x5b,
+    DW_OP_reg12 = 0x5c,
+    DW_OP_reg13 = 0x5d,
+    DW_OP_reg14 = 0x5e,
+    DW_OP_reg15 = 0x5f,
+    DW_OP_reg16 = 0x60,
+    DW_OP_reg17 = 0x61,
+    DW_OP_reg18 = 0x62,
+    DW_OP_reg19 = 0x63,
+    DW_OP_reg20 = 0x64,
+    DW_OP_reg21 = 0x65,
+    DW_OP_reg22 = 0x66,
+    DW_OP_reg23 = 0x67,
+    DW_OP_reg24 = 0x68,
+    DW_OP_reg25 = 0x69,
+    DW_OP_reg26 = 0x6a,
+    DW_OP_reg27 = 0x6b,
+    DW_OP_reg28 = 0x6c,
+    DW_OP_reg29 = 0x6d,
+    DW_OP_reg30 = 0x6e,
+    DW_OP_reg31 = 0x6f,
+    DW_OP_breg0 = 0x70,
+    DW_OP_breg1 = 0x71,
+    DW_OP_breg2 = 0x72,
+    DW_OP_breg3 = 0x73,
+    DW_OP_breg4 = 0x74,
+    DW_OP_breg5 = 0x75,
+    DW_OP_breg6 = 0x76,
+    DW_OP_breg7 = 0x77,
+    DW_OP_breg8 = 0x78,
+    DW_OP_breg9 = 0x79,
+    DW_OP_breg10 = 0x7a,
+    DW_OP_breg11 = 0x7b,
+    DW_OP_breg12 = 0x7c,
+    DW_OP_breg13 = 0x7d,
+    DW_OP_breg14 = 0x7e,
+    DW_OP_breg15 = 0x7f,
+    DW_OP_breg16 = 0x80,
+    DW_OP_breg17 = 0x81,
+    DW_OP_breg18 = 0x82,
+    DW_OP_breg19 = 0x83,
+    DW_OP_breg20 = 0x84,
+    DW_OP_breg21 = 0x85,
+    DW_OP_breg22 = 0x86,
+    DW_OP_breg23 = 0x87,
+    DW_OP_breg24 = 0x88,
+    DW_OP_breg25 = 0x89,
+    DW_OP_breg26 = 0x8a,
+    DW_OP_breg27 = 0x8b,
+    DW_OP_breg28 = 0x8c,
+    DW_OP_breg29 = 0x8d,
+    DW_OP_breg30 = 0x8e,
+    DW_OP_breg31 = 0x8f,
+    DW_OP_regx = 0x90,
+    DW_OP_fbreg = 0x91,
+    DW_OP_bregx = 0x92,
+    DW_OP_piece = 0x93,
+    DW_OP_deref_size = 0x94,
+    DW_OP_xderef_size = 0x95,
+    DW_OP_nop = 0x96
+  };
+
+#define DW_OP_lo_user	0x80	/* implementation-defined range start */
+#define DW_OP_hi_user	0xff	/* implementation-defined range end */
+
+/* Type encodings.  */
+
+enum dwarf_type
+  {
+    DW_ATE_void = 0x0,
+    DW_ATE_address = 0x1,
+    DW_ATE_boolean = 0x2,
+    DW_ATE_complex_float = 0x3,
+    DW_ATE_float = 0x4,
+    DW_ATE_signed = 0x5,
+    DW_ATE_signed_char = 0x6,
+    DW_ATE_unsigned = 0x7,
+    DW_ATE_unsigned_char = 0x8
+  };
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+enum dwarf_array_dim_ordering
+  {
+    DW_ORD_row_major = 0,
+    DW_ORD_col_major = 1
+  };
+
+/* access attribute */
+enum dwarf_access_attribute
+  {
+    DW_ACCESS_public = 1,
+    DW_ACCESS_protected = 2,
+    DW_ACCESS_private = 3
+  };
+
+/* visibility */
+enum dwarf_visibility_attribute
+  {
+    DW_VIS_local = 1,
+    DW_VIS_exported = 2,
+    DW_VIS_qualified = 3
+  };
+
+/* virtuality */
+enum dwarf_virtuality_attribute
+  {
+    DW_VIRTUALITY_none = 0,
+    DW_VIRTUALITY_virtual = 1,
+    DW_VIRTUALITY_pure_virtual = 2
+  };
+
+/* case sensitivity */
+enum dwarf_id_case
+  {
+    DW_ID_case_sensitive = 0,
+    DW_ID_up_case = 1,
+    DW_ID_down_case = 2,
+    DW_ID_case_insensitive = 3
+  };
+
+/* calling convention */
+enum dwarf_calling_convention
+  {
+    DW_CC_normal = 0x1,
+    DW_CC_program = 0x2,
+    DW_CC_nocall = 0x3
+  };
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* inline attribute */
+enum dwarf_inline_attribute
+  {
+    DW_INL_not_inlined = 0,
+    DW_INL_inlined = 1,
+    DW_INL_declared_not_inlined = 2,
+    DW_INL_declared_inlined = 3
+  };
+
+/* discriminant lists */
+enum dwarf_discrim_list
+  {
+    DW_DSC_label = 0,
+    DW_DSC_range = 1
+  };
+
+/* line number opcodes */
+enum dwarf_line_number_ops
+  {
+    DW_LNS_extended_op = 0,
+    DW_LNS_copy = 1,
+    DW_LNS_advance_pc = 2,
+    DW_LNS_advance_line = 3,
+    DW_LNS_set_file = 4,
+    DW_LNS_set_column = 5,
+    DW_LNS_negate_stmt = 6,
+    DW_LNS_set_basic_block = 7,
+    DW_LNS_const_add_pc = 8,
+    DW_LNS_fixed_advance_pc = 9
+  };
+
+/* line number extended opcodes */
+enum dwarf_line_number_x_ops
+  {
+    DW_LNE_end_sequence = 1,
+    DW_LNE_set_address = 2,
+    DW_LNE_define_file = 3
+  };
+
+/* call frame information */
+enum dwarf_call_frame_info
+  {
+    DW_CFA_advance_loc = 0x40,
+    DW_CFA_offset = 0x80,
+    DW_CFA_restore = 0xc0,
+    DW_CFA_nop = 0x00,
+    DW_CFA_set_loc = 0x01,
+    DW_CFA_advance_loc1 = 0x02,
+    DW_CFA_advance_loc2 = 0x03,
+    DW_CFA_advance_loc4 = 0x04,
+    DW_CFA_offset_extended = 0x05,
+    DW_CFA_restore_extended = 0x06,
+    DW_CFA_undefined = 0x07,
+    DW_CFA_same_value = 0x08,
+    DW_CFA_register = 0x09,
+    DW_CFA_remember_state = 0x0a,
+    DW_CFA_restore_state = 0x0b,
+    DW_CFA_def_cfa = 0x0c,
+    DW_CFA_def_cfa_register = 0x0d,
+    DW_CFA_def_cfa_offset = 0x0e,
+    DW_CFA_def_cfa_expression = 0x0f,
+    DW_CFA_expression = 0x10,
+    /* Dwarf 2.1 */
+    DW_CFA_offset_extended_sf = 0x11,
+    DW_CFA_def_cfa_sf = 0x12,
+    DW_CFA_def_cfa_offset_sf = 0x13,
+
+    /* SGI/MIPS specific */
+    DW_CFA_MIPS_advance_loc8 = 0x1d,
+    
+    /* GNU extensions */
+    DW_CFA_GNU_window_save = 0x2d,
+    DW_CFA_GNU_args_size = 0x2e,
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+  };
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_low_user   0x1c
+#define DW_CFA_high_user  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+
+enum dwarf_source_language
+  {
+    DW_LANG_C89 = 0x0001,
+    DW_LANG_C = 0x0002,
+    DW_LANG_Ada83 = 0x0003,
+    DW_LANG_C_plus_plus = 0x0004,
+    DW_LANG_Cobol74 = 0x0005,
+    DW_LANG_Cobol85 = 0x0006,
+    DW_LANG_Fortran77 = 0x0007,
+    DW_LANG_Fortran90 = 0x0008,
+    DW_LANG_Pascal83 = 0x0009,
+    DW_LANG_Modula2 = 0x000a,
+    DW_LANG_Java = 0x000b,
+    DW_LANG_Mips_Assembler = 0x8001
+  };
+
+
+#define DW_LANG_lo_user 0x8000	/* implementation-defined range start */
+#define DW_LANG_hi_user 0xffff	/* implementation-defined range start */
+
+/* Names and codes for macro information.  */
+
+enum dwarf_macinfo_record_type
+  {
+    DW_MACINFO_define = 1,
+    DW_MACINFO_undef = 2,
+    DW_MACINFO_start_file = 3,
+    DW_MACINFO_end_file = 4,
+    DW_MACINFO_vendor_ext = 255
+  };
--- libc/sysdeps/generic/frame-dwarf2.c.gcc	Thu Jul  5 17:39:57 2001
+++ libc/sysdeps/generic/frame-dwarf2.c	Mon Jul  9 00:54:57 2001
@@ -0,0 +1,990 @@
+/* Subroutines needed for unwinding DWARF 2 format stack frame info
+   for exception handling.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* It is incorrect to include config.h here, because this file is being
+   compiled for the target, and hence definitions concerning only the host
+   do not apply.  */
+
+#ifdef _LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <libintl.h>
+#include <dwarf2.h>
+#define DWARF2_FRAME_UNWIND_V2
+#define NEED__Unwind_GetFrameForV2
+#include <unwind-pe.h>
+
+/* Values for the 'saved' field in struct frame_state defined in
+   unwind-pe.h.  */
+#define REG_UNSAVED 0
+#define REG_SAVED_OFFSET 1
+#define REG_SAVED_REG 2
+
+#define DWARF2_UNWIND_INFO 1
+#else /* _LIBC */
+#include "tconfig.h"
+#include "tsystem.h"
+
+#include "defaults.h"
+
+#ifdef DWARF2_UNWIND_INFO
+#include "dwarf2.h"
+#include "frame.h"
+#include "gthr.h"
+
+#ifdef __GTHREAD_MUTEX_INIT
+static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
+#else
+static __gthread_mutex_t object_mutex;
+#endif
+
+/* Don't use `fancy_abort' here even if config.h says to use it.  */
+#ifdef abort
+#undef abort
+#endif
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* _LIBC */
+
+#ifdef DWARF2_UNWIND_INFO
+/* Some types used by the DWARF 2 spec.  */
+
+typedef          int  sword __attribute__ ((mode (SI)));
+typedef unsigned int  uword __attribute__ ((mode (SI)));
+typedef unsigned int  uaddr __attribute__ ((mode (pointer)));
+typedef          int  saddr __attribute__ ((mode (pointer)));
+typedef unsigned char ubyte;
+
+/* Terminology:
+   CIE - Common Information Element
+   FDE - Frame Descriptor Element
+
+   There is one per function, and it describes where the function code
+   is located, and what the register lifetimes and stack layout are
+   within the function.
+
+   The data structures are defined in the DWARF specfication, although
+   not in a very readable way (see LITERATURE).
+
+   Every time an exception is thrown, the code needs to locate the FDE
+   for the current function, and starts to look for exception regions
+   from that FDE. This works in a two-level search:
+   a) in a linear search, find the shared image (i.e. DLL) containing
+      the PC
+   b) using the FDE table for that shared object, locate the FDE using
+      binary search (which requires the sorting).  */   
+
+/* The first few fields of a CIE.  The CIE_id field is 0 for a CIE,
+   to distinguish it from a valid FDE.  FDEs are aligned to an addressing
+   unit boundary, but the fields within are unaligned.  */
+
+struct dwarf_cie {
+  uword length;
+  sword CIE_id;
+  ubyte version;
+  char augmentation[0];
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+/* The first few fields of an FDE.  */
+
+struct dwarf_fde {
+  uword length;
+  sword CIE_delta;
+  void* pc_begin;
+  uaddr pc_range;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+#ifndef _LIBC
+typedef struct dwarf_fde fde;
+
+/* Objects to be searched for frame unwind info.  */
+
+static struct object *objects;
+
+/* The information we care about from a CIE.  */
+
+struct cie_info {
+  char *augmentation;
+  void *eh_ptr;
+  void *pc;
+  int code_align;
+  int data_align;
+  unsigned ra_regno;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
+};
+
+/* This is undefined below if we need it to be an actual function.  */
+#define init_object_mutex_once()
+
+#if __GTHREADS
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+
+/* Helper for init_object_mutex_once.  */
+
+static void
+init_object_mutex (void)
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
+}
+
+/* Call this to arrange to initialize the object mutex.  */
+
+#undef init_object_mutex_once
+static void
+init_object_mutex_once (void)
+{
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  __gthread_once (&once, init_object_mutex);
+}
+
+#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
+#endif /* __GTHREADS */
+#endif /* !_LIBC */
+  
+/* The current unwind state, plus a saved copy for DW_CFA_remember_state.  */
+
+struct frame_state_internal
+{
+  struct frame_state s;
+  struct frame_state_internal *saved_state;
+};
+
+/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_uleb128 (unsigned char *buf, unsigned *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+
+  while (1)
+    {
+      unsigned byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      if ((byte & 0x80) == 0)
+	break;
+      shift += 7;
+    }
+  *r = result;
+  return buf;
+}
+
+/* Decode the signed LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_sleb128 (unsigned char *buf, int *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+  unsigned byte;
+
+  while (1)
+    {
+      byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	break;
+    }
+  if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
+    result |= - (1 << shift);
+
+  *r = result;
+  return buf;
+}
+
+/* Read unaligned data from the instruction buffer.  */
+
+union unaligned {
+  void *p;
+  unsigned b2 __attribute__ ((mode (HI)));
+  unsigned b4 __attribute__ ((mode (SI)));
+  unsigned b8 __attribute__ ((mode (DI)));
+} __attribute__ ((packed));
+static inline void *
+read_pointer (void *p)
+{ union unaligned *up = p; return up->p; }
+static inline unsigned
+read_1byte (void *p)
+{ return *(unsigned char *)p; }
+static inline unsigned
+read_2byte (void *p)
+{ union unaligned *up = p; return up->b2; }
+static inline unsigned
+read_4byte (void *p)
+{ union unaligned *up = p; return up->b4; }
+static inline unsigned long
+read_8byte (void *p)
+{ union unaligned *up = p; return up->b8; }
+
+/* Return the address of the FDE after P.  */
+
+static inline fde *
+next_fde (fde *p)
+{
+  return (fde *)(((char *)p) + p->length + sizeof (p->length));
+}
+
+#ifndef _LIBC
+/* Ordering function for FDEs.  Functions can't overlap, so we just compare
+   their starting addresses.  */
+
+static inline saddr
+fde_compare (fde *x, fde *y)
+{
+  return (saddr)x->pc_begin - (saddr)y->pc_begin;
+}
+
+#include "frame.c"
+
+static size_t
+count_fdes (fde *this_fde)
+{
+  size_t count;
+
+  for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs and linked once FDE entries.  */
+      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+	continue;
+
+      ++count;
+    }
+
+  return count;
+}
+
+static void
+add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
+{
+  void *pc_begin = *beg_ptr;
+  void *pc_end = *end_ptr;
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs and linked once FDE entries.  */
+      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+	continue;
+
+      fde_insert (accu, this_fde);
+
+      if (this_fde->pc_begin < pc_begin)
+	pc_begin = this_fde->pc_begin;
+      if (this_fde->pc_begin + this_fde->pc_range > pc_end)
+	pc_end = this_fde->pc_begin + this_fde->pc_range;
+    }
+
+  *beg_ptr = pc_begin;
+  *end_ptr = pc_end;
+}
+
+/* search this fde table for the one containing the pc */
+static fde *
+search_fdes (fde *this_fde, void *pc)
+{
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs and linked once FDE entries.  */
+      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+	continue;
+
+      if ((uaddr)((char *)pc - (char *)this_fde->pc_begin) < this_fde->pc_range)
+	return this_fde;
+    }
+  return NULL;
+}
+
+/* Set up a sorted array of pointers to FDEs for a loaded object.  We
+   count up the entries before allocating the array because it's likely to
+   be faster.  We can be called multiple times, should we have failed to
+   allocate a sorted fde array on a previous occasion.  */
+
+static void
+frame_init (struct object* ob)
+{
+  size_t count;
+  fde_accumulator accu;
+  void *pc_begin, *pc_end;
+  fde **array;
+
+  if (ob->pc_begin)
+    count = ob->count;
+  else if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (count = 0; *p; ++p)
+	count += count_fdes (*p);
+    }
+  else
+    count = count_fdes (ob->fde_begin);
+  ob->count = count;
+
+  if (!start_fde_sort (&accu, count) && ob->pc_begin)
+    return;
+
+  pc_begin = (void*)(uaddr)-1;
+  pc_end = 0;
+
+  if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (; *p; ++p)
+	add_fdes (*p, &accu, &pc_begin, &pc_end);
+    }
+  else
+    add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
+
+  array = end_fde_sort (&accu, count);
+  if (array)
+    ob->fde_array = array;
+  ob->pc_begin = pc_begin;
+  ob->pc_end = pc_end;
+}
+
+/* Return a pointer to the FDE for the function containing PC.  */
+
+static fde *
+find_fde (void *pc)
+{
+  struct object *ob;
+  size_t lo, hi;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
+  /* Linear search through the objects, to find the one containing the pc. */
+  for (ob = objects; ob; ob = ob->next)
+    {
+      if (ob->pc_begin == 0)
+	frame_init (ob);
+      if (pc >= ob->pc_begin && pc < ob->pc_end)
+	break;
+    }
+
+  if (ob == 0)
+    {
+      __gthread_mutex_unlock (&object_mutex);
+      return 0;
+    }
+
+  if (!ob->fde_array || (void *)ob->fde_array == (void *)ob->fde_begin)
+    frame_init (ob);
+
+  if (ob->fde_array && (void *)ob->fde_array != (void *)ob->fde_begin)
+    {
+      __gthread_mutex_unlock (&object_mutex);
+      
+      /* Standard binary search algorithm.  */
+      for (lo = 0, hi = ob->count; lo < hi; )
+	{
+	  size_t i = (lo + hi) / 2;
+	  fde *f = ob->fde_array[i];
+
+	  if (pc < f->pc_begin)
+	    hi = i;
+	  else if (pc >= f->pc_begin + f->pc_range)
+	    lo = i + 1;
+	  else
+	    return f;
+	}
+    }
+  else
+    {
+      /* Long slow labourious linear search, cos we've no memory. */
+      fde *f;
+      
+      if (ob->fde_array)
+	{
+	  fde **p = ob->fde_array;
+	  
+	  do
+	    {
+	      f = search_fdes (*p, pc);
+	      if (f)
+		break;
+	      p++;
+	    }
+	  while (*p);
+	}
+      else
+	f = search_fdes (ob->fde_begin, pc);
+      __gthread_mutex_unlock (&object_mutex);
+      return f;
+    }
+  return 0;
+}
+#endif /* !_LIBC */
+
+static inline struct dwarf_cie *
+get_cie (fde *f)
+{
+  return ((void *)&f->CIE_delta) - f->CIE_delta;
+}
+
+/* Extract any interesting information from the CIE for the translation
+   unit F belongs to.  */
+
+static void *
+extract_cie_info (fde *f, struct cie_info *c)
+{
+  unsigned char *aug;
+  void *p;
+  void *ret = NULL;
+
+  c->augmentation = get_cie (f)->augmentation;
+  aug = c->augmentation;
+  p = aug + strlen (aug) + 1;
+
+  /* "eh" was used by g++ v2; recognize and store.  */
+  if (aug[0] == 'e' && aug[1] == 'h')
+    {
+      c->eh_ptr = read_pointer (p);
+      p += sizeof (void *);
+    }
+
+  /* Immediately following the augmentation are the code and
+     data alignment and return address column.  */
+  p = decode_uleb128 (p, &c->code_align);
+  p = decode_sleb128 (p, &c->data_align);
+  c->ra_regno = *(unsigned char *)p++;
+  c->lsda_encoding = DW_EH_PE_omit;
+
+  if (c->eh_ptr != NULL)
+    return p;
+
+  /* If the augmentation starts with 'z', then a uleb128 immediately
+     follows containing the length of the augmentation field following
+     the size.  */
+  if (*aug == 'z')
+    {
+      int i;
+
+      p = decode_uleb128 (p, &i);
+      ret = p + i;
+
+      c->saw_z = 1;
+      ++aug;
+    }
+
+  /* Iterate over recognized augmentation subsequences.  */
+  while (*aug != '\0')
+    {
+      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
+      if (aug[0] == 'L')
+	{
+	  c->lsda_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
+      else if (aug[0] == 'R')
+	{
+	  c->fde_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "P" indicates a personality routine in the CIE augmentation.  */
+      else if (aug[0] == 'P')
+	{
+#ifdef NEED__Unwind_GetFrameForV2
+	  error (EXIT_FAILURE, 0,
+		 _("%c: Unsupported gcc v3 exception augmentation."),
+		 aug[0]);
+#else
+	  /* We don't support the V3 frame in gcc 2.9x.  */
+	  abort ();
+#endif
+	}
+
+      /* Otherwise we have an unknown augmentation string.
+	 Bail unless we saw a 'z' prefix.  */
+      else
+	return ret;
+    }
+
+  return ret ? ret : p;
+}
+
+/* Decode a DW_OP stack operation.  */
+
+static void *
+decode_stack_op (unsigned char *buf, struct frame_state *state)
+{
+  enum dwarf_location_atom op;
+  int offset;
+
+  op = *buf++;
+  switch (op)
+    {
+    case DW_OP_reg0:
+    case DW_OP_reg1:
+    case DW_OP_reg2:
+    case DW_OP_reg3:
+    case DW_OP_reg4:
+    case DW_OP_reg5:
+    case DW_OP_reg6:
+    case DW_OP_reg7:
+    case DW_OP_reg8:
+    case DW_OP_reg9:
+    case DW_OP_reg10:
+    case DW_OP_reg11:
+    case DW_OP_reg12:
+    case DW_OP_reg13:
+    case DW_OP_reg14:
+    case DW_OP_reg15:
+    case DW_OP_reg16:
+    case DW_OP_reg17:
+    case DW_OP_reg18:
+    case DW_OP_reg19:
+    case DW_OP_reg20:
+    case DW_OP_reg21:
+    case DW_OP_reg22:
+    case DW_OP_reg23:
+    case DW_OP_reg24:
+    case DW_OP_reg25:
+    case DW_OP_reg26:
+    case DW_OP_reg27:
+    case DW_OP_reg28:
+    case DW_OP_reg29:
+    case DW_OP_reg30:
+    case DW_OP_reg31:
+      state->cfa_reg = op - DW_OP_reg0;
+      break;
+    case DW_OP_regx:
+      buf = decode_sleb128 (buf, &offset);
+      state->cfa_reg = offset;
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+      state->cfa_reg = op - DW_OP_breg0;
+      buf = decode_sleb128 (buf, &offset);
+      state->base_offset = offset;
+      break;
+    case DW_OP_bregx:
+      buf = decode_sleb128 (buf, &offset);
+      state->cfa_reg = offset;
+      buf = decode_sleb128 (buf, &offset);
+      state->base_offset = offset;
+      break;
+    case DW_OP_deref:
+      state->indirect = 1;
+      break;
+    case DW_OP_plus_uconst:
+      buf = decode_uleb128 (buf, &offset);
+      state->cfa_offset = offset;
+      break;
+    default:
+      abort ();
+    }
+  return buf;
+}
+/* Decode one instruction's worth of DWARF 2 call frame information.
+   Used by __frame_state_for.  Takes pointers P to the instruction to
+   decode, STATE to the current register unwind information, INFO to the
+   current CIE information, and PC to the current PC value.  Returns a
+   pointer to the next instruction.  */
+
+static void *
+execute_cfa_insn (void *p, struct frame_state_internal *state,
+		  struct cie_info *info)
+{
+  unsigned insn = *(unsigned char *)p++;
+  unsigned reg;
+  int offset;
+
+  if (insn & DW_CFA_advance_loc)
+    info->pc += ((insn & 0x3f) * info->code_align);
+  else if (insn & DW_CFA_offset)
+    {
+      reg = (insn & 0x3f);
+      p = decode_uleb128 (p, &offset);
+      if (reg == state->s.cfa_reg)
+	/* Don't record anything about this register; it's only used to
+	   reload SP in the epilogue.  We don't want to copy in SP
+	   values for outer frames; we handle restoring SP specially.  */;
+      else
+	{
+	  offset *= info->data_align;
+	  state->s.saved[reg] = REG_SAVED_OFFSET;
+	  state->s.reg_or_offset[reg] = offset;
+	}
+    }
+  else if (insn & DW_CFA_restore)
+    {
+      reg = (insn & 0x3f);
+      state->s.saved[reg] = REG_UNSAVED;
+    }
+  else switch (insn)
+    {
+    case DW_CFA_set_loc:
+      info->pc = read_pointer (p);
+      p += sizeof (void *);
+      break;
+    case DW_CFA_advance_loc1:
+      info->pc += read_1byte (p);
+      p += 1;
+      break;
+    case DW_CFA_advance_loc2:
+      info->pc += read_2byte (p);
+      p += 2;
+      break;
+    case DW_CFA_advance_loc4:
+      info->pc += read_4byte (p);
+      p += 4;
+      break;
+
+    case DW_CFA_offset_extended:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      if (reg == state->s.cfa_reg)
+	/* Don't record anything; see above.  */;
+      else
+	{
+	  offset *= info->data_align;
+	  state->s.saved[reg] = REG_SAVED_OFFSET;
+	  state->s.reg_or_offset[reg] = offset;
+	}
+      break;
+    case DW_CFA_restore_extended:
+      p = decode_uleb128 (p, &reg);
+      state->s.saved[reg] = REG_UNSAVED;
+      break;
+
+    case DW_CFA_undefined:
+    case DW_CFA_same_value:
+    case DW_CFA_nop:
+      break;
+
+    case DW_CFA_register:
+      {
+	unsigned reg2;
+	p = decode_uleb128 (p, &reg);
+	p = decode_uleb128 (p, &reg2);
+	state->s.saved[reg] = REG_SAVED_REG;
+	state->s.reg_or_offset[reg] = reg2;
+      }
+      break;
+
+    case DW_CFA_def_cfa:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_reg = reg;
+      state->s.cfa_offset = offset;
+      break;
+    case DW_CFA_def_cfa_register:
+      p = decode_uleb128 (p, &reg);
+      state->s.cfa_reg = reg;
+      break;
+    case DW_CFA_def_cfa_offset:
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_offset = offset;
+      break;
+    case DW_CFA_def_cfa_expression:
+      {
+	void *end;
+	state->s.cfa_reg = 0;
+	state->s.cfa_offset = 0;
+	state->s.base_offset = 0;
+	state->s.indirect = 0;
+
+	p = decode_uleb128 (p, &offset);
+	end = p + offset;
+	while (p < end)
+	  p = decode_stack_op (p, &(state->s));
+	break;
+      }
+      
+    case DW_CFA_remember_state:
+      {
+	struct frame_state_internal *save =
+	  (struct frame_state_internal *)
+	  malloc (sizeof (struct frame_state_internal));
+	memcpy (save, state, sizeof (struct frame_state_internal));
+	state->saved_state = save;
+      }
+      break;
+    case DW_CFA_restore_state:
+      {
+	struct frame_state_internal *save = state->saved_state;
+	memcpy (state, save, sizeof (struct frame_state_internal));
+	free (save);
+      }
+      break;
+
+      /* FIXME: Hardcoded for SPARC register window configuration.  */
+    case DW_CFA_GNU_window_save:
+      for (reg = 16; reg < 32; ++reg)
+	{
+	  state->s.saved[reg] = REG_SAVED_OFFSET;
+	  state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
+	}
+      break;
+
+    case DW_CFA_GNU_args_size:
+      p = decode_uleb128 (p, &offset);
+      state->s.args_size = offset;
+      break;
+
+    case DW_CFA_GNU_negative_offset_extended:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = -offset;
+      break;
+
+    default:
+      abort ();
+    }
+  return p;
+}
+
+/* Called from __throw to find the registers to restore for a given
+   PC_TARGET.  The caller should allocate a local variable of `struct
+   frame_state' (declared in frame.h) and pass its address to STATE_IN.  */
+
+#if defined(__linux__) && defined(__sparc__) && !defined(__arch64__)
+/* Grab some info from parent register window so that we don't
+   have to flush register windows and look it up on the stack.  */
+asm ("	.text					\n\
+	.globl __frame_state_for		\n\
+	.type __frame_state_for, #function	\n\
+__frame_state_for:				\n\
+	mov	%fp, %o2			\n\
+	b	___frame_state_for		\n\
+	 mov	%i0, %o3			\n\
+     ");
+
+static struct frame_state *
+___frame_state_for (void *pc_target, struct frame_state *state_in, void *pfp,
+		    int i0)
+#elif defined(__linux__) && defined(__alpha__)
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in, long a2)
+#else
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+#endif
+{
+  fde *f;
+  void *insn;
+  struct cie_info info;
+  size_t s;
+  struct frame_state_internal state;
+#ifdef NEED__Unwind_GetFrameForV2
+  struct dwarf_eh_bases bases;
+
+  f = _Unwind_Find_FDE (pc_target, &bases);
+#else
+  f = find_fde (pc_target);
+#endif
+  if (f == 0)
+    return 0;
+
+  memset (&info, 0, sizeof (info));
+  insn = extract_cie_info (f, &info);
+  if (insn == 0)
+    return 0;
+
+  memset (&state, 0, sizeof (state));
+  state.s.retaddr_column = info.ra_regno;
+  state.s.eh_ptr = info.eh_ptr;
+  
+  if (info.lsda_encoding == DW_EH_PE_omit
+      && info.fde_encoding == 0)
+    {
+      void *end;
+
+      /* First decode all the insns in the CIE.  */
+      end = next_fde ((fde*) get_cie (f));
+      while (insn < end)
+ 	insn = execute_cfa_insn (insn, &state, &info);
+
+      insn = ((fde *)f) + 1;
+
+      if (info.augmentation[0] == 'z')
+	{
+	  int i;
+	  insn = decode_uleb128 (insn, &i);
+	  insn += i;
+	}
+
+      /* Then the insns in the FDE up to our target PC.  */
+      end = next_fde (f);
+      info.pc = f->pc_begin;
+      while (insn < end && info.pc <= pc_target)
+	insn = execute_cfa_insn (insn, &state, &info);
+    }
+  else
+#ifdef NEED__Unwind_GetFrameForV2
+    _Unwind_GetFrameForV2 (pc_target, insn, f, &bases, &state.s, &info);
+#else
+    /* We don't support the V3 frame in gcc 2.9x.  */
+    abort ();
+#endif
+
+#ifdef __linux__
+  /* Binary compatibility problem: In June 2000, 2 fields
+     were added at the end of struct frame_state. If for some reason
+     __throw (or __rethrow) comes from binary/shared lib compiled
+     with egcs 1.x.y or gcc-2.95.x and __frame_state_for comes from
+     glibc compiled with gcc-2.96-RH up (gcc-3_0-branch in Apr 2001
+     works that way still), then we can overflow __throw's stack.
+     To fix this, we try to find out who calls us.
+     __frame_state_for is called by next_stack_level and __throw/__rethrow.
+     Of these, __throw/__rethrow does not care about indirect/base_offset
+     fields and next_stack_level can be found out because that's the only
+     routine which where state_in does not point into its stackframe.  */
+  s = (size_t) &((struct frame_state *)0)->base_offset;
+# ifdef __i386__
+  {
+    unsigned long pbp, bp;
+    unsigned char *ppc;
+
+    asm ("movl (%%ebp), %0; movl 4(%%ebp), %1; movl %%ebp, %2"
+	 : "=r" (pbp), "=r" (ppc), "=r" (bp));
+    if (pbp < (unsigned long)state_in && pbp - bp == 0x40)
+      /* We've been called from next_stack_level function.
+	 All gcc-2.96-RH rpms shipped by Red Hat satisfy pbp - bp == 64,
+	 none egcs 1.x.y Red Hat shipped do.  */
+      {
+	unsigned char *end;
+	int indirect = 0;
+
+	/* Skim next_stack_level to see if it compares 0x74(base),0
+	   and reads from 0x70(base).  Stop at ret instruction.  */
+	for (end = ppc + 512; ppc < end && *ppc != 0xc3 && indirect < 2;
+	     ppc++)
+	  {
+	    if (*ppc == 0x74 && ppc[1] == 0)
+	      indirect++;
+	    else if (*ppc == 0x70)
+	      indirect++;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+      }
+  }
+# elif defined(__sparc__) && !defined(__arch64__)
+  if (pfp < (unsigned long)state_in && i0 == 0)
+    /* We've been called from next_stack_level function.
+       All gcc-2.96-RH rpms shipped by Red Hat clear %i0 in next_stack_level
+       before calling __frame_state_for, all egcs 1.x.y just copy
+       %i0 into %o0, so it is guaranteed to be non-NULL.  */
+    {
+      unsigned int *ppc, *end;
+      int indirect = 0;
+
+      ppc = (unsigned int) __builtin_return_address (0);
+
+      /* Skim next_stack_level to see if it does a ld?b [? + 0x218]
+	 and ld?w [? + 0x214]. Stop at ret instruction.  */
+      for (end = ppc + 128; ppc < end && indirect < 2
+	   && (*ppc | 0x00080000) != 0x81cfe008; ppc++)
+	switch (*ppc & 0xc1b83fff)
+	  {
+	    case 0xc0082218: /* ld?b [? + 0x218], ? */
+	    case 0xc0002214: /* ld?w [? + 0x214], ? */
+	      indirect++;
+	      break;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+    }
+# elif defined(__alpha__)
+  if ((long)state_in == a2)
+    /* We've been called most probably from next_stack_level (it has 3 arguments
+       and passes its third argument as second argument to __frame_state_for).  */
+    {
+      unsigned int *ppc, *end;
+      int indirect = 0;
+
+      /* Skim next_stack_level to see if it does a ldq ?,624(?)
+	 and ldl ?,632(?) resp. ldbu ?,632(?). Stop at ret instruction.  */
+      for (end = ppc + 128; ppc < end && indirect < 2
+	   && *ppc != 0x6bfa8001; ppc++)
+	switch (*ppc & 0xfc00ffff)
+	  {
+	    case 0xa4000270: /* ldq ?,624(?) */
+	    case 0xa0000278: /* ldl ?,632(?) */
+	    case 0xa8000278: /* ldbu ?,632(?) */
+	      indirect++;
+	      break;
+	  }
+	if (indirect == 2)
+	  s = sizeof (state.s);
+    }
+# else
+  s = sizeof (state.s);
+# endif
+#else
+  s = sizeof (state.s);
+#endif
+  if (state.s.indirect && s < sizeof (state.s))
+    abort ();
+  memcpy (state_in, &state.s, s);
+  return state_in;
+}
+#endif /* DWARF2_UNWIND_INFO */
--- libc/sysdeps/generic/frame.c.gcc	Mon Jul  9 09:33:32 2001
+++ libc/sysdeps/generic/frame.c	Mon Jul  9 10:13:42 2001
@@ -0,0 +1,966 @@
+/* Subroutines needed for unwinding stack frames for exception handling.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997, 1998, 2000 Free Software Foundation, Inc.
+   Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/* It is incorrect to include config.h here, because this file is being
+   compiled for the target, and hence definitions concerning only the host
+   do not apply.  */
+
+#ifdef _LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <libintl.h>
+#include <dwarf2.h>
+#define DWARF2_FRAME_UNWIND_V2
+#define NEED__Unwind_GetFrameForV2
+#define NEED_DWARF2_FRAME_UNWIND_OLD_OBJECT
+#include <unwind-pe.h>
+
+/* Values for the 'saved' field in struct frame_state defined in
+   unwind-pe.h.  */
+#define REG_UNSAVED 0
+#define REG_SAVED_OFFSET 1
+#define REG_SAVED_REG 2
+
+#define DWARF2_UNWIND_INFO 1
+#else /* _LIBC */
+#include "tconfig.h"
+
+/* We disable this when inhibit_libc, so that gcc can still be built without
+   needing header files first.  */
+/* ??? This is not a good solution, since prototypes may be required in
+   some cases for correct code.  See also libgcc2.c.  */
+#ifndef inhibit_libc
+/* fixproto guarantees these system headers exist. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include "defaults.h"
+
+#ifdef DWARF2_UNWIND_INFO
+#include "dwarf2.h"
+#include <stddef.h>
+#include "frame.h"
+#include "gthr.h"
+
+#ifdef __GTHREAD_MUTEX_INIT
+static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
+#else
+static __gthread_mutex_t object_mutex;
+#endif
+
+/* Don't use `fancy_abort' here even if config.h says to use it.  */
+#ifdef abort
+#undef abort
+#endif
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* _LIBC */
+
+#ifdef DWARF2_UNWIND_INFO
+/* Some types used by the DWARF 2 spec.  */
+
+typedef          int  sword __attribute__ ((mode (SI)));
+typedef unsigned int  uword __attribute__ ((mode (SI)));
+typedef unsigned int  uaddr __attribute__ ((mode (pointer)));
+typedef          int  saddr __attribute__ ((mode (pointer)));
+typedef unsigned char ubyte;
+
+/* Terminology:
+   CIE - Common Information Element
+   FDE - Frame Descriptor Element
+
+   There is one per function, and it describes where the function code
+   is located, and what the register lifetimes and stack layout are
+   within the function.
+
+   The data structures are defined in the DWARF specfication, although
+   not in a very readable way (see LITERATURE).
+
+   Every time an exception is thrown, the code needs to locate the FDE
+   for the current function, and starts to look for exception regions
+   from that FDE. This works in a two-level search:
+   a) in a linear search, find the shared image (i.e. DLL) containing
+      the PC
+   b) using the FDE table for that shared object, locate the FDE using
+      binary search (which requires the sorting).  */   
+
+/* The first few fields of a CIE.  The CIE_id field is 0 for a CIE,
+   to distinguish it from a valid FDE.  FDEs are aligned to an addressing
+   unit boundary, but the fields within are unaligned.  */
+
+struct dwarf_cie {
+  uword length;
+  sword CIE_id;
+  ubyte version;
+  char augmentation[0];
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+/* The first few fields of an FDE.  */
+
+struct dwarf_fde {
+  uword length;
+  sword CIE_delta;
+  void* pc_begin;
+  uaddr pc_range;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+#ifndef _LIBC
+typedef struct dwarf_fde fde;
+
+/* Objects to be searched for frame unwind info.  */
+
+static struct object *objects;
+
+/* The information we care about from a CIE.  */
+
+struct cie_info {
+  char *augmentation;
+  void *eh_ptr;
+  void *pc;
+  int code_align;
+  int data_align;
+  unsigned ra_regno;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
+};
+
+/* This is undefined below if we need it to be an actual function.  */
+#define init_object_mutex_once()
+
+#if __GTHREADS
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+
+/* Helper for init_object_mutex_once.  */
+
+static void
+init_object_mutex (void)
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
+}
+
+/* Call this to arrange to initialize the object mutex.  */
+
+#undef init_object_mutex_once
+static void
+init_object_mutex_once (void)
+{
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  __gthread_once (&once, init_object_mutex);
+}
+
+#endif /* __GTHREAD_MUTEX_INIT_FUNCTION */
+#endif /* __GTHREADS */
+#endif /* !_LIBC */
+  
+/* The current unwind state, plus a saved copy for DW_CFA_remember_state.  */
+
+struct frame_state_internal
+{
+  struct frame_state s;
+  struct frame_state_internal *saved_state;
+};
+
+/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_uleb128 (unsigned char *buf, unsigned *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+
+  while (1)
+    {
+      unsigned byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      if ((byte & 0x80) == 0)
+	break;
+      shift += 7;
+    }
+  *r = result;
+  return buf;
+}
+
+/* Decode the signed LEB128 constant at BUF into the variable pointed to
+   by R, and return the new value of BUF.  */
+
+static void *
+decode_sleb128 (unsigned char *buf, int *r)
+{
+  unsigned shift = 0;
+  unsigned result = 0;
+  unsigned byte;
+
+  while (1)
+    {
+      byte = *buf++;
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	break;
+    }
+  if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
+    result |= - (1 << shift);
+
+  *r = result;
+  return buf;
+}
+
+/* Read unaligned data from the instruction buffer.  */
+
+union unaligned {
+  void *p;
+  unsigned b2 __attribute__ ((mode (HI)));
+  unsigned b4 __attribute__ ((mode (SI)));
+  unsigned b8 __attribute__ ((mode (DI)));
+} __attribute__ ((packed));
+static inline void *
+read_pointer (void *p)
+{ union unaligned *up = p; return up->p; }
+static inline unsigned
+read_1byte (void *p)
+{ return *(unsigned char *)p; }
+static inline unsigned
+read_2byte (void *p)
+{ union unaligned *up = p; return up->b2; }
+static inline unsigned
+read_4byte (void *p)
+{ union unaligned *up = p; return up->b4; }
+static inline unsigned long
+read_8byte (void *p)
+{ union unaligned *up = p; return up->b8; }
+
+/* Return the address of the FDE after P.  */
+
+static inline fde *
+next_fde (fde *p)
+{
+  return (fde *)(((char *)p) + p->length + sizeof (p->length));
+}
+
+#ifndef _LIBC
+/* Ordering function for FDEs.  Functions can't overlap, so we just compare
+   their starting addresses.  */
+
+static inline saddr
+fde_compare (fde *x, fde *y)
+{
+  return (saddr)x->pc_begin - (saddr)y->pc_begin;
+}
+
+/* Sorting an array of FDEs by address.
+   (Ideally we would have the linker sort the FDEs so we don't have to do
+   it at run time. But the linkers are not yet prepared for this.)  */
+
+/* This is a special mix of insertion sort and heap sort, optimized for
+   the data sets that actually occur. They look like
+   101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
+   I.e. a linearly increasing sequence (coming from functions in the text
+   section), with additionally a few unordered elements (coming from functions
+   in gnu_linkonce sections) whose values are higher than the values in the
+   surrounding linear sequence (but not necessarily higher than the values
+   at the end of the linear sequence!).
+   The worst-case total run time is O(N) + O(n log (n)), where N is the
+   total number of FDEs and n is the number of erratic ones.  */
+
+typedef struct fde_vector
+{
+  fde **array;
+  size_t count;
+} fde_vector;
+
+typedef struct fde_accumulator
+{
+  fde_vector linear;
+  fde_vector erratic;
+} fde_accumulator;
+
+static inline void
+start_fde_sort (fde_accumulator *accu, size_t count)
+{
+  accu->linear.array = (fde **) malloc (sizeof (fde *) * count);
+  accu->erratic.array = (fde **) malloc (sizeof (fde *) * count);
+  accu->linear.count = 0;
+  accu->erratic.count = 0;
+}
+
+static inline void
+fde_insert (fde_accumulator *accu, fde *this_fde)
+{
+  accu->linear.array[accu->linear.count++] = this_fde;
+}
+
+/* Split LINEAR into a linear sequence with low values and an erratic
+   sequence with high values, put the linear one (of longest possible
+   length) into LINEAR and the erratic one into ERRATIC. This is O(N).  */
+static inline void
+fde_split (fde_vector *linear, fde_vector *erratic)
+{
+  size_t count = linear->count;
+  size_t linear_max = (size_t) -1;
+  size_t previous_max[count];
+  size_t i, j;
+
+  for (i = 0; i < count; i++)
+    {
+      for (j = linear_max;
+           j != (size_t) -1
+           && fde_compare (linear->array[i], linear->array[j]) < 0;
+           j = previous_max[j])
+        {
+          erratic->array[erratic->count++] = linear->array[j];
+          linear->array[j] = (fde *) NULL;
+        }
+      previous_max[i] = j;
+      linear_max = i;
+    }
+
+  for (i = 0, j = 0; i < count; i++)
+    if (linear->array[i] != (fde *) NULL)
+      linear->array[j++] = linear->array[i];
+  linear->count = j;
+}
+
+/* This is O(n log(n)).  BSD/OS defines heapsort in stdlib.h, so we must
+   use a name that does not conflict.  */
+static inline void
+frame_heapsort (fde_vector *erratic)
+{
+  /* For a description of this algorithm, see:
+     Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
+     p. 60-61. */
+  fde ** a = erratic->array;
+  /* A portion of the array is called a "heap" if for all i>=0:
+     If i and 2i+1 are valid indices, then a[i] >= a[2i+1].
+     If i and 2i+2 are valid indices, then a[i] >= a[2i+2]. */
+#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
+  size_t n = erratic->count;
+  size_t m = n;
+  size_t i;
+
+  while (m > 0)
+    {
+      /* Invariant: a[m..n-1] is a heap. */
+      m--;
+      for (i = m; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
+    }
+  while (n > 1)
+    {
+      /* Invariant: a[0..n-1] is a heap. */
+      n--;
+      SWAP (a[0], a[n]);
+      for (i = 0; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
+    }
+#undef SWAP
+}
+
+/* Merge V1 and V2, both sorted, and put the result into V1. */
+static void
+fde_merge (fde_vector *v1, const fde_vector *v2)
+{
+  size_t i1, i2;
+  fde * fde2;
+
+  i2 = v2->count;
+  if (i2 > 0)
+    {
+      i1 = v1->count;
+      do {
+        i2--;
+        fde2 = v2->array[i2];
+        while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0)
+          {
+            v1->array[i1+i2] = v1->array[i1-1];
+            i1--;
+          }
+        v1->array[i1+i2] = fde2;
+      } while (i2 > 0);
+      v1->count += v2->count;
+    }
+}
+
+static fde **
+end_fde_sort (fde_accumulator *accu, size_t count)
+{
+  if (accu->linear.count != count)
+    abort ();
+  fde_split (&accu->linear, &accu->erratic);
+  if (accu->linear.count + accu->erratic.count != count)
+    abort ();
+  frame_heapsort (&accu->erratic);
+  fde_merge (&accu->linear, &accu->erratic);
+  free (accu->erratic.array);
+  return accu->linear.array;
+}
+
+static size_t
+count_fdes (fde *this_fde)
+{
+  size_t count;
+
+  for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs and linked once FDE entries.  */
+      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+	continue;
+
+      ++count;
+    }
+
+  return count;
+}
+
+static void
+add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
+{
+  void *pc_begin = *beg_ptr;
+  void *pc_end = *end_ptr;
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      /* Skip CIEs and linked once FDE entries.  */
+      if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+	continue;
+
+      fde_insert (accu, this_fde);
+
+      if (this_fde->pc_begin < pc_begin)
+	pc_begin = this_fde->pc_begin;
+      if (this_fde->pc_begin + this_fde->pc_range > pc_end)
+	pc_end = this_fde->pc_begin + this_fde->pc_range;
+    }
+
+  *beg_ptr = pc_begin;
+  *end_ptr = pc_end;
+}
+
+/* Set up a sorted array of pointers to FDEs for a loaded object.  We
+   count up the entries before allocating the array because it's likely to
+   be faster.  */
+
+static void
+frame_init (struct object* ob)
+{
+  size_t count;
+  fde_accumulator accu;
+  void *pc_begin, *pc_end;
+
+  if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (count = 0; *p; ++p)
+	count += count_fdes (*p);
+    }
+  else
+    count = count_fdes (ob->fde_begin);
+
+  ob->count = count;
+
+  start_fde_sort (&accu, count);
+  pc_begin = (void*)(uaddr)-1;
+  pc_end = 0;
+
+  if (ob->fde_array)
+    {
+      fde **p = ob->fde_array;
+      for (; *p; ++p)
+	add_fdes (*p, &accu, &pc_begin, &pc_end);
+    }
+  else
+    add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
+
+  ob->fde_array = end_fde_sort (&accu, count);
+  ob->pc_begin = pc_begin;
+  ob->pc_end = pc_end;
+}
+
+/* Return a pointer to the FDE for the function containing PC.  */
+
+static fde *
+find_fde (void *pc)
+{
+  struct object *ob;
+  size_t lo, hi;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
+  for (ob = objects; ob; ob = ob->next)
+    {
+      if (ob->pc_begin == 0)
+	frame_init (ob);
+      if (pc >= ob->pc_begin && pc < ob->pc_end)
+	break;
+    }
+
+  __gthread_mutex_unlock (&object_mutex);
+
+  if (ob == 0)
+    return 0;
+
+  /* Standard binary search algorithm.  */
+  for (lo = 0, hi = ob->count; lo < hi; )
+    {
+      size_t i = (lo + hi) / 2;
+      fde *f = ob->fde_array[i];
+
+      if (pc < f->pc_begin)
+	hi = i;
+      else if (pc >= f->pc_begin + f->pc_range)
+	lo = i + 1;
+      else
+	return f;
+    }
+
+  return 0;
+}
+#endif /* !_LIBC */
+
+static inline struct dwarf_cie *
+get_cie (fde *f)
+{
+  return ((void *)&f->CIE_delta) - f->CIE_delta;
+}
+
+/* Extract any interesting information from the CIE for the translation
+   unit F belongs to.  */
+
+static void *
+extract_cie_info (fde *f, struct cie_info *c)
+{
+  unsigned char *aug;
+  void *p;
+  void *ret = NULL;
+
+  c->augmentation = get_cie (f)->augmentation;
+  aug = c->augmentation;
+  p = aug + strlen (aug) + 1;
+
+  /* "eh" was used by g++ v2; recognize and store.  */
+  if (aug[0] == 'e' && aug[1] == 'h')
+    {
+      c->eh_ptr = read_pointer (p);
+      p += sizeof (void *);
+    }
+
+  /* Immediately following the augmentation are the code and
+     data alignment and return address column.  */
+  p = decode_uleb128 (p, &c->code_align);
+  p = decode_sleb128 (p, &c->data_align);
+  c->ra_regno = *(unsigned char *)p++;
+  c->lsda_encoding = DW_EH_PE_omit;
+
+  if (c->eh_ptr != NULL)
+    return p;
+
+  /* If the augmentation starts with 'z', then a uleb128 immediately
+     follows containing the length of the augmentation field following
+     the size.  */
+  if (*aug == 'z')
+    {
+      int i;
+
+      p = decode_uleb128 (p, &i);
+      ret = p + i;
+
+      c->saw_z = 1;
+      ++aug;
+    }
+
+  /* Iterate over recognized augmentation subsequences.  */
+  while (*aug != '\0')
+    {
+      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
+      if (aug[0] == 'L')
+	{
+	  c->lsda_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
+      else if (aug[0] == 'R')
+	{
+	  c->fde_encoding = *(unsigned char *)p++;
+	  aug += 1;
+	}
+
+      /* "P" indicates a personality routine in the CIE augmentation.  */
+      else if (aug[0] == 'P')
+	{
+#ifdef NEED__Unwind_GetFrameForV2
+	  error (EXIT_FAILURE, 0,
+		 _("%c: Unsupported gcc v3 exception augmentation."),
+		 aug[0]);
+#else
+	  /* We don't support the V3 frame in gcc 2.9x.  */
+	  abort ();
+#endif
+	}
+
+      /* Otherwise we have an unknown augmentation string.
+	 Bail unless we saw a 'z' prefix.  */
+      else
+	return ret;
+    }
+
+  return ret ? ret : p;
+}
+
+/* Decode one instruction's worth of DWARF 2 call frame information.
+   Used by __frame_state_for.  Takes pointers P to the instruction to
+   decode, STATE to the current register unwind information, INFO to the
+   current CIE information, and PC to the current PC value.  Returns a
+   pointer to the next instruction.  */
+
+static void *
+execute_cfa_insn (void *p, struct frame_state_internal *state,
+		  struct cie_info *info)
+{
+  unsigned insn = *(unsigned char *)p++;
+  unsigned reg;
+  int offset;
+
+  if (insn & DW_CFA_advance_loc)
+    info->pc += ((insn & 0x3f) * info->code_align);
+  else if (insn & DW_CFA_offset)
+    {
+      reg = (insn & 0x3f);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = offset;
+    }
+  else if (insn & DW_CFA_restore)
+    {
+      reg = (insn & 0x3f);
+      state->s.saved[reg] = REG_UNSAVED;
+    }
+  else switch (insn)
+    {
+    case DW_CFA_set_loc:
+      info->pc = read_pointer (p);
+      p += sizeof (void *);
+      break;
+    case DW_CFA_advance_loc1:
+      info->pc += read_1byte (p);
+      p += 1;
+      break;
+    case DW_CFA_advance_loc2:
+      info->pc += read_2byte (p);
+      p += 2;
+      break;
+    case DW_CFA_advance_loc4:
+      info->pc += read_4byte (p);
+      p += 4;
+      break;
+
+    case DW_CFA_offset_extended:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = offset;
+      break;
+    case DW_CFA_restore_extended:
+      p = decode_uleb128 (p, &reg);
+      state->s.saved[reg] = REG_UNSAVED;
+      break;
+
+    case DW_CFA_undefined:
+    case DW_CFA_same_value:
+    case DW_CFA_nop:
+      break;
+
+    case DW_CFA_register:
+      {
+	unsigned reg2;
+	p = decode_uleb128 (p, &reg);
+	p = decode_uleb128 (p, &reg2);
+	state->s.saved[reg] = REG_SAVED_REG;
+	state->s.reg_or_offset[reg] = reg2;
+      }
+      break;
+
+    case DW_CFA_def_cfa:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_reg = reg;
+      state->s.cfa_offset = offset;
+      break;
+    case DW_CFA_def_cfa_register:
+      p = decode_uleb128 (p, &reg);
+      state->s.cfa_reg = reg;
+      break;
+    case DW_CFA_def_cfa_offset:
+      p = decode_uleb128 (p, &offset);
+      state->s.cfa_offset = offset;
+      break;
+      
+    case DW_CFA_remember_state:
+      {
+	struct frame_state_internal *save =
+	  (struct frame_state_internal *)
+	  malloc (sizeof (struct frame_state_internal));
+	memcpy (save, state, sizeof (struct frame_state_internal));
+	state->saved_state = save;
+      }
+      break;
+    case DW_CFA_restore_state:
+      {
+	struct frame_state_internal *save = state->saved_state;
+	memcpy (state, save, sizeof (struct frame_state_internal));
+	free (save);
+      }
+      break;
+
+      /* FIXME: Hardcoded for SPARC register window configuration.  */
+    case DW_CFA_GNU_window_save:
+      for (reg = 16; reg < 32; ++reg)
+	{
+	  state->s.saved[reg] = REG_SAVED_OFFSET;
+	  state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
+	}
+      break;
+
+    case DW_CFA_GNU_args_size:
+      p = decode_uleb128 (p, &offset);
+      state->s.args_size = offset;
+      break;
+
+    case DW_CFA_GNU_negative_offset_extended:
+      p = decode_uleb128 (p, &reg);
+      p = decode_uleb128 (p, &offset);
+      offset *= info->data_align;
+      state->s.saved[reg] = REG_SAVED_OFFSET;
+      state->s.reg_or_offset[reg] = -offset;
+      break;
+
+    default:
+      abort ();
+    }
+  return p;
+}
+
+#ifndef _LIBC
+/* Called from crtbegin.o to register the unwind info for an object.  */
+
+void
+__register_frame_info (void *begin, struct object *ob)
+{
+  ob->fde_begin = begin;
+
+  ob->pc_begin = ob->pc_end = 0;
+  ob->fde_array = 0;
+  ob->count = 0;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
+  ob->next = objects;
+  objects = ob;
+
+  __gthread_mutex_unlock (&object_mutex);
+}
+
+void
+__register_frame (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info (begin, ob);                       
+}
+
+/* Similar, but BEGIN is actually a pointer to a table of unwind entries
+   for different translation units.  Called from the file generated by
+   collect2.  */
+
+void
+__register_frame_info_table (void *begin, struct object *ob)
+{
+  ob->fde_begin = begin;
+  ob->fde_array = begin;
+
+  ob->pc_begin = ob->pc_end = 0;
+  ob->count = 0;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
+  ob->next = objects;
+  objects = ob;
+
+  __gthread_mutex_unlock (&object_mutex);
+}
+
+void
+__register_frame_table (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info_table (begin, ob);
+}
+
+/* Called from crtbegin.o to deregister the unwind info for an object.  */
+
+void *
+__deregister_frame_info (void *begin)
+{
+  struct object **p;
+
+  init_object_mutex_once ();
+  __gthread_mutex_lock (&object_mutex);
+
+  p = &objects;
+  while (*p)
+    {
+      if ((*p)->fde_begin == begin)
+	{
+	  struct object *ob = *p;
+	  *p = (*p)->next;
+
+	  /* If we've run init_frame for this object, free the FDE array.  */
+	  if (ob->pc_begin)
+	    free (ob->fde_array);
+
+	  __gthread_mutex_unlock (&object_mutex);
+	  return (void *) ob;
+	}
+      p = &((*p)->next);
+    }
+
+  __gthread_mutex_unlock (&object_mutex);
+  abort ();
+}
+
+void
+__deregister_frame (void *begin)
+{
+  free (__deregister_frame_info (begin));
+}
+#endif /* !_LIBC */
+
+/* Called from __throw to find the registers to restore for a given
+   PC_TARGET.  The caller should allocate a local variable of `struct
+   frame_state' (declared in frame.h) and pass its address to STATE_IN.  */
+
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+{
+  fde *f;
+  void *insn, *end, *pc;
+  struct cie_info info;
+  struct frame_state_internal state;
+#ifdef NEED__Unwind_GetFrameForV2
+  struct dwarf_eh_bases bases;
+
+  f = _Unwind_Find_FDE (pc_target, &bases);
+#else
+  f = find_fde (pc_target);
+#endif
+  if (f == 0)
+    return 0;
+
+  memset (&info, 0, sizeof (info));
+  insn = extract_cie_info (f, &info);
+  if (insn == 0)
+    return 0;
+
+  memset (&state, 0, sizeof (state));
+  state.s.retaddr_column = info.ra_regno;
+  state.s.eh_ptr = info.eh_ptr;
+  
+  if (info.lsda_encoding == DW_EH_PE_omit
+      && info.fde_encoding == 0)
+    {
+      void *end;
+
+      /* First decode all the insns in the CIE.  */
+      end = next_fde ((fde*) get_cie (f));
+      while (insn < end)
+ 	insn = execute_cfa_insn (insn, &state, &info);
+
+      insn = ((fde *)f) + 1;
+
+      if (info.augmentation[0] == 'z')
+	{
+	  int i;
+	  insn = decode_uleb128 (insn, &i);
+	  insn += i;
+	}
+
+      /* Then the insns in the FDE up to our target PC.  */
+      end = next_fde (f);
+      info.pc = f->pc_begin;
+      while (insn < end && info.pc <= pc_target)
+	insn = execute_cfa_insn (insn, &state, &info);
+    }
+  else
+#ifdef NEED__Unwind_GetFrameForV2
+    _Unwind_GetFrameForV2 (pc_target, insn, f, &bases, &state.s, &info);
+#else
+    /* We don't support the V3 frame in gcc 2.9x.  */
+    abort ();
+#endif
+
+  memcpy (state_in, &state.s, sizeof (state.s));
+  return state_in;
+}
+#endif /* DWARF2_UNWIND_INFO */
--- libc/sysdeps/generic/gccframe.h.gcc	Sat Jul  7 16:45:49 2001
+++ libc/sysdeps/generic/gccframe.h	Mon Jul  9 10:23:01 2001
@@ -17,8 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* This must match what's in frame.h in gcc. */
-
+#ifdef NEED_DWARF2_FRAME_UNWIND_OLD_OBJECT
 struct object
 {
   void *pc_begin;
@@ -28,3 +27,36 @@ struct object
   __SIZE_TYPE__ count;
   struct object *next;
 };
+#else
+#include <sys/types.h>
+
+struct dwarf_fde;
+struct fde_vector;
+
+struct object
+{
+  void *pc_begin;
+  void *tbase;
+  void *dbase;
+  union {
+    struct dwarf_fde *single;
+    struct dwarf_fde **array;
+    struct fde_vector *sort;
+  } u;
+
+  union {
+    struct {
+      unsigned long sorted : 1;
+      unsigned long from_array : 1;
+      unsigned long mixed_encoding : 1;
+      unsigned long encoding : 8;
+      /* ??? Wish there was an easy way to detect a 64-bit host here;
+	 we've got 32 bits left to play with... */
+      unsigned long count : 21;
+    } b;
+    size_t i;
+  } s;
+
+  struct object *next;
+};
+#endif
--- libc/sysdeps/generic/unwind-dw2-fde.c.gcc	Fri Jul  6 17:33:15 2001
+++ libc/sysdeps/generic/unwind-dw2-fde.c	Sun Jul  8 19:08:12 2001
@@ -0,0 +1,1009 @@
+/* Subroutines needed for unwinding stack frames for exception handling.  */
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#ifdef _LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <dwarf2.h>
+#include <unwind.h>
+#include <unwind-pe.h>
+#include <unwind-dw2-fde.h>
+#else
+#include "tconfig.h"
+#include "tsystem.h"
+#include "dwarf2.h"
+#include "unwind.h"
+#include "unwind-pe.h"
+#include "unwind-dw2-fde.h"
+#include "gthr.h"
+#endif
+
+/* The unseen_objects list contains objects that have been registered
+   but not yet categorized in any way.  The seen_objects list has had
+   it's pc_begin and count fields initialized at minimum, and is sorted
+   by decreasing value of pc_begin.  */
+static struct object *unseen_objects;
+static struct object *seen_objects;
+
+#ifdef _LIBC
+__libc_lock_define_initialized_recursive (static, object_lock)
+#define init_object_mutex_once()
+#define object_mutex_lock()	__libc_lock_lock (object_lock)
+#define object_mutex_unlock()	__libc_lock_unlock (object_lock)
+#else
+#define object_mutex_lock()	__gthread_mutex_lock (&object_mutex)
+#define object_mutex_unlock()	__gthread_mutex_unlock (&object_mutex)
+#ifdef __GTHREAD_MUTEX_INIT
+static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
+#else
+static __gthread_mutex_t object_mutex;
+#endif
+
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
+static void 
+init_object_mutex (void)
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&object_mutex);
+}
+
+static void
+init_object_mutex_once (void)
+{
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  __gthread_once (&once, init_object_mutex);
+}
+#else
+#define init_object_mutex_once()
+#endif
+#endif /* _LIBC */
+
+/* Called from crtbegin.o to register the unwind info for an object.  */
+
+void
+__register_frame_info_bases (void *begin, struct object *ob,
+			     void *tbase, void *dbase)
+{
+  ob->pc_begin = (void *)-1;
+  ob->tbase = tbase;
+  ob->dbase = dbase;
+  ob->u.single = begin;
+  ob->s.i = 0;
+  ob->s.b.encoding = DW_EH_PE_omit;
+
+  init_object_mutex_once ();
+  object_mutex_lock();
+
+  ob->next = unseen_objects;
+  unseen_objects = ob;
+
+  object_mutex_unlock();
+}
+
+void
+__register_frame_info (void *begin, struct object *ob)
+{
+  __register_frame_info_bases (begin, ob, 0, 0);
+}
+
+void
+__register_frame (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info (begin, ob);                       
+}
+
+/* Similar, but BEGIN is actually a pointer to a table of unwind entries
+   for different translation units.  Called from the file generated by
+   collect2.  */
+
+void
+__register_frame_info_table_bases (void *begin, struct object *ob,
+				   void *tbase, void *dbase)
+{
+  ob->pc_begin = (void *)-1;
+  ob->tbase = tbase;
+  ob->dbase = dbase;
+  ob->u.array = begin;
+  ob->s.i = 0;
+  ob->s.b.from_array = 1;
+  ob->s.b.encoding = DW_EH_PE_omit;
+
+  init_object_mutex_once ();
+  object_mutex_lock();
+
+  ob->next = unseen_objects;
+  unseen_objects = ob;
+
+  object_mutex_unlock();
+}
+
+void
+__register_frame_info_table (void *begin, struct object *ob)
+{
+  __register_frame_info_table_bases (begin, ob, 0, 0);
+}
+
+void
+__register_frame_table (void *begin)
+{
+  struct object *ob = (struct object *) malloc (sizeof (struct object));
+  __register_frame_info_table (begin, ob);
+}
+
+/* Called from crtbegin.o to deregister the unwind info for an object.  */
+/* ??? Glibc has for a while now exported __register_frame_info and
+   __deregister_frame_info.  If we call __register_frame_info_bases
+   from crtbegin (wherein it is declared weak), and this object does
+   not get pulled from libgcc.a for other reasons, then the
+   invocation of __deregister_frame_info will be resolved from glibc.
+   Since the registration did not happen there, we'll abort.
+
+   Therefore, declare a new deregistration entry point that does the
+   exact same thing, but will resolve to the same library as 
+   implements __register_frame_info_bases.  */
+
+void *
+__deregister_frame_info_bases (void *begin)
+{
+  struct object **p;
+  struct object *ob = 0;
+
+  init_object_mutex_once ();
+  object_mutex_lock();
+
+  for (p = &unseen_objects; *p ; p = &(*p)->next)
+    if ((*p)->u.single == begin)
+      {
+	ob = *p;
+	*p = ob->next;
+	goto out;
+      }
+
+  for (p = &seen_objects; *p ; p = &(*p)->next)
+    if ((*p)->s.b.sorted)
+      {
+	if ((*p)->u.sort->orig_data == begin)
+	  {
+	    ob = *p;
+	    *p = ob->next;
+	    free (ob->u.sort);
+	    goto out;
+	  }
+      }
+    else
+      {
+	if ((*p)->u.single == begin)
+	  {
+	    ob = *p;
+	    *p = ob->next;
+	    goto out;
+	  }
+      }
+
+  object_mutex_unlock();
+  abort ();
+
+ out:
+  object_mutex_unlock();
+  return (void *) ob;
+}
+
+void *
+__deregister_frame_info (void *begin)
+{
+  return __deregister_frame_info_bases (begin);
+}
+
+void
+__deregister_frame (void *begin)
+{
+  free (__deregister_frame_info (begin));
+}
+
+
+/* Like base_of_encoded_value, but take the base from a struct object
+   instead of an _Unwind_Context.  */
+
+static _Unwind_Ptr
+base_from_object (unsigned char encoding, struct object *ob)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x70)
+    {
+    case DW_EH_PE_absptr:
+    case DW_EH_PE_pcrel:
+    case DW_EH_PE_aligned:
+      return 0;
+
+    case DW_EH_PE_textrel:
+      return (_Unwind_Ptr) ob->tbase;
+    case DW_EH_PE_datarel:
+      return (_Unwind_Ptr) ob->dbase;
+    }
+  abort ();
+}
+
+/* Return the FDE pointer encoding from the CIE.  */
+/* ??? This is a subset of extract_cie_info from unwind-dw2.c.  */
+
+static int
+get_cie_encoding (struct dwarf_cie *cie)
+{
+  const unsigned char *aug, *p;
+  _Unwind_Ptr dummy;
+
+  aug = cie->augmentation;
+  if (aug[0] != 'z')
+    return DW_EH_PE_absptr;
+
+  p = aug + strlen (aug) + 1;		/* Skip the augmentation string.  */
+  p = read_uleb128 (p, &dummy);		/* Skip code alignment.  */
+  p = read_sleb128 (p, &dummy);		/* Skip data alignment.  */
+  p++;					/* Skip return address column.  */
+
+  aug++;				/* Skip 'z' */
+  p = read_uleb128 (p, &dummy);		/* Skip augmentation length.  */
+  while (1)
+    {
+      /* This is what we're looking for.  */
+      if (*aug == 'R')
+	return *p;
+      /* Personality encoding and pointer.  */
+      else if (*aug == 'P')
+	{
+	  /* ??? Avoid dereferencing indirect pointers, since we're
+	     faking the base address.  Gotta keep DW_EH_PE_aligned
+	     intact, however.  */
+	  p = read_encoded_value_with_base (*p & 0x7F, 0, p + 1, &dummy);
+	}
+      /* LSDA encoding.  */
+      else if (*aug == 'L')
+	p++;
+      /* Otherwise end of string, or unknown augmentation.  */
+      else
+	return DW_EH_PE_absptr;
+      aug++;
+    }
+}
+
+static inline int
+get_fde_encoding (struct dwarf_fde *f)
+{
+  return get_cie_encoding (get_cie (f));
+}
+
+
+/* Sorting an array of FDEs by address.
+   (Ideally we would have the linker sort the FDEs so we don't have to do
+   it at run time. But the linkers are not yet prepared for this.)  */
+
+/* Comparison routines.  Three variants of increasing complexity.  */
+
+static saddr
+fde_unencoded_compare (struct object *ob __attribute__((unused)),
+		       fde *x, fde *y)
+{
+  return *(saddr *)x->pc_begin - *(saddr *)y->pc_begin;
+}
+
+static saddr
+fde_single_encoding_compare (struct object *ob, fde *x, fde *y)
+{
+  _Unwind_Ptr base, x_ptr, y_ptr;
+
+  base = base_from_object (ob->s.b.encoding, ob);
+  read_encoded_value_with_base (ob->s.b.encoding, base, x->pc_begin, &x_ptr);
+  read_encoded_value_with_base (ob->s.b.encoding, base, y->pc_begin, &y_ptr);
+
+  return x_ptr - y_ptr;
+}
+
+static saddr
+fde_mixed_encoding_compare (struct object *ob, fde *x, fde *y)
+{
+  int x_encoding, y_encoding;
+  _Unwind_Ptr x_ptr, y_ptr;
+
+  x_encoding = get_fde_encoding (x);
+  read_encoded_value_with_base (x_encoding, base_from_object (x_encoding, ob),
+				x->pc_begin, &x_ptr);
+
+  y_encoding = get_fde_encoding (y);
+  read_encoded_value_with_base (y_encoding, base_from_object (y_encoding, ob),
+				y->pc_begin, &y_ptr);
+
+  return x_ptr - y_ptr;
+}
+
+typedef saddr (*fde_compare_t) (struct object *, fde *, fde *);
+
+
+/* This is a special mix of insertion sort and heap sort, optimized for
+   the data sets that actually occur. They look like
+   101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
+   I.e. a linearly increasing sequence (coming from functions in the text
+   section), with additionally a few unordered elements (coming from functions
+   in gnu_linkonce sections) whose values are higher than the values in the
+   surrounding linear sequence (but not necessarily higher than the values
+   at the end of the linear sequence!).
+   The worst-case total run time is O(N) + O(n log (n)), where N is the
+   total number of FDEs and n is the number of erratic ones.  */
+
+struct fde_accumulator
+{
+  struct fde_vector *linear;
+  struct fde_vector *erratic;
+};
+
+static inline int
+start_fde_sort (struct fde_accumulator *accu, size_t count)
+{
+  size_t size;
+  if (! count)
+    return 0;
+
+  size = sizeof (struct fde_vector) + sizeof (fde *) * count;
+  if ((accu->linear = (struct fde_vector *) malloc (size)))
+    {
+      accu->linear->count = 0;
+      if ((accu->erratic = (struct fde_vector *) malloc (size)))
+	accu->erratic->count = 0;
+      return 1;
+    }
+  else
+    return 0;  
+}
+
+static inline void
+fde_insert (struct fde_accumulator *accu, fde *this_fde)
+{
+  if (accu->linear)
+    accu->linear->array[accu->linear->count++] = this_fde;
+}
+
+/* Split LINEAR into a linear sequence with low values and an erratic
+   sequence with high values, put the linear one (of longest possible
+   length) into LINEAR and the erratic one into ERRATIC. This is O(N).
+   
+   Because the longest linear sequence we are trying to locate within the
+   incoming LINEAR array can be interspersed with (high valued) erratic
+   entries.  We construct a chain indicating the sequenced entries.
+   To avoid having to allocate this chain, we overlay it onto the space of
+   the ERRATIC array during construction.  A final pass iterates over the
+   chain to determine what should be placed in the ERRATIC array, and
+   what is the linear sequence.  This overlay is safe from aliasing.  */
+
+static inline void
+fde_split (struct object *ob, fde_compare_t fde_compare,
+	   struct fde_vector *linear, struct fde_vector *erratic)
+{
+  static fde *marker;
+  size_t count = linear->count;
+  fde **chain_end = &marker;
+  size_t i, j, k;
+
+  /* This should optimize out, but it is wise to make sure this assumption
+     is correct. Should these have different sizes, we cannot cast between
+     them and the overlaying onto ERRATIC will not work.  */
+  if (sizeof (fde *) != sizeof (fde **))
+    abort ();
+  
+  for (i = 0; i < count; i++)
+    {
+      fde **probe;
+      
+      for (probe = chain_end;
+           probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0;
+           probe = chain_end)
+        {
+          chain_end = (fde **)erratic->array[probe - linear->array];
+          erratic->array[probe - linear->array] = NULL;
+        }
+      erratic->array[i] = (fde *)chain_end;
+      chain_end = &linear->array[i];
+    }
+
+  /* Each entry in LINEAR which is part of the linear sequence we have
+     discovered will correspond to a non-NULL entry in the chain we built in
+     the ERRATIC array.  */
+  for (i = j = k = 0; i < count; i++)
+    if (erratic->array[i])
+      linear->array[j++] = linear->array[i];
+    else
+      erratic->array[k++] = linear->array[i];
+  linear->count = j;
+  erratic->count = k;
+}
+
+/* This is O(n log(n)).  BSD/OS defines heapsort in stdlib.h, so we must
+   use a name that does not conflict.  */
+
+static void
+frame_heapsort (struct object *ob, fde_compare_t fde_compare,
+		struct fde_vector *erratic)
+{
+  /* For a description of this algorithm, see:
+     Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
+     p. 60-61. */
+  fde ** a = erratic->array;
+  /* A portion of the array is called a "heap" if for all i>=0:
+     If i and 2i+1 are valid indices, then a[i] >= a[2i+1].
+     If i and 2i+2 are valid indices, then a[i] >= a[2i+2]. */
+#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
+  size_t n = erratic->count;
+  size_t m = n;
+  size_t i;
+
+  while (m > 0)
+    {
+      /* Invariant: a[m..n-1] is a heap. */
+      m--;
+      for (i = m; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (ob, a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
+    }
+  while (n > 1)
+    {
+      /* Invariant: a[0..n-1] is a heap. */
+      n--;
+      SWAP (a[0], a[n]);
+      for (i = 0; 2*i+1 < n; )
+        {
+          if (2*i+2 < n
+              && fde_compare (ob, a[2*i+2], a[2*i+1]) > 0
+              && fde_compare (ob, a[2*i+2], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+2]);
+              i = 2*i+2;
+            }
+          else if (fde_compare (ob, a[2*i+1], a[i]) > 0)
+            {
+              SWAP (a[i], a[2*i+1]);
+              i = 2*i+1;
+            }
+          else
+            break;
+        }
+    }
+#undef SWAP
+}
+
+/* Merge V1 and V2, both sorted, and put the result into V1. */
+static inline void
+fde_merge (struct object *ob, fde_compare_t fde_compare,
+	   struct fde_vector *v1, struct fde_vector *v2)
+{
+  size_t i1, i2;
+  fde * fde2;
+
+  i2 = v2->count;
+  if (i2 > 0)
+    {
+      i1 = v1->count;
+      do {
+        i2--;
+        fde2 = v2->array[i2];
+        while (i1 > 0 && fde_compare (ob, v1->array[i1-1], fde2) > 0)
+          {
+            v1->array[i1+i2] = v1->array[i1-1];
+            i1--;
+          }
+        v1->array[i1+i2] = fde2;
+      } while (i2 > 0);
+      v1->count += v2->count;
+    }
+}
+
+static inline void
+end_fde_sort (struct object *ob, struct fde_accumulator *accu, size_t count)
+{
+  fde_compare_t fde_compare;
+
+  if (accu->linear && accu->linear->count != count)
+    abort ();
+
+  if (ob->s.b.mixed_encoding)
+    fde_compare = fde_mixed_encoding_compare;
+  else if (ob->s.b.encoding == DW_EH_PE_absptr)
+    fde_compare = fde_unencoded_compare;
+  else
+    fde_compare = fde_single_encoding_compare;
+
+  if (accu->erratic)
+    {
+      fde_split (ob, fde_compare, accu->linear, accu->erratic);
+      if (accu->linear->count + accu->erratic->count != count)
+	abort ();
+      frame_heapsort (ob, fde_compare, accu->erratic);
+      fde_merge (ob, fde_compare, accu->linear, accu->erratic);
+      free (accu->erratic);
+    }
+  else
+    {
+      /* We've not managed to malloc an erratic array,
+	 so heap sort in the linear one.  */
+      frame_heapsort (ob, fde_compare, accu->linear);
+    }
+}
+
+
+/* Update encoding, mixed_encoding, and pc_begin for OB for the 
+   fde array beginning at THIS_FDE.  Return the number of fdes
+   encountered along the way.  */
+
+static size_t
+classify_object_over_fdes (struct object *ob, fde *this_fde)
+{
+  struct dwarf_cie *last_cie = 0;
+  size_t count = 0;
+  int encoding = DW_EH_PE_absptr;
+  _Unwind_Ptr base = 0;
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      struct dwarf_cie *this_cie;
+      _Unwind_Ptr mask, pc_begin;
+
+      /* Skip CIEs.  */
+      if (this_fde->CIE_delta == 0)
+	continue;
+
+      /* Determine the encoding for this FDE.  Note mixed encoded
+	 objects for later.  */
+      this_cie = get_cie (this_fde);
+      if (this_cie != last_cie)
+	{
+	  last_cie = this_cie;
+	  encoding = get_cie_encoding (this_cie);
+	  base = base_from_object (encoding, ob);
+	  if (ob->s.b.encoding == DW_EH_PE_omit)
+	    ob->s.b.encoding = encoding;
+	  else if (ob->s.b.encoding != encoding)
+	    ob->s.b.mixed_encoding = 1;
+	}
+
+      read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
+				    &pc_begin);
+
+      /* Take care to ignore link-once functions that were removed.
+	 In these cases, the function address will be NULL, but if
+	 the encoding is smaller than a pointer a true NULL may not
+	 be representable.  Assume 0 in the representable bits is NULL.  */
+      mask = size_of_encoded_value (encoding);
+      if (mask < sizeof (void *))
+	mask = (1L << (mask << 3)) - 1;
+      else
+	mask = -1;
+
+      if ((pc_begin & mask) == 0)
+	continue;
+
+      count += 1;
+      if ((void *)pc_begin < ob->pc_begin)
+	ob->pc_begin = (void *)pc_begin;
+    }
+
+  return count;
+}
+
+static void
+add_fdes (struct object *ob, struct fde_accumulator *accu, fde *this_fde)
+{
+  struct dwarf_cie *last_cie = 0;
+  int encoding = ob->s.b.encoding;
+  _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      struct dwarf_cie *this_cie;
+
+      /* Skip CIEs.  */
+      if (this_fde->CIE_delta == 0)
+	continue;
+
+      if (ob->s.b.mixed_encoding)
+	{
+	  /* Determine the encoding for this FDE.  Note mixed encoded
+	     objects for later.  */
+	  this_cie = get_cie (this_fde);
+	  if (this_cie != last_cie)
+	    {
+	      last_cie = this_cie;
+	      encoding = get_cie_encoding (this_cie);
+	      base = base_from_object (encoding, ob);
+	    }
+	}
+
+      if (encoding == DW_EH_PE_absptr)
+	{
+	  if (*(_Unwind_Ptr *)this_fde->pc_begin == 0)
+	    continue;
+	}
+      else
+	{
+	  _Unwind_Ptr pc_begin, mask;
+
+	  read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
+					&pc_begin);
+
+	  /* Take care to ignore link-once functions that were removed.
+	     In these cases, the function address will be NULL, but if
+	     the encoding is smaller than a pointer a true NULL may not
+	     be representable.  Assume 0 in the representable bits is NULL.  */
+	  mask = size_of_encoded_value (encoding);
+	  if (mask < sizeof (void *))
+	    mask = (1L << (mask << 3)) - 1;
+	  else
+	    mask = -1;
+
+	  if ((pc_begin & mask) == 0)
+	    continue;
+	}
+
+      fde_insert (accu, this_fde);
+    }
+}
+
+/* Set up a sorted array of pointers to FDEs for a loaded object.  We
+   count up the entries before allocating the array because it's likely to
+   be faster.  We can be called multiple times, should we have failed to
+   allocate a sorted fde array on a previous occasion.  */
+
+static inline void
+init_object (struct object* ob)
+{
+  struct fde_accumulator accu;
+  size_t count;
+
+  count = ob->s.b.count;
+  if (count == 0)
+    {
+      if (ob->s.b.from_array)
+	{
+	  fde **p = ob->u.array;
+	  for (count = 0; *p; ++p)
+	    count += classify_object_over_fdes (ob, *p);
+	}
+      else
+	count = classify_object_over_fdes (ob, ob->u.single);
+
+      /* The count field we have in the main struct object is somewhat
+	 limited, but should suffice for virtually all cases.  If the
+	 counted value doesn't fit, re-write a zero.  The worst that
+	 happens is that we re-count next time -- admittedly non-trivial
+	 in that this implies some 2M fdes, but at least we function.  */
+      ob->s.b.count = count;
+      if (ob->s.b.count != count)
+	ob->s.b.count = 0;
+    }
+
+  if (!start_fde_sort (&accu, count))
+    return;
+
+  if (ob->s.b.from_array)
+    {
+      fde **p;
+      for (p = ob->u.array; *p; ++p)
+        add_fdes (ob, &accu, *p);
+    }
+  else
+    add_fdes (ob, &accu, ob->u.single);
+
+  end_fde_sort (ob, &accu, count);
+
+  /* Save the original fde pointer, since this is the key by which the
+     DSO will deregister the object.  */
+  accu.linear->orig_data = ob->u.single;
+  ob->u.sort = accu.linear;
+
+  ob->s.b.sorted = 1;
+}
+
+/* A linear search through a set of FDEs for the given PC.  This is
+   used when there was insufficient memory to allocate and sort an
+   array.  */
+
+static fde *
+linear_search_fdes (struct object *ob, fde *this_fde, void *pc)
+{
+  struct dwarf_cie *last_cie = 0;
+  int encoding = ob->s.b.encoding;
+  _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob);
+
+  for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+    {
+      struct dwarf_cie *this_cie;
+      _Unwind_Ptr pc_begin, pc_range;
+
+      /* Skip CIEs.  */
+      if (this_fde->CIE_delta == 0)
+	continue;
+
+      if (ob->s.b.mixed_encoding)
+	{
+	  /* Determine the encoding for this FDE.  Note mixed encoded
+	     objects for later.  */
+	  this_cie = get_cie (this_fde);
+	  if (this_cie != last_cie)
+	    {
+	      last_cie = this_cie;
+	      encoding = get_cie_encoding (this_cie);
+	      base = base_from_object (encoding, ob);
+	    }
+	}
+
+      if (encoding == DW_EH_PE_absptr)
+	{
+	  pc_begin = ((_Unwind_Ptr *)this_fde->pc_begin)[0];
+	  pc_range = ((_Unwind_Ptr *)this_fde->pc_begin)[1];
+	  if (pc_begin == 0)
+	    continue;
+	}
+      else
+	{
+	  _Unwind_Ptr mask;
+	  const char *p;
+
+	  p = read_encoded_value_with_base (encoding, base,
+					    this_fde->pc_begin, &pc_begin);
+	  read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
+
+	  /* Take care to ignore link-once functions that were removed.
+	     In these cases, the function address will be NULL, but if
+	     the encoding is smaller than a pointer a true NULL may not
+	     be representable.  Assume 0 in the representable bits is NULL.  */
+	  mask = size_of_encoded_value (encoding);
+	  if (mask < sizeof (void *))
+	    mask = (1L << (mask << 3)) - 1;
+	  else
+	    mask = -1;
+
+	  if ((pc_begin & mask) == 0)
+	    continue;
+	}
+
+      if ((_Unwind_Ptr)pc - pc_begin < pc_range)
+        return this_fde;
+    }
+
+  return NULL;
+}
+
+/* Binary search for an FDE containing the given PC.  Here are three
+   implementations of increasing complexity.  */
+
+static inline fde *
+binary_search_unencoded_fdes (struct object *ob, void *pc)
+{
+  struct fde_vector *vec = ob->u.sort;
+  size_t lo, hi;
+      
+  for (lo = 0, hi = vec->count; lo < hi; )
+    {
+      size_t i = (lo + hi) / 2;
+      fde *f = vec->array[i];
+      void *pc_begin;
+      uaddr pc_range;
+
+      pc_begin = ((void **)f->pc_begin)[0];
+      pc_range = ((uaddr *)f->pc_begin)[1];
+
+      if (pc < pc_begin)
+	hi = i;
+      else if (pc >= pc_begin + pc_range)
+	lo = i + 1;
+      else
+	return f;
+    }
+
+  return NULL;
+}
+
+static inline fde *
+binary_search_single_encoding_fdes (struct object *ob, void *pc)
+{
+  struct fde_vector *vec = ob->u.sort;
+  int encoding = ob->s.b.encoding;
+  _Unwind_Ptr base = base_from_object (encoding, ob);
+  size_t lo, hi;
+      
+  for (lo = 0, hi = vec->count; lo < hi; )
+    {
+      size_t i = (lo + hi) / 2;
+      fde *f = vec->array[i];
+      _Unwind_Ptr pc_begin, pc_range;
+      const char *p;
+
+      p = read_encoded_value_with_base (encoding, base, f->pc_begin,
+					&pc_begin);
+      read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
+
+      if ((_Unwind_Ptr)pc < pc_begin)
+	hi = i;
+      else if ((_Unwind_Ptr)pc >= pc_begin + pc_range)
+	lo = i + 1;
+      else
+	return f;
+    }
+
+  return NULL;
+}
+
+static inline fde *
+binary_search_mixed_encoding_fdes (struct object *ob, void *pc)
+{
+  struct fde_vector *vec = ob->u.sort;
+  size_t lo, hi;
+      
+  for (lo = 0, hi = vec->count; lo < hi; )
+    {
+      size_t i = (lo + hi) / 2;
+      fde *f = vec->array[i];
+      _Unwind_Ptr pc_begin, pc_range;
+      const char *p;
+      int encoding;
+
+      encoding = get_fde_encoding (f);
+      p = read_encoded_value_with_base (encoding,
+					base_from_object (encoding, ob),
+					f->pc_begin, &pc_begin);
+      read_encoded_value_with_base (encoding & 0x0F, 0, p, &pc_range);
+
+      if ((_Unwind_Ptr)pc < pc_begin)
+	hi = i;
+      else if ((_Unwind_Ptr)pc >= pc_begin + pc_range)
+	lo = i + 1;
+      else
+	return f;
+    }
+
+  return NULL;
+}
+
+static fde *
+search_object (struct object* ob, void *pc)
+{
+  /* If the data hasn't been sorted, try to do this now.  We may have
+     more memory available than last time we tried.  */
+  if (! ob->s.b.sorted)
+    {
+      init_object (ob);
+
+      /* Despite the above comment, the normal reason to get here is
+	 that we've not processed this object before.  A quick range
+	 check is in order.  */
+      if (pc < ob->pc_begin)
+	return NULL;
+    }
+
+  if (ob->s.b.sorted)
+    {
+      if (ob->s.b.mixed_encoding)
+	return binary_search_mixed_encoding_fdes (ob, pc);
+      else if (ob->s.b.encoding == DW_EH_PE_absptr)
+	return binary_search_unencoded_fdes (ob, pc);
+      else
+	return binary_search_single_encoding_fdes (ob, pc);
+    }
+  else
+    {
+      /* Long slow labourious linear search, cos we've no memory.  */
+      if (ob->s.b.from_array)
+        {
+          fde **p;
+	  for (p = ob->u.array; *p ; p++)
+	    {
+	      fde *f = linear_search_fdes (ob, *p, pc);
+              if (f)
+		return f;
+            }
+	  return NULL;
+	}
+      else
+	return linear_search_fdes (ob, ob->u.single, pc);
+    }
+}
+
+fde *
+_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
+{
+  struct object *ob;
+  fde *f = NULL;
+
+  init_object_mutex_once ();
+  object_mutex_lock();
+
+  /* Linear search through the classified objects, to find the one
+     containing the pc.  Note that pc_begin is sorted decending, and
+     we expect objects to be non-overlapping.  */
+  for (ob = seen_objects; ob; ob = ob->next)
+    if (pc >= ob->pc_begin)
+      {
+	f = search_object (ob, pc);
+	if (f)
+	  goto fini;
+	break;
+      }
+
+  /* Classify and search the objects we've not yet processed.  */
+  while ((ob = unseen_objects))
+    {
+      struct object **p;
+
+      unseen_objects = ob->next;
+      f = search_object (ob, pc);
+
+      /* Insert the object into the classified list.  */
+      for (p = &seen_objects; *p ; p = &(*p)->next)
+	if ((*p)->pc_begin < ob->pc_begin)
+	  break;
+      ob->next = *p;
+      *p = ob;
+
+      if (f)
+	goto fini;
+    }
+
+ fini:
+  object_mutex_unlock();
+
+  if (f)
+    {
+      int encoding;
+
+      bases->tbase = ob->tbase;
+      bases->dbase = ob->dbase;
+
+      encoding = ob->s.b.encoding;
+      if (ob->s.b.mixed_encoding)
+	encoding = get_fde_encoding (f);
+      read_encoded_value_with_base (encoding, base_from_object (encoding, ob),
+				    f->pc_begin, (_Unwind_Ptr *)&bases->func);
+    }
+
+  return f;
+}
--- libc/sysdeps/generic/unwind-dw2-fde.h.gcc	Fri Jul  6 15:06:02 2001
+++ libc/sysdeps/generic/unwind-dw2-fde.h	Sun Jul  8 19:10:40 2001
@@ -0,0 +1,161 @@
+/* Subroutines needed for unwinding stack frames for exception handling.  */
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Support different versions of gcc and glibc.  */
+#if defined _LIBC && defined __flexarr
+#define DW_EH_flexarr __flexarr
+#endif
+
+#ifndef DW_EH_flexarr
+#define DW_EH_flexarr []
+#endif
+
+struct fde_vector
+{
+  void *orig_data;
+  size_t count;
+  struct dwarf_fde *array DW_EH_flexarr;
+};
+
+#ifndef _LIBC
+struct object
+{
+  void *pc_begin;
+  void *tbase;
+  void *dbase;
+  union {
+    struct dwarf_fde *single;
+    struct dwarf_fde **array;
+    struct fde_vector *sort;
+  } u;
+
+  union {
+    struct {
+      unsigned long sorted : 1;
+      unsigned long from_array : 1;
+      unsigned long mixed_encoding : 1;
+      unsigned long encoding : 8;
+      /* ??? Wish there was an easy way to detect a 64-bit host here;
+	 we've got 32 bits left to play with... */
+      unsigned long count : 21;
+    } b;
+    size_t i;
+  } s;
+
+  struct object *next;
+};
+#endif
+
+/* This is the original definition of struct object.  While the struct
+   itself was opaque to users, they did know how large it was, and
+   allocate one statically in crtbegin for each DSO.  Keep this around
+   so that we're aware of the static size limitations for the new struct.  */
+struct old_object
+{
+  void *pc_begin;
+  void *pc_end;
+  struct dwarf_fde *fde_begin;
+  struct dwarf_fde **fde_array;
+  size_t count;
+  struct old_object *next;
+};
+
+extern void __register_frame_info_bases (void *, struct object *,
+					 void *, void *);
+extern void __register_frame_info (void *, struct object *);
+extern void __register_frame (void *);
+extern void __register_frame_info_table_bases (void *, struct object *,
+					       void *, void *);
+extern void __register_frame_info_table (void *, struct object *);
+extern void __register_frame_table (void *);
+extern void *__deregister_frame_info (void *);
+extern void *__deregister_frame_info_bases (void *);
+extern void __deregister_frame (void *);
+
+
+typedef          int  sword __attribute__ ((mode (SI)));
+typedef unsigned int  uword __attribute__ ((mode (SI)));
+typedef unsigned int  uaddr __attribute__ ((mode (pointer)));
+typedef          int  saddr __attribute__ ((mode (pointer)));
+typedef unsigned char ubyte;
+
+/* Terminology:
+   CIE - Common Information Element
+   FDE - Frame Descriptor Element
+
+   There is one per function, and it describes where the function code
+   is located, and what the register lifetimes and stack layout are
+   within the function.
+
+   The data structures are defined in the DWARF specfication, although
+   not in a very readable way (see LITERATURE).
+
+   Every time an exception is thrown, the code needs to locate the FDE
+   for the current function, and starts to look for exception regions
+   from that FDE. This works in a two-level search:
+   a) in a linear search, find the shared image (i.e. DLL) containing
+      the PC
+   b) using the FDE table for that shared object, locate the FDE using
+      binary search (which requires the sorting).  */   
+
+/* The first few fields of a CIE.  The CIE_id field is 0 for a CIE,
+   to distinguish it from a valid FDE.  FDEs are aligned to an addressing
+   unit boundary, but the fields within are unaligned.  */
+struct dwarf_cie
+{
+  uword length;
+  sword CIE_id;
+  ubyte version;
+  unsigned char augmentation DW_EH_flexarr;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+/* The first few fields of an FDE.  */
+struct dwarf_fde
+{
+  uword length;
+  sword CIE_delta;
+  unsigned char pc_begin DW_EH_flexarr;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+#ifndef DWARF2_FRAME_UNWIND_V2
+/* Locate the CIE for a given FDE.  */
+
+static inline struct dwarf_cie *
+get_cie (struct dwarf_fde *f)
+{
+  return (void *)&f->CIE_delta - f->CIE_delta;
+}
+
+static inline struct dwarf_fde *
+next_fde (struct dwarf_fde *f)
+{
+  return (struct dwarf_fde *)((char *)f + f->length + sizeof (f->length));
+}
+#endif /* !DWARF2_FRAME_UNWIND_V2 */
--- libc/sysdeps/generic/unwind-dw2.c.gcc	Fri Jul  6 15:06:02 2001
+++ libc/sysdeps/generic/unwind-dw2.c	Sun Jul  8 18:58:58 2001
@@ -0,0 +1,1225 @@
+/* DWARF2 exception handling and frame unwind runtime interface routines.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef _LIBC
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <libintl.h>
+#include <dwarf2.h>
+#include <unwind.h>
+#define NEED__Unwind_GetFrameForV2
+#include <unwind-pe.h>
+#include <unwind-dw2-fde.h>
+
+#undef USING_SJLJ_EXCEPTIONS
+#define USING_SJLJ_EXCEPTIONS 0
+#else
+#include "tconfig.h"
+#include "tsystem.h"
+#include "dwarf2.h"
+#include "unwind.h"
+#include "unwind-pe.h"
+#include "unwind-dw2-fde.h"
+#include "gthr.h"
+#endif
+
+
+#if !USING_SJLJ_EXCEPTIONS
+
+/* A target can override (perhaps for backward compatibility) how
+   many dwarf2 columns are unwound.  */
+#ifndef DWARF_FRAME_REGISTERS
+#define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
+#endif
+
+/* This is the register and unwind state for a particular frame.  */
+struct _Unwind_Context
+{
+  void *reg[DWARF_FRAME_REGISTERS+1];
+  void *cfa;
+  void *ra;
+  void *lsda;
+  struct dwarf_eh_bases bases;
+  _Unwind_Word args_size;
+};
+
+#ifndef NEED__Unwind_GetFrameForV2
+#ifndef STACK_GROWS_DOWNWARD
+#define STACK_GROWS_DOWNWARD 0
+#else
+#undef STACK_GROWS_DOWNWARD
+#define STACK_GROWS_DOWNWARD 1
+#endif
+
+/* Byte size of every register managed by these routines.  */
+static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS];
+#endif /* NEED__Unwind_GetFrameForV2 */
+
+
+/* The result of interpreting the frame unwind info for a frame.
+   This is all symbolic at this point, as none of the values can
+   be resolved until the target pc is located.  */
+typedef struct
+{
+  /* Each register save state can be described in terms of a CFA slot,
+     another register, or a location expression.  */
+  struct frame_state_reg_info
+  {
+    struct {
+      union {
+	unsigned int reg;
+	_Unwind_Sword offset;
+	const unsigned char *exp;
+      } loc;
+      enum {
+	REG_UNSAVED,
+	REG_SAVED_OFFSET,
+	REG_SAVED_REG,
+	REG_SAVED_EXP,
+      } how;
+    } reg[DWARF_FRAME_REGISTERS+1];
+
+    /* Used to implement DW_CFA_remember_state.  */
+    struct frame_state_reg_info *prev;
+  } regs;
+
+  /* The CFA can be described in terms of a reg+offset or a
+     location expression.  */
+  _Unwind_Sword cfa_offset;
+  _Unwind_Word cfa_reg;
+  const unsigned char *cfa_exp;
+  enum {
+    CFA_UNSET,
+    CFA_REG_OFFSET,
+    CFA_EXP,
+  } cfa_how;
+
+  /* The PC described by the current frame state.  */
+  void *pc;
+
+  /* The information we care about from the CIE/FDE.  */
+  _Unwind_Personality_Fn personality;
+  signed int data_align;
+  unsigned int code_align;
+  unsigned char retaddr_column;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
+} _Unwind_FrameState;
+
+/* Read unaligned data from the instruction buffer.  */
+
+union unaligned
+{
+  void *p;
+  unsigned u2 __attribute__ ((mode (HI)));
+  unsigned u4 __attribute__ ((mode (SI)));
+  unsigned u8 __attribute__ ((mode (DI)));
+  signed s2 __attribute__ ((mode (HI)));
+  signed s4 __attribute__ ((mode (SI)));
+  signed s8 __attribute__ ((mode (DI)));
+} __attribute__ ((packed));
+
+static inline void *
+read_pointer (const void *p) { const union unaligned *up = p; return up->p; }
+
+static inline int
+read_1u (const void *p) { return *(const unsigned char *)p; }
+
+static inline int
+read_1s (const void *p) { return *(const signed char *)p; }
+
+static inline int
+read_2u (const void *p) { const union unaligned *up = p; return up->u2; }
+
+static inline int
+read_2s (const void *p) { const union unaligned *up = p; return up->s2; }
+
+static inline unsigned int
+read_4u (const void *p) { const union unaligned *up = p; return up->u4; }
+
+static inline int
+read_4s (const void *p) { const union unaligned *up = p; return up->s4; }
+
+static inline unsigned long
+read_8u (const void *p) { const union unaligned *up = p; return up->u8; }
+
+static inline unsigned long
+read_8s (const void *p) { const union unaligned *up = p; return up->s8; }
+
+/* Get the value of register REG as saved in CONTEXT.  */
+
+inline _Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *context, int index)
+{
+  /* This will segfault if the register hasn't been saved.  */
+  return * (_Unwind_Word *) context->reg[index];
+}
+
+/* Overwrite the saved value for register REG in CONTEXT with VAL.  */
+
+inline void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+  * (_Unwind_Word *) context->reg[index] = val;
+}
+
+/* Retrieve the return address for CONTEXT.  */
+
+inline _Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->ra;
+}
+
+/* Overwrite the return address for CONTEXT with VAL.  */
+
+inline void
+_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
+{
+  context->ra = (void *) val;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
+{
+  return context->lsda;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->bases.func;
+}
+
+#ifndef __ia64__
+_Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->bases.dbase;
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *context)
+{
+  return (_Unwind_Ptr) context->bases.tbase;
+}
+#endif
+
+#ifndef NEED__Unwind_GetFrameForV2
+/* Extract any interesting information from the CIE for the translation
+   unit F belongs to.  Return a pointer to the byte after the augmentation,
+   or NULL if we encountered an undecipherable augmentation.  */
+
+static const unsigned char *
+extract_cie_info (struct dwarf_cie *cie, struct _Unwind_Context *context,
+		  _Unwind_FrameState *fs)
+{
+  const unsigned char *aug = cie->augmentation;
+  const unsigned char *p = aug + strlen (aug) + 1;
+  const unsigned char *ret = NULL;
+  _Unwind_Ptr tmp;
+
+  /* Immediately following the augmentation are the code and
+     data alignment and return address column.  */
+  p = read_uleb128 (p, &tmp); fs->code_align = tmp;
+  p = read_sleb128 (p, &tmp); fs->data_align = (saddr) tmp;
+  fs->retaddr_column = *p++;
+  fs->lsda_encoding = DW_EH_PE_omit;
+
+  /* If the augmentation starts with 'z', then a uleb128 immediately
+     follows containing the length of the augmentation field following
+     the size.  */
+  if (*aug == 'z')
+    {
+      p = read_uleb128 (p, &tmp);
+      ret = p + tmp;
+
+      fs->saw_z = 1;
+      ++aug;
+    }
+
+  /* Iterate over recognized augmentation subsequences.  */
+  while (*aug != '\0')
+    {
+      /* "eh" was used by g++ v2; recognize and skip.  */
+      if (aug[0] == 'e' && aug[1] == 'h')
+	{
+	  p += sizeof (void *);
+	  aug += 2;
+	}
+
+      /* "L" indicates a byte showing how the LSDA pointer is encoded.  */
+      else if (aug[0] == 'L')
+	{
+	  fs->lsda_encoding = *p++;
+	  aug += 1;
+	}
+
+      /* "R" indicates a byte indicating how FDE addresses are encoded.  */
+      else if (aug[0] == 'R')
+	{
+	  fs->fde_encoding = *p++;
+	  aug += 1;
+	}
+
+      /* "P" indicates a personality routine in the CIE augmentation.  */
+      else if (aug[0] == 'P')
+	{
+	  p = read_encoded_value (context, *p, p + 1,
+				  (_Unwind_Ptr *) &fs->personality);
+	  aug += 1;
+	}
+
+      /* Otherwise we have an unknown augmentation string.
+	 Bail unless we saw a 'z' prefix.  */
+      else
+	return ret;
+    }
+
+  return ret ? ret : p;
+}
+
+
+/* Decode a DW_OP stack program.  Return the top of stack.  Push INITIAL
+   onto the stack to start.  */
+
+static _Unwind_Word
+execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
+		  struct _Unwind_Context *context, _Unwind_Word initial)
+{
+  _Unwind_Word stack[64];	/* ??? Assume this is enough. */
+  int stack_elt;
+
+  stack[0] = initial;
+  stack_elt = 1;
+
+  while (op_ptr < op_end)
+    {
+      enum dwarf_location_atom op = *op_ptr++;
+      _Unwind_Word result, reg;
+      _Unwind_Sword offset;
+      _Unwind_Ptr ptrtmp;
+
+      switch (op)
+	{
+	case DW_OP_lit0:
+	case DW_OP_lit1:
+	case DW_OP_lit2:
+	case DW_OP_lit3:
+	case DW_OP_lit4:
+	case DW_OP_lit5:
+	case DW_OP_lit6:
+	case DW_OP_lit7:
+	case DW_OP_lit8:
+	case DW_OP_lit9:
+	case DW_OP_lit10:
+	case DW_OP_lit11:
+	case DW_OP_lit12:
+	case DW_OP_lit13:
+	case DW_OP_lit14:
+	case DW_OP_lit15:
+	case DW_OP_lit16:
+	case DW_OP_lit17:
+	case DW_OP_lit18:
+	case DW_OP_lit19:
+	case DW_OP_lit20:
+	case DW_OP_lit21:
+	case DW_OP_lit22:
+	case DW_OP_lit23:
+	case DW_OP_lit24:
+	case DW_OP_lit25:
+	case DW_OP_lit26:
+	case DW_OP_lit27:
+	case DW_OP_lit28:
+	case DW_OP_lit29:
+	case DW_OP_lit30:
+	case DW_OP_lit31:
+	  result = op - DW_OP_lit0;
+	  break;
+
+	case DW_OP_addr:
+	  result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr);
+	  op_ptr += sizeof (void *);
+	  break;
+
+	case DW_OP_const1u:
+	  result = read_1u (op_ptr);
+	  op_ptr += 1;
+	  break;
+	case DW_OP_const1s:
+	  result = read_1s (op_ptr);
+	  op_ptr += 1;
+	  break;
+	case DW_OP_const2u:
+	  result = read_2u (op_ptr);
+	  op_ptr += 2;
+	  break;
+	case DW_OP_const2s:
+	  result = read_2s (op_ptr);
+	  op_ptr += 2;
+	  break;
+	case DW_OP_const4u:
+	  result = read_4u (op_ptr);
+	  op_ptr += 4;
+	  break;
+	case DW_OP_const4s:
+	  result = read_4s (op_ptr);
+	  op_ptr += 4;
+	  break;
+	case DW_OP_const8u:
+	  result = read_8u (op_ptr);
+	  op_ptr += 8;
+	  break;
+	case DW_OP_const8s:
+	  result = read_8s (op_ptr);
+	  op_ptr += 8;
+	  break;
+	case DW_OP_constu:
+	  op_ptr = read_uleb128 (op_ptr, &ptrtmp);
+	  result = ptrtmp;
+	  break;
+	case DW_OP_consts:
+	  op_ptr = read_sleb128 (op_ptr, &ptrtmp);
+	  result = (saddr)ptrtmp;
+	  break;
+
+	case DW_OP_reg0:
+	case DW_OP_reg1:
+	case DW_OP_reg2:
+	case DW_OP_reg3:
+	case DW_OP_reg4:
+	case DW_OP_reg5:
+	case DW_OP_reg6:
+	case DW_OP_reg7:
+	case DW_OP_reg8:
+	case DW_OP_reg9:
+	case DW_OP_reg10:
+	case DW_OP_reg11:
+	case DW_OP_reg12:
+	case DW_OP_reg13:
+	case DW_OP_reg14:
+	case DW_OP_reg15:
+	case DW_OP_reg16:
+	case DW_OP_reg17:
+	case DW_OP_reg18:
+	case DW_OP_reg19:
+	case DW_OP_reg20:
+	case DW_OP_reg21:
+	case DW_OP_reg22:
+	case DW_OP_reg23:
+	case DW_OP_reg24:
+	case DW_OP_reg25:
+	case DW_OP_reg26:
+	case DW_OP_reg27:
+	case DW_OP_reg28:
+	case DW_OP_reg29:
+	case DW_OP_reg30:
+	case DW_OP_reg31:
+	  result = _Unwind_GetGR (context, op - DW_OP_reg0);
+	  break;
+	case DW_OP_regx:
+	  op_ptr = read_uleb128 (op_ptr, &ptrtmp); reg = ptrtmp;
+	  result = _Unwind_GetGR (context, reg);
+	  break;
+
+	case DW_OP_breg0:
+	case DW_OP_breg1:
+	case DW_OP_breg2:
+	case DW_OP_breg3:
+	case DW_OP_breg4:
+	case DW_OP_breg5:
+	case DW_OP_breg6:
+	case DW_OP_breg7:
+	case DW_OP_breg8:
+	case DW_OP_breg9:
+	case DW_OP_breg10:
+	case DW_OP_breg11:
+	case DW_OP_breg12:
+	case DW_OP_breg13:
+	case DW_OP_breg14:
+	case DW_OP_breg15:
+	case DW_OP_breg16:
+	case DW_OP_breg17:
+	case DW_OP_breg18:
+	case DW_OP_breg19:
+	case DW_OP_breg20:
+	case DW_OP_breg21:
+	case DW_OP_breg22:
+	case DW_OP_breg23:
+	case DW_OP_breg24:
+	case DW_OP_breg25:
+	case DW_OP_breg26:
+	case DW_OP_breg27:
+	case DW_OP_breg28:
+	case DW_OP_breg29:
+	case DW_OP_breg30:
+	case DW_OP_breg31:
+	  op_ptr = read_sleb128 (op_ptr, &ptrtmp); offset = (saddr)ptrtmp;
+	  result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset;
+	  break;
+	case DW_OP_bregx:
+	  op_ptr = read_uleb128 (op_ptr, &ptrtmp); reg = ptrtmp;
+	  op_ptr = read_sleb128 (op_ptr, &ptrtmp); offset = (saddr)ptrtmp;
+	  result = _Unwind_GetGR (context, reg) + offset;
+	  break;
+
+	case DW_OP_dup:
+	  if (stack_elt < 1)
+	    abort ();
+	  result = stack[stack_elt - 1];
+	  break;
+
+	case DW_OP_drop:
+	  if (--stack_elt < 0)
+	    abort ();
+	  goto no_push;
+
+	case DW_OP_pick:
+	  offset = *op_ptr++;
+	  if (offset >= stack_elt - 1)
+	    abort ();
+	  result = stack[stack_elt - 1 - offset];
+	  break;
+
+	case DW_OP_over:
+	  if (stack_elt < 2)
+	    abort ();
+	  result = stack[stack_elt - 2];
+	  break;
+
+	case DW_OP_rot:
+	  {
+	    _Unwind_Word t1, t2, t3;
+
+	    if (stack_elt < 3)
+	      abort ();
+	    t1 = stack[stack_elt - 1];
+	    t2 = stack[stack_elt - 2];
+	    t3 = stack[stack_elt - 3];
+	    stack[stack_elt - 1] = t2;
+	    stack[stack_elt - 2] = t3;
+	    stack[stack_elt - 3] = t1;
+	    goto no_push;
+	  }
+
+	case DW_OP_deref:
+	case DW_OP_deref_size:
+	case DW_OP_abs:
+	case DW_OP_neg:
+	case DW_OP_not:
+	case DW_OP_plus_uconst:
+	  /* Unary operations.  */
+	  if (--stack_elt < 0)
+	    abort ();
+	  result = stack[stack_elt];
+
+	  switch (op)
+	    {
+	    case DW_OP_deref:
+	      {
+		void *ptr = (void *)(_Unwind_Ptr) result;
+		result = (_Unwind_Ptr) read_pointer (ptr);
+	      }
+	      break;
+
+	    case DW_OP_deref_size:
+	      {
+		void *ptr = (void *)(_Unwind_Ptr) result;
+		switch (*op_ptr++)
+		  {
+		  case 1:
+		    result = read_1u (ptr);
+		    break;
+		  case 2:
+		    result = read_2u (ptr);
+		    break;
+		  case 4:
+		    result = read_4u (ptr);
+		    break;
+		  case 8:
+		    result = read_8u (ptr);
+		    break;
+		  default:
+		    abort ();
+		  }
+	      }
+	      break;
+
+	    case DW_OP_abs:
+	      if ((_Unwind_Sword) result < 0)
+		result = -result;
+	      break;
+	    case DW_OP_neg:
+	      result = -result;
+	      break;
+	    case DW_OP_not:
+	      result = ~result;
+	      break;
+	    case DW_OP_plus_uconst:
+	      op_ptr = read_uleb128 (op_ptr, &ptrtmp); reg = ptrtmp;
+	      result += reg;
+	      break;
+	    }
+	  break;
+
+	case DW_OP_and:
+	case DW_OP_div:
+	case DW_OP_minus:
+	case DW_OP_mod:
+	case DW_OP_mul:
+	case DW_OP_or:
+	case DW_OP_plus:
+	case DW_OP_le:
+	case DW_OP_ge:
+	case DW_OP_eq:
+	case DW_OP_lt:
+	case DW_OP_gt:
+	case DW_OP_ne:
+	  {
+	    /* Binary operations.  */
+	    _Unwind_Word first, second;
+	  if ((stack_elt -= 2) < 0)
+	    abort ();
+	  second = stack[stack_elt];
+	  first = stack[stack_elt + 1];
+
+	  switch (op)
+	    {
+	    case DW_OP_and:
+	      result = second & first;
+	      break;
+	    case DW_OP_div:
+	      result = (_Unwind_Sword)second / (_Unwind_Sword)first;
+	      break;
+	    case DW_OP_minus:
+	      result = second - first;
+	      break;
+	    case DW_OP_mod:
+	      result = (_Unwind_Sword)second % (_Unwind_Sword)first;
+	      break;
+	    case DW_OP_mul:
+	      result = second * first;
+	      break;
+	    case DW_OP_or:
+	      result = second | first;
+	      break;
+	    case DW_OP_plus:
+	      result = second + first;
+	      break;
+	    case DW_OP_shl:
+	      result = second << first;
+	      break;
+	    case DW_OP_shr:
+	      result = second >> first;
+	      break;
+	    case DW_OP_shra:
+	      result = (_Unwind_Sword)second >> first;
+	      break;
+	    case DW_OP_xor:
+	      result = second ^ first;
+	      break;
+	    case DW_OP_le:
+	      result = (_Unwind_Sword)first <= (_Unwind_Sword)second;
+	      break;
+	    case DW_OP_ge:
+	      result = (_Unwind_Sword)first >= (_Unwind_Sword)second;
+	      break;
+	    case DW_OP_eq:
+	      result = (_Unwind_Sword)first == (_Unwind_Sword)second;
+	      break;
+	    case DW_OP_lt:
+	      result = (_Unwind_Sword)first < (_Unwind_Sword)second;
+	      break;
+	    case DW_OP_gt:
+	      result = (_Unwind_Sword)first > (_Unwind_Sword)second;
+	      break;
+	    case DW_OP_ne:
+	      result = (_Unwind_Sword)first != (_Unwind_Sword)second;
+	      break;
+	    }
+	  }
+	  break;
+
+	case DW_OP_skip:
+	  offset = read_2s (op_ptr);
+	  op_ptr += 2;
+	  op_ptr += offset;
+	  goto no_push;
+
+	case DW_OP_bra:
+	  if (--stack_elt < 0)
+	    abort ();
+	  offset = read_2s (op_ptr);
+	  op_ptr += 2;
+	  if (stack[stack_elt] != 0)
+	    op_ptr += offset;
+	  goto no_push;
+
+	case DW_OP_nop:
+	  goto no_push;
+
+	default:
+	  abort ();
+	}
+
+      /* Most things push a result value.  */
+      if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack))
+	abort ();
+      stack[++stack_elt] = result;
+    no_push:;
+    }
+
+  /* We were executing this program to get a value.  It should be
+     at top of stack.  */
+  if (--stack_elt < 0)
+    abort ();
+  return stack[stack_elt];
+}
+#endif /* !NEED__Unwind_GetFrameForV2 */
+
+/* Decode DWARF 2 call frame information. Takes pointers the
+   instruction sequence to decode, current register information and
+   CIE info, and the PC range to evaluate.  */
+
+static void
+execute_cfa_program (const unsigned char *insn_ptr,
+		     const unsigned char *insn_end,
+		     struct _Unwind_Context *context,
+		     _Unwind_FrameState *fs)
+{
+  struct frame_state_reg_info *unused_rs = NULL;
+
+  /* Don't allow remember/restore between CIE and FDE programs.  */
+  fs->regs.prev = NULL;
+
+  while (insn_ptr < insn_end && fs->pc < context->ra)
+    {
+      unsigned char insn = *insn_ptr++;
+      _Unwind_Word reg;
+      _Unwind_Sword offset;
+      _Unwind_Ptr ptrtmp;
+
+      if (insn & DW_CFA_advance_loc)
+	fs->pc += (insn & 0x3f) * fs->code_align;
+      else if (insn & DW_CFA_offset)
+	{
+	  reg = insn & 0x3f;
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  offset = ptrtmp * fs->data_align;
+	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+	  fs->regs.reg[reg].loc.offset = offset;
+	}
+      else if (insn & DW_CFA_restore)
+	{
+	  reg = insn & 0x3f;
+	  fs->regs.reg[reg].how = REG_UNSAVED;
+	}
+      else switch (insn)
+	{
+	case DW_CFA_set_loc:
+	  insn_ptr = read_encoded_value (context, fs->fde_encoding,
+					 insn_ptr, (_Unwind_Ptr *) &fs->pc);
+	  break;
+
+	case DW_CFA_advance_loc1:
+	  fs->pc += read_1u (insn_ptr) * fs->code_align;
+	  insn_ptr += 1;
+	  break;
+	case DW_CFA_advance_loc2:
+	  fs->pc += read_2u (insn_ptr) * fs->code_align;
+	  insn_ptr += 2;
+	  break;
+	case DW_CFA_advance_loc4:
+	  fs->pc += read_4u (insn_ptr) * fs->code_align;
+	  insn_ptr += 4;
+	  break;
+
+	case DW_CFA_offset_extended:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  offset = ptrtmp * fs->data_align;
+	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+	  fs->regs.reg[reg].loc.offset = offset;
+	  break;
+
+	case DW_CFA_restore_extended:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	  fs->regs.reg[reg].how = REG_UNSAVED;
+	  break;
+
+	case DW_CFA_undefined:
+	case DW_CFA_same_value:
+	case DW_CFA_nop:
+	  break;
+
+	case DW_CFA_register:
+	  {
+	    _Unwind_Word reg2;
+	    insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	    insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg2 = ptrtmp;
+	    fs->regs.reg[reg].how = REG_SAVED_REG;
+	    fs->regs.reg[reg].loc.reg = reg2;
+	  }
+	  break;
+      
+	case DW_CFA_remember_state:
+	  {
+	    struct frame_state_reg_info *new_rs;
+	    if (unused_rs)
+	      {
+		new_rs = unused_rs;
+		unused_rs = unused_rs->prev;
+	      }
+	    else
+	      new_rs = alloca (sizeof (struct frame_state_reg_info));
+
+	    *new_rs = fs->regs;
+	    fs->regs.prev = new_rs;
+	  }
+	  break;
+
+	case DW_CFA_restore_state:
+	  {
+	    struct frame_state_reg_info *old_rs = fs->regs.prev;
+	    fs->regs = *old_rs;
+	    old_rs->prev = unused_rs;
+	    unused_rs = old_rs;
+	  }
+	  break;
+
+	case DW_CFA_def_cfa:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_reg = ptrtmp;
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_offset = ptrtmp;
+	  fs->cfa_how = CFA_REG_OFFSET;
+	  break;
+
+	case DW_CFA_def_cfa_register:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_reg = ptrtmp;
+	  fs->cfa_how = CFA_REG_OFFSET;
+	  break;
+
+	case DW_CFA_def_cfa_offset:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_offset = ptrtmp;
+	  /* cfa_how deliberately not set.  */
+	  break;
+
+	case DW_CFA_def_cfa_expression:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_exp = insn_ptr;
+	  fs->cfa_how = CFA_EXP;
+	  insn_ptr += ptrtmp;
+	  break;
+
+	case DW_CFA_expression:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->regs.reg[reg].how = REG_SAVED_EXP;
+	  fs->regs.reg[reg].loc.exp = insn_ptr;
+	  insn_ptr += ptrtmp;
+	  break;
+
+	  /* From the 2.1 draft.  */
+	case DW_CFA_offset_extended_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	  insn_ptr = read_sleb128 (insn_ptr, &ptrtmp);
+	  offset = (saddr)ptrtmp * fs->data_align;
+	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+	  fs->regs.reg[reg].loc.offset = offset;
+	  break;
+	  
+	case DW_CFA_def_cfa_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_reg = ptrtmp;
+	  insn_ptr = read_sleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_offset = (saddr)ptrtmp;
+	  fs->cfa_how = CFA_REG_OFFSET;
+	  break;
+
+	case DW_CFA_def_cfa_offset_sf:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  fs->cfa_offset = ptrtmp;
+	  /* cfa_how deliberately not set.  */
+	  break;
+
+	case DW_CFA_GNU_window_save:
+	  /* ??? Hardcoded for SPARC register window configuration.  */
+	  for (reg = 16; reg < 32; ++reg)
+	    {
+	      fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+	      fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
+	    }
+	  break;
+
+	case DW_CFA_GNU_args_size:
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  context->args_size = ptrtmp;
+	  break;
+
+	case DW_CFA_GNU_negative_offset_extended:
+	  /* Obsoleted by DW_CFA_offset_extended_sf, but used by
+	     older PowerPC code.  */
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp); reg = ptrtmp;
+	  insn_ptr = read_uleb128 (insn_ptr, &ptrtmp);
+	  offset = ptrtmp * fs->data_align;
+	  fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+	  fs->regs.reg[reg].loc.offset = -offset;
+	  break;
+
+	default:
+	  abort ();
+	}
+    }
+}
+
+#ifdef NEED__Unwind_GetFrameForV2
+void
+_Unwind_GetFrameForV2 (void *pc_target, const unsigned char *insn,
+		       fde *fde, struct dwarf_eh_bases * bases,
+		       struct frame_state *state,
+		       struct cie_info *info)
+{
+  struct _Unwind_Context context;
+  _Unwind_FrameState fs;
+  struct dwarf_cie *cie;
+  const unsigned char *aug, *end;
+  size_t s;
+
+  memset (&context, 0, sizeof (context));
+  context.args_size = 0;
+  context.lsda = 0;
+  context.ra = pc_target;
+  memcpy (&context.bases, bases, sizeof(*bases));
+
+  memset (&fs, 0, sizeof (fs));
+  fs.pc = context.bases.func;
+  fs.retaddr_column = info->ra_regno;
+  fs.code_align = info->code_align;
+  fs.data_align = info->data_align;
+  fs.lsda_encoding = info->lsda_encoding;
+  fs.fde_encoding = info->fde_encoding;
+  fs.saw_z = info->saw_z;
+
+  cie = get_cie (fde);
+
+  /* First decode all the insns in the CIE.  */
+  end = (unsigned char *) next_fde ((struct dwarf_fde *) cie);
+  execute_cfa_program (insn, end, &context, &fs);
+
+  /* Locate augmentation for the fde.  */
+  aug = (unsigned char *)fde + sizeof (*fde);
+  aug += 2 * size_of_encoded_value (fs.fde_encoding);
+  insn = NULL;
+  if (fs.saw_z)
+    {
+      _Unwind_Ptr i;
+      aug = read_uleb128 (aug, &i);
+      insn = aug + i;
+    }
+  if (fs.lsda_encoding != DW_EH_PE_omit)
+    aug = read_encoded_value (&context, fs.lsda_encoding, aug,
+			      (_Unwind_Ptr *) &context.lsda);
+
+  /* Then the insns in the FDE up to our target PC.  */
+  if (insn == NULL)
+    insn = aug;
+  end = (unsigned char *) next_fde (fde);
+  execute_cfa_program (insn, end, &context, &fs);
+
+  /* Now we convert to the old g++ v2 frame format.  */
+  state->cfa_reg = fs.cfa_reg;
+  state->cfa_offset = fs.cfa_offset;
+  state->args_size = context.args_size;
+
+  for (s = 0; s <= DWARF_FRAME_REGISTERS; s++)
+    {
+      switch (fs.regs.reg[s].how)
+	{
+	case REG_UNSAVED:
+	  state->saved[s] = REG_UNSAVED;
+	  break;
+	case REG_SAVED_OFFSET:
+	  state->saved[s] = REG_SAVED_OFFSET;
+	  state->reg_or_offset[s] = fs.regs.reg[s].loc.offset;
+	  break;
+	case REG_SAVED_REG:
+	  state->saved[s] = REG_SAVED_REG;
+	  state->reg_or_offset[s] = fs.regs.reg[s].loc.reg;
+	  break;
+	case REG_SAVED_EXP:
+	  /* g++ v2 doesn't support REG_SAVED_EXP.  */
+	  error (EXIT_FAILURE, 0,
+		 _("REG_SAVED_EXP: Unsupported gcc v3 exception frame state."));
+	  break;
+	}
+    }
+}
+#else /* NEED__Unwind_GetFrameForV2 */
+static _Unwind_Reason_Code
+uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  struct dwarf_fde *fde;
+  struct dwarf_cie *cie;
+  const unsigned char *aug, *insn, *end;
+
+  memset (fs, 0, sizeof (*fs));
+  context->args_size = 0;
+  context->lsda = 0;
+
+  fde = _Unwind_Find_FDE (context->ra - 1, &context->bases);
+  if (fde == NULL)
+    {
+      /* Couldn't find frame unwind info for this function.  Try a
+	 target-specific fallback mechanism.  This will necessarily
+	 not profide a personality routine or LSDA.  */
+#ifdef MD_FALLBACK_FRAME_STATE_FOR
+      MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
+      return _URC_END_OF_STACK;
+    success:
+      return _URC_NO_REASON;
+#else
+      return _URC_END_OF_STACK;
+#endif
+    }
+
+  fs->pc = context->bases.func;
+
+  cie = get_cie (fde);
+  insn = extract_cie_info (cie, context, fs);
+  if (insn == NULL)
+    /* CIE contained unknown augmentation.  */
+    return _URC_FATAL_PHASE1_ERROR;
+
+  /* First decode all the insns in the CIE.  */
+  end = (unsigned char *) next_fde ((struct dwarf_fde *) cie);
+  execute_cfa_program (insn, end, context, fs);
+
+  /* Locate augmentation for the fde.  */
+  aug = (unsigned char *)fde + sizeof (*fde);
+  aug += 2 * size_of_encoded_value (fs->fde_encoding);
+  insn = NULL;
+  if (fs->saw_z)
+    {
+      _Unwind_Ptr i;
+      aug = read_uleb128 (aug, &i);
+      insn = aug + i;
+    }
+  if (fs->lsda_encoding != DW_EH_PE_omit)
+    aug = read_encoded_value (context, fs->lsda_encoding, aug,
+			      (_Unwind_Ptr *) &context->lsda);
+
+  /* Then the insns in the FDE up to our target PC.  */
+  if (insn == NULL)
+    insn = aug;
+  end = (unsigned char *) next_fde (fde);
+  execute_cfa_program (insn, end, context, fs);
+
+  return _URC_NO_REASON;
+}
+
+
+static void
+uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  struct _Unwind_Context orig_context = *context;
+  void *cfa;
+  long i;
+
+  /* Compute this frame's CFA.  */
+  switch (fs->cfa_how)
+    {
+    case CFA_REG_OFFSET:
+      /* Special handling here: Many machines do not use a frame pointer,
+	 and track the CFA only through offsets from the stack pointer from
+	 one frame to the next.  In this case, the stack pointer is never
+	 stored, so it has no saved address in the context.  What we do 
+	 have is the CFA from the previous stack frame.  */
+      if (context->reg[fs->cfa_reg] == NULL)
+	cfa = context->cfa;
+      else
+	cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->cfa_reg);
+      cfa += fs->cfa_offset;
+      break;
+
+    case CFA_EXP:
+      /* ??? No way of knowing what register number is the stack pointer
+	 to do the same sort of handling as above.  Assume that if the
+	 CFA calculation is so complicated as to require a stack program
+	 that this will not be a problem.  */
+      {
+	const unsigned char *exp = fs->cfa_exp;
+	_Unwind_Ptr len;
+
+	exp = read_uleb128 (exp, &len);
+	cfa = (void *) (_Unwind_Ptr)
+	  execute_stack_op (exp, exp + len, context, 0);
+	break;
+      }
+
+    default:
+      abort ();
+    }
+  context->cfa = cfa;
+
+  /* Compute the addresses of all registers saved in this frame.  */
+  for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
+    switch (fs->regs.reg[i].how)
+      {
+      case REG_UNSAVED:
+	break;
+      case REG_SAVED_OFFSET:
+	context->reg[i] = cfa + fs->regs.reg[i].loc.offset;
+	break;
+      case REG_SAVED_REG:
+	context->reg[i] = orig_context.reg[fs->regs.reg[i].loc.reg];
+	break;
+      case REG_SAVED_EXP:
+	{
+	  const unsigned char *exp = fs->regs.reg[i].loc.exp;
+	  _Unwind_Ptr len;
+	  _Unwind_Ptr val;
+
+	  exp = read_uleb128 (exp, &len);
+	  val = execute_stack_op (exp, exp + len, &orig_context,
+				  (_Unwind_Ptr) cfa);
+	  context->reg[i] = (void *) val;
+	}
+	break;
+      }
+}
+
+static void
+uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+  uw_update_context_1 (context, fs);
+
+  /* Compute the return address now, since the return address column
+     can change from frame to frame.  */
+  context->ra = __builtin_extract_return_addr
+    ((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
+}
+
+/* Fill in CONTEXT for top-of-stack.  The only valid registers at this
+   level will be the return address and the CFA.  */
+   
+#define uw_init_context(CONTEXT)					\
+do {									\
+  /* Do any necessary initialization to access arbitrary stack frames.	\
+     On the SPARC, this means flushing the register windows.  */	\
+  __builtin_unwind_init ();						\
+  uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (),			\
+		     __builtin_return_address (0));			\
+} while (0)
+
+static void
+uw_init_context_1 (struct _Unwind_Context *context,
+		   void *outer_cfa, void *outer_ra)
+{
+  void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
+  _Unwind_FrameState fs;
+
+  memset (context, 0, sizeof (struct _Unwind_Context));
+  context->ra = ra;
+
+  if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
+    abort ();
+
+  /* Force the frame state to use the known cfa value.  */
+  context->cfa = outer_cfa;
+  fs.cfa_how = CFA_REG_OFFSET;
+  fs.cfa_reg = 0;
+  fs.cfa_offset = 0;
+
+  uw_update_context_1 (context, &fs);
+
+  /* If the return address column was saved in a register in the
+     initialization context, then we can't see it in the given
+     call frame data.  So have the initialization context tell us.  */
+  context->ra = __builtin_extract_return_addr (outer_ra);
+}
+
+
+/* Install TARGET into CURRENT so that we can return to it.  This is a
+   macro because __builtin_eh_return must be invoked in the context of
+   our caller.  */
+
+#define uw_install_context(CURRENT, TARGET)				\
+do {									\
+  long offset = uw_install_context_1 ((CURRENT), (TARGET));		\
+  void *handler = __builtin_frob_return_addr ((TARGET)->ra);		\
+  __builtin_eh_return (offset, handler);				\
+} while (0)
+
+static inline void
+init_dwarf_reg_size_table (void)
+{
+  __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table);
+}
+
+static long
+uw_install_context_1 (struct _Unwind_Context *current,
+		      struct _Unwind_Context *target)
+{
+  long i;
+
+#if __GTHREADS
+  {
+    static __gthread_once_t once_regsizes = __GTHREAD_ONCE_INIT;
+    if (__gthread_once (&once_regsizes, init_dwarf_reg_size_table) != 0
+	|| dwarf_reg_size_table[0] == 0)
+      init_dwarf_reg_size_table ();
+  }
+#else
+  if (dwarf_reg_size_table[0] == 0)
+    init_dwarf_reg_size_table ();
+#endif
+
+  for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
+    {
+      void *c = current->reg[i];
+      void *t = target->reg[i];
+      if (t && c && t != c)
+	memcpy (c, t, dwarf_reg_size_table[i]);
+    }
+
+  /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
+  if (STACK_GROWS_DOWNWARD)
+    return target->cfa - current->cfa + target->args_size;
+  else
+    return current->cfa - target->cfa - target->args_size;
+}
+
+static inline _Unwind_Ptr
+uw_identify_context (struct _Unwind_Context *context)
+{
+  return _Unwind_GetIP (context);
+}
+
+
+#include "unwind.inc"
+
+#endif /* NEED__Unwind_GetFrameForV2 */
+
+#endif /* !USING_SJLJ_EXCEPTIONS */
--- libc/sysdeps/generic/unwind-pe.h.gcc	Fri Jul  6 15:06:02 2001
+++ libc/sysdeps/generic/unwind-pe.h	Sun Jul  8 18:54:29 2001
@@ -0,0 +1,318 @@
+/* Exception handling and frame unwind runtime interface routines.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* @@@ Really this should be out of line, but this also causes link
+   compatibility problems with the base ABI.  This is slightly better
+   than duplicating code, however.  */
+
+#ifdef _LIBC
+#include <gccframe.h>
+#endif
+
+/* If using C++, references to abort have to be qualified with std::. */
+#if __cplusplus
+#define __gxx_abort std::abort
+#else
+#define __gxx_abort abort
+#endif
+
+/* Pointer encodings, from dwarf2.h.  */
+#define DW_EH_PE_absptr         0x00
+#define DW_EH_PE_omit           0xff
+
+#define DW_EH_PE_uleb128        0x01
+#define DW_EH_PE_udata2         0x02
+#define DW_EH_PE_udata4         0x03
+#define DW_EH_PE_udata8         0x04
+#define DW_EH_PE_sleb128        0x09
+#define DW_EH_PE_sdata2         0x0A
+#define DW_EH_PE_sdata4         0x0B
+#define DW_EH_PE_sdata8         0x0C
+#define DW_EH_PE_signed         0x08
+
+#define DW_EH_PE_pcrel          0x10
+#define DW_EH_PE_textrel        0x20
+#define DW_EH_PE_datarel        0x30
+#define DW_EH_PE_funcrel        0x40
+#define DW_EH_PE_aligned        0x50
+
+#define DW_EH_PE_indirect	0x80
+
+struct dwarf_eh_bases
+{
+  void *tbase;
+  void *dbase;
+  void *func;
+};
+
+/* It is shared by both v2 and v3 dwarf2 frame unwind code.  */
+struct dwarf_fde;
+typedef struct dwarf_fde fde;
+
+extern fde * _Unwind_Find_FDE (void *, struct dwarf_eh_bases *);
+
+#ifdef NEED__Unwind_GetFrameForV2
+#ifndef DWARF_FRAME_REGISTERS
+# ifdef FIRST_PSEUDO_REGISTER
+#  define DWARF_FRAME_REGISTERS FIRST_PSEUDO_REGISTER
+# else
+#  error DWARF_FRAME_REGISTERS is not defined.
+# endif
+#endif
+
+/* This is the register and unwind state for a particular frame. It
+   is used by the v2 dwarf2 frame unwind code.  */
+
+typedef struct frame_state
+{
+  void *cfa;
+  void *eh_ptr;
+  long cfa_offset;
+  long args_size;
+  long reg_or_offset[DWARF_FRAME_REGISTERS+1];
+  unsigned short cfa_reg;
+  unsigned short retaddr_column;
+  char saved[DWARF_FRAME_REGISTERS+1];
+  long base_offset;
+  char indirect;
+} frame_state;
+
+/* The information we care about from a CIE. It is used by the v2
+   dwarf2 frame unwind code.  */
+
+struct cie_info {
+  char *augmentation;
+  void *eh_ptr;
+  void *pc;
+  int code_align;
+  int data_align;
+  unsigned ra_regno;
+  unsigned char fde_encoding;
+  unsigned char lsda_encoding;
+  unsigned char saw_z;
+};
+
+/* Convert the v3 frame into the v2 frame. It is used to unwind the v3
+   frame in the v2 unwinder.  */
+extern void _Unwind_GetFrameForV2 (void *pc_target,
+				   const unsigned char *insn, fde *f,
+				   struct dwarf_eh_bases *bases,
+				   struct frame_state *state,
+				   struct cie_info *info);
+#endif /* NEED__Unwind_GetFrameForV2 */
+
+#ifndef DWARF2_FRAME_UNWIND_V2
+/* Given an encoding, return the number of bytes the format occupies.
+   This is only defined for fixed-size encodings, and so does not
+   include leb128.  */
+
+static unsigned int
+size_of_encoded_value (unsigned char encoding)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x07)
+    {
+    case DW_EH_PE_absptr:
+      return sizeof (void *);
+    case DW_EH_PE_udata2:
+      return 2;
+    case DW_EH_PE_udata4:
+      return 4;
+    case DW_EH_PE_udata8:
+      return 8;
+    }
+  __gxx_abort ();
+}
+
+/* Given an encoding and an _Unwind_Context, return the base to which
+   the encoding is relative.  This base may then be passed to
+   read_encoded_value_with_base for use when the _Unwind_Context is
+   not available.  */
+
+static _Unwind_Ptr
+base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+
+  switch (encoding & 0x70)
+    {
+    case DW_EH_PE_absptr:
+    case DW_EH_PE_pcrel:
+    case DW_EH_PE_aligned:
+      return 0;
+
+    case DW_EH_PE_textrel:
+      return _Unwind_GetTextRelBase (context);
+    case DW_EH_PE_datarel:
+      return _Unwind_GetDataRelBase (context);
+    case DW_EH_PE_funcrel:
+      return _Unwind_GetRegionStart (context);
+    }
+  __gxx_abort ();
+}
+
+/* Load an encoded value from memory at P.  The value is returned in VAL;
+   The function returns P incremented past the value.  BASE is as given
+   by base_of_encoded_value for this encoding in the appropriate context.  */
+
+static const unsigned char *
+read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
+			      const unsigned char *p, _Unwind_Ptr *val)
+{
+  union unaligned
+    {
+      void *ptr;
+      unsigned u2 __attribute__ ((mode (HI)));
+      unsigned u4 __attribute__ ((mode (SI)));
+      unsigned u8 __attribute__ ((mode (DI)));
+      signed s2 __attribute__ ((mode (HI)));
+      signed s4 __attribute__ ((mode (SI)));
+      signed s8 __attribute__ ((mode (DI)));
+    } __attribute__((__packed__));
+
+  union unaligned *u = (union unaligned *) p;
+  _Unwind_Ptr result;
+
+  if (encoding == DW_EH_PE_aligned)
+    {
+      _Unwind_Ptr a = (_Unwind_Ptr)p;
+      a = (a + sizeof (void *) - 1) & - sizeof(void *);
+      result = *(_Unwind_Ptr *) a;
+      p = (const unsigned char *)(a + sizeof (void *));
+    }
+  else
+    {
+      switch (encoding & 0x0f)
+	{
+	case DW_EH_PE_absptr:
+	  result = (_Unwind_Ptr) u->ptr;
+	  p += sizeof (void *);
+	  break;
+
+	case DW_EH_PE_uleb128:
+	  {
+	    unsigned int shift = 0;
+	    unsigned char byte;
+
+	    result = 0;
+	    do
+	      {
+		byte = *p++;
+		result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
+		shift += 7;
+	      }
+	    while (byte & 0x80);
+	  }
+	  break;
+
+	case DW_EH_PE_sleb128:
+	  {
+	    unsigned int shift = 0;
+	    unsigned char byte;
+
+	    result = 0;
+	    do
+	      {
+		byte = *p++;
+		result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
+		shift += 7;
+	      }
+	    while (byte & 0x80);
+
+	    if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
+	      result |= -(1L << shift);
+	  }
+	  break;
+
+	case DW_EH_PE_udata2:
+	  result = u->u2;
+	  p += 2;
+	  break;
+	case DW_EH_PE_udata4:
+	  result = u->u4;
+	  p += 4;
+	  break;
+	case DW_EH_PE_udata8:
+	  result = u->u8;
+	  p += 8;
+	  break;
+
+	case DW_EH_PE_sdata2:
+	  result = u->s2;
+	  p += 2;
+	  break;
+	case DW_EH_PE_sdata4:
+	  result = u->s4;
+	  p += 4;
+	  break;
+	case DW_EH_PE_sdata8:
+	  result = u->s8;
+	  p += 8;
+	  break;
+
+	default:
+	  __gxx_abort ();
+	}
+
+      if (result != 0)
+	{
+	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
+		     ? (_Unwind_Ptr)u : base);
+	  if (encoding & DW_EH_PE_indirect)
+	    result = *(_Unwind_Ptr *)result;
+	}
+    }
+
+  *val = result;
+  return p;
+}
+
+/* Like read_encoded_value_with_base, but get the base from the context
+   rather than providing it directly.  */
+
+static inline const unsigned char *
+read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
+		    const unsigned char *p, _Unwind_Ptr *val)
+{
+  return read_encoded_value_with_base (encoding,
+		base_of_encoded_value (encoding, context),
+		p, val);
+}
+
+/* Read an unsigned leb128 value from P, store the value in VAL, return
+   P incremented past the value.  */
+
+static inline const unsigned char *
+read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
+{
+  return read_encoded_value_with_base (DW_EH_PE_uleb128, 0, p, val);
+}
+
+/* Similar, but read a signed leb128 value.  */
+
+static inline const unsigned char *
+read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
+{
+  return read_encoded_value_with_base (DW_EH_PE_sleb128, 0, p, val);
+}
+#endif /* !DWARF2_FRAME_UNWIND_V2 */
--- libc/sysdeps/generic/unwind.h.gcc	Fri Jul  6 15:06:02 2001
+++ libc/sysdeps/generic/unwind.h	Sun May 13 00:10:02 2001
@@ -0,0 +1,191 @@
+/* Exception handling and frame unwind runtime interface routines.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This is derived from the C++ ABI for IA-64.  Where we diverge
+   for cross-architecture compatibility are noted with "@@@".  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Level 1: Base ABI  */
+
+/* @@@ The IA-64 ABI uses uint64 throughout.  Most places this is
+   inefficient for 32-bit and smaller machines.  */
+typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
+typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+
+/* @@@ The IA-64 ABI uses a 64-bit word to identify the producer and
+   consumer of an exception.  We'll go along with this for now even on
+   32-bit machines.  We'll need to provide some other option for
+   16-bit machines and for machines with > 8 bits per byte.  */
+typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
+
+/* The unwind interface uses reason codes in several contexts to
+   identify the reasons for failures or other actions.  */
+typedef enum
+{
+  _URC_NO_REASON = 0,
+  _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+  _URC_FATAL_PHASE2_ERROR = 2,
+  _URC_FATAL_PHASE1_ERROR = 3,
+  _URC_NORMAL_STOP = 4,
+  _URC_END_OF_STACK = 5,
+  _URC_HANDLER_FOUND = 6,
+  _URC_INSTALL_CONTEXT = 7,
+  _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+
+/* The unwind interface uses a pointer to an exception header object
+   as its representation of an exception being thrown. In general, the
+   full representation of an exception object is language- and
+   implementation-specific, but it will be prefixed by a header
+   understood by the unwind interface.  */
+
+struct _Unwind_Exception;
+
+typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
+					      struct _Unwind_Exception *);
+
+struct _Unwind_Exception
+{
+  _Unwind_Exception_Class exception_class;
+  _Unwind_Exception_Cleanup_Fn exception_cleanup;
+  _Unwind_Word private_1;
+  _Unwind_Word private_2;
+
+  /* @@@ The IA-64 ABI says that this structure must be double-word aligned.
+     Taking that literally does not make much sense generically.  Instead we
+     provide the maximum alignment required by any type for the machine.  */
+} __attribute__((__aligned__));
+
+
+/* The ACTIONS argument to the personality routine is a bitwise OR of one
+   or more of the following constants.  */
+typedef int _Unwind_Action;
+
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+
+/* This is an opaque type used to refer to a system-specific data
+   structure used by the system unwinder. This context is created and
+   destroyed by the system, and passed to the personality routine
+   during unwinding.  */
+struct _Unwind_Context;
+
+/* Raise an exception, passing along the given exception object.  */
+extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
+
+/* Raise an exception for forced unwinding.  */
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *, void *);
+
+extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
+						 _Unwind_Stop_Fn,
+						 void *);
+
+/* Helper to invoke the exception_cleanup routine.  */
+extern void _Unwind_DeleteException (struct _Unwind_Exception *);
+
+/* Resume propagation of an existing exception.  This is used after
+   e.g. executing cleanup code, and not to implement rethrowing.  */
+extern void _Unwind_Resume (struct _Unwind_Exception *);
+
+/* These functions are used for communicating information about the unwind
+   context (i.e. the unwind descriptors and the user register state) between
+   the unwind library and the personality routine and landing pad.  Only
+   selected registers maybe manipulated.  */
+
+extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int);
+extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
+
+extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
+extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
+
+extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
+
+extern _Unwind_Ptr _Unwind_GetRegionStart (struct _Unwind_Context *);
+
+
+/* The personality routine is the function in the C++ (or other language)
+   runtime library which serves as an interface between the system unwind
+   library and language-specific exception handling semantics.  It is
+   specific to the code fragment described by an unwind info block, and
+   it is always referenced via the pointer in the unwind info block, and
+   hence it has no ABI-specified name. 
+
+   Note that this implies that two different C++ implementations can
+   use different names, and have different contents in the language
+   specific data area.  Moreover, that the language specific data 
+   area contains no version info because name of the function invoked
+   provides more effective versioning by detecting at link time the
+   lack of code to handle the different data format.  */
+   
+typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)
+     (int, _Unwind_Action, _Unwind_Exception_Class,
+      struct _Unwind_Exception *, struct _Unwind_Context *);
+
+/* @@@ The following alternate entry points are for setjmp/longjmp
+   based unwinding.  */
+
+struct SjLj_Function_Context;
+extern void _Unwind_SjLj_Register (struct SjLj_Function_Context *);
+extern void _Unwind_SjLj_Unregister (struct SjLj_Function_Context *);
+
+extern _Unwind_Reason_Code _Unwind_SjLj_RaiseException
+     (struct _Unwind_Exception *);
+extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind
+     (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
+extern void _Unwind_SjLj_Resume (struct _Unwind_Exception *);
+
+/* @@@ The following provide access to the base addresses for text
+   and data-relative addressing in the LDSA.  In order to stay link
+   compatible with the standard ABI for IA-64, we inline these.  */
+
+#ifdef __ia64__
+#include <stdlib.h>
+
+static inline _Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *_C)
+{
+  /* The GP is stored in R1.  */
+  return _Unwind_GetGR (_C, 1);
+}
+
+static inline _Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *_C)
+{
+  abort ();
+  return 0;
+}
+#else
+extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *);
+extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
--- libc/sysdeps/i386/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/i386/gccframe.h	Mon Jul  9 10:24:21 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  i386 version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define DWARF_FRAME_REGISTERS 17
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/m68k/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/m68k/gccframe.h	Mon Jul  9 10:25:48 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  M68k version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 24
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/mips/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/mips/gccframe.h	Mon Jul  9 10:26:02 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  Mips version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 76
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/powerpc/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/powerpc/gccframe.h	Mon Jul  9 10:27:03 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  Powerpc version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define DWARF_FRAME_REGISTERS 77
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/s390/s390-32/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/s390/s390-32/gccframe.h	Mon Jul  9 10:28:27 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  S390 version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 20
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/sparc/gccframe.h.gcc	Wed Jul  4 21:37:34 2001
+++ libc/sysdeps/sparc/gccframe.h	Mon Jul  9 10:27:16 2001
@@ -0,0 +1,22 @@
+/* Definition of object in frame unwind info.  Sparc version.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define FIRST_PSEUDO_REGISTER 101
+
+#include <sysdeps/generic/gccframe.h>
--- libc/sysdeps/unix/sysv/linux/Versions.gcc	Thu Nov 23 01:04:30 2000
+++ libc/sysdeps/unix/sysv/linux/Versions	Fri Jul  6 17:39:37 2001
@@ -94,4 +94,10 @@ libc {
     # p*
     pivot_root;
   }
+  GCC_3.0 {
+    # Exception handling support functions from libgcc in gcc 3.0
+    __register_frame_info_bases; __deregister_frame_info_bases;
+    __register_frame_info_table_bases;
+    _Unwind_Find_FDE;
+  }
 }
--- libc/sysdeps/unix/sysv/linux/alpha/Makefile.gcc	Mon Mar 20 12:23:05 2000
+++ libc/sysdeps/unix/sysv/linux/alpha/Makefile	Mon Jul  9 09:37:30 2001
@@ -23,3 +23,11 @@ ifeq ($(subdir),signal)
 sysdep_routines += rt_sigsuspend rt_sigprocmask rt_sigtimedwait	\
 		   rt_sigqueueinfo rt_sigaction rt_sigpending
 endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
+endif
--- libc/sysdeps/unix/sysv/linux/arm/Makefile.gcc	Fri Mar  9 22:36:31 2001
+++ libc/sysdeps/unix/sysv/linux/arm/Makefile	Mon Jul  9 09:37:35 2001
@@ -19,4 +19,10 @@ sysdep-dl-routines += dl-procinfo
 sysdep_routines += dl-procinfo
 # extra shared linker files to link only into dl-allobjs.so
 sysdep-rtld-routines += dl-procinfo
+
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
 endif
--- libc/sysdeps/unix/sysv/linux/i386/Makefile.gcc	Wed May 23 17:29:06 2001
+++ libc/sysdeps/unix/sysv/linux/i386/Makefile	Mon Jul  9 09:37:41 2001
@@ -12,6 +12,12 @@ sysdep-dl-routines += dl-procinfo
 sysdep_routines += dl-procinfo
 # extra shared linker files to link only into dl-allobjs.so
 sysdep-rtld-routines += dl-procinfo
+
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
 endif
 
 ifeq ($(subdir),resource)
--- libc/sysdeps/unix/sysv/linux/m68k/Makefile.gcc	Sat Oct 14 10:48:34 2000
+++ libc/sysdeps/unix/sysv/linux/m68k/Makefile	Mon Jul  9 09:37:46 2001
@@ -10,6 +10,12 @@ endif
 ifeq ($(subdir),elf)
 sysdep-others += lddlibc4
 install-bin += lddlibc4
+
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
 endif
 
 ifeq ($(subdir),resource)
--- libc/sysdeps/unix/sysv/linux/mips/Makefile.gcc	Fri May  4 20:54:13 2001
+++ libc/sysdeps/unix/sysv/linux/mips/Makefile	Mon Jul  9 09:37:50 2001
@@ -9,3 +9,11 @@ sysdep_routines += cachectl cacheflush s
 
 sysdep_headers += sys/cachectl.h sys/sysmips.h sys/tas.h
 endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
+endif
--- libc/sysdeps/unix/sysv/linux/powerpc/Makefile.gcc	Wed May 23 17:29:06 2001
+++ libc/sysdeps/unix/sysv/linux/powerpc/Makefile	Mon Jul  9 09:37:55 2001
@@ -6,3 +6,11 @@ endif
 ifeq ($(subdir),resource)
 sysdep_routines += oldgetrlimit64
 endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
+endif
--- libc/sysdeps/unix/sysv/linux/s390/s390-32/Makefile.gcc	Wed May 23 17:29:06 2001
+++ libc/sysdeps/unix/sysv/linux/s390/s390-32/Makefile	Mon Jul  9 09:37:59 2001
@@ -6,3 +6,11 @@ endif
 ifeq ($(subdir),resource)
 sysdep_routines += oldgetrlimit64
 endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
+endif
--- libc/sysdeps/unix/sysv/linux/sparc/Makefile.gcc	Wed Nov 15 17:48:14 2000
+++ libc/sysdeps/unix/sysv/linux/sparc/Makefile	Mon Jul  9 09:38:04 2001
@@ -42,3 +42,11 @@ $(objpfx)syscall-%.h $(objpfx)syscall-%.
 	mv -f $(@:.h=.d)-t2 $(@:.h=.d)
 
 endif
+
+ifeq ($(subdir),elf)
+ifeq (yes,$(build-shared))
+# This is needed to support g++ v2 and v3.
+sysdep_routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+shared-only-routines += $(FRAME-UNWINDER-V2) unwind-dw2 unwind-dw2-fde
+endif
+endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]