This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
PATCH: The gcc v2/v3 frame unwinder for glibc.
- To: GNU C Library <libc-alpha at sourceware dot cygnus dot com>, gcc at gcc dot gnu dot org
- Subject: PATCH: The gcc v2/v3 frame unwinder for glibc.
- From: "H . J . Lu" <hjl at lucon dot org>
- Date: Mon, 9 Jul 2001 11:02:00 -0700
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, ®);
+ p = decode_uleb128 (p, &offset);
+ if (reg == state->s.cfa_reg)
+ /* Don't record anything; see above. */;
+ else
+ {
+ offset *= info->data_align;
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = offset;
+ }
+ break;
+ case DW_CFA_restore_extended:
+ p = decode_uleb128 (p, ®);
+ state->s.saved[reg] = REG_UNSAVED;
+ break;
+
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_nop:
+ break;
+
+ case DW_CFA_register:
+ {
+ unsigned reg2;
+ p = decode_uleb128 (p, ®);
+ p = decode_uleb128 (p, ®2);
+ state->s.saved[reg] = REG_SAVED_REG;
+ state->s.reg_or_offset[reg] = reg2;
+ }
+ break;
+
+ case DW_CFA_def_cfa:
+ p = decode_uleb128 (p, ®);
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_reg = reg;
+ state->s.cfa_offset = offset;
+ break;
+ case DW_CFA_def_cfa_register:
+ p = decode_uleb128 (p, ®);
+ state->s.cfa_reg = reg;
+ break;
+ case DW_CFA_def_cfa_offset:
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_offset = offset;
+ break;
+ case DW_CFA_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, ®);
+ 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, ®);
+ 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, ®);
+ state->s.saved[reg] = REG_UNSAVED;
+ break;
+
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_nop:
+ break;
+
+ case DW_CFA_register:
+ {
+ unsigned reg2;
+ p = decode_uleb128 (p, ®);
+ p = decode_uleb128 (p, ®2);
+ state->s.saved[reg] = REG_SAVED_REG;
+ state->s.reg_or_offset[reg] = reg2;
+ }
+ break;
+
+ case DW_CFA_def_cfa:
+ p = decode_uleb128 (p, ®);
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_reg = reg;
+ state->s.cfa_offset = offset;
+ break;
+ case DW_CFA_def_cfa_register:
+ p = decode_uleb128 (p, ®);
+ state->s.cfa_reg = reg;
+ break;
+ case DW_CFA_def_cfa_offset:
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_offset = offset;
+ break;
+
+ case DW_CFA_remember_state:
+ {
+ struct frame_state_internal *save =
+ (struct frame_state_internal *)
+ malloc (sizeof (struct frame_state_internal));
+ memcpy (save, state, sizeof (struct frame_state_internal));
+ state->saved_state = save;
+ }
+ break;
+ case DW_CFA_restore_state:
+ {
+ struct frame_state_internal *save = state->saved_state;
+ memcpy (state, save, sizeof (struct frame_state_internal));
+ free (save);
+ }
+ break;
+
+ /* FIXME: Hardcoded for SPARC register window configuration. */
+ case DW_CFA_GNU_window_save:
+ for (reg = 16; reg < 32; ++reg)
+ {
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
+ }
+ break;
+
+ case DW_CFA_GNU_args_size:
+ p = decode_uleb128 (p, &offset);
+ state->s.args_size = offset;
+ break;
+
+ case DW_CFA_GNU_negative_offset_extended:
+ p = decode_uleb128 (p, ®);
+ p = decode_uleb128 (p, &offset);
+ offset *= info->data_align;
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = -offset;
+ break;
+
+ default:
+ abort ();
+ }
+ return p;
+}
+
+#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 = ▮
+ 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