From: Rainer Orth Date: Fri, 5 Aug 2011 14:37:48 +0000 (+0000) Subject: Makefile.in (UNWIND_H): Remove. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=201cdb743879cbffd38c53d8ebf85fa9fff1e0e4;p=gcc.git Makefile.in (UNWIND_H): Remove. gcc: * Makefile.in (UNWIND_H): Remove. (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): Move to ../libgcc/Makefile.in. (LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL): Likewise. (LIBUNWINDDEP): Remove. (libgcc-support): Remove LIB2ADDEH, $(srcdir)/emutls.c dependencies. (libgcc.mvars): Remove LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED, LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL. (stmp-int-hdrs): Remove $(UNWIND_H) dependency. Don't copy $(UNWIND_H). * config.gcc (ia64*-*-linux*): Remove with_system_libunwind handling. * configure.ac (GCC_CHECK_UNWIND_GETIPINFO): Remove. * aclocal.m4: Regenerate. * configure: Regenerate. * emutls.c, unwind-c.c, unwind-compat.c, unwind-compat.h, unwind-dw2-fde-compat.c, unwind-dw2-fde-glibc.c, unwind-dw2-fde.c, unwind-dw2-fde.h, unwind-dw2.c, unwind-dw2.h, unwind-generic.h, unwind-pe.h, unwind-sjlj.c, unwind.inc: Move to ../libgcc. * unwind-dw2-fde-darwin.c: Move to ../libgcc/config. * config/arm/libunwind.S, config/arm/pr-support.c, config/arm/unwind-arm.c, config/arm/unwind-arm.h: Move to ../libgcc/config/arm. * config/arm/t-bpabi (UNWIND_H, LIB2ADDEH): Remove. * config/arm/t-symbian (UNWIND_H, LIB2ADDEH): Remove. * config/frv/t-frv ($(T)frvbegin$(objext)): Use $(srcdir)/../libgcc to refer to unwind-dw2-fde.h. ($(T)frvend$(objext)): Likewise. * config/ia64/t-glibc (LIB2ADDEH): Remove. * config/ia64/t-glibc-libunwind: Move to ../libgcc/config/ia64. * config/ia64/fde-glibc.c, config/ia64/fde-vms.c, config/ia64/unwind-ia64.c, config/ia64/unwind-ia64.h: Move to ../libgcc/config/ia64. * config/ia64/t-hpux (LIB2ADDEH): Remove. * config/ia64/t-ia64 (LIB2ADDEH): Remove. * config/ia64/t-vms (LIB2ADDEH): Remove. * config/ia64/vms.h (UNW_IVMS_MODE, MD_UNW_COMPATIBLE_PERSONALITY_P): Remove. * config/picochip/t-picochip (LIB2ADDEH): Remove. * config/rs6000/aix.h (R_LR, MD_FROB_UPDATE_CONTEXT): Remove. * config/rs6000/t-darwin (LIB2ADDEH): Remove. * config/rs6000/darwin-fallback.c: Move to ../libgcc/config/rs6000. * config/sh/t-sh ($(T)unwind-dw2-Os-4-200.o): Use $(srcdir)/../libgcc to refer to unwinder sources. * config/spu/t-spu-elf (LIB2ADDEH): Remove. * config/t-darwin (LIB2ADDEH): Remove. * config/t-freebsd (LIB2ADDEH): Remove. * config/t-libunwind (LIB2ADDEH, LIB2ADDEHSTATIC): Remove. * config/t-libunwind-elf: Move to ../libgcc/config. * config/t-linux (LIB2ADDEH): Remove. * config/t-sol2 (LIB2ADDEH): Remove. * config/xtensa/t-xtensa (LIB2ADDEH): Remove. * system.h (MD_FROB_UPDATE_CONTEXT): Poison. gcc/po: * EXCLUDES (unwind-c.c, unwind-dw2-fde-darwin.c) (unwind-dw2-fde-glibc.c, unwind-dw2-fde.c, unwind-dw2-fde.h) (unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h): Remove. libgcc: * Makefile.in (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): New variables. (LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL): New variables. (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): Add $(srcdir)/emutls.c. (install-unwind_h): New target. (all): Depend on it. * config.host (unwind_header): New variable. (*-*-freebsd*): Set tmake_file to t-eh-dw2-dip. (*-*-linux*, frv-*-*linux*, *-*-kfreebsd*-gnu, *-*-knetbsd*-gnu, *-*-gnu*): Likewise, also for *-*-kopensolaris*-gnu. (*-*-solaris2*): Add t-eh-dw2-dip to tmake_file. (arm*-*-linux*): Add arm/t-bpabi for arm*-*-linux-*eabi. Set unwind_header. (arm*-*-uclinux*): Add arm/t-bpabi for arm*-*-uclinux*eabi. Set unwind_header. (arm*-*-eabi*, arm*-*-symbianelf*): Add arm/t-bpabi for arm*-*-eabi*. Add arm/t-symbian to tmake_file for arm*-*-symbianelf*. Set unwind_header. (ia64*-*-elf*): Add ia64/t-eh-ia64 to tmake_file. (ia64*-*-freebsd*): Likewise. (ia64*-*-linux*): Add ia64/t-glibc, ia64/t-eh-ia64, t-libunwind to tmake_file. Add t-libunwind-elf, ia64/t-glibc-libunwind unless $with_system_libunwind. (ia64*-*-hpux*): Set tmake_file. (ia64-hp-*vms*): Add ia64/t-eh-ia64 to tmake_file. (picochip-*-*): Set tmake_file. (rs6000-ibm-aix4.[3456789]*, powerpc-ibm-aix4.[3456789]*): Set md_unwind_header. (rs6000-ibm-aix5.1.*, powerpc-ibm-aix5.1.*): Likewise. (rs6000-ibm-aix[56789].*, powerpc-ibm-aix[56789].*): Likewise. (s390x-ibm-tpf*): Add t-eh-dw2-dip to tmake_file. (xtensa*-*-elf*): Set tmake_file. (xtensa*-*-linux*): Likewise. * configure.ac: Include ../config/unwind_ipinfo.m4. Call GCC_CHECK_UNWIND_GETIPINFO. Link unwind.h to $unwind_header. * configure: Regenerate. * emutls.c, unwind-c.c, unwind-compat.c, unwind-compat.h, unwind-dw2-fde-compat.c, unwind-dw2-fde-dip.c, unwind-dw2-fde.c, unwind-dw2-fde.h, unwind-dw2.c, unwind-dw2.h, unwind-generic.h, unwind-pe.h, unwind-sjlj.c, unwind.inc: New files. * config/unwind-dw2-fde-darwin.c: New file. * config/arm/libunwind.S, config/arm/pr-support.c, config/arm/t-bpabi, config/arm/t-symbian, config/arm/unwind-arm.c, config/arm/unwind-arm.h,: New files. * config/ia64/fde-glibc.c, config/ia64/fde-vms.c, config/ia64/t-eh-ia64, config/ia64/t-glibc, config/ia64/t-glibc-libunwind, config/ia64/t-hpux, config/ia64/t-vms, config/ia64/unwind-ia64.c, config/ia64/unwind-ia64.h: New files. * config/picochip/t-picochip: New file. * config/rs6000/aix-unwind.h, config/rs6000/darwin-fallback.c: New files. * config/rs6000/t-darwin (LIB2ADDEH): Set. * config/s390/t-tpf (LIB2ADDEH): Remove. * config/t-darwin (LIB2ADDEH): Set. * config/t-eh-dw2-dip: New file. * config/t-libunwind, config/t-libunwind-elf: New files. * config/t-sol2 (LIB2ADDEH): Remove. * config/xtensa/t-xtensa: New file. gcc/ada: * gcc-interface/Makefile.in (raise-gcc.o): Search $(srcdir)/../libgcc. libgo: * Makefile.am (AM_CFLAGS): Search $(srcdir)/../libgcc. * Makefile.in: Regenerate. libjava: * configure.ac (GCC_UNWIND_INCLUDE): Rename to LIBGCC_UNWIND_INCLUDE. Point to $(multi_basedir)/./libjava/../libgcc. * configure: Regenerate. * Makefile.am (GCC_UNWIND_INCLUDE): Reflect this. * Makefile.in: Regenerate. libobjc: * Makefile.in (INCLUDES): Search $(srcdir)/$(MULTISRCTOP)../libgcc. libstdc++-v3: * acinclude.m4 (GLIBCXX_EXPORT_INCLUDES): Point TOPLEVEL_INCLUDES to $(toplevel_srcdir)/libgcc. * configure: Regenerate. From-SVN: r177447 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f269930732d..438e8bb95f0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,59 @@ +2011-08-05 Rainer Orth + + * Makefile.in (UNWIND_H): Remove. + (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): Move to + ../libgcc/Makefile.in. + (LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL): Likewise. + (LIBUNWINDDEP): Remove. + (libgcc-support): Remove LIB2ADDEH, $(srcdir)/emutls.c dependencies. + (libgcc.mvars): Remove LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED, + LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL. + (stmp-int-hdrs): Remove $(UNWIND_H) dependency. + Don't copy $(UNWIND_H). + * config.gcc (ia64*-*-linux*): Remove with_system_libunwind + handling. + * configure.ac (GCC_CHECK_UNWIND_GETIPINFO): Remove. + * aclocal.m4: Regenerate. + * configure: Regenerate. + * emutls.c, unwind-c.c, unwind-compat.c, unwind-compat.h, + unwind-dw2-fde-compat.c, unwind-dw2-fde-glibc.c, unwind-dw2-fde.c, + unwind-dw2-fde.h, unwind-dw2.c, unwind-dw2.h, unwind-generic.h, + unwind-pe.h, unwind-sjlj.c, unwind.inc: Move to ../libgcc. + * unwind-dw2-fde-darwin.c: Move to ../libgcc/config. + * config/arm/libunwind.S, config/arm/pr-support.c, + config/arm/unwind-arm.c, config/arm/unwind-arm.h: Move to + ../libgcc/config/arm. + * config/arm/t-bpabi (UNWIND_H, LIB2ADDEH): Remove. + * config/arm/t-symbian (UNWIND_H, LIB2ADDEH): Remove. + * config/frv/t-frv ($(T)frvbegin$(objext)): Use + $(srcdir)/../libgcc to refer to unwind-dw2-fde.h. + ($(T)frvend$(objext)): Likewise. + * config/ia64/t-glibc (LIB2ADDEH): Remove. + * config/ia64/t-glibc-libunwind: Move to ../libgcc/config/ia64. + * config/ia64/fde-glibc.c, config/ia64/fde-vms.c, + config/ia64/unwind-ia64.c, config/ia64/unwind-ia64.h: Move to + ../libgcc/config/ia64. + * config/ia64/t-hpux (LIB2ADDEH): Remove. + * config/ia64/t-ia64 (LIB2ADDEH): Remove. + * config/ia64/t-vms (LIB2ADDEH): Remove. + * config/ia64/vms.h (UNW_IVMS_MODE, + MD_UNW_COMPATIBLE_PERSONALITY_P): Remove. + * config/picochip/t-picochip (LIB2ADDEH): Remove. + * config/rs6000/aix.h (R_LR, MD_FROB_UPDATE_CONTEXT): Remove. + * config/rs6000/t-darwin (LIB2ADDEH): Remove. + * config/rs6000/darwin-fallback.c: Move to ../libgcc/config/rs6000. + * config/sh/t-sh ($(T)unwind-dw2-Os-4-200.o): Use + $(srcdir)/../libgcc to refer to unwinder sources. + * config/spu/t-spu-elf (LIB2ADDEH): Remove. + * config/t-darwin (LIB2ADDEH): Remove. + * config/t-freebsd (LIB2ADDEH): Remove. + * config/t-libunwind (LIB2ADDEH, LIB2ADDEHSTATIC): Remove. + * config/t-libunwind-elf: Move to ../libgcc/config. + * config/t-linux (LIB2ADDEH): Remove. + * config/t-sol2 (LIB2ADDEH): Remove. + * config/xtensa/t-xtensa (LIB2ADDEH): Remove. + * system.h (MD_FROB_UPDATE_CONTEXT): Poison. + 2011-08-05 H.J. Lu * config/i386/i386.c (processor_alias_table): Add core-avx-i. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 0204f93208a..889deb16240 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -378,8 +378,6 @@ USER_H = $(srcdir)/ginclude/float.h \ USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@ USER_H_INC_NEXT_POST = @user_headers_inc_next_post@ -UNWIND_H = $(srcdir)/unwind-generic.h - # The GCC to use for compiling crt*.o. # Usually the one we just built. # Don't use this as a dependency--use $(GCC_PASSES). @@ -693,18 +691,6 @@ CRTSTUFF_CFLAGS = -O2 $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \ -fno-stack-protector \ $(INHIBIT_LIBC_CFLAGS) -# Additional sources to handle exceptions; overridden by targets as needed. -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c -LIB2ADDEHSTATIC = $(LIB2ADDEH) -LIB2ADDEHSHARED = $(LIB2ADDEH) - -# Don't build libunwind by default. -LIBUNWIND = -LIBUNWINDDEP = -SHLIBUNWIND_LINK = -SHLIBUNWIND_INSTALL = - # nm flags to list global symbols in libgcc object files. SHLIB_NM_FLAGS = -pg @@ -1898,7 +1884,7 @@ GCC_EXTRA_PARTS := $(sort $(EXTRA_MULTILIB_PARTS) $(EXTRA_PARTS)) libgcc-support: libgcc.mvars stmp-int-hdrs $(TCONFIG_H) \ $(MACHMODE_H) $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \ - $(LIB2ADD_ST) $(LIB2ADDEH) $(srcdir)/emutls.c gcov-iov.h $(SFP_MACHINE) + $(LIB2ADD_ST) gcov-iov.h $(SFP_MACHINE) libgcc.mvars: config.status Makefile $(LIB2ADD) $(LIB2ADD_ST) specs \ xgcc$(exeext) @@ -1909,13 +1895,7 @@ libgcc.mvars: config.status Makefile $(LIB2ADD) $(LIB2ADD_ST) specs \ echo LIB2FUNCS_EXCLUDE = '$(LIB2FUNCS_EXCLUDE)' >> tmp-libgcc.mvars echo LIB2ADD = '$(call srcdirify,$(LIB2ADD))' >> tmp-libgcc.mvars echo LIB2ADD_ST = '$(call srcdirify,$(LIB2ADD_ST))' >> tmp-libgcc.mvars - echo LIB2ADDEH = '$(call srcdirify,$(LIB2ADDEH) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars - echo LIB2ADDEHSTATIC = '$(call srcdirify,$(LIB2ADDEHSTATIC) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars - echo LIB2ADDEHSHARED = '$(call srcdirify,$(LIB2ADDEHSHARED) $(srcdir)/emutls.c)' >> tmp-libgcc.mvars echo LIB2_SIDITI_CONV_FUNCS = '$(LIB2_SIDITI_CONV_FUNCS)' >> tmp-libgcc.mvars - echo LIBUNWIND = '$(call srcdirify,$(LIBUNWIND))' >> tmp-libgcc.mvars - echo SHLIBUNWIND_LINK = '$(SHLIBUNWIND_LINK)' >> tmp-libgcc.mvars - echo SHLIBUNWIND_INSTALL = '$(SHLIBUNWIND_INSTALL)' >> tmp-libgcc.mvars echo FPBIT = '$(FPBIT)' >> tmp-libgcc.mvars echo FPBIT_FUNCS = '$(FPBIT_FUNCS)' >> tmp-libgcc.mvars echo LIB2_DIVMOD_FUNCS = '$(LIB2_DIVMOD_FUNCS)' >> tmp-libgcc.mvars @@ -4114,7 +4094,7 @@ gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS) # be rebuilt. # Build the include directories. -stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) $(UNWIND_H) fixinc_list +stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) fixinc_list # Copy in the headers provided with gcc. # The sed command gets just the last file name component; # this is necessary because VPATH could add a dirname. @@ -4146,9 +4126,6 @@ stmp-int-hdrs: $(STMP_FIXINC) $(USER_H) $(UNWIND_H) fixinc_list chmod a+r include/$$file; \ fi; \ done - rm -f include/unwind.h - cp $(UNWIND_H) include/unwind.h - chmod a+r include/unwind.h rm -f include/stdint.h if [ $(USE_GCC_STDINT) = wrap ]; then \ rm -f include/stdint-gcc.h; \ diff --git a/gcc/aclocal.m4 b/gcc/aclocal.m4 index 73afd7fedee..1b90b2f5ee6 100644 --- a/gcc/aclocal.m4 +++ b/gcc/aclocal.m4 @@ -116,6 +116,5 @@ m4_include([../config/lib-prefix.m4]) m4_include([../config/override.m4]) m4_include([../config/progtest.m4]) m4_include([../config/stdint.m4]) -m4_include([../config/unwind_ipinfo.m4]) m4_include([../config/warnings.m4]) m4_include([acinclude.m4]) diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index ce02f4f2889..743fa0e57dc 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2011-08-05 Rainer Orth + + * gcc-interface/Makefile.in (raise-gcc.o): Search + $(srcdir)/../libgcc. + 2011-08-05 Bob Duff * sinfo.ads, sinfo.adb (Subpool_Handle_Name): New attribute for @@ -100,6 +105,7 @@ necessary. * put_scos.adb: Code simplification based on above change. +>>>>>>> .r177446 2011-08-05 Robert Dewar * sem_ch3.adb, gnatcmd.adb, switch-c.adb, exp_attr.adb, make.adb, diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in index 1642cc8622b..1e7a392edf4 100644 --- a/gcc/ada/gcc-interface/Makefile.in +++ b/gcc/ada/gcc-interface/Makefile.in @@ -2773,7 +2773,7 @@ vx_stack_info.o : vx_stack_info.c raise-gcc.o : raise-gcc.c raise.h $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ADA_CFLAGS) \ - -iquote $(srcdir) \ + -iquote $(srcdir)/../libgcc \ $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) cio.o : cio.c diff --git a/gcc/config.gcc b/gcc/config.gcc index 94f15d8706d..673b768b770 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1604,9 +1604,6 @@ ia64*-*-freebsd*) ia64*-*-linux*) tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h ia64/sysv4.h ia64/linux.h" tmake_file="${tmake_file} ia64/t-ia64 t-libunwind ia64/t-glibc" - if test x$with_system_libunwind != xyes ; then - tmake_file="${tmake_file} t-libunwind-elf ia64/t-glibc-libunwind" - fi target_cpu_default="MASK_GNU_AS|MASK_GNU_LD" extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" ;; diff --git a/gcc/config/arm/libunwind.S b/gcc/config/arm/libunwind.S deleted file mode 100644 index 48eb592fd1a..00000000000 --- a/gcc/config/arm/libunwind.S +++ /dev/null @@ -1,363 +0,0 @@ -/* Support functions for the unwinder. - Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Paul Brook - - This file 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 3, or (at your option) any - later version. - - This file 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* An executable stack is *not* required for these functions. */ -#if defined(__ELF__) && defined(__linux__) -.section .note.GNU-stack,"",%progbits -.previous -#endif - -#ifdef __ARM_EABI__ -/* Some attributes that are common to all routines in this file. */ - /* Tag_ABI_align_needed: This code does not require 8-byte - alignment from the caller. */ - /* .eabi_attribute 24, 0 -- default setting. */ - /* Tag_ABI_align_preserved: This code preserves 8-byte - alignment in any callee. */ - .eabi_attribute 25, 1 -#endif /* __ARM_EABI__ */ - -#ifndef __symbian__ - -#include "lib1funcs.asm" - -.macro UNPREFIX name - .global SYM (\name) - EQUIV SYM (\name), SYM (__\name) -.endm - -#if (__ARM_ARCH__ == 4) -/* Some coprocessors require armv5. We know this code will never be run on - other cpus. Tell gas to allow armv5, but only mark the objects as armv4. - */ -.arch armv5t -#ifdef __ARM_ARCH_4T__ -.object_arch armv4t -#else -.object_arch armv4 -#endif -#endif - -#ifdef __ARM_ARCH_6M__ - -/* r0 points to a 16-word block. Upload these values to the actual core - state. */ -FUNC_START restore_core_regs - mov r1, r0 - add r1, r1, #52 - ldmia r1!, {r3, r4, r5} - sub r3, r3, #4 - mov ip, r3 - str r5, [r3] - mov lr, r4 - /* Restore r8-r11. */ - mov r1, r0 - add r1, r1, #32 - ldmia r1!, {r2, r3, r4, r5} - mov r8, r2 - mov r9, r3 - mov sl, r4 - mov fp, r5 - mov r1, r0 - add r1, r1, #8 - ldmia r1!, {r2, r3, r4, r5, r6, r7} - ldr r1, [r0, #4] - ldr r0, [r0] - mov sp, ip - pop {pc} - FUNC_END restore_core_regs - UNPREFIX restore_core_regs - -/* ARMV6M does not have coprocessors, so these should never be used. */ -FUNC_START gnu_Unwind_Restore_VFP - RET - -/* Store VFR regsters d0-d15 to the address in r0. */ -FUNC_START gnu_Unwind_Save_VFP - RET - -/* Load VFP registers d0-d15 from the address in r0. - Use this to load from FSTMD format. */ -FUNC_START gnu_Unwind_Restore_VFP_D - RET - -/* Store VFP registers d0-d15 to the address in r0. - Use this to store in FLDMD format. */ -FUNC_START gnu_Unwind_Save_VFP_D - RET - -/* Load VFP registers d16-d31 from the address in r0. - Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ -FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 - RET - -/* Store VFP registers d16-d31 to the address in r0. - Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ -FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 - RET - -FUNC_START gnu_Unwind_Restore_WMMXD - RET - -FUNC_START gnu_Unwind_Save_WMMXD - RET - -FUNC_START gnu_Unwind_Restore_WMMXC - RET - -FUNC_START gnu_Unwind_Save_WMMXC - RET - -.macro UNWIND_WRAPPER name nargs - FUNC_START \name - /* Create a phase2_vrs structure. */ - /* Save r0 in the PC slot so we can use it as a scratch register. */ - push {r0} - add r0, sp, #4 - push {r0, lr} /* Push original SP and LR. */ - /* Make space for r8-r12. */ - sub sp, sp, #20 - /* Save low registers. */ - push {r0, r1, r2, r3, r4, r5, r6, r7} - /* Save high registers. */ - add r0, sp, #32 - mov r1, r8 - mov r2, r9 - mov r3, sl - mov r4, fp - mov r5, ip - stmia r0!, {r1, r2, r3, r4, r5} - /* Restore original low register values. */ - add r0, sp, #4 - ldmia r0!, {r1, r2, r3, r4, r5} - /* Restore orginial r0. */ - ldr r0, [sp, #60] - str r0, [sp] - /* Demand-save flags, plus an extra word for alignment. */ - mov r3, #0 - push {r2, r3} - /* Point r1 at the block. Pass r[0..nargs) unchanged. */ - add r\nargs, sp, #4 - - bl SYM (__gnu\name) - - ldr r3, [sp, #64] - add sp, sp, #72 - bx r3 - - FUNC_END \name - UNPREFIX \name -.endm - -#else /* !__ARM_ARCH_6M__ */ - -/* r0 points to a 16-word block. Upload these values to the actual core - state. */ -ARM_FUNC_START restore_core_regs - /* We must use sp as the base register when restoring sp. Push the - last 3 registers onto the top of the current stack to achieve - this. */ - add r1, r0, #52 - ldmia r1, {r3, r4, r5} /* {sp, lr, pc}. */ -#if defined(__thumb2__) - /* Thumb-2 doesn't allow sp in a load-multiple instruction, so push - the target address onto the target stack. This is safe as - we're always returning to somewhere further up the call stack. */ - mov ip, r3 - mov lr, r4 - str r5, [ip, #-4]! -#elif defined(__INTERWORKING__) - /* Restore pc into ip. */ - mov r2, r5 - stmfd sp!, {r2, r3, r4} -#else - stmfd sp!, {r3, r4, r5} -#endif - /* Don't bother restoring ip. */ - ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp} -#if defined(__thumb2__) - /* Pop the return address off the target stack. */ - mov sp, ip - pop {pc} -#elif defined(__INTERWORKING__) - /* Pop the three registers we pushed earlier. */ - ldmfd sp, {ip, sp, lr} - bx ip -#else - ldmfd sp, {sp, lr, pc} -#endif - FUNC_END restore_core_regs - UNPREFIX restore_core_regs - -/* Load VFP registers d0-d15 from the address in r0. - Use this to load from FSTMX format. */ -ARM_FUNC_START gnu_Unwind_Restore_VFP - /* Use the generic coprocessor form so that gas doesn't complain - on soft-float targets. */ - ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */ - RET - -/* Store VFP registers d0-d15 to the address in r0. - Use this to store in FSTMX format. */ -ARM_FUNC_START gnu_Unwind_Save_VFP - /* Use the generic coprocessor form so that gas doesn't complain - on soft-float targets. */ - stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */ - RET - -/* Load VFP registers d0-d15 from the address in r0. - Use this to load from FSTMD format. */ -ARM_FUNC_START gnu_Unwind_Restore_VFP_D - ldc p11,cr0,[r0],{0x20} /* fldmiad r0, {d0-d15} */ - RET - -/* Store VFP registers d0-d15 to the address in r0. - Use this to store in FLDMD format. */ -ARM_FUNC_START gnu_Unwind_Save_VFP_D - stc p11,cr0,[r0],{0x20} /* fstmiad r0, {d0-d15} */ - RET - -/* Load VFP registers d16-d31 from the address in r0. - Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ -ARM_FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 - ldcl p11,cr0,[r0],{0x20} /* vldm r0, {d16-d31} */ - RET - -/* Store VFP registers d16-d31 to the address in r0. - Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ -ARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 - stcl p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */ - RET - -ARM_FUNC_START gnu_Unwind_Restore_WMMXD - /* Use the generic coprocessor form so that gas doesn't complain - on non-iWMMXt targets. */ - ldcl p1, cr0, [r0], #8 /* wldrd wr0, [r0], #8 */ - ldcl p1, cr1, [r0], #8 /* wldrd wr1, [r0], #8 */ - ldcl p1, cr2, [r0], #8 /* wldrd wr2, [r0], #8 */ - ldcl p1, cr3, [r0], #8 /* wldrd wr3, [r0], #8 */ - ldcl p1, cr4, [r0], #8 /* wldrd wr4, [r0], #8 */ - ldcl p1, cr5, [r0], #8 /* wldrd wr5, [r0], #8 */ - ldcl p1, cr6, [r0], #8 /* wldrd wr6, [r0], #8 */ - ldcl p1, cr7, [r0], #8 /* wldrd wr7, [r0], #8 */ - ldcl p1, cr8, [r0], #8 /* wldrd wr8, [r0], #8 */ - ldcl p1, cr9, [r0], #8 /* wldrd wr9, [r0], #8 */ - ldcl p1, cr10, [r0], #8 /* wldrd wr10, [r0], #8 */ - ldcl p1, cr11, [r0], #8 /* wldrd wr11, [r0], #8 */ - ldcl p1, cr12, [r0], #8 /* wldrd wr12, [r0], #8 */ - ldcl p1, cr13, [r0], #8 /* wldrd wr13, [r0], #8 */ - ldcl p1, cr14, [r0], #8 /* wldrd wr14, [r0], #8 */ - ldcl p1, cr15, [r0], #8 /* wldrd wr15, [r0], #8 */ - RET - -ARM_FUNC_START gnu_Unwind_Save_WMMXD - /* Use the generic coprocessor form so that gas doesn't complain - on non-iWMMXt targets. */ - stcl p1, cr0, [r0], #8 /* wstrd wr0, [r0], #8 */ - stcl p1, cr1, [r0], #8 /* wstrd wr1, [r0], #8 */ - stcl p1, cr2, [r0], #8 /* wstrd wr2, [r0], #8 */ - stcl p1, cr3, [r0], #8 /* wstrd wr3, [r0], #8 */ - stcl p1, cr4, [r0], #8 /* wstrd wr4, [r0], #8 */ - stcl p1, cr5, [r0], #8 /* wstrd wr5, [r0], #8 */ - stcl p1, cr6, [r0], #8 /* wstrd wr6, [r0], #8 */ - stcl p1, cr7, [r0], #8 /* wstrd wr7, [r0], #8 */ - stcl p1, cr8, [r0], #8 /* wstrd wr8, [r0], #8 */ - stcl p1, cr9, [r0], #8 /* wstrd wr9, [r0], #8 */ - stcl p1, cr10, [r0], #8 /* wstrd wr10, [r0], #8 */ - stcl p1, cr11, [r0], #8 /* wstrd wr11, [r0], #8 */ - stcl p1, cr12, [r0], #8 /* wstrd wr12, [r0], #8 */ - stcl p1, cr13, [r0], #8 /* wstrd wr13, [r0], #8 */ - stcl p1, cr14, [r0], #8 /* wstrd wr14, [r0], #8 */ - stcl p1, cr15, [r0], #8 /* wstrd wr15, [r0], #8 */ - RET - -ARM_FUNC_START gnu_Unwind_Restore_WMMXC - /* Use the generic coprocessor form so that gas doesn't complain - on non-iWMMXt targets. */ - ldc2 p1, cr8, [r0], #4 /* wldrw wcgr0, [r0], #4 */ - ldc2 p1, cr9, [r0], #4 /* wldrw wcgr1, [r0], #4 */ - ldc2 p1, cr10, [r0], #4 /* wldrw wcgr2, [r0], #4 */ - ldc2 p1, cr11, [r0], #4 /* wldrw wcgr3, [r0], #4 */ - RET - -ARM_FUNC_START gnu_Unwind_Save_WMMXC - /* Use the generic coprocessor form so that gas doesn't complain - on non-iWMMXt targets. */ - stc2 p1, cr8, [r0], #4 /* wstrw wcgr0, [r0], #4 */ - stc2 p1, cr9, [r0], #4 /* wstrw wcgr1, [r0], #4 */ - stc2 p1, cr10, [r0], #4 /* wstrw wcgr2, [r0], #4 */ - stc2 p1, cr11, [r0], #4 /* wstrw wcgr3, [r0], #4 */ - RET - -/* Wrappers to save core registers, then call the real routine. */ - -.macro UNWIND_WRAPPER name nargs - ARM_FUNC_START \name - /* Create a phase2_vrs structure. */ - /* Split reg push in two to ensure the correct value for sp. */ -#if defined(__thumb2__) - mov ip, sp - push {lr} /* PC is ignored. */ - push {ip, lr} /* Push original SP and LR. */ -#else - stmfd sp!, {sp, lr, pc} -#endif - stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip} - - /* Demand-save flags, plus an extra word for alignment. */ - mov r3, #0 - stmfd sp!, {r2, r3} - - /* Point r1 at the block. Pass r[0..nargs) unchanged. */ - add r\nargs, sp, #4 -#if defined(__thumb__) && !defined(__thumb2__) - /* Switch back to thumb mode to avoid interworking hassle. */ - adr ip, .L1_\name - orr ip, ip, #1 - bx ip - .thumb -.L1_\name: - bl SYM (__gnu\name) __PLT__ - ldr r3, [sp, #64] - add sp, #72 - bx r3 -#else - bl SYM (__gnu\name) __PLT__ - ldr lr, [sp, #64] - add sp, sp, #72 - RET -#endif - FUNC_END \name - UNPREFIX \name -.endm - -#endif /* !__ARM_ARCH_6M__ */ - -UNWIND_WRAPPER _Unwind_RaiseException 1 -UNWIND_WRAPPER _Unwind_Resume 1 -UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1 -UNWIND_WRAPPER _Unwind_ForcedUnwind 3 -UNWIND_WRAPPER _Unwind_Backtrace 2 - -#endif /* ndef __symbian__ */ diff --git a/gcc/config/arm/pr-support.c b/gcc/config/arm/pr-support.c deleted file mode 100644 index deee661e264..00000000000 --- a/gcc/config/arm/pr-support.c +++ /dev/null @@ -1,401 +0,0 @@ -/* ARM EABI compliant unwinding routines - Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. - Contributed by Paul Brook - - This file 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 3, or (at your option) any - later version. - - This file 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "unwind.h" - -/* We add a prototype for abort here to avoid creating a dependency on - target headers. */ -extern void abort (void); - -typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ - -/* Misc constants. */ -#define R_IP 12 -#define R_SP 13 -#define R_LR 14 -#define R_PC 15 - -#define uint32_highbit (((_uw) 1) << 31) - -void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); - -/* Unwind descriptors. */ - -typedef struct -{ - _uw16 length; - _uw16 offset; -} EHT16; - -typedef struct -{ - _uw length; - _uw offset; -} EHT32; - -/* Calculate the address encoded by a 31-bit self-relative offset at address - P. Copy of routine in unwind-arm.c. */ - -static inline _uw -selfrel_offset31 (const _uw *p) -{ - _uw offset; - - offset = *p; - /* Sign extend to 32 bits. */ - if (offset & (1 << 30)) - offset |= 1u << 31; - - return offset + (_uw) p; -} - - -/* Personality routine helper functions. */ - -#define CODE_FINISH (0xb0) - -/* Return the next byte of unwinding information, or CODE_FINISH if there is - no data remaining. */ -static inline _uw8 -next_unwind_byte (__gnu_unwind_state * uws) -{ - _uw8 b; - - if (uws->bytes_left == 0) - { - /* Load another word */ - if (uws->words_left == 0) - return CODE_FINISH; /* Nothing left. */ - uws->words_left--; - uws->data = *(uws->next++); - uws->bytes_left = 3; - } - else - uws->bytes_left--; - - /* Extract the most significant byte. */ - b = (uws->data >> 24) & 0xff; - uws->data <<= 8; - return b; -} - -/* Execute the unwinding instructions described by UWS. */ -_Unwind_Reason_Code -__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) -{ - _uw op; - int set_pc; - _uw reg; - - set_pc = 0; - for (;;) - { - op = next_unwind_byte (uws); - if (op == CODE_FINISH) - { - /* If we haven't already set pc then copy it from lr. */ - if (!set_pc) - { - _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, - ®); - _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, - ®); - set_pc = 1; - } - /* Drop out of the loop. */ - break; - } - if ((op & 0x80) == 0) - { - /* vsp = vsp +- (imm6 << 2 + 4). */ - _uw offset; - - offset = ((op & 0x3f) << 2) + 4; - _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - if (op & 0x40) - reg -= offset; - else - reg += offset; - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - continue; - } - - if ((op & 0xf0) == 0x80) - { - op = (op << 8) | next_unwind_byte (uws); - if (op == 0x8000) - { - /* Refuse to unwind. */ - return _URC_FAILURE; - } - /* Pop r4-r15 under mask. */ - op = (op << 4) & 0xfff0; - if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) - != _UVRSR_OK) - return _URC_FAILURE; - if (op & (1 << R_PC)) - set_pc = 1; - continue; - } - if ((op & 0xf0) == 0x90) - { - op &= 0xf; - if (op == 13 || op == 15) - /* Reserved. */ - return _URC_FAILURE; - /* vsp = r[nnnn]. */ - _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®); - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - continue; - } - if ((op & 0xf0) == 0xa0) - { - /* Pop r4-r[4+nnn], [lr]. */ - _uw mask; - - mask = (0xff0 >> (7 - (op & 7))) & 0xff0; - if (op & 8) - mask |= (1 << R_LR); - if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf0) == 0xb0) - { - /* op == 0xb0 already handled. */ - if (op == 0xb1) - { - op = next_unwind_byte (uws); - if (op == 0 || ((op & 0xf0) != 0)) - /* Spare. */ - return _URC_FAILURE; - /* Pop r0-r4 under mask. */ - if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xb2) - { - /* vsp = vsp + 0x204 + (uleb128 << 2). */ - int shift; - - _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, - ®); - op = next_unwind_byte (uws); - shift = 2; - while (op & 0x80) - { - reg += ((op & 0x7f) << shift); - shift += 7; - op = next_unwind_byte (uws); - } - reg += ((op & 0x7f) << shift) + 0x204; - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, - ®); - continue; - } - if (op == 0xb3) - { - /* Pop VFP registers with fldmx. */ - op = next_unwind_byte (uws); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xfc) == 0xb4) - { - /* Pop FPA E[4]-E[4+nn]. */ - op = 0x40000 | ((op & 3) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* op & 0xf8 == 0xb8. */ - /* Pop VFP D[8]-D[8+nnn] with fldmx. */ - op = 0x80000 | ((op & 7) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf0) == 0xc0) - { - if (op == 0xc6) - { - /* Pop iWMMXt D registers. */ - op = next_unwind_byte (uws); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xc7) - { - op = next_unwind_byte (uws); - if (op == 0 || (op & 0xf0) != 0) - /* Spare. */ - return _URC_FAILURE; - /* Pop iWMMXt wCGR{3,2,1,0} under mask. */ - if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf8) == 0xc0) - { - /* Pop iWMMXt wR[10]-wR[10+nnn]. */ - op = 0xa0000 | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xc8) - { -#ifndef __VFP_FP__ - /* Pop FPA registers. */ - op = next_unwind_byte (uws); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) - != _UVRSR_OK) - return _URC_FAILURE; - continue; -#else - /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */ - op = next_unwind_byte (uws); - op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) - != _UVRSR_OK) - return _URC_FAILURE; - continue; -#endif - } - if (op == 0xc9) - { - /* Pop VFP registers with fldmd. */ - op = next_unwind_byte (uws); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* Spare. */ - return _URC_FAILURE; - } - if ((op & 0xf8) == 0xd0) - { - /* Pop VFP D[8]-D[8+nnn] with fldmd. */ - op = 0x80000 | ((op & 7) + 1); - if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* Spare. */ - return _URC_FAILURE; - } - return _URC_OK; -} - - -/* Execute the unwinding instructions associated with a frame. UCBP and - CONTEXT are the current exception object and virtual CPU state - respectively. */ - -_Unwind_Reason_Code -__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context) -{ - _uw *ptr; - __gnu_unwind_state uws; - - ptr = (_uw *) ucbp->pr_cache.ehtp; - /* Skip over the personality routine address. */ - ptr++; - /* Setup the unwinder state. */ - uws.data = (*ptr) << 8; - uws.next = ptr + 1; - uws.bytes_left = 3; - uws.words_left = ((*ptr) >> 24) & 0xff; - - return __gnu_unwind_execute (context, &uws); -} - -/* Get the _Unwind_Control_Block from an _Unwind_Context. */ - -static inline _Unwind_Control_Block * -unwind_UCB_from_context (_Unwind_Context * context) -{ - return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP); -} - -/* Get the start address of the function being unwound. */ - -_Unwind_Ptr -_Unwind_GetRegionStart (_Unwind_Context * context) -{ - _Unwind_Control_Block *ucbp; - - ucbp = unwind_UCB_from_context (context); - return (_Unwind_Ptr) ucbp->pr_cache.fnstart; -} - -/* Find the Language specific exception data. */ - -void * -_Unwind_GetLanguageSpecificData (_Unwind_Context * context) -{ - _Unwind_Control_Block *ucbp; - _uw *ptr; - - /* Get a pointer to the exception table entry. */ - ucbp = unwind_UCB_from_context (context); - ptr = (_uw *) ucbp->pr_cache.ehtp; - /* Skip the personality routine address. */ - ptr++; - /* Skip the unwind opcodes. */ - ptr += (((*ptr) >> 24) & 0xff) + 1; - - return ptr; -} - - -/* These two should never be used. */ - -_Unwind_Ptr -_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused))) -{ - abort (); -} - -_Unwind_Ptr -_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused))) -{ - abort (); -} diff --git a/gcc/config/arm/t-bpabi b/gcc/config/arm/t-bpabi index 78812b35bd8..b6b5f40d723 100644 --- a/gcc/config/arm/t-bpabi +++ b/gcc/config/arm/t-bpabi @@ -25,11 +25,6 @@ LIB2FUNCS_EXTRA = $(srcdir)/config/arm/bpabi.c \ LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/arm/fp16.c -UNWIND_H = $(srcdir)/config/arm/unwind-arm.h -LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \ - $(srcdir)/config/arm/libunwind.S \ - $(srcdir)/config/arm/pr-support.c $(srcdir)/unwind-c.c - # Add the BPABI names. SHLIB_MAPFILES += $(srcdir)/config/arm/libgcc-bpabi.ver diff --git a/gcc/config/arm/t-symbian b/gcc/config/arm/t-symbian index 3be83f445aa..f074591acbe 100644 --- a/gcc/config/arm/t-symbian +++ b/gcc/config/arm/t-symbian @@ -30,10 +30,6 @@ LIB1ASMFUNCS += \ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ _fixsfsi _fixunssfsi -# Include the gcc personality routine -UNWIND_H = $(srcdir)/config/arm/unwind-arm.h -LIB2ADDEH = $(srcdir)/unwind-c.c $(srcdir)/config/arm/pr-support.c - # Include half-float helpers. LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/arm/fp16.c diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c deleted file mode 100644 index 90d258d3c80..00000000000 --- a/gcc/config/arm/unwind-arm.c +++ /dev/null @@ -1,1283 +0,0 @@ -/* ARM EABI compliant unwinding routines. - Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. - Contributed by Paul Brook - - This file 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 3, or (at your option) any - later version. - - This file 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "unwind.h" - -/* We add a prototype for abort here to avoid creating a dependency on - target headers. */ -extern void abort (void); - -/* Definitions for C++ runtime support routines. We make these weak - declarations to avoid pulling in libsupc++ unnecessarily. */ -typedef unsigned char bool; - -typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ -enum __cxa_type_match_result - { - ctm_failed = 0, - ctm_succeeded = 1, - ctm_succeeded_with_ptr_to_base = 2 - }; - -void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); -bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp); -enum __cxa_type_match_result __attribute__((weak)) __cxa_type_match - (_Unwind_Control_Block *ucbp, const type_info *rttip, - bool is_reference, void **matched_object); - -_Unwind_Ptr __attribute__((weak)) -__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); - -/* Misc constants. */ -#define R_IP 12 -#define R_SP 13 -#define R_LR 14 -#define R_PC 15 - -#define EXIDX_CANTUNWIND 1 -#define uint32_highbit (((_uw) 1) << 31) - -#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1) -#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) -#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) -#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) - -struct core_regs -{ - _uw r[16]; -}; - -/* We use normal integer types here to avoid the compiler generating - coprocessor instructions. */ -struct vfp_regs -{ - _uw64 d[16]; - _uw pad; -}; - -struct vfpv3_regs -{ - /* Always populated via VSTM, so no need for the "pad" field from - vfp_regs (which is used to store the format word for FSTMX). */ - _uw64 d[16]; -}; - -struct fpa_reg -{ - _uw w[3]; -}; - -struct fpa_regs -{ - struct fpa_reg f[8]; -}; - -struct wmmxd_regs -{ - _uw64 wd[16]; -}; - -struct wmmxc_regs -{ - _uw wc[4]; -}; - -/* Unwind descriptors. */ - -typedef struct -{ - _uw16 length; - _uw16 offset; -} EHT16; - -typedef struct -{ - _uw length; - _uw offset; -} EHT32; - -/* The ABI specifies that the unwind routines may only use core registers, - except when actually manipulating coprocessor state. This allows - us to write one implementation that works on all platforms by - demand-saving coprocessor registers. - - During unwinding we hold the coprocessor state in the actual hardware - registers and allocate demand-save areas for use during phase1 - unwinding. */ - -typedef struct -{ - /* The first fields must be the same as a phase2_vrs. */ - _uw demand_save_flags; - struct core_regs core; - _uw prev_sp; /* Only valid during forced unwinding. */ - struct vfp_regs vfp; - struct vfpv3_regs vfp_regs_16_to_31; - struct fpa_regs fpa; - struct wmmxd_regs wmmxd; - struct wmmxc_regs wmmxc; -} phase1_vrs; - -#define DEMAND_SAVE_VFP 1 /* VFP state has been saved if not set */ -#define DEMAND_SAVE_VFP_D 2 /* VFP state is for FLDMD/FSTMD if set */ -#define DEMAND_SAVE_VFP_V3 4 /* VFPv3 state for regs 16 .. 31 has - been saved if not set */ -#define DEMAND_SAVE_WMMXD 8 /* iWMMXt data registers have been - saved if not set. */ -#define DEMAND_SAVE_WMMXC 16 /* iWMMXt control registers have been - saved if not set. */ - -/* This must match the structure created by the assembly wrappers. */ -typedef struct -{ - _uw demand_save_flags; - struct core_regs core; -} phase2_vrs; - - -/* An exception index table entry. */ - -typedef struct __EIT_entry -{ - _uw fnoffset; - _uw content; -} __EIT_entry; - -/* Assembly helper functions. */ - -/* Restore core register state. Never returns. */ -void __attribute__((noreturn)) restore_core_regs (struct core_regs *); - - -/* Coprocessor register state manipulation functions. */ - -/* Routines for FLDMX/FSTMX format... */ -void __gnu_Unwind_Save_VFP (struct vfp_regs * p); -void __gnu_Unwind_Restore_VFP (struct vfp_regs * p); -void __gnu_Unwind_Save_WMMXD (struct wmmxd_regs * p); -void __gnu_Unwind_Restore_WMMXD (struct wmmxd_regs * p); -void __gnu_Unwind_Save_WMMXC (struct wmmxc_regs * p); -void __gnu_Unwind_Restore_WMMXC (struct wmmxc_regs * p); - -/* ...and those for FLDMD/FSTMD format... */ -void __gnu_Unwind_Save_VFP_D (struct vfp_regs * p); -void __gnu_Unwind_Restore_VFP_D (struct vfp_regs * p); - -/* ...and those for VLDM/VSTM format, saving/restoring only registers - 16 through 31. */ -void __gnu_Unwind_Save_VFP_D_16_to_31 (struct vfpv3_regs * p); -void __gnu_Unwind_Restore_VFP_D_16_to_31 (struct vfpv3_regs * p); - -/* Restore coprocessor state after phase1 unwinding. */ -static void -restore_non_core_regs (phase1_vrs * vrs) -{ - if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0) - { - if (vrs->demand_save_flags & DEMAND_SAVE_VFP_D) - __gnu_Unwind_Restore_VFP_D (&vrs->vfp); - else - __gnu_Unwind_Restore_VFP (&vrs->vfp); - } - - if ((vrs->demand_save_flags & DEMAND_SAVE_VFP_V3) == 0) - __gnu_Unwind_Restore_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31); - - if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXD) == 0) - __gnu_Unwind_Restore_WMMXD (&vrs->wmmxd); - if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXC) == 0) - __gnu_Unwind_Restore_WMMXC (&vrs->wmmxc); -} - -/* A better way to do this would probably be to compare the absolute address - with a segment relative relocation of the same symbol. */ - -extern int __text_start; -extern int __data_start; - -/* The exception index table location. */ -extern __EIT_entry __exidx_start; -extern __EIT_entry __exidx_end; - -/* ABI defined personality routines. */ -extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak)); -extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1 (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak)); -extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2 (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak)); - -/* ABI defined routine to store a virtual register to memory. */ - -_Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - _uw regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) -{ - phase1_vrs *vrs = (phase1_vrs *) context; - - switch (regclass) - { - case _UVRSC_CORE: - if (representation != _UVRSD_UINT32 - || regno > 15) - return _UVRSR_FAILED; - *(_uw *) valuep = vrs->core.r[regno]; - return _UVRSR_OK; - - case _UVRSC_VFP: - case _UVRSC_FPA: - case _UVRSC_WMMXD: - case _UVRSC_WMMXC: - return _UVRSR_NOT_IMPLEMENTED; - - default: - return _UVRSR_FAILED; - } -} - - -/* ABI defined function to load a virtual register from memory. */ - -_Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - _uw regno, - _Unwind_VRS_DataRepresentation representation, - void *valuep) -{ - phase1_vrs *vrs = (phase1_vrs *) context; - - switch (regclass) - { - case _UVRSC_CORE: - if (representation != _UVRSD_UINT32 - || regno > 15) - return _UVRSR_FAILED; - - vrs->core.r[regno] = *(_uw *) valuep; - return _UVRSR_OK; - - case _UVRSC_VFP: - case _UVRSC_FPA: - case _UVRSC_WMMXD: - case _UVRSC_WMMXC: - return _UVRSR_NOT_IMPLEMENTED; - - default: - return _UVRSR_FAILED; - } -} - - -/* ABI defined function to pop registers off the stack. */ - -_Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - _uw discriminator, - _Unwind_VRS_DataRepresentation representation) -{ - phase1_vrs *vrs = (phase1_vrs *) context; - - switch (regclass) - { - case _UVRSC_CORE: - { - _uw *ptr; - _uw mask; - int i; - - if (representation != _UVRSD_UINT32) - return _UVRSR_FAILED; - - mask = discriminator & 0xffff; - ptr = (_uw *) vrs->core.r[R_SP]; - /* Pop the requested registers. */ - for (i = 0; i < 16; i++) - { - if (mask & (1 << i)) - vrs->core.r[i] = *(ptr++); - } - /* Writeback the stack pointer value if it wasn't restored. */ - if ((mask & (1 << R_SP)) == 0) - vrs->core.r[R_SP] = (_uw) ptr; - } - return _UVRSR_OK; - - case _UVRSC_VFP: - { - _uw start = discriminator >> 16; - _uw count = discriminator & 0xffff; - struct vfp_regs tmp; - struct vfpv3_regs tmp_16_to_31; - int tmp_count; - _uw *sp; - _uw *dest; - int num_vfpv3_regs = 0; - - /* We use an approximation here by bounding _UVRSD_DOUBLE - register numbers at 32 always, since we can't detect if - VFPv3 isn't present (in such a case the upper limit is 16). */ - if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) - || start + count > (representation == _UVRSD_VFPX ? 16 : 32) - || (representation == _UVRSD_VFPX && start >= 16)) - return _UVRSR_FAILED; - - /* Check if we're being asked to pop VFPv3-only registers - (numbers 16 through 31). */ - if (start >= 16) - num_vfpv3_regs = count; - else if (start + count > 16) - num_vfpv3_regs = start + count - 16; - - if (num_vfpv3_regs && representation != _UVRSD_DOUBLE) - return _UVRSR_FAILED; - - /* Demand-save coprocessor registers for stage1. */ - if (start < 16 && (vrs->demand_save_flags & DEMAND_SAVE_VFP)) - { - vrs->demand_save_flags &= ~DEMAND_SAVE_VFP; - - if (representation == _UVRSD_DOUBLE) - { - /* Save in FLDMD/FSTMD format. */ - vrs->demand_save_flags |= DEMAND_SAVE_VFP_D; - __gnu_Unwind_Save_VFP_D (&vrs->vfp); - } - else - { - /* Save in FLDMX/FSTMX format. */ - vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_D; - __gnu_Unwind_Save_VFP (&vrs->vfp); - } - } - - if (num_vfpv3_regs > 0 - && (vrs->demand_save_flags & DEMAND_SAVE_VFP_V3)) - { - vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_V3; - __gnu_Unwind_Save_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31); - } - - /* Restore the registers from the stack. Do this by saving the - current VFP registers to a memory area, moving the in-memory - values into that area, and restoring from the whole area. - For _UVRSD_VFPX we assume FSTMX standard format 1. */ - if (representation == _UVRSD_VFPX) - __gnu_Unwind_Save_VFP (&tmp); - else - { - /* Save registers 0 .. 15 if required. */ - if (start < 16) - __gnu_Unwind_Save_VFP_D (&tmp); - - /* Save VFPv3 registers 16 .. 31 if required. */ - if (num_vfpv3_regs) - __gnu_Unwind_Save_VFP_D_16_to_31 (&tmp_16_to_31); - } - - /* Work out how many registers below register 16 need popping. */ - tmp_count = num_vfpv3_regs > 0 ? 16 - start : count; - - /* Copy registers below 16, if needed. - The stack address is only guaranteed to be word aligned, so - we can't use doubleword copies. */ - sp = (_uw *) vrs->core.r[R_SP]; - if (tmp_count > 0) - { - tmp_count *= 2; - dest = (_uw *) &tmp.d[start]; - while (tmp_count--) - *(dest++) = *(sp++); - } - - /* Copy VFPv3 registers numbered >= 16, if needed. */ - if (num_vfpv3_regs > 0) - { - /* num_vfpv3_regs is needed below, so copy it. */ - int tmp_count_2 = num_vfpv3_regs * 2; - int vfpv3_start = start < 16 ? 16 : start; - - dest = (_uw *) &tmp_16_to_31.d[vfpv3_start - 16]; - while (tmp_count_2--) - *(dest++) = *(sp++); - } - - /* Skip the format word space if using FLDMX/FSTMX format. */ - if (representation == _UVRSD_VFPX) - sp++; - - /* Set the new stack pointer. */ - vrs->core.r[R_SP] = (_uw) sp; - - /* Reload the registers. */ - if (representation == _UVRSD_VFPX) - __gnu_Unwind_Restore_VFP (&tmp); - else - { - /* Restore registers 0 .. 15 if required. */ - if (start < 16) - __gnu_Unwind_Restore_VFP_D (&tmp); - - /* Restore VFPv3 registers 16 .. 31 if required. */ - if (num_vfpv3_regs > 0) - __gnu_Unwind_Restore_VFP_D_16_to_31 (&tmp_16_to_31); - } - } - return _UVRSR_OK; - - case _UVRSC_FPA: - return _UVRSR_NOT_IMPLEMENTED; - - case _UVRSC_WMMXD: - { - _uw start = discriminator >> 16; - _uw count = discriminator & 0xffff; - struct wmmxd_regs tmp; - _uw *sp; - _uw *dest; - - if ((representation != _UVRSD_UINT64) || start + count > 16) - return _UVRSR_FAILED; - - if (vrs->demand_save_flags & DEMAND_SAVE_WMMXD) - { - /* Demand-save resisters for stage1. */ - vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXD; - __gnu_Unwind_Save_WMMXD (&vrs->wmmxd); - } - - /* Restore the registers from the stack. Do this by saving the - current WMMXD registers to a memory area, moving the in-memory - values into that area, and restoring from the whole area. */ - __gnu_Unwind_Save_WMMXD (&tmp); - - /* The stack address is only guaranteed to be word aligned, so - we can't use doubleword copies. */ - sp = (_uw *) vrs->core.r[R_SP]; - dest = (_uw *) &tmp.wd[start]; - count *= 2; - while (count--) - *(dest++) = *(sp++); - - /* Set the new stack pointer. */ - vrs->core.r[R_SP] = (_uw) sp; - - /* Reload the registers. */ - __gnu_Unwind_Restore_WMMXD (&tmp); - } - return _UVRSR_OK; - - case _UVRSC_WMMXC: - { - int i; - struct wmmxc_regs tmp; - _uw *sp; - - if ((representation != _UVRSD_UINT32) || discriminator > 16) - return _UVRSR_FAILED; - - if (vrs->demand_save_flags & DEMAND_SAVE_WMMXC) - { - /* Demand-save resisters for stage1. */ - vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXC; - __gnu_Unwind_Save_WMMXC (&vrs->wmmxc); - } - - /* Restore the registers from the stack. Do this by saving the - current WMMXC registers to a memory area, moving the in-memory - values into that area, and restoring from the whole area. */ - __gnu_Unwind_Save_WMMXC (&tmp); - - sp = (_uw *) vrs->core.r[R_SP]; - for (i = 0; i < 4; i++) - if (discriminator & (1 << i)) - tmp.wc[i] = *(sp++); - - /* Set the new stack pointer. */ - vrs->core.r[R_SP] = (_uw) sp; - - /* Reload the registers. */ - __gnu_Unwind_Restore_WMMXC (&tmp); - } - return _UVRSR_OK; - - default: - return _UVRSR_FAILED; - } -} - - -/* Core unwinding functions. */ - -/* Calculate the address encoded by a 31-bit self-relative offset at address - P. */ -static inline _uw -selfrel_offset31 (const _uw *p) -{ - _uw offset; - - offset = *p; - /* Sign extend to 32 bits. */ - if (offset & (1 << 30)) - offset |= 1u << 31; - else - offset &= ~(1u << 31); - - return offset + (_uw) p; -} - - -/* Perform a binary search for RETURN_ADDRESS in TABLE. The table contains - NREC entries. */ - -static const __EIT_entry * -search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) -{ - _uw next_fn; - _uw this_fn; - int n, left, right; - - if (nrec == 0) - return (__EIT_entry *) 0; - - left = 0; - right = nrec - 1; - - while (1) - { - n = (left + right) / 2; - this_fn = selfrel_offset31 (&table[n].fnoffset); - if (n != nrec - 1) - next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1; - else - next_fn = (_uw)0 - 1; - - if (return_address < this_fn) - { - if (n == left) - return (__EIT_entry *) 0; - right = n - 1; - } - else if (return_address <= next_fn) - return &table[n]; - else - left = n + 1; - } -} - -/* Find the exception index table eintry for the given address. - Fill in the relevant fields of the UCB. - Returns _URC_FAILURE if an error occurred, _URC_OK on success. */ - -static _Unwind_Reason_Code -get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) -{ - const __EIT_entry * eitp; - int nrec; - - /* The return address is the address of the instruction following the - call instruction (plus one in thumb mode). If this was the last - instruction in the function the address will lie in the following - function. Subtract 2 from the address so that it points within the call - instruction itself. */ - return_address -= 2; - - if (__gnu_Unwind_Find_exidx) - { - eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address, - &nrec); - if (!eitp) - { - UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; - } - } - else - { - eitp = &__exidx_start; - nrec = &__exidx_end - &__exidx_start; - } - - eitp = search_EIT_table (eitp, nrec, return_address); - - if (!eitp) - { - UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; - } - ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset); - - /* Can this frame be unwound at all? */ - if (eitp->content == EXIDX_CANTUNWIND) - { - UCB_PR_ADDR (ucbp) = 0; - return _URC_END_OF_STACK; - } - - /* Obtain the address of the "real" __EHT_Header word. */ - - if (eitp->content & uint32_highbit) - { - /* It is immediate data. */ - ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; - ucbp->pr_cache.additional = 1; - } - else - { - /* The low 31 bits of the content field are a self-relative - offset to an _Unwind_EHT_Entry structure. */ - ucbp->pr_cache.ehtp = - (_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content); - ucbp->pr_cache.additional = 0; - } - - /* Discover the personality routine address. */ - if (*ucbp->pr_cache.ehtp & (1u << 31)) - { - /* One of the predefined standard routines. */ - _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf; - if (idx == 0) - UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr0; - else if (idx == 1) - UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr1; - else if (idx == 2) - UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr2; - else - { /* Failed */ - UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; - } - } - else - { - /* Execute region offset to PR */ - UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp); - } - return _URC_OK; -} - - -/* Perform phase2 unwinding. VRS is the initial virtual register state. */ - -static void __attribute__((noreturn)) -unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs) -{ - _Unwind_Reason_Code pr_result; - - do - { - /* Find the entry for this routine. */ - if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK) - abort (); - - UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC]; - - /* Call the pr to decide what to do. */ - pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) - (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); - } - while (pr_result == _URC_CONTINUE_UNWIND); - - if (pr_result != _URC_INSTALL_CONTEXT) - abort(); - - restore_core_regs (&vrs->core); -} - -/* Perform phase2 forced unwinding. */ - -static _Unwind_Reason_Code -unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs, - int resuming) -{ - _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp); - void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp); - _Unwind_Reason_Code pr_result = 0; - /* We use phase1_vrs here even though we do not demand save, for the - prev_sp field. */ - phase1_vrs saved_vrs, next_vrs; - - /* Save the core registers. */ - saved_vrs.core = entry_vrs->core; - /* We don't need to demand-save the non-core registers, because we - unwind in a single pass. */ - saved_vrs.demand_save_flags = 0; - - /* Unwind until we reach a propagation barrier. */ - do - { - _Unwind_State action; - _Unwind_Reason_Code entry_code; - _Unwind_Reason_Code stop_code; - - /* Find the entry for this routine. */ - entry_code = get_eit_entry (ucbp, saved_vrs.core.r[R_PC]); - - if (resuming) - { - action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND; - resuming = 0; - } - else - action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND; - - if (entry_code == _URC_OK) - { - UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC]; - - next_vrs = saved_vrs; - - /* Call the pr to decide what to do. */ - pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) - (action, ucbp, (void *) &next_vrs); - - saved_vrs.prev_sp = next_vrs.core.r[R_SP]; - } - else - { - /* Treat any failure as the end of unwinding, to cope more - gracefully with missing EH information. Mixed EH and - non-EH within one object will usually result in failure, - because the .ARM.exidx tables do not indicate the end - of the code to which they apply; but mixed EH and non-EH - shared objects should return an unwind failure at the - entry of a non-EH shared object. */ - action |= _US_END_OF_STACK; - - saved_vrs.prev_sp = saved_vrs.core.r[R_SP]; - } - - stop_code = stop_fn (1, action, ucbp->exception_class, ucbp, - (void *)&saved_vrs, stop_arg); - if (stop_code != _URC_NO_REASON) - return _URC_FAILURE; - - if (entry_code != _URC_OK) - return entry_code; - - saved_vrs = next_vrs; - } - while (pr_result == _URC_CONTINUE_UNWIND); - - if (pr_result != _URC_INSTALL_CONTEXT) - { - /* Some sort of failure has occurred in the pr and probably the - pr returned _URC_FAILURE. */ - return _URC_FAILURE; - } - - restore_core_regs (&saved_vrs.core); -} - -/* This is a very limited implementation of _Unwind_GetCFA. It returns - the stack pointer as it is about to be unwound, and is only valid - while calling the stop function during forced unwinding. If the - current personality routine result is going to run a cleanup, this - will not be the CFA; but when the frame is really unwound, it will - be. */ - -_Unwind_Word -_Unwind_GetCFA (_Unwind_Context *context) -{ - return ((phase1_vrs *) context)->prev_sp; -} - -/* Perform phase1 unwinding. UCBP is the exception being thrown, and - entry_VRS is the register state on entry to _Unwind_RaiseException. */ - -_Unwind_Reason_Code -__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *); - -_Unwind_Reason_Code -__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, - phase2_vrs * entry_vrs) -{ - phase1_vrs saved_vrs; - _Unwind_Reason_Code pr_result; - - /* Set the pc to the call site. */ - entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; - - /* Save the core registers. */ - saved_vrs.core = entry_vrs->core; - /* Set demand-save flags. */ - saved_vrs.demand_save_flags = ~(_uw) 0; - - /* Unwind until we reach a propagation barrier. */ - do - { - /* Find the entry for this routine. */ - if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) - return _URC_FAILURE; - - /* Call the pr to decide what to do. */ - pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) - (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); - } - while (pr_result == _URC_CONTINUE_UNWIND); - - /* We've unwound as far as we want to go, so restore the original - register state. */ - restore_non_core_regs (&saved_vrs); - if (pr_result != _URC_HANDLER_FOUND) - { - /* Some sort of failure has occurred in the pr and probably the - pr returned _URC_FAILURE. */ - return _URC_FAILURE; - } - - unwind_phase2 (ucbp, entry_vrs); -} - -/* Resume unwinding after a cleanup has been run. UCBP is the exception - being thrown and ENTRY_VRS is the register state on entry to - _Unwind_Resume. */ -_Unwind_Reason_Code -__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *, - _Unwind_Stop_Fn, void *, phase2_vrs *); - -_Unwind_Reason_Code -__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp, - _Unwind_Stop_Fn stop_fn, void *stop_arg, - phase2_vrs *entry_vrs) -{ - UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn; - UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg; - - /* Set the pc to the call site. */ - entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; - - return unwind_phase2_forced (ucbp, entry_vrs, 0); -} - -_Unwind_Reason_Code -__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *); - -_Unwind_Reason_Code -__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs) -{ - _Unwind_Reason_Code pr_result; - - /* Recover the saved address. */ - entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp); - - if (UCB_FORCED_STOP_FN (ucbp)) - { - unwind_phase2_forced (ucbp, entry_vrs, 1); - - /* We can't return failure at this point. */ - abort (); - } - - /* Call the cached PR. */ - pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) - (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); - - switch (pr_result) - { - case _URC_INSTALL_CONTEXT: - /* Upload the registers to enter the landing pad. */ - restore_core_regs (&entry_vrs->core); - - case _URC_CONTINUE_UNWIND: - /* Continue unwinding the next frame. */ - unwind_phase2 (ucbp, entry_vrs); - - default: - abort (); - } -} - -_Unwind_Reason_Code -__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *); - -_Unwind_Reason_Code -__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp, - phase2_vrs * entry_vrs) -{ - if (!UCB_FORCED_STOP_FN (ucbp)) - return __gnu_Unwind_RaiseException (ucbp, entry_vrs); - - /* Set the pc to the call site. */ - entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; - /* Continue unwinding the next frame. */ - return unwind_phase2_forced (ucbp, entry_vrs, 0); -} - -/* Clean up an exception object when unwinding is complete. */ -void -_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused))) -{ -} - - -/* Get the _Unwind_Control_Block from an _Unwind_Context. */ - -static inline _Unwind_Control_Block * -unwind_UCB_from_context (_Unwind_Context * context) -{ - return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP); -} - - -/* Free an exception. */ - -void -_Unwind_DeleteException (_Unwind_Exception * exc) -{ - if (exc->exception_cleanup) - (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); -} - - -/* Perform stack backtrace through unwind data. */ -_Unwind_Reason_Code -__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, - phase2_vrs * entry_vrs); -_Unwind_Reason_Code -__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, - phase2_vrs * entry_vrs) -{ - phase1_vrs saved_vrs; - _Unwind_Reason_Code code; - - _Unwind_Control_Block ucb; - _Unwind_Control_Block *ucbp = &ucb; - - /* Set the pc to the call site. */ - entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; - - /* Save the core registers. */ - saved_vrs.core = entry_vrs->core; - /* Set demand-save flags. */ - saved_vrs.demand_save_flags = ~(_uw) 0; - - do - { - /* Find the entry for this routine. */ - if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) - { - code = _URC_FAILURE; - break; - } - - /* The dwarf unwinder assumes the context structure holds things - like the function and LSDA pointers. The ARM implementation - caches these in the exception header (UCB). To avoid - rewriting everything we make the virtual IP register point at - the UCB. */ - _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp); - - /* Call trace function. */ - if ((*trace) ((_Unwind_Context *) &saved_vrs, trace_argument) - != _URC_NO_REASON) - { - code = _URC_FAILURE; - break; - } - - /* Call the pr to decide what to do. */ - code = ((personality_routine) UCB_PR_ADDR (ucbp)) - (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, - ucbp, (void *) &saved_vrs); - } - while (code != _URC_END_OF_STACK - && code != _URC_FAILURE); - - restore_non_core_regs (&saved_vrs); - return code; -} - - -/* Common implementation for ARM ABI defined personality routines. - ID is the index of the personality routine, other arguments are as defined - by __aeabi_unwind_cpp_pr{0,1,2}. */ - -static _Unwind_Reason_Code -__gnu_unwind_pr_common (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context, - int id) -{ - __gnu_unwind_state uws; - _uw *data; - _uw offset; - _uw len; - _uw rtti_count; - int phase2_call_unexpected_after_unwind = 0; - int in_range = 0; - int forced_unwind = state & _US_FORCE_UNWIND; - - state &= _US_ACTION_MASK; - - data = (_uw *) ucbp->pr_cache.ehtp; - uws.data = *(data++); - uws.next = data; - if (id == 0) - { - uws.data <<= 8; - uws.words_left = 0; - uws.bytes_left = 3; - } - else - { - uws.words_left = (uws.data >> 16) & 0xff; - uws.data <<= 16; - uws.bytes_left = 2; - data += uws.words_left; - } - - /* Restore the saved pointer. */ - if (state == _US_UNWIND_FRAME_RESUME) - data = (_uw *) ucbp->cleanup_cache.bitpattern[0]; - - if ((ucbp->pr_cache.additional & 1) == 0) - { - /* Process descriptors. */ - while (*data) - { - _uw addr; - _uw fnstart; - - if (id == 2) - { - len = ((EHT32 *) data)->length; - offset = ((EHT32 *) data)->offset; - data += 2; - } - else - { - len = ((EHT16 *) data)->length; - offset = ((EHT16 *) data)->offset; - data++; - } - - fnstart = ucbp->pr_cache.fnstart + (offset & ~1); - addr = _Unwind_GetGR (context, R_PC); - in_range = (fnstart <= addr && addr < fnstart + (len & ~1)); - - switch (((offset & 1) << 1) | (len & 1)) - { - case 0: - /* Cleanup. */ - if (state != _US_VIRTUAL_UNWIND_FRAME - && in_range) - { - /* Cleanup in range, and we are running cleanups. */ - _uw lp; - - /* Landing pad address is 31-bit pc-relative offset. */ - lp = selfrel_offset31 (data); - data++; - /* Save the exception data pointer. */ - ucbp->cleanup_cache.bitpattern[0] = (_uw) data; - if (!__cxa_begin_cleanup (ucbp)) - return _URC_FAILURE; - /* Setup the VRS to enter the landing pad. */ - _Unwind_SetGR (context, R_PC, lp); - return _URC_INSTALL_CONTEXT; - } - /* Cleanup not in range, or we are in stage 1. */ - data++; - break; - - case 1: - /* Catch handler. */ - if (state == _US_VIRTUAL_UNWIND_FRAME) - { - if (in_range) - { - /* Check for a barrier. */ - _uw rtti; - bool is_reference = (data[0] & uint32_highbit) != 0; - void *matched; - enum __cxa_type_match_result match_type; - - /* Check for no-throw areas. */ - if (data[1] == (_uw) -2) - return _URC_FAILURE; - - /* The thrown object immediately follows the ECB. */ - matched = (void *)(ucbp + 1); - if (data[1] != (_uw) -1) - { - /* Match a catch specification. */ - rtti = _Unwind_decode_target2 ((_uw) &data[1]); - match_type = __cxa_type_match (ucbp, - (type_info *) rtti, - is_reference, - &matched); - } - else - match_type = ctm_succeeded; - - if (match_type) - { - ucbp->barrier_cache.sp = - _Unwind_GetGR (context, R_SP); - // ctm_succeeded_with_ptr_to_base really - // means _c_t_m indirected the pointer - // object. We have to reconstruct the - // additional pointer layer by using a temporary. - if (match_type == ctm_succeeded_with_ptr_to_base) - { - ucbp->barrier_cache.bitpattern[2] - = (_uw) matched; - ucbp->barrier_cache.bitpattern[0] - = (_uw) &ucbp->barrier_cache.bitpattern[2]; - } - else - ucbp->barrier_cache.bitpattern[0] = (_uw) matched; - ucbp->barrier_cache.bitpattern[1] = (_uw) data; - return _URC_HANDLER_FOUND; - } - } - /* Handler out of range, or not matched. */ - } - else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) - && ucbp->barrier_cache.bitpattern[1] == (_uw) data) - { - /* Matched a previous propagation barrier. */ - _uw lp; - - /* Setup for entry to the handler. */ - lp = selfrel_offset31 (data); - _Unwind_SetGR (context, R_PC, lp); - _Unwind_SetGR (context, 0, (_uw) ucbp); - return _URC_INSTALL_CONTEXT; - } - /* Catch handler not matched. Advance to the next descriptor. */ - data += 2; - break; - - case 2: - rtti_count = data[0] & 0x7fffffff; - /* Exception specification. */ - if (state == _US_VIRTUAL_UNWIND_FRAME) - { - if (in_range && (!forced_unwind || !rtti_count)) - { - /* Match against the exception specification. */ - _uw i; - _uw rtti; - void *matched; - - for (i = 0; i < rtti_count; i++) - { - matched = (void *)(ucbp + 1); - rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]); - if (__cxa_type_match (ucbp, (type_info *) rtti, 0, - &matched)) - break; - } - - if (i == rtti_count) - { - /* Exception does not match the spec. */ - ucbp->barrier_cache.sp = - _Unwind_GetGR (context, R_SP); - ucbp->barrier_cache.bitpattern[0] = (_uw) matched; - ucbp->barrier_cache.bitpattern[1] = (_uw) data; - return _URC_HANDLER_FOUND; - } - } - /* Handler out of range, or exception is permitted. */ - } - else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) - && ucbp->barrier_cache.bitpattern[1] == (_uw) data) - { - /* Matched a previous propagation barrier. */ - _uw lp; - /* Record the RTTI list for __cxa_call_unexpected. */ - ucbp->barrier_cache.bitpattern[1] = rtti_count; - ucbp->barrier_cache.bitpattern[2] = 0; - ucbp->barrier_cache.bitpattern[3] = 4; - ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1]; - - if (data[0] & uint32_highbit) - { - data += rtti_count + 1; - /* Setup for entry to the handler. */ - lp = selfrel_offset31 (data); - data++; - _Unwind_SetGR (context, R_PC, lp); - _Unwind_SetGR (context, 0, (_uw) ucbp); - return _URC_INSTALL_CONTEXT; - } - else - phase2_call_unexpected_after_unwind = 1; - } - if (data[0] & uint32_highbit) - data++; - data += rtti_count + 1; - break; - - default: - /* Should never happen. */ - return _URC_FAILURE; - } - /* Finished processing this descriptor. */ - } - } - - if (__gnu_unwind_execute (context, &uws) != _URC_OK) - return _URC_FAILURE; - - if (phase2_call_unexpected_after_unwind) - { - /* Enter __cxa_unexpected as if called from the call site. */ - _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC)); - _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected); - return _URC_INSTALL_CONTEXT; - } - - return _URC_CONTINUE_UNWIND; -} - - -/* ABI defined personality routine entry points. */ - -_Unwind_Reason_Code -__aeabi_unwind_cpp_pr0 (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) -{ - return __gnu_unwind_pr_common (state, ucbp, context, 0); -} - -_Unwind_Reason_Code -__aeabi_unwind_cpp_pr1 (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) -{ - return __gnu_unwind_pr_common (state, ucbp, context, 1); -} - -_Unwind_Reason_Code -__aeabi_unwind_cpp_pr2 (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context) -{ - return __gnu_unwind_pr_common (state, ucbp, context, 2); -} diff --git a/gcc/config/arm/unwind-arm.h b/gcc/config/arm/unwind-arm.h deleted file mode 100644 index 1a51d8d4824..00000000000 --- a/gcc/config/arm/unwind-arm.h +++ /dev/null @@ -1,281 +0,0 @@ -/* Header file for the ARM EABI unwinder - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 - Free Software Foundation, Inc. - Contributed by Paul Brook - - This file 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 3, or (at your option) any - later version. - - This file 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* Language-independent unwinder header public defines. This contains both - ABI defined objects, and GNU support routines. */ - -#ifndef UNWIND_ARM_H -#define UNWIND_ARM_H - -#define __ARM_EABI_UNWINDER__ 1 - -#ifdef __cplusplus -extern "C" { -#endif - typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); - typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); - typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); - typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); - typedef _Unwind_Word _uw; - typedef unsigned _uw64 __attribute__((mode(__DI__))); - typedef unsigned _uw16 __attribute__((mode(__HI__))); - typedef unsigned _uw8 __attribute__((mode(__QI__))); - - typedef enum - { - _URC_OK = 0, /* operation completed successfully */ - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9 /* unspecified failure of some kind */ - } - _Unwind_Reason_Code; - - typedef enum - { - _US_VIRTUAL_UNWIND_FRAME = 0, - _US_UNWIND_FRAME_STARTING = 1, - _US_UNWIND_FRAME_RESUME = 2, - _US_ACTION_MASK = 3, - _US_FORCE_UNWIND = 8, - _US_END_OF_STACK = 16 - } - _Unwind_State; - - /* Provided only for compatibility with existing code. */ - typedef int _Unwind_Action; -#define _UA_SEARCH_PHASE 1 -#define _UA_CLEANUP_PHASE 2 -#define _UA_HANDLER_FRAME 4 -#define _UA_FORCE_UNWIND 8 -#define _UA_END_OF_STACK 16 -#define _URC_NO_REASON _URC_OK - - typedef struct _Unwind_Control_Block _Unwind_Control_Block; - typedef struct _Unwind_Context _Unwind_Context; - typedef _uw _Unwind_EHT_Header; - - - /* UCB: */ - - struct _Unwind_Control_Block - { - char exception_class[8]; - void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); - /* Unwinder cache, private fields for the unwinder's use */ - struct - { - _uw reserved1; /* Forced unwind stop fn, 0 if not forced */ - _uw reserved2; /* Personality routine address */ - _uw reserved3; /* Saved callsite address */ - _uw reserved4; /* Forced unwind stop arg */ - _uw reserved5; - } - unwinder_cache; - /* Propagation barrier cache (valid after phase 1): */ - struct - { - _uw sp; - _uw bitpattern[5]; - } - barrier_cache; - /* Cleanup cache (preserved over cleanup): */ - struct - { - _uw bitpattern[4]; - } - cleanup_cache; - /* Pr cache (for pr's benefit): */ - struct - { - _uw fnstart; /* function start address */ - _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ - _uw additional; /* additional data */ - _uw reserved1; - } - pr_cache; - long long int :0; /* Force alignment to 8-byte boundary */ - }; - - /* Virtual Register Set*/ - - typedef enum - { - _UVRSC_CORE = 0, /* integer register */ - _UVRSC_VFP = 1, /* vfp */ - _UVRSC_FPA = 2, /* fpa */ - _UVRSC_WMMXD = 3, /* Intel WMMX data register */ - _UVRSC_WMMXC = 4 /* Intel WMMX control register */ - } - _Unwind_VRS_RegClass; - - typedef enum - { - _UVRSD_UINT32 = 0, - _UVRSD_VFPX = 1, - _UVRSD_FPAX = 2, - _UVRSD_UINT64 = 3, - _UVRSD_FLOAT = 4, - _UVRSD_DOUBLE = 5 - } - _Unwind_VRS_DataRepresentation; - - typedef enum - { - _UVRSR_OK = 0, - _UVRSR_NOT_IMPLEMENTED = 1, - _UVRSR_FAILED = 2 - } - _Unwind_VRS_Result; - - /* Frame unwinding state. */ - typedef struct - { - /* The current word (bytes packed msb first). */ - _uw data; - /* Pointer to the next word of data. */ - _uw *next; - /* The number of bytes left in this word. */ - _uw8 bytes_left; - /* The number of words pointed to by ptr. */ - _uw8 words_left; - } - __gnu_unwind_state; - - typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *); - - _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, - _uw, _Unwind_VRS_DataRepresentation, - void *); - - _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, - _uw, _Unwind_VRS_DataRepresentation, - void *); - - _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, - _uw, _Unwind_VRS_DataRepresentation); - - - /* Support functions for the PR. */ -#define _Unwind_Exception _Unwind_Control_Block - typedef char _Unwind_Exception_Class[8]; - - void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); - _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); - - /* These two should never be used. */ - _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); - _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); - - /* Interface functions: */ - _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); - void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); - _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); - - typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) - (int, _Unwind_Action, _Unwind_Exception_Class, - _Unwind_Control_Block *, struct _Unwind_Context *, void *); - _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, - _Unwind_Stop_Fn, void *); - /* @@@ Use unwind data to perform a stack backtrace. The trace callback - is called for every stack frame in the call chain, but no cleanup - actions are performed. */ - typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *); - _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, - void*); - - _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); - void _Unwind_Complete(_Unwind_Control_Block *ucbp); - void _Unwind_DeleteException (_Unwind_Exception *); - - _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, - _Unwind_Context *); - _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, - __gnu_unwind_state *); - - /* Decode an R_ARM_TARGET2 relocation. */ - static inline _Unwind_Word - _Unwind_decode_target2 (_Unwind_Word ptr) - { - _Unwind_Word tmp; - - tmp = *(_Unwind_Word *) ptr; - /* Zero values are always NULL. */ - if (!tmp) - return 0; - -#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) - /* Pc-relative indirect. */ - tmp += ptr; - tmp = *(_Unwind_Word *) tmp; -#elif defined(__symbian__) || defined(__uClinux__) - /* Absolute pointer. Nothing more to do. */ -#else - /* Pc-relative pointer. */ - tmp += ptr; -#endif - return tmp; - } - - static inline _Unwind_Word - _Unwind_GetGR (_Unwind_Context *context, int regno) - { - _uw val; - _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); - return val; - } - - /* Return the address of the instruction, not the actual IP value. */ -#define _Unwind_GetIP(context) \ - (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) - -#define _Unwind_GetIPInfo(context, ip_before_insn) \ - (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) - - static inline void - _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) - { - _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); - } - - /* The dwarf unwinder doesn't understand arm/thumb state. We assume the - landing pad uses the same instruction set as the call site. */ -#define _Unwind_SetIP(context, val) \ - _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) - -/* leb128 type numbers have a potentially unlimited size. - The target of the following definitions of _sleb128_t and _uleb128_t - is to have efficient data types large enough to hold the leb128 type - numbers used in the unwind code. */ -typedef long _sleb128_t; -typedef unsigned long _uleb128_t; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* defined UNWIND_ARM_H */ diff --git a/gcc/config/frv/t-frv b/gcc/config/frv/t-frv index 0c58bb16713..2729008879c 100644 --- a/gcc/config/frv/t-frv +++ b/gcc/config/frv/t-frv @@ -1,4 +1,4 @@ -# Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2004, 2011 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -81,12 +81,12 @@ EXTRA_MULTILIB_PARTS=frvbegin.o frvend.o FRVSTUFF_CFLAGS = $(TARGET_LIBGCC2_CFLAGS) $(T)frvbegin$(objext): $(srcdir)/config/frv/frvbegin.c $(GCC_PASSES) \ - $(CONFIG_H) defaults.h unwind-dw2-fde.h gbl-ctors.h + $(CONFIG_H) defaults.h $(srcdir)/../libgcc/unwind-dw2-fde.h gbl-ctors.h $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) $(FRVSTUFF_CFLAGS) \ -c $(srcdir)/config/frv/frvbegin.c -o $(T)frvbegin$(objext) $(T)frvend$(objext): $(srcdir)/config/frv/frvend.c $(GCC_PASSES) \ - $(CONFIG_H) defaults.h unwind-dw2-fde.h gbl-ctors.h + $(CONFIG_H) defaults.h $(srcdir)/../libgcc/unwind-dw2-fde.h gbl-ctors.h $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) $(FRVSTUFF_CFLAGS) \ -c $(srcdir)/config/frv/frvend.c -o $(T)frvend$(objext) diff --git a/gcc/config/ia64/fde-glibc.c b/gcc/config/ia64/fde-glibc.c deleted file mode 100644 index 12760b96eda..00000000000 --- a/gcc/config/ia64/fde-glibc.c +++ /dev/null @@ -1,162 +0,0 @@ -/* Copyright (C) 2000, 2001, 2003, 2009 Free Software Foundation, Inc. - Contributed by Richard Henderson . - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* Locate the FDE entry for a given address, using glibc ld.so routines - to avoid register/deregister calls at DSO load/unload. */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif -#include "config.h" -#include -#include -#include -#include "unwind-ia64.h" - -#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \ - || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG)) -# error You need GLIBC 2.2.4 or later on IA-64 Linux -#endif - -struct unw_ia64_callback_data -{ - Elf64_Addr pc; - unsigned long *segment_base; - unsigned long *gp; - struct unw_table_entry *ret; -}; - -static int -_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) -{ - struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr; - const Elf64_Phdr *phdr, *p_unwind, *p_dynamic; - long n, match; - Elf64_Addr load_base, seg_base; - struct unw_table_entry *f_base, *f; - size_t lo, hi; - - /* Make sure struct dl_phdr_info is at least as big as we need. */ - if (size < offsetof (struct dl_phdr_info, dlpi_phnum) - + sizeof (info->dlpi_phnum)) - return -1; - - match = 0; - phdr = info->dlpi_phdr; - load_base = info->dlpi_addr; - p_unwind = NULL; - p_dynamic = NULL; - seg_base = ~(Elf64_Addr) 0; - - /* See if PC falls into one of the loaded segments. Find the unwind - segment at the same time. */ - for (n = info->dlpi_phnum; --n >= 0; phdr++) - { - if (phdr->p_type == PT_LOAD) - { - Elf64_Addr vaddr = phdr->p_vaddr + load_base; - if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) - match = 1; - if (vaddr < seg_base) - seg_base = vaddr; - } - else if (phdr->p_type == PT_IA_64_UNWIND) - p_unwind = phdr; - else if (phdr->p_type == PT_DYNAMIC) - p_dynamic = phdr; - } - if (!match || !p_unwind) - return 0; - - /* Search for the FDE within the unwind segment. */ - - f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base); - lo = 0; - hi = p_unwind->p_memsz / sizeof (struct unw_table_entry); - - while (lo < hi) - { - size_t mid = (lo + hi) / 2; - - f = f_base + mid; - if (data->pc < f->start_offset + seg_base) - hi = mid; - else if (data->pc >= f->end_offset + seg_base) - lo = mid + 1; - else - goto found; - } - /* No need to search for further libraries when we know pc is contained - in this library. */ - return 1; - - found: - *data->segment_base = seg_base; - *data->gp = 0; - data->ret = f; - - if (p_dynamic) - { - /* For dynamically linked executables and shared libraries, - DT_PLTGOT is the gp value for that object. */ - Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base); - for (; dyn->d_tag != DT_NULL ; dyn++) - if (dyn->d_tag == DT_PLTGOT) - { - /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */ - *data->gp = dyn->d_un.d_ptr; - break; - } - } - else - { - /* Otherwise this is a static executable with no _DYNAMIC. - The gp is constant program-wide. */ - register unsigned long gp __asm__("gp"); - *data->gp = gp; - } - - return 1; -} - -/* Return a pointer to the unwind table entry for the function - containing PC. */ - -struct unw_table_entry * -_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, - unsigned long *gp, - struct unw_table_entry *ent ATTRIBUTE_UNUSED) -{ - struct unw_ia64_callback_data data; - - data.pc = (Elf64_Addr) pc; - data.segment_base = segment_base; - data.gp = gp; - data.ret = NULL; - - if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) - return NULL; - - return data.ret; -} diff --git a/gcc/config/ia64/fde-vms.c b/gcc/config/ia64/fde-vms.c deleted file mode 100644 index b310f0d11b6..00000000000 --- a/gcc/config/ia64/fde-vms.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Copyright (C) 2004, 2009 Free Software Foundation, Inc. - Contributed by Douglas B Rupp - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* Locate the FDE entry for a given address, using VMS Starlet routines - to avoid register/deregister calls at DSO load/unload. */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include -#include -#include -#include "unwind-ia64.h" - -#define __int64 long -#include -#ifndef SS$_NORMAL -#define SS$_NORMAL 1 -#endif - -typedef struct -{ - unsigned long start_offset; - unsigned long end_offset; - unsigned long info_offset; - unsigned long gp_value; -} vms_unw_table_entry; - -typedef unsigned long long uqword; - -/* ENTRY is the unwind table entry found for a PC part of call chain we're - unwinding through. Return whether we should force the generic unwinder - to resort to "fallback" processing. */ - -static int -force_fallback_processing_for (void * pc, vms_unw_table_entry * entry) -{ - static int eh_debug = -1; - - uqword * unw_info_block = (uqword *)entry->info_offset; - uqword header = *unw_info_block; - - /* We need to force fallback processing in two cases: - - 1/ The exception dispatch frame, since only our fallback - processing knows how to properly unwind through it, and - - 2/ A bottom of stack frame, since only our fallback processing - will ensure we don't try to unwind further past it, which - would get us into unknown territory and likely cause a severe - crash along the way. - - The two cases are indicated by non-default values for specific - bits in the OS Specific Data (OSSD) General Information block - associated with such frames. */ - - ossddef * ossd; - - if (eh_debug == -1) - { - char * EH_DEBUG = getenv ("EH_DEBUG"); - eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0; - } - - if (eh_debug) - { - printf ("pc @ 0x%p, block @ 0x%p, header = 0x%016llx\n", - pc, unw_info_block, header); - printf ("mode = %d, length = %ld, handler = %d\n", - (int)UNW_IVMS_MODE (header), UNW_LENGTH (header), - UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header)); - } - - /* An OSSD block is there for IVMS_MODE == 3 only. */ - if (UNW_IVMS_MODE (header) != 3) - return 0; - - /* The OSSD block is found past the header, unwind descriptor area - and condition handler pointer, if any. */ - ossd = (ossddef *) - /* Beware: uqword pointer arithmetic below. */ - (unw_info_block - + 1 - + UNW_LENGTH (header) - + (UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header))); - - /* "A General Information segment may be omitted if all of its fields - would have their default values. If a General Information segment - is present, it must be the first in the OSSD area." So ... */ - - if (eh_debug) - printf ("ossd @ 0x%p\n", ossd); - - if (eh_debug && ossd->ossd$v_type == OSSD$K_GENERAL_INFO) - printf ("exc_frame = %d - bot_frame = %d - base_frame = %d\n", - ossd->ossd$v_exception_frame, - ossd->ossd$v_bottom_of_stack, - ossd->ossd$v_base_frame); - - return - ossd->ossd$v_type == OSSD$K_GENERAL_INFO - && (ossd->ossd$v_exception_frame - || ossd->ossd$v_bottom_of_stack || ossd->ossd$v_base_frame); -} - -/* Return a pointer to the unwind table entry for the function - containing PC, 0 if we cannot find an entry or if the one we find - calls for fallback processing. */ - -struct unw_table_entry * -_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, - unsigned long *gp, struct unw_table_entry *ent) -{ - vms_unw_table_entry vueblock; - - if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL) - return 0; - - /* If there is no unwind information, use fallback. */ - if (vueblock.info_offset == 0) - return 0; - - /* If we need to force fallback processing, just pretend there is - no entry. */ - if (force_fallback_processing_for (pc, &vueblock)) - return 0; - - *segment_base = 0; /* ??? Fixme. ??? */ - *gp = vueblock.gp_value; - ent->start_offset = vueblock.start_offset; - ent->end_offset = vueblock.end_offset; - ent->info_offset = vueblock.info_offset; - - return ent; -} diff --git a/gcc/config/ia64/t-glibc b/gcc/config/ia64/t-glibc index e6d72b94a87..ce18a92e275 100644 --- a/gcc/config/ia64/t-glibc +++ b/gcc/config/ia64/t-glibc @@ -1,5 +1 @@ -# Use system libunwind library on IA-64 GLIBC based system. -LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ - $(srcdir)/unwind-compat.c - SHLIB_MAPFILES += $(srcdir)/config/ia64/libgcc-glibc.ver diff --git a/gcc/config/ia64/t-glibc-libunwind b/gcc/config/ia64/t-glibc-libunwind deleted file mode 100644 index df78f1d094f..00000000000 --- a/gcc/config/ia64/t-glibc-libunwind +++ /dev/null @@ -1,4 +0,0 @@ -# Build libunwind for IA-64 GLIBC based system. -LIBUNWIND = $(srcdir)/config/ia64/fde-glibc.c \ - $(srcdir)/config/ia64/unwind-ia64.c -LIBUNWINDDEP = unwind.inc diff --git a/gcc/config/ia64/t-hpux b/gcc/config/ia64/t-hpux index a97ab5c4478..4aa661441b2 100644 --- a/gcc/config/ia64/t-hpux +++ b/gcc/config/ia64/t-hpux @@ -1,5 +1,5 @@ # Copyright (C) 2001, 2002, 2003, 2004, 2005, -# 2006 Free Software Foundation, Inc. +# 2006, 2011 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -50,8 +50,6 @@ LIBGCC1_TEST = T_CFLAGS += -DUSE_LIBUNWIND_EXCEPTIONS -LIB2ADDEH = $(srcdir)/unwind-c.c - SHLIB_EXT = .so # Must include -lunwind in the link, so that libgcc_s.so has the necessary # DT_NEEDED entry for libunwind. diff --git a/gcc/config/ia64/t-ia64 b/gcc/config/ia64/t-ia64 index 4f013e2d591..f130f7c09d1 100644 --- a/gcc/config/ia64/t-ia64 +++ b/gcc/config/ia64/t-ia64 @@ -43,9 +43,6 @@ SHLIB_MAPFILES += $(srcdir)/config/ia64/libgcc-ia64.ver # Effectively disable the crtbegin/end rules using crtstuff.c T = disable -LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \ - $(srcdir)/unwind-c.c - ia64-c.o: $(srcdir)/config/ia64/ia64-c.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(CPPLIB_H) $(C_COMMON_H) $(C_PRAGMA_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ diff --git a/gcc/config/ia64/t-vms b/gcc/config/ia64/t-vms index bcd753401f1..094d53483ee 100644 --- a/gcc/config/ia64/t-vms +++ b/gcc/config/ia64/t-vms @@ -32,8 +32,6 @@ $(T)crtinitS.o: $(srcdir)/config/ia64/vms-crtinit.asm $(GCC_PASSES) $(GCC_FOR_TARGET) -I. -c -o $(T)crtinitS.o -x assembler-with-cpp \ $(srcdir)/config/ia64/vms-crtinit.asm -LIB2ADDEH += $(srcdir)/config/ia64/fde-vms.c - # Shared library macros shlib_version:=$(shell echo $(BASEVER_c) | sed -e 's/\./,/' -e 's/\.//g') SHLIB_EXT = .exe diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c deleted file mode 100644 index 061bd4b8980..00000000000 --- a/gcc/config/ia64/unwind-ia64.c +++ /dev/null @@ -1,2458 +0,0 @@ -/* Subroutines needed for unwinding IA-64 standard format stack frame - info for exception handling. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, - 2009, 2011 Free Software Foundation, Inc. - Contributed by Andrew MacLeod - Andrew Haley - David Mosberger-Tang - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "unwind.h" -#include "unwind-ia64.h" -#include "unwind-compat.h" -#include "ia64intrin.h" - -/* This isn't thread safe, but nice for occasional tests. */ -#undef ENABLE_MALLOC_CHECKING - -#ifndef __USING_SJLJ_EXCEPTIONS__ - - -/* By default, assume personality routine interface compatibility with - our expectations. */ -#ifndef MD_UNW_COMPATIBLE_PERSONALITY_P -#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) 1 -#endif - -enum unw_application_register -{ - UNW_AR_BSP, - UNW_AR_BSPSTORE, - UNW_AR_PFS, - UNW_AR_RNAT, - UNW_AR_UNAT, - UNW_AR_LC, - UNW_AR_EC, - UNW_AR_FPSR, - UNW_AR_RSC, - UNW_AR_CCV -}; - -enum unw_register_index -{ - /* Primary UNAT. */ - UNW_REG_PRI_UNAT_GR, - UNW_REG_PRI_UNAT_MEM, - - /* Memory Stack. */ - UNW_REG_PSP, /* previous memory stack pointer */ - - /* Register Stack. */ - UNW_REG_BSP, /* register stack pointer */ - UNW_REG_BSPSTORE, - UNW_REG_PFS, /* previous function state */ - UNW_REG_RNAT, - /* Return Pointer. */ - UNW_REG_RP, - - /* Special preserved registers. */ - UNW_REG_UNAT, UNW_REG_PR, UNW_REG_LC, UNW_REG_FPSR, - - /* Non-stacked general registers. */ - UNW_REG_R2, - UNW_REG_R4 = UNW_REG_R2 + 2, - UNW_REG_R7 = UNW_REG_R2 + 5, - UNW_REG_R31 = UNW_REG_R2 + 29, - - /* Non-stacked floating point registers. */ - UNW_REG_F2, - UNW_REG_F5 = UNW_REG_F2 + 3, - UNW_REG_F16 = UNW_REG_F2 + 14, - UNW_REG_F31 = UNW_REG_F2 + 29, - - /* Branch registers. */ - UNW_REG_B0, UNW_REG_B1, - UNW_REG_B5 = UNW_REG_B1 + 4, - - UNW_NUM_REGS -}; - -enum unw_where -{ - UNW_WHERE_NONE, /* register isn't saved at all */ - UNW_WHERE_GR, /* register is saved in a general register */ - UNW_WHERE_FR, /* register is saved in a floating-point register */ - UNW_WHERE_BR, /* register is saved in a branch register */ - UNW_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ - UNW_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ - - /* At the end of each prologue these locations get resolved to - UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively. */ - UNW_WHERE_SPILL_HOME, /* register is saved in its spill home */ - UNW_WHERE_GR_SAVE /* register is saved in next general register */ -}; - -#define UNW_WHEN_NEVER 0x7fffffff - -struct unw_reg_info -{ - unsigned long val; /* save location: register number or offset */ - enum unw_where where; /* where the register gets saved */ - int when; /* when the register gets saved */ -}; - -struct unw_reg_state { - struct unw_reg_state *next; /* next (outer) element on state stack */ - struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */ -}; - -struct unw_labeled_state { - struct unw_labeled_state *next; /* next labeled state (or NULL) */ - unsigned long label; /* label for this state */ - struct unw_reg_state saved_state; -}; - -typedef struct unw_state_record -{ - unsigned int first_region : 1; /* is this the first region? */ - unsigned int done : 1; /* are we done scanning descriptors? */ - unsigned int any_spills : 1; /* got any register spills? */ - unsigned int in_body : 1; /* are we inside a body? */ - unsigned int no_reg_stack_frame : 1; /* Don't adjust bsp for i&l regs */ - unsigned char *imask; /* imask of spill_mask record or NULL */ - unsigned long pr_val; /* predicate values */ - unsigned long pr_mask; /* predicate mask */ - long spill_offset; /* psp-relative offset for spill base */ - int region_start; - int region_len; - int epilogue_start; - int epilogue_count; - int when_target; - - unsigned char gr_save_loc; /* next general register to use for saving */ - unsigned char return_link_reg; /* branch register for return link */ - unsigned short unwabi; - - struct unw_labeled_state *labeled_states; /* list of all labeled states */ - struct unw_reg_state curr; /* current state */ - - _Unwind_Personality_Fn personality; - -} _Unwind_FrameState; - -enum unw_nat_type -{ - UNW_NAT_NONE, /* NaT not represented */ - UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */ - UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */ - UNW_NAT_REGSTK /* NaT is in rnat */ -}; - -struct unw_stack -{ - unsigned long limit; - unsigned long top; -}; - -struct _Unwind_Context -{ - /* Initial frame info. */ - unsigned long rnat; /* rse nat collection */ - unsigned long regstk_top; /* lowest address of rbs stored register - which uses context->rnat collection */ - - /* Current frame info. */ - unsigned long bsp; /* backing store pointer value - corresponding to psp. */ - unsigned long sp; /* stack pointer value */ - unsigned long psp; /* previous sp value */ - unsigned long rp; /* return pointer */ - unsigned long pr; /* predicate collection */ - - unsigned long region_start; /* start of unwind region */ - unsigned long gp; /* global pointer value */ - void *lsda; /* language specific data area */ - - /* Preserved state. */ - unsigned long *bsp_loc; /* previous bsp save location - Appears to be write-only? */ - unsigned long *bspstore_loc; - unsigned long *pfs_loc; /* Save location for pfs in current - (corr. to sp) frame. Target - contains cfm for caller. */ - unsigned long *signal_pfs_loc;/* Save location for pfs in current - signal frame. Target contains - pfs for caller. */ - unsigned long *pri_unat_loc; - unsigned long *unat_loc; - unsigned long *lc_loc; - unsigned long *fpsr_loc; - - unsigned long eh_data[4]; - - struct unw_ireg - { - unsigned long *loc; - struct unw_ireg_nat - { - enum unw_nat_type type : 3; - signed long off : 61; /* NaT word is at loc+nat.off */ - } nat; - } ireg[32 - 2]; /* Indexed by - 2 */ - - unsigned long *br_loc[8]; - void *fr_loc[32 - 2]; - - /* ??? We initially point pri_unat_loc here. The entire NAT bit - logic needs work. */ - unsigned long initial_unat; -}; - -typedef unsigned long unw_word; - -/* Implicit register save order. See section 11.4.2.3 Rules for Using - Unwind Descriptors, rule 3. */ - -static unsigned char const save_order[] = -{ - UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR, - UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR -}; - - -#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) - -/* MASK is a bitmap describing the allocation state of emergency buffers, - with bit set indicating free. Return >= 0 if allocation is successful; - < 0 if failure. */ - -static inline int -atomic_alloc (unsigned int *mask) -{ - unsigned int old = *mask, ret, new; - - while (1) - { - if (old == 0) - return -1; - ret = old & -old; - new = old & ~ret; - new = __sync_val_compare_and_swap (mask, old, new); - if (old == new) - break; - old = new; - } - - return __builtin_ffs (ret) - 1; -} - -/* Similarly, free an emergency buffer. */ - -static inline void -atomic_free (unsigned int *mask, int bit) -{ - __sync_xor_and_fetch (mask, 1 << bit); -} - - -#define SIZE(X) (sizeof(X) / sizeof(*(X))) -#define MASK_FOR(X) ((2U << (SIZE (X) - 1)) - 1) -#define PTR_IN(X, P) ((P) >= (X) && (P) < (X) + SIZE (X)) - -static struct unw_reg_state emergency_reg_state[32]; -static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state); - -static struct unw_labeled_state emergency_labeled_state[8]; -static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state); - -#ifdef ENABLE_MALLOC_CHECKING -static int reg_state_alloced; -static int labeled_state_alloced; -#endif - -/* Allocation and deallocation of structures. */ - -static struct unw_reg_state * -alloc_reg_state (void) -{ - struct unw_reg_state *rs; - -#ifdef ENABLE_MALLOC_CHECKING - reg_state_alloced++; -#endif - - rs = malloc (sizeof (struct unw_reg_state)); - if (!rs) - { - int n = atomic_alloc (&emergency_reg_state_free); - if (n >= 0) - rs = &emergency_reg_state[n]; - } - - return rs; -} - -static void -free_reg_state (struct unw_reg_state *rs) -{ -#ifdef ENABLE_MALLOC_CHECKING - reg_state_alloced--; -#endif - - if (PTR_IN (emergency_reg_state, rs)) - atomic_free (&emergency_reg_state_free, rs - emergency_reg_state); - else - free (rs); -} - -static struct unw_labeled_state * -alloc_label_state (void) -{ - struct unw_labeled_state *ls; - -#ifdef ENABLE_MALLOC_CHECKING - labeled_state_alloced++; -#endif - - ls = malloc(sizeof(struct unw_labeled_state)); - if (!ls) - { - int n = atomic_alloc (&emergency_labeled_state_free); - if (n >= 0) - ls = &emergency_labeled_state[n]; - } - - return ls; -} - -static void -free_label_state (struct unw_labeled_state *ls) -{ -#ifdef ENABLE_MALLOC_CHECKING - labeled_state_alloced--; -#endif - - if (PTR_IN (emergency_labeled_state, ls)) - atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls); - else - free (ls); -} - -/* Routines to manipulate the state stack. */ - -static void -push (struct unw_state_record *sr) -{ - struct unw_reg_state *rs = alloc_reg_state (); - memcpy (rs, &sr->curr, sizeof (*rs)); - sr->curr.next = rs; -} - -static void -pop (struct unw_state_record *sr) -{ - struct unw_reg_state *rs = sr->curr.next; - - if (!rs) - abort (); - memcpy (&sr->curr, rs, sizeof(*rs)); - free_reg_state (rs); -} - -/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */ - -static struct unw_reg_state * -dup_state_stack (struct unw_reg_state *rs) -{ - struct unw_reg_state *copy, *prev = NULL, *first = NULL; - - while (rs) - { - copy = alloc_reg_state (); - memcpy (copy, rs, sizeof(*copy)); - if (first) - prev->next = copy; - else - first = copy; - rs = rs->next; - prev = copy; - } - - return first; -} - -/* Free all stacked register states (but not RS itself). */ -static void -free_state_stack (struct unw_reg_state *rs) -{ - struct unw_reg_state *p, *next; - - for (p = rs->next; p != NULL; p = next) - { - next = p->next; - free_reg_state (p); - } - rs->next = NULL; -} - -/* Free all labeled states. */ - -static void -free_label_states (struct unw_labeled_state *ls) -{ - struct unw_labeled_state *next; - - for (; ls ; ls = next) - { - next = ls->next; - - free_state_stack (&ls->saved_state); - free_label_state (ls); - } -} - -/* Unwind decoder routines */ - -static enum unw_register_index __attribute__((const)) -decode_abreg (unsigned char abreg, int memory) -{ - switch (abreg) - { -#if TARGET_ABI_OPEN_VMS - /* OpenVMS Calling Standard specifies R3 - R31. */ - case 0x03 ... 0x1f: return UNW_REG_R2 + (abreg - 0x02); -#else - /* Standard Intel ABI specifies GR 4 - 7. */ - case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04); -#endif - case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22); - case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30); - case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41); - case 0x60: return UNW_REG_PR; - case 0x61: return UNW_REG_PSP; - case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR; - case 0x63: return UNW_REG_RP; - case 0x64: return UNW_REG_BSP; - case 0x65: return UNW_REG_BSPSTORE; - case 0x66: return UNW_REG_RNAT; - case 0x67: return UNW_REG_UNAT; - case 0x68: return UNW_REG_FPSR; - case 0x69: return UNW_REG_PFS; - case 0x6a: return UNW_REG_LC; - default: - abort (); - } -} - -static void -set_reg (struct unw_reg_info *reg, enum unw_where where, - int when, unsigned long val) -{ - reg->val = val; - reg->where = where; - if (reg->when == UNW_WHEN_NEVER) - reg->when = when; -} - -static void -alloc_spill_area (unsigned long *offp, unsigned long regsize, - struct unw_reg_info *lo, struct unw_reg_info *hi) -{ - struct unw_reg_info *reg; - - for (reg = hi; reg >= lo; --reg) - { - if (reg->where == UNW_WHERE_SPILL_HOME) - { - reg->where = UNW_WHERE_PSPREL; - *offp -= regsize; - reg->val = *offp; - } - } -} - -static inline void -spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, - unw_word t) -{ - struct unw_reg_info *reg; - - for (reg = *regp; reg <= lim; ++reg) - { - if (reg->where == UNW_WHERE_SPILL_HOME) - { - reg->when = t; - *regp = reg + 1; - return; - } - } - /* Excess spill. */ - abort (); -} - -static void -finish_prologue (struct unw_state_record *sr) -{ - struct unw_reg_info *reg; - unsigned long off; - int i; - - /* First, resolve implicit register save locations - (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */ - - for (i = 0; i < (int) sizeof (save_order); ++i) - { - reg = sr->curr.reg + save_order[i]; - if (reg->where == UNW_WHERE_GR_SAVE) - { - reg->where = UNW_WHERE_GR; - reg->val = sr->gr_save_loc++; - } - } - - /* Next, compute when the fp, general, and branch registers get saved. - This must come before alloc_spill_area() because we need to know - which registers are spilled to their home locations. */ - if (sr->imask) - { - static unsigned char const limit[3] = { - UNW_REG_F31, UNW_REG_R7, UNW_REG_B5 - }; - - unsigned char kind, mask = 0, *cp = sr->imask; - int t; - struct unw_reg_info *(regs[3]); - - regs[0] = sr->curr.reg + UNW_REG_F2; - regs[1] = sr->curr.reg + UNW_REG_R4; - regs[2] = sr->curr.reg + UNW_REG_B1; - - for (t = 0; t < sr->region_len; ++t) - { - if ((t & 3) == 0) - mask = *cp++; - kind = (mask >> 2*(3-(t & 3))) & 3; - if (kind > 0) - spill_next_when (®s[kind - 1], sr->curr.reg + limit[kind - 1], - sr->region_start + t); - } - } - - /* Next, lay out the memory stack spill area. */ - if (sr->any_spills) - { - off = sr->spill_offset; - alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2, - sr->curr.reg + UNW_REG_F31); - alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_B1, - sr->curr.reg + UNW_REG_B5); - alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_R4, - sr->curr.reg + UNW_REG_R7); - } -} - -/* - * Region header descriptors. - */ - -static void -desc_prologue (int body, unw_word rlen, unsigned char mask, - unsigned char grsave, struct unw_state_record *sr) -{ - int i; - - if (!(sr->in_body || sr->first_region)) - finish_prologue (sr); - sr->first_region = 0; - - /* Check if we're done. */ - if (sr->when_target < sr->region_start + sr->region_len) - { - sr->done = 1; - return; - } - - for (i = 0; i < sr->epilogue_count; ++i) - pop (sr); - - sr->epilogue_count = 0; - sr->epilogue_start = UNW_WHEN_NEVER; - - if (!body) - push (sr); - - sr->region_start += sr->region_len; - sr->region_len = rlen; - sr->in_body = body; - - if (!body) - { - for (i = 0; i < 4; ++i) - { - if (mask & 0x8) - set_reg (sr->curr.reg + save_order[i], UNW_WHERE_GR, - sr->region_start + sr->region_len - 1, grsave++); - mask <<= 1; - } - sr->gr_save_loc = grsave; - sr->any_spills = 0; - sr->imask = 0; - sr->spill_offset = 0x10; /* default to psp+16 */ - } -} - -/* - * Prologue descriptors. - */ - -static inline void -desc_abi (unsigned char abi, - unsigned char context, - struct unw_state_record *sr) -{ - sr->unwabi = (abi << 8) | context; -} - -static inline void -desc_br_gr (unsigned char brmask, unsigned char gr, - struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 5; ++i) - { - if (brmask & 1) - set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR, - sr->region_start + sr->region_len - 1, gr++); - brmask >>= 1; - } -} - -static inline void -desc_br_mem (unsigned char brmask, struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 5; ++i) - { - if (brmask & 1) - { - set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME, - sr->region_start + sr->region_len - 1, 0); - sr->any_spills = 1; - } - brmask >>= 1; - } -} - -static inline void -desc_frgr_mem (unsigned char grmask, unw_word frmask, - struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 4; ++i) - { - if ((grmask & 1) != 0) - { - set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, - sr->region_start + sr->region_len - 1, 0); - sr->any_spills = 1; - } - grmask >>= 1; - } - for (i = 0; i < 20; ++i) - { - if ((frmask & 1) != 0) - { - enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4; - set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME, - sr->region_start + sr->region_len - 1, 0); - sr->any_spills = 1; - } - frmask >>= 1; - } -} - -static inline void -desc_fr_mem (unsigned char frmask, struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 4; ++i) - { - if ((frmask & 1) != 0) - { - set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, - sr->region_start + sr->region_len - 1, 0); - sr->any_spills = 1; - } - frmask >>= 1; - } -} - -static inline void -desc_gr_gr (unsigned char grmask, unsigned char gr, - struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 4; ++i) - { - if ((grmask & 1) != 0) - set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR, - sr->region_start + sr->region_len - 1, gr++); - grmask >>= 1; - } -} - -static inline void -desc_gr_mem (unsigned char grmask, struct unw_state_record *sr) -{ - int i; - - for (i = 0; i < 4; ++i) - { - if ((grmask & 1) != 0) - { - set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, - sr->region_start + sr->region_len - 1, 0); - sr->any_spills = 1; - } - grmask >>= 1; - } -} - -static inline void -desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) -{ - set_reg (sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, - sr->region_start + MIN ((int)t, sr->region_len - 1), 16*size); -} - -static inline void -desc_mem_stack_v (unw_word t, struct unw_state_record *sr) -{ - sr->curr.reg[UNW_REG_PSP].when - = sr->region_start + MIN ((int)t, sr->region_len - 1); -} - -static inline void -desc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr) -{ - set_reg (sr->curr.reg + reg, UNW_WHERE_GR, - sr->region_start + sr->region_len - 1, dst); -} - -static inline void -desc_reg_psprel (unsigned char reg, unw_word pspoff, - struct unw_state_record *sr) -{ - set_reg (sr->curr.reg + reg, UNW_WHERE_PSPREL, - sr->region_start + sr->region_len - 1, - 0x10 - 4*pspoff); -} - -static inline void -desc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr) -{ - set_reg (sr->curr.reg + reg, UNW_WHERE_SPREL, - sr->region_start + sr->region_len - 1, - 4*spoff); -} - -static inline void -desc_rp_br (unsigned char dst, struct unw_state_record *sr) -{ - sr->return_link_reg = dst; -} - -static inline void -desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) -{ - struct unw_reg_info *reg = sr->curr.reg + regnum; - - if (reg->where == UNW_WHERE_NONE) - reg->where = UNW_WHERE_GR_SAVE; - reg->when = sr->region_start + MIN ((int)t, sr->region_len - 1); -} - -static inline void -desc_spill_base (unw_word pspoff, struct unw_state_record *sr) -{ - sr->spill_offset = 0x10 - 4*pspoff; -} - -static inline unsigned char * -desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr) -{ - sr->imask = imaskp; - return imaskp + (2*sr->region_len + 7)/8; -} - -/* - * Body descriptors. - */ -static inline void -desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) -{ - sr->epilogue_start = sr->region_start + sr->region_len - 1 - t; - sr->epilogue_count = ecount + 1; -} - -static inline void -desc_copy_state (unw_word label, struct unw_state_record *sr) -{ - struct unw_labeled_state *ls; - - for (ls = sr->labeled_states; ls; ls = ls->next) - { - if (ls->label == label) - { - free_state_stack (&sr->curr); - memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr)); - sr->curr.next = dup_state_stack (ls->saved_state.next); - return; - } - } - abort (); -} - -static inline void -desc_label_state (unw_word label, struct unw_state_record *sr) -{ - struct unw_labeled_state *ls = alloc_label_state (); - - ls->label = label; - memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state)); - ls->saved_state.next = dup_state_stack (sr->curr.next); - - /* Insert into list of labeled states. */ - ls->next = sr->labeled_states; - sr->labeled_states = ls; -} - -/* - * General descriptors. - */ - -static inline int -desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) -{ - if (sr->when_target <= sr->region_start + MIN ((int)t, sr->region_len - 1)) - return 0; - if (qp > 0) - { - if ((sr->pr_val & (1UL << qp)) == 0) - return 0; - sr->pr_mask |= (1UL << qp); - } - return 1; -} - -static inline void -desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, - struct unw_state_record *sr) -{ - struct unw_reg_info *r; - - if (! desc_is_active (qp, t, sr)) - return; - - r = sr->curr.reg + decode_abreg (abreg, 0); - r->where = UNW_WHERE_NONE; - r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); - r->val = 0; -} - -static inline void -desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, - unsigned char x, unsigned char ytreg, - struct unw_state_record *sr) -{ - enum unw_where where = UNW_WHERE_GR; - struct unw_reg_info *r; - - if (! desc_is_active (qp, t, sr)) - return; - - if (x) - where = UNW_WHERE_BR; - else if (ytreg & 0x80) - where = UNW_WHERE_FR; - - r = sr->curr.reg + decode_abreg (abreg, 0); - r->where = where; - r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); - r->val = ytreg & 0x7f; -} - -static inline void -desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, - unw_word pspoff, struct unw_state_record *sr) -{ - struct unw_reg_info *r; - - if (! desc_is_active (qp, t, sr)) - return; - - r = sr->curr.reg + decode_abreg (abreg, 1); - r->where = UNW_WHERE_PSPREL; - r->when = sr->region_start + MIN((int)t, sr->region_len - 1); - r->val = 0x10 - 4*pspoff; -} - -static inline void -desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, - unw_word spoff, struct unw_state_record *sr) -{ - struct unw_reg_info *r; - - if (! desc_is_active (qp, t, sr)) - return; - - r = sr->curr.reg + decode_abreg (abreg, 1); - r->where = UNW_WHERE_SPREL; - r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); - r->val = 4*spoff; -} - - -#define UNW_DEC_BAD_CODE(code) abort (); - -/* Region headers. */ -#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg) -#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg) - -/* Prologue descriptors. */ -#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg) -#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg) -#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg) -#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg) -#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg) -#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg) -#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg) -#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg) -#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg) -#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg) -#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg) -#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg) -#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg) -#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg) -#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg) -#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg) -#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg) -#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg) -#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg) -#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg) -#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg)) - -/* Body descriptors. */ -#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg) -#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg) -#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg) - -/* General unwind descriptors. */ -#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg) -#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg) -#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg) -#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg) -#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg) -#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg) -#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg) -#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) - - -/* - * Generic IA-64 unwind info decoder. - * - * This file is used both by the Linux kernel and objdump. Please keep - * the copies of this file in sync. - * - * You need to customize the decoder by defining the following - * macros/constants before including this file: - * - * Types: - * unw_word Unsigned integer type with at least 64 bits - * - * Register names: - * UNW_REG_BSP - * UNW_REG_BSPSTORE - * UNW_REG_FPSR - * UNW_REG_LC - * UNW_REG_PFS - * UNW_REG_PR - * UNW_REG_RNAT - * UNW_REG_PSP - * UNW_REG_RP - * UNW_REG_UNAT - * - * Decoder action macros: - * UNW_DEC_BAD_CODE(code) - * UNW_DEC_ABI(fmt,abi,context,arg) - * UNW_DEC_BR_GR(fmt,brmask,gr,arg) - * UNW_DEC_BR_MEM(fmt,brmask,arg) - * UNW_DEC_COPY_STATE(fmt,label,arg) - * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) - * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) - * UNW_DEC_FR_MEM(fmt,frmask,arg) - * UNW_DEC_GR_GR(fmt,grmask,gr,arg) - * UNW_DEC_GR_MEM(fmt,grmask,arg) - * UNW_DEC_LABEL_STATE(fmt,label,arg) - * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) - * UNW_DEC_MEM_STACK_V(fmt,t,arg) - * UNW_DEC_PRIUNAT_GR(fmt,r,arg) - * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) - * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) - * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) - * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) - * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) - * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) - * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) - * UNW_DEC_REG_REG(fmt,src,dst,arg) - * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) - * UNW_DEC_REG_WHEN(fmt,reg,t,arg) - * UNW_DEC_RESTORE(fmt,t,abreg,arg) - * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) - * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) - * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) - * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) - * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) - * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) - * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) - * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) - * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) - */ - -static unw_word -unw_decode_uleb128 (unsigned char **dpp) -{ - unsigned shift = 0; - unw_word byte, result = 0; - unsigned char *bp = *dpp; - - while (1) - { - byte = *bp++; - result |= (byte & 0x7f) << shift; - if ((byte & 0x80) == 0) - break; - shift += 7; - } - *dpp = bp; - return result; -} - -static unsigned char * -unw_decode_x1 (unsigned char *dp, - unsigned char code __attribute__((unused)), - void *arg) -{ - unsigned char byte1, abreg; - unw_word t, off; - - byte1 = *dp++; - t = unw_decode_uleb128 (&dp); - off = unw_decode_uleb128 (&dp); - abreg = (byte1 & 0x7f); - if (byte1 & 0x80) - UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); - else - UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); - return dp; -} - -static unsigned char * -unw_decode_x2 (unsigned char *dp, - unsigned char code __attribute__((unused)), - void *arg) -{ - unsigned char byte1, byte2, abreg, x, ytreg; - unw_word t; - - byte1 = *dp++; byte2 = *dp++; - t = unw_decode_uleb128 (&dp); - abreg = (byte1 & 0x7f); - ytreg = byte2; - x = (byte1 >> 7) & 1; - if ((byte1 & 0x80) == 0 && ytreg == 0) - UNW_DEC_RESTORE(X2, t, abreg, arg); - else - UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); - return dp; -} - -static unsigned char * -unw_decode_x3 (unsigned char *dp, - unsigned char code __attribute__((unused)), - void *arg) -{ - unsigned char byte1, byte2, abreg, qp; - unw_word t, off; - - byte1 = *dp++; byte2 = *dp++; - t = unw_decode_uleb128 (&dp); - off = unw_decode_uleb128 (&dp); - - qp = (byte1 & 0x3f); - abreg = (byte2 & 0x7f); - - if (byte1 & 0x80) - UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); - else - UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); - return dp; -} - -static unsigned char * -unw_decode_x4 (unsigned char *dp, - unsigned char code __attribute__((unused)), - void *arg) -{ - unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; - unw_word t; - - byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; - t = unw_decode_uleb128 (&dp); - - qp = (byte1 & 0x3f); - abreg = (byte2 & 0x7f); - x = (byte2 >> 7) & 1; - ytreg = byte3; - - if ((byte2 & 0x80) == 0 && byte3 == 0) - UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); - else - UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); - return dp; -} - -static unsigned char * -unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) -{ - int body = (code & 0x20) != 0; - unw_word rlen; - - rlen = (code & 0x1f); - UNW_DEC_PROLOGUE(R1, body, rlen, arg); - return dp; -} - -static unsigned char * -unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) -{ - unsigned char byte1, mask, grsave; - unw_word rlen; - - byte1 = *dp++; - - mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); - grsave = (byte1 & 0x7f); - rlen = unw_decode_uleb128 (&dp); - UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); - return dp; -} - -static unsigned char * -unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) -{ - unw_word rlen; - - rlen = unw_decode_uleb128 (&dp); - UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); - return dp; -} - -static unsigned char * -unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) -{ - unsigned char brmask = (code & 0x1f); - - UNW_DEC_BR_MEM(P1, brmask, arg); - return dp; -} - -static unsigned char * -unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) -{ - if ((code & 0x10) == 0) - { - unsigned char byte1 = *dp++; - - UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), - (byte1 & 0x7f), arg); - } - else if ((code & 0x08) == 0) - { - unsigned char byte1 = *dp++, r, dst; - - r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); - dst = (byte1 & 0x7f); - switch (r) - { - case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; - case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; - case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; - case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; - case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; - case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; - case 6: UNW_DEC_RP_BR(P3, dst, arg); break; - case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; - case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; - case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; - case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; - case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; - default: UNW_DEC_BAD_CODE(r); break; - } - } - else if ((code & 0x7) == 0) - UNW_DEC_SPILL_MASK(P4, dp, arg); - else if ((code & 0x7) == 1) - { - unw_word grmask, frmask, byte1, byte2, byte3; - - byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; - grmask = ((byte1 >> 4) & 0xf); - frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; - UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); - } - else - UNW_DEC_BAD_CODE(code); - return dp; -} - -static unsigned char * -unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) -{ - int gregs = (code & 0x10) != 0; - unsigned char mask = (code & 0x0f); - - if (gregs) - UNW_DEC_GR_MEM(P6, mask, arg); - else - UNW_DEC_FR_MEM(P6, mask, arg); - return dp; -} - -static unsigned char * -unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) -{ - unsigned char r, byte1, byte2; - unw_word t, size; - - if ((code & 0x10) == 0) - { - r = (code & 0xf); - t = unw_decode_uleb128 (&dp); - switch (r) - { - case 0: - size = unw_decode_uleb128 (&dp); - UNW_DEC_MEM_STACK_F(P7, t, size, arg); - break; - - case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; - case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; - case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; - case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; - case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; - case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; - case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; - case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; - case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; - case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; - case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; - case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; - case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; - case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; - case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; - default: UNW_DEC_BAD_CODE(r); break; - } - } - else - { - switch (code & 0xf) - { - case 0x0: /* p8 */ - { - r = *dp++; - t = unw_decode_uleb128 (&dp); - switch (r) - { - case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; - case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; - case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; - case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; - case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; - case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; - case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; - case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; - case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; - case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; - case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; - case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; - case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; - case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; - case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; - case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; - case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; - case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; - case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; - default: UNW_DEC_BAD_CODE(r); break; - } - } - break; - - case 0x1: - byte1 = *dp++; byte2 = *dp++; - UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); - break; - - case 0xf: /* p10 */ - byte1 = *dp++; byte2 = *dp++; - UNW_DEC_ABI(P10, byte1, byte2, arg); - break; - - case 0x9: - return unw_decode_x1 (dp, code, arg); - - case 0xa: - return unw_decode_x2 (dp, code, arg); - - case 0xb: - return unw_decode_x3 (dp, code, arg); - - case 0xc: - return unw_decode_x4 (dp, code, arg); - - default: - UNW_DEC_BAD_CODE(code); - break; - } - } - return dp; -} - -static unsigned char * -unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) -{ - unw_word label = (code & 0x1f); - - if ((code & 0x20) != 0) - UNW_DEC_COPY_STATE(B1, label, arg); - else - UNW_DEC_LABEL_STATE(B1, label, arg); - return dp; -} - -static unsigned char * -unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) -{ - unw_word t; - - t = unw_decode_uleb128 (&dp); - UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); - return dp; -} - -static unsigned char * -unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) -{ - unw_word t, ecount, label; - - if ((code & 0x10) == 0) - { - t = unw_decode_uleb128 (&dp); - ecount = unw_decode_uleb128 (&dp); - UNW_DEC_EPILOGUE(B3, t, ecount, arg); - } - else if ((code & 0x07) == 0) - { - label = unw_decode_uleb128 (&dp); - if ((code & 0x08) != 0) - UNW_DEC_COPY_STATE(B4, label, arg); - else - UNW_DEC_LABEL_STATE(B4, label, arg); - } - else - switch (code & 0x7) - { - case 1: return unw_decode_x1 (dp, code, arg); - case 2: return unw_decode_x2 (dp, code, arg); - case 3: return unw_decode_x3 (dp, code, arg); - case 4: return unw_decode_x4 (dp, code, arg); - default: UNW_DEC_BAD_CODE(code); break; - } - return dp; -} - -typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); - -static const unw_decoder unw_decode_table[2][8] = -{ - /* prologue table: */ - { - unw_decode_r1, /* 0 */ - unw_decode_r1, - unw_decode_r2, - unw_decode_r3, - unw_decode_p1, /* 4 */ - unw_decode_p2_p5, - unw_decode_p6, - unw_decode_p7_p10 - }, - { - unw_decode_r1, /* 0 */ - unw_decode_r1, - unw_decode_r2, - unw_decode_r3, - unw_decode_b1, /* 4 */ - unw_decode_b1, - unw_decode_b2, - unw_decode_b3_x4 - } -}; - -/* - * Decode one descriptor and return address of next descriptor. - */ -static inline unsigned char * -unw_decode (unsigned char *dp, int inside_body, void *arg) -{ - unw_decoder decoder; - unsigned char code; - - code = *dp++; - decoder = unw_decode_table[inside_body][code >> 5]; - dp = (*decoder) (dp, code, arg); - return dp; -} - - -/* RSE helper functions. */ - -static inline unsigned long -ia64_rse_slot_num (unsigned long *addr) -{ - return (((unsigned long) addr) >> 3) & 0x3f; -} - -/* Return TRUE if ADDR is the address of an RNAT slot. */ -static inline unsigned long -ia64_rse_is_rnat_slot (unsigned long *addr) -{ - return ia64_rse_slot_num (addr) == 0x3f; -} - -/* Returns the address of the RNAT slot that covers the slot at - address SLOT_ADDR. */ -static inline unsigned long * -ia64_rse_rnat_addr (unsigned long *slot_addr) -{ - return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3)); -} - -/* Calculate the number of registers in the dirty partition starting at - BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY - divided by eight because the 64th slot is used to store ar.rnat. */ -static inline unsigned long -ia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp) -{ - unsigned long slots = (bsp - bspstore); - - return slots - (ia64_rse_slot_num (bspstore) + slots)/0x40; -} - -/* The inverse of the above: given bspstore and the number of - registers, calculate ar.bsp. */ -static inline unsigned long * -ia64_rse_skip_regs (unsigned long *addr, long num_regs) -{ - long delta = ia64_rse_slot_num (addr) + num_regs; - - if (num_regs < 0) - delta -= 0x3e; - return addr + num_regs + delta/0x3f; -} - - -/* Copy register backing store from SRC to DST, LEN words - (which include both saved registers and nat collections). - DST_RNAT is a partial nat collection for DST. SRC and DST - don't have to be equal modulo 64 slots, so it cannot be - done with a simple memcpy as the nat collections will be - at different relative offsets and need to be combined together. */ -static void -ia64_copy_rbs (struct _Unwind_Context *info, unsigned long dst, - unsigned long src, long len, unsigned long dst_rnat) -{ - long count; - unsigned long src_rnat; - unsigned long shift1, shift2; - - len <<= 3; - dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1; - src_rnat = src >= info->regstk_top - ? info->rnat : *(unsigned long *) (src | 0x1f8); - src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1); - /* Just to make sure. */ - src_rnat &= ~(1UL << 63); - shift1 = ((dst - src) >> 3) & 0x3f; - if ((dst & 0x1f8) < (src & 0x1f8)) - shift1--; - shift2 = 0x3f - shift1; - if ((dst & 0x1f8) >= (src & 0x1f8)) - { - count = ~dst & 0x1f8; - goto first; - } - count = ~src & 0x1f8; - goto second; - while (len > 0) - { - src_rnat = src >= info->regstk_top - ? info->rnat : *(unsigned long *) (src | 0x1f8); - /* Just to make sure. */ - src_rnat &= ~(1UL << 63); - count = shift2 << 3; -first: - if (count > len) - count = len; - memcpy ((char *) dst, (char *) src, count); - dst += count; - src += count; - len -= count; - dst_rnat |= (src_rnat << shift1) & ~(1UL << 63); - if (len <= 0) - break; - *(long *) dst = dst_rnat; - dst += 8; - dst_rnat = 0; - count = shift1 << 3; -second: - if (count > len) - count = len; - memcpy ((char *) dst, (char *) src, count); - dst += count; - src += count + 8; - len -= count + 8; - dst_rnat |= (src_rnat >> shift2); - } - if ((dst & 0x1f8) == 0x1f8) - { - *(long *) dst = dst_rnat; - dst += 8; - dst_rnat = 0; - } - /* Set info->regstk_top to lowest rbs address which will use - info->rnat collection. */ - info->regstk_top = dst & ~0x1ffUL; - info->rnat = dst_rnat; -} - -/* Unwind accessors. */ - -static void -unw_access_gr (struct _Unwind_Context *info, int regnum, - unsigned long *val, char *nat, int write) -{ - unsigned long *addr, *nat_addr = 0, nat_mask = 0, dummy_nat; - struct unw_ireg *ireg; - - if ((unsigned) regnum - 1 >= 127) - abort (); - - if (regnum < 1) - { - nat_addr = addr = &dummy_nat; - dummy_nat = 0; - } - else if (regnum < 32) - { - /* Access a non-stacked register. */ - ireg = &info->ireg[regnum - 2]; - addr = ireg->loc; - if (addr) - { - nat_addr = addr + ireg->nat.off; - switch (ireg->nat.type) - { - case UNW_NAT_VAL: - /* Simulate getf.sig/setf.sig. */ - if (write) - { - if (*nat) - { - /* Write NaTVal and be done with it. */ - addr[0] = 0; - addr[1] = 0x1fffe; - return; - } - addr[1] = 0x1003e; - } - else if (addr[0] == 0 && addr[1] == 0x1ffe) - { - /* Return NaT and be done with it. */ - *val = 0; - *nat = 1; - return; - } - /* FALLTHRU */ - - case UNW_NAT_NONE: - dummy_nat = 0; - nat_addr = &dummy_nat; - break; - - case UNW_NAT_MEMSTK: - nat_mask = 1UL << ((long) addr & 0x1f8)/8; - break; - - case UNW_NAT_REGSTK: - if ((unsigned long) addr >= info->regstk_top) - nat_addr = &info->rnat; - else - nat_addr = ia64_rse_rnat_addr (addr); - nat_mask = 1UL << ia64_rse_slot_num (addr); - break; - } - } - } - else - { - /* Access a stacked register. */ - addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32); - if ((unsigned long) addr >= info->regstk_top) - nat_addr = &info->rnat; - else - nat_addr = ia64_rse_rnat_addr (addr); - nat_mask = 1UL << ia64_rse_slot_num (addr); - } - - if (write) - { - *addr = *val; - if (*nat) - *nat_addr |= nat_mask; - else - *nat_addr &= ~nat_mask; - } - else - { - *val = *addr; - *nat = (*nat_addr & nat_mask) != 0; - } -} - -/* Get the value of register REG as saved in CONTEXT. */ - -_Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) -{ - _Unwind_Word ret; - char nat; - - if (index == 1) - return context->gp; - else if (index >= 15 && index <= 18) - return context->eh_data[index - 15]; - else - unw_access_gr (context, index, &ret, &nat, 0); - - return ret; -} - -/* Overwrite the saved value for register REG in CONTEXT with VAL. */ - -void -_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) -{ - char nat = 0; - - if (index == 1) - context->gp = val; - else if (index >= 15 && index <= 18) - context->eh_data[index - 15] = val; - else - unw_access_gr (context, index, &val, &nat, 1); -} - -/* Retrieve the return address for CONTEXT. */ - -inline _Unwind_Ptr -_Unwind_GetIP (struct _Unwind_Context *context) -{ - return context->rp; -} - -inline _Unwind_Ptr -_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) -{ - *ip_before_insn = 0; - return context->rp; -} - -/* Overwrite the return address for CONTEXT with VAL. */ - -inline void -_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) -{ - context->rp = val; -} - -void * -_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) -{ - return context->lsda; -} - -_Unwind_Ptr -_Unwind_GetRegionStart (struct _Unwind_Context *context) -{ - return context->region_start; -} - -void * -_Unwind_FindEnclosingFunction (void *pc) -{ - struct unw_table_entry *entp, ent; - unsigned long segment_base, gp; - - entp = _Unwind_FindTableEntry (pc, &segment_base, &gp, &ent); - if (entp == NULL) - return NULL; - else - return (void *)(segment_base + entp->start_offset); -} - -/* Get the value of the CFA as saved in CONTEXT. In GCC/Dwarf2 parlance, - the CFA is the value of the stack pointer on entry; In IA-64 unwind - parlance, this is the PSP. */ - -_Unwind_Word -_Unwind_GetCFA (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->psp; -} - -/* Get the value of the Backing Store Pointer as saved in CONTEXT. */ - -_Unwind_Word -_Unwind_GetBSP (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->bsp; -} - -#include "md-unwind-support.h" - -static _Unwind_Reason_Code -uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - struct unw_table_entry *entp, ent; - unsigned long *unw, header, length; - unsigned char *insn, *insn_end; - unsigned long segment_base; - struct unw_reg_info *r; - - memset (fs, 0, sizeof (*fs)); - for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) - r->when = UNW_WHEN_NEVER; - context->lsda = 0; - - entp = _Unwind_FindTableEntry ((void *) context->rp, - &segment_base, &context->gp, &ent); - if (entp == NULL) - { - /* Couldn't find unwind info for this function. Try an - os-specific fallback mechanism. This will necessarily - not provide a personality routine or LSDA. */ -#ifdef MD_FALLBACK_FRAME_STATE_FOR - if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON) - return _URC_NO_REASON; -#endif - - /* [SCRA 11.4.1] A leaf function with no memory stack, no exception - handlers, and which keeps the return value in B0 does not need - an unwind table entry. - - This can only happen in the frame after unwinding through a signal - handler. Avoid infinite looping by requiring that B0 != RP. - RP == 0 terminates the chain. */ - if (context->br_loc[0] - && *context->br_loc[0] != context->rp - && context->rp != 0) - goto skip_unwind_info; - - return _URC_END_OF_STACK; - } - - context->region_start = entp->start_offset + segment_base; - fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3 - + (context->rp & 15); - - unw = (unsigned long *) (entp->info_offset + segment_base); - header = *unw; - length = UNW_LENGTH (header); - - /* Some operating systems use the personality routine slot in way not - compatible with what we expect. For instance, OpenVMS uses this slot to - designate "condition handlers" with very different arguments than what we - would be providing. Such cases are typically identified from OS specific - bits in the unwind information block header, and checked by the target - MD_UNW_COMPATIBLE_PERSONALITY_P macro. - - We just pretend there is no personality from our standpoint in such - situations, and expect GCC not to set the identifying bits itself so that - compatible personalities for GCC compiled code are called. - - Of course, this raises the question of what combinations of native/GCC - calls can be expected to behave properly exception handling-wise. We are - not to provide a magic answer here, merely to prevent crashes assuming - users know what they are doing. - - ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK as well. */ - - if (MD_UNW_COMPATIBLE_PERSONALITY_P (header) - && (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header))) - { - fs->personality = - *(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp); - context->lsda = unw + length + 2; - } - - insn = (unsigned char *) (unw + 1); - insn_end = (unsigned char *) (unw + 1 + length); - while (!fs->done && insn < insn_end) - insn = unw_decode (insn, fs->in_body, fs); - - free_label_states (fs->labeled_states); - free_state_stack (&fs->curr); - -#ifdef ENABLE_MALLOC_CHECKING - if (reg_state_alloced || labeled_state_alloced) - abort (); -#endif - - /* If we're in the epilogue, sp has been restored and all values - on the memory stack below psp also have been restored. */ - if (fs->when_target > fs->epilogue_start) - { - struct unw_reg_info *r; - - fs->curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; - fs->curr.reg[UNW_REG_PSP].val = 0; - for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) - if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) - || r->where == UNW_WHERE_SPREL) - r->where = UNW_WHERE_NONE; - } - -skip_unwind_info: - /* If RP didn't get saved, generate entry for the return link register. */ - if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target) - { - fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; - fs->curr.reg[UNW_REG_RP].when = -1; - fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg; - } - - /* There is a subtlety for the frame after unwinding through a signal - handler: should we restore the cfm as usual or the pfs? We can't - restore both because we use br.ret to resume execution of user code. - For other frames the procedure is by definition non-leaf so the pfs - is saved and restored and thus effectively dead in the body; only - the cfm need therefore be restored. - - Here we have 2 cases: - - either the pfs is saved and restored and thus effectively dead - like in regular frames; then we do nothing special and restore - the cfm. - - or the pfs is not saved and thus live; but in that case the - procedure is necessarily leaf so the cfm is effectively dead - and we restore the pfs. */ - if (context->signal_pfs_loc) - { - if (fs->curr.reg[UNW_REG_PFS].when >= fs->when_target) - context->pfs_loc = context->signal_pfs_loc; - context->signal_pfs_loc = NULL; - } - - return _URC_NO_REASON; -} - -static void -uw_update_reg_address (struct _Unwind_Context *context, - _Unwind_FrameState *fs, - enum unw_register_index regno) -{ - struct unw_reg_info *r = fs->curr.reg + regno; - void *addr; - unsigned long rval; - - if (r->where == UNW_WHERE_NONE || r->when >= fs->when_target) - return; - - rval = r->val; - switch (r->where) - { - case UNW_WHERE_GR: - if (rval >= 32) - addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32); - else if (rval >= 2) - addr = context->ireg[rval - 2].loc; - else if (rval == 0) - { - static const unsigned long dummy; - addr = (void *) &dummy; - } - else - abort (); - break; - - case UNW_WHERE_FR: - if (rval >= 2 && rval < 32) - addr = context->fr_loc[rval - 2]; - else - abort (); - break; - - case UNW_WHERE_BR: - /* Note that while RVAL can only be 1-5 from normal descriptors, - we can want to look at B0, B6 and B7 due to having manually unwound a - signal frame. */ - if (rval < 8) - addr = context->br_loc[rval]; - else - abort (); - break; - - case UNW_WHERE_SPREL: - addr = (void *)(context->sp + rval); - break; - - case UNW_WHERE_PSPREL: - addr = (void *)(context->psp + rval); - break; - - default: - abort (); - } - - switch (regno) - { - case UNW_REG_R2 ... UNW_REG_R31: - context->ireg[regno - UNW_REG_R2].loc = addr; - switch (r->where) - { - case UNW_WHERE_GR: - if (rval >= 32) - { - context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK; - context->ireg[regno - UNW_REG_R2].nat.off - = context->pri_unat_loc - (unsigned long *) addr; - } - else if (rval >= 2) - { - context->ireg[regno - UNW_REG_R2].nat - = context->ireg[rval - 2].nat; - } - else if (rval == 0) - { - context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE; - context->ireg[regno - UNW_REG_R2].nat.off = 0; - } - else - abort (); - break; - - case UNW_WHERE_FR: - context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_VAL; - context->ireg[regno - UNW_REG_R2].nat.off = 0; - break; - - case UNW_WHERE_BR: - context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE; - context->ireg[regno - UNW_REG_R2].nat.off = 0; - break; - - case UNW_WHERE_PSPREL: - case UNW_WHERE_SPREL: - context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK; - context->ireg[regno - UNW_REG_R2].nat.off - = context->pri_unat_loc - (unsigned long *) addr; - break; - - default: - abort (); - } - break; - - case UNW_REG_F2 ... UNW_REG_F31: - context->fr_loc[regno - UNW_REG_F2] = addr; - break; - - case UNW_REG_B1 ... UNW_REG_B5: - context->br_loc[regno - UNW_REG_B0] = addr; - break; - - case UNW_REG_BSP: - context->bsp_loc = addr; - break; - case UNW_REG_BSPSTORE: - context->bspstore_loc = addr; - break; - case UNW_REG_PFS: - context->pfs_loc = addr; - break; - case UNW_REG_RP: - context->rp = *(unsigned long *)addr; - break; - case UNW_REG_UNAT: - context->unat_loc = addr; - break; - case UNW_REG_PR: - context->pr = *(unsigned long *) addr; - break; - case UNW_REG_LC: - context->lc_loc = addr; - break; - case UNW_REG_FPSR: - context->fpsr_loc = addr; - break; - - case UNW_REG_PSP: - context->psp = *(unsigned long *)addr; - break; - - default: - abort (); - } -} - -static void -uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - long i; - -#ifdef MD_HANDLE_UNWABI - MD_HANDLE_UNWABI (context, fs); -#endif - - context->sp = context->psp; - - /* First, set PSP. Subsequent instructions may depend on this value. */ - if (fs->when_target > fs->curr.reg[UNW_REG_PSP].when) - { - if (fs->curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE) - context->psp = context->psp + fs->curr.reg[UNW_REG_PSP].val; - else - uw_update_reg_address (context, fs, UNW_REG_PSP); - } - - /* Determine the location of the primary UNaT. */ - { - int i; - if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_GR].when) - i = UNW_REG_PRI_UNAT_MEM; - else if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when) - i = UNW_REG_PRI_UNAT_GR; - else if (fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when - > fs->curr.reg[UNW_REG_PRI_UNAT_GR].when) - i = UNW_REG_PRI_UNAT_MEM; - else - i = UNW_REG_PRI_UNAT_GR; - uw_update_reg_address (context, fs, i); - } - - /* Compute the addresses of all registers saved in this frame. */ - for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i) - uw_update_reg_address (context, fs, i); - - /* Unwind BSP for the local registers allocated this frame. */ - /* ??? What to do with stored BSP or BSPSTORE registers. */ - /* We assert that we are either at a call site, or we have - just unwound through a signal frame. In either case - pfs_loc is valid. */ - if (!(fs -> no_reg_stack_frame)) - { - unsigned long pfs = *context->pfs_loc; - unsigned long sol = (pfs >> 7) & 0x7f; - context->bsp = (unsigned long) - ia64_rse_skip_regs ((unsigned long *) context->bsp, -sol); - } -} - -static void -uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - uw_update_context (context, fs); -} - -/* Fill in CONTEXT for top-of-stack. The only valid registers at this - level will be the return address and the CFA. Note that CFA = SP+16. */ - -#define uw_init_context(CONTEXT) \ - do { \ - /* ??? There is a whole lot o code in uw_install_context that \ - tries to avoid spilling the entire machine state here. We \ - should try to make that work again. */ \ - __builtin_unwind_init(); \ - uw_init_context_1 (CONTEXT, __builtin_ia64_bsp ()); \ - } while (0) - -static void __attribute__((noinline)) -uw_init_context_1 (struct _Unwind_Context *context, void *bsp) -{ - void *rp = __builtin_extract_return_addr (__builtin_return_address (0)); - /* Set psp to the caller's stack pointer. */ - void *psp = __builtin_dwarf_cfa () - 16; - _Unwind_FrameState fs; - unsigned long rnat, tmp1, tmp2; - - /* Flush the register stack to memory so that we can access it. - Get rse nat collection for the last incomplete rbs chunk of - registers at the same time. For this RSE needs to be turned - into the mandatory only mode. */ - asm ("mov.m %1 = ar.rsc;;\n\t" - "and %2 = 0x1c, %1;;\n\t" - "mov.m ar.rsc = %2;;\n\t" - "flushrs;;\n\t" - "mov.m %0 = ar.rnat;;\n\t" - "mov.m ar.rsc = %1\n\t" - : "=r" (rnat), "=r" (tmp1), "=r" (tmp2)); - - memset (context, 0, sizeof (struct _Unwind_Context)); - context->bsp = (unsigned long) bsp; - /* Set context->regstk_top to lowest rbs address which will use - context->rnat collection. */ - context->regstk_top = context->bsp & ~0x1ffULL; - context->rnat = rnat; - context->psp = (unsigned long) psp; - context->rp = (unsigned long) rp; - asm ("mov %0 = sp" : "=r" (context->sp)); - asm ("mov %0 = pr" : "=r" (context->pr)); - context->pri_unat_loc = &context->initial_unat; /* ??? */ - - if (uw_frame_state_for (context, &fs) != _URC_NO_REASON) - abort (); - - uw_update_context (context, &fs); -} - -/* Install (i.e. longjmp to) the contents of TARGET. */ - -static void __attribute__((noreturn)) -uw_install_context (struct _Unwind_Context *current __attribute__((unused)), - struct _Unwind_Context *target) -{ - unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0; - long i; - - /* Copy integer register data from the target context to a - temporary buffer. Do this so that we can frob AR.UNAT - to get the NaT bits for these registers set properly. */ - for (i = 4; i <= 7; ++i) - { - char nat; - void *t = target->ireg[i - 2].loc; - if (t) - { - unw_access_gr (target, i, &ireg_buf[i - 4], &nat, 0); - ireg_nat |= (long)nat << (((size_t)&ireg_buf[i - 4] >> 3) & 0x3f); - /* Set p6 - p9. */ - ireg_pr |= 4L << i; - } - } - - /* The value in uc_bsp that we've computed is that for the - target function. The value that we install below will be - adjusted by the BR.RET instruction based on the contents - of AR.PFS. So we must unadjust that here. */ - target->bsp = (unsigned long) - ia64_rse_skip_regs ((unsigned long *)target->bsp, - (*target->pfs_loc >> 7) & 0x7f); - - if (target->bsp < target->regstk_top) - target->rnat = *ia64_rse_rnat_addr ((unsigned long *) target->bsp); - - /* Provide assembly with the offsets into the _Unwind_Context. */ - asm volatile ("uc_rnat = %0" - : : "i"(offsetof (struct _Unwind_Context, rnat))); - asm volatile ("uc_bsp = %0" - : : "i"(offsetof (struct _Unwind_Context, bsp))); - asm volatile ("uc_psp = %0" - : : "i"(offsetof (struct _Unwind_Context, psp))); - asm volatile ("uc_rp = %0" - : : "i"(offsetof (struct _Unwind_Context, rp))); - asm volatile ("uc_pr = %0" - : : "i"(offsetof (struct _Unwind_Context, pr))); - asm volatile ("uc_gp = %0" - : : "i"(offsetof (struct _Unwind_Context, gp))); - asm volatile ("uc_pfs_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, pfs_loc))); - asm volatile ("uc_unat_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, unat_loc))); - asm volatile ("uc_lc_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, lc_loc))); - asm volatile ("uc_fpsr_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, fpsr_loc))); - asm volatile ("uc_eh_data = %0" - : : "i"(offsetof (struct _Unwind_Context, eh_data))); - asm volatile ("uc_br_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, br_loc))); - asm volatile ("uc_fr_loc = %0" - : : "i"(offsetof (struct _Unwind_Context, fr_loc))); - - asm volatile ( - /* Load up call-saved non-window integer registers from ireg_buf. */ - "add r20 = 8, %1 \n\t" - "mov ar.unat = %2 \n\t" - "mov pr = %3, 0x3c0 \n\t" - ";; \n\t" - "(p6) ld8.fill r4 = [%1] \n\t" - "(p7) ld8.fill r5 = [r20] \n\t" - "add r21 = uc_br_loc + 16, %0 \n\t" - "adds %1 = 16, %1 \n\t" - "adds r20 = 16, r20 \n\t" - ";; \n\t" - "(p8) ld8.fill r6 = [%1] \n\t" - "(p9) ld8.fill r7 = [r20] \n\t" - "add r20 = uc_br_loc + 8, %0 \n\t" - ";; \n\t" - /* Load up call-saved branch registers. */ - "ld8 r22 = [r20], 16 \n\t" - "ld8 r23 = [r21], 16 \n\t" - ";; \n\t" - "ld8 r24 = [r20], 16 \n\t" - "ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 32)\n\t" - ";; \n\t" - "ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 40)\n\t" - "ld8 r27 = [r21], 24 \n\t" - "cmp.ne p6, p0 = r0, r22 \n\t" - ";; \n\t" - "ld8 r28 = [r20], 8 \n\t" - "(p6) ld8 r22 = [r22] \n\t" - "cmp.ne p7, p0 = r0, r23 \n\t" - ";; \n\t" - "(p7) ld8 r23 = [r23] \n\t" - "cmp.ne p8, p0 = r0, r24 \n\t" - ";; \n\t" - "(p8) ld8 r24 = [r24] \n\t" - "(p6) mov b1 = r22 \n\t" - "cmp.ne p9, p0 = r0, r25 \n\t" - ";; \n\t" - "(p9) ld8 r25 = [r25] \n\t" - "(p7) mov b2 = r23 \n\t" - "cmp.ne p6, p0 = r0, r26 \n\t" - ";; \n\t" - "(p6) ld8 r26 = [r26] \n\t" - "(p8) mov b3 = r24 \n\t" - "cmp.ne p7, p0 = r0, r27 \n\t" - ";; \n\t" - /* Load up call-saved fp registers. */ - "(p7) ldf.fill f2 = [r27] \n\t" - "(p9) mov b4 = r25 \n\t" - "cmp.ne p8, p0 = r0, r28 \n\t" - ";; \n\t" - "(p8) ldf.fill f3 = [r28] \n\t" - "(p6) mov b5 = r26 \n\t" - ";; \n\t" - "ld8 r29 = [r20], 16*8 - 4*8 \n\t" - "ld8 r30 = [r21], 17*8 - 5*8 \n\t" - ";; \n\t" - "ld8 r22 = [r20], 16 \n\t" - "ld8 r23 = [r21], 16 \n\t" - ";; \n\t" - "ld8 r24 = [r20], 16 \n\t" - "ld8 r25 = [r21] \n\t" - "cmp.ne p6, p0 = r0, r29 \n\t" - ";; \n\t" - "ld8 r26 = [r20], 8 \n\t" - "(p6) ldf.fill f4 = [r29] \n\t" - "cmp.ne p7, p0 = r0, r30 \n\t" - ";; \n\t" - "ld8 r27 = [r20], 8 \n\t" - "(p7) ldf.fill f5 = [r30] \n\t" - "cmp.ne p6, p0 = r0, r22 \n\t" - ";; \n\t" - "ld8 r28 = [r20], 8 \n\t" - "(p6) ldf.fill f16 = [r22] \n\t" - "cmp.ne p7, p0 = r0, r23 \n\t" - ";; \n\t" - "ld8 r29 = [r20], 8 \n\t" - "(p7) ldf.fill f17 = [r23] \n\t" - "cmp.ne p6, p0 = r0, r24 \n\t" - ";; \n\t" - "ld8 r22 = [r20], 8 \n\t" - "(p6) ldf.fill f18 = [r24] \n\t" - "cmp.ne p7, p0 = r0, r25 \n\t" - ";; \n\t" - "ld8 r23 = [r20], 8 \n\t" - "(p7) ldf.fill f19 = [r25] \n\t" - "cmp.ne p6, p0 = r0, r26 \n\t" - ";; \n\t" - "ld8 r24 = [r20], 8 \n\t" - "(p6) ldf.fill f20 = [r26] \n\t" - "cmp.ne p7, p0 = r0, r27 \n\t" - ";; \n\t" - "ld8 r25 = [r20], 8 \n\t" - "(p7) ldf.fill f21 = [r27] \n\t" - "cmp.ne p6, p0 = r0, r28 \n\t" - ";; \n\t" - "ld8 r26 = [r20], 8 \n\t" - "(p6) ldf.fill f22 = [r28] \n\t" - "cmp.ne p7, p0 = r0, r29 \n\t" - ";; \n\t" - "ld8 r27 = [r20], 8 \n\t" - ";; \n\t" - "ld8 r28 = [r20], 8 \n\t" - "(p7) ldf.fill f23 = [r29] \n\t" - "cmp.ne p6, p0 = r0, r22 \n\t" - ";; \n\t" - "ld8 r29 = [r20], 8 \n\t" - "(p6) ldf.fill f24 = [r22] \n\t" - "cmp.ne p7, p0 = r0, r23 \n\t" - ";; \n\t" - "(p7) ldf.fill f25 = [r23] \n\t" - "cmp.ne p6, p0 = r0, r24 \n\t" - "cmp.ne p7, p0 = r0, r25 \n\t" - ";; \n\t" - "(p6) ldf.fill f26 = [r24] \n\t" - "(p7) ldf.fill f27 = [r25] \n\t" - "cmp.ne p6, p0 = r0, r26 \n\t" - ";; \n\t" - "(p6) ldf.fill f28 = [r26] \n\t" - "cmp.ne p7, p0 = r0, r27 \n\t" - "cmp.ne p6, p0 = r0, r28 \n\t" - ";; \n\t" - "(p7) ldf.fill f29 = [r27] \n\t" - "(p6) ldf.fill f30 = [r28] \n\t" - "cmp.ne p7, p0 = r0, r29 \n\t" - ";; \n\t" - "(p7) ldf.fill f31 = [r29] \n\t" - "add r20 = uc_rnat, %0 \n\t" - "add r21 = uc_bsp, %0 \n\t" - ";; \n\t" - /* Load the balance of the thread state from the context. */ - "ld8 r22 = [r20], uc_psp - uc_rnat \n\t" - "ld8 r23 = [r21], uc_gp - uc_bsp \n\t" - ";; \n\t" - "ld8 r24 = [r20], uc_pfs_loc - uc_psp \n\t" - "ld8 r1 = [r21], uc_rp - uc_gp \n\t" - ";; \n\t" - "ld8 r25 = [r20], uc_unat_loc - uc_pfs_loc\n\t" - "ld8 r26 = [r21], uc_pr - uc_rp \n\t" - ";; \n\t" - "ld8 r27 = [r20], uc_lc_loc - uc_unat_loc\n\t" - "ld8 r28 = [r21], uc_fpsr_loc - uc_pr \n\t" - ";; \n\t" - "ld8 r29 = [r20], uc_eh_data - uc_lc_loc\n\t" - "ld8 r30 = [r21], uc_eh_data + 8 - uc_fpsr_loc\n\t" - ";; \n\t" - /* Load data for the exception handler. */ - "ld8 r15 = [r20], 16 \n\t" - "ld8 r16 = [r21], 16 \n\t" - ";; \n\t" - "ld8 r17 = [r20] \n\t" - "ld8 r18 = [r21] \n\t" - ";; \n\t" - /* Install the balance of the thread state loaded above. */ - "cmp.ne p6, p0 = r0, r25 \n\t" - "cmp.ne p7, p0 = r0, r27 \n\t" - ";; \n\t" - "(p6) ld8 r25 = [r25] \n\t" - "(p7) ld8 r27 = [r27] \n\t" - ";; \n\t" - "(p7) mov.m ar.unat = r27 \n\t" - "(p6) mov.i ar.pfs = r25 \n\t" - "cmp.ne p9, p0 = r0, r29 \n\t" - ";; \n\t" - "(p9) ld8 r29 = [r29] \n\t" - "cmp.ne p6, p0 = r0, r30 \n\t" - ";; \n\t" - "(p6) ld8 r30 = [r30] \n\t" - /* Don't clobber p6-p9, which are in use at present. */ - "mov pr = r28, ~0x3c0 \n\t" - "(p9) mov.i ar.lc = r29 \n\t" - ";; \n\t" - "mov.m r25 = ar.rsc \n\t" - "(p6) mov.m ar.fpsr = r30 \n\t" - ";; \n\t" - "and r29 = 0x1c, r25 \n\t" - "mov b0 = r26 \n\t" - ";; \n\t" - "mov.m ar.rsc = r29 \n\t" - ";; \n\t" - /* This must be done before setting AR.BSPSTORE, otherwise - AR.BSP will be initialized with a random displacement - below the value we want, based on the current number of - dirty stacked registers. */ - "loadrs \n\t" - "invala \n\t" - ";; \n\t" - "mov.m ar.bspstore = r23 \n\t" - ";; \n\t" - "mov.m ar.rnat = r22 \n\t" - ";; \n\t" - "mov.m ar.rsc = r25 \n\t" - "mov sp = r24 \n\t" - "br.ret.sptk.few b0" - : : "r"(target), "r"(ireg_buf), "r"(ireg_nat), "r"(ireg_pr) - : "r15", "r16", "r17", "r18", "r20", "r21", "r22", - "r23", "r24", "r25", "r26", "r27", "r28", "r29", - "r30", "r31"); - /* NOTREACHED */ - while (1); -} - -static inline _Unwind_Ptr -uw_identify_context (struct _Unwind_Context *context) -{ - return _Unwind_GetIP (context); -} - -#include "unwind.inc" - -#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) -alias (_Unwind_Backtrace); -alias (_Unwind_DeleteException); -alias (_Unwind_FindEnclosingFunction); -alias (_Unwind_ForcedUnwind); -alias (_Unwind_GetBSP); -alias (_Unwind_GetCFA); -alias (_Unwind_GetGR); -alias (_Unwind_GetIP); -alias (_Unwind_GetLanguageSpecificData); -alias (_Unwind_GetRegionStart); -alias (_Unwind_RaiseException); -alias (_Unwind_Resume); -alias (_Unwind_Resume_or_Rethrow); -alias (_Unwind_SetGR); -alias (_Unwind_SetIP); -#endif - -#endif diff --git a/gcc/config/ia64/unwind-ia64.h b/gcc/config/ia64/unwind-ia64.h deleted file mode 100644 index b98f048fdb5..00000000000 --- a/gcc/config/ia64/unwind-ia64.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (C) 1999, 2000, 2001, 2007, 2009 Free Software Foundation, Inc. - Contributed by Andrew MacLeod - Andrew Haley - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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 GCC; see the file COPYING3. If not see - . */ - -struct unw_table_entry -{ - unsigned long start_offset; - unsigned long end_offset; - unsigned long info_offset; -}; - -/* Accessors to fields of an unwind info block header. In this common file to - be visible from all the units involved in a target implementation. */ - -#ifndef __USING_SJLJ_EXCEPTIONS__ -#define UNW_VER(x) ((x) >> 48) -#define UNW_FLAG_MASK 0x0000ffff00000000 -#define UNW_FLAG_OSMASK 0x0000f00000000000 -#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L) -#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L) -#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffL) -#endif - -extern struct unw_table_entry * -_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, - unsigned long *gp, struct unw_table_entry *ent) - __attribute__ ((__visibility__ ("hidden"))); diff --git a/gcc/config/ia64/vms.h b/gcc/config/ia64/vms.h index 847d79afa1d..853e0239d3b 100644 --- a/gcc/config/ia64/vms.h +++ b/gcc/config/ia64/vms.h @@ -139,9 +139,6 @@ STATIC func_ptr __CTOR_LIST__[1] \ /* Define this to be nonzero if static stack checking is supported. */ #define STACK_CHECK_STATIC_BUILTIN 1 -#define UNW_IVMS_MODE(HEADER) (((HEADER) >> 44) & 0x3L) -#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) (!UNW_IVMS_MODE (HEADER)) - /* Minimum amount of stack required to recover from an anticipated stack overflow detection. The default value conveys an estimate of the amount of stack required to propagate an exception. */ diff --git a/gcc/config/picochip/t-picochip b/gcc/config/picochip/t-picochip index ba4394eceeb..4df74a01fc6 100644 --- a/gcc/config/picochip/t-picochip +++ b/gcc/config/picochip/t-picochip @@ -43,9 +43,6 @@ LIB2FUNCS_EXTRA = \ LIB1ASMFUNCS = _mulsc3 _divsc3 LIB1ASMSRC = picochip/libgccExtras/fake_libgcc.asm -# Turn off the building of exception handling libraries. -LIB2ADDEH = - # Turn off ranlib on target libraries. RANLIB_FOR_TARGET = cat diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index 13d317f508a..2c678a3a247 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -209,40 +209,6 @@ /* And similarly for general purpose registers. */ #define GP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) < 32) -/* If the current unwind info (FS) does not contain explicit info - saving R2, then we have to do a minor amount of code reading to - figure out if it was saved. The big problem here is that the - code that does the save/restore is generated by the linker, so - we have no good way to determine at compile time what to do. */ - -#define R_LR 65 - -#ifdef __64BIT__ -#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \ - do { \ - if ((FS)->regs.reg[2].how == REG_UNSAVED) \ - { \ - unsigned int *insn \ - = (unsigned int *) \ - _Unwind_GetGR ((CTX), R_LR); \ - if (*insn == 0xE8410028) \ - _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \ - } \ - } while (0) -#else -#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \ - do { \ - if ((FS)->regs.reg[2].how == REG_UNSAVED) \ - { \ - unsigned int *insn \ - = (unsigned int *) \ - _Unwind_GetGR ((CTX), R_LR); \ - if (*insn == 0x80410014) \ - _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20); \ - } \ - } while (0) -#endif - #define PROFILE_HOOK(LABEL) output_profile_hook (LABEL) /* No version of AIX fully supports AltiVec or 64-bit instructions in diff --git a/gcc/config/rs6000/darwin-fallback.c b/gcc/config/rs6000/darwin-fallback.c deleted file mode 100644 index 4591071ea74..00000000000 --- a/gcc/config/rs6000/darwin-fallback.c +++ /dev/null @@ -1,487 +0,0 @@ -/* Fallback frame-state unwinder for Darwin. - Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#ifdef __ppc__ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "dwarf2.h" -#include "unwind.h" -#include "unwind-dw2.h" -#include -#include -#include -#include - -#define R_LR 65 -#define R_CTR 66 -#define R_CR2 70 -#define R_XER 76 -#define R_VR0 77 -#define R_VRSAVE 109 -#define R_VSCR 110 -#define R_SPEFSCR 112 - -typedef unsigned long reg_unit; - -/* Place in GPRS the parameters to the first 'sc' instruction that would - have been executed if we were returning from this CONTEXT, or - return false if an unexpected instruction is encountered. */ - -static bool -interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context) -{ - uint32_t *pc = (uint32_t *)_Unwind_GetIP (context); - uint32_t cr; - reg_unit lr = (reg_unit) pc; - reg_unit ctr = 0; - uint32_t *invalid_address = NULL; - - int i; - - for (i = 0; i < 13; i++) - gprs[i] = 1; - gprs[1] = _Unwind_GetCFA (context); - for (; i < 32; i++) - gprs[i] = _Unwind_GetGR (context, i); - cr = _Unwind_GetGR (context, R_CR2); - - /* For each supported Libc, we have to track the code flow - all the way back into the kernel. - - This code is believed to support all released Libc/Libsystem builds since - Jaguar 6C115, including all the security updates. To be precise, - - Libc Libsystem Build(s) - 262~1 60~37 6C115 - 262~1 60.2~4 6D52 - 262~1 61~3 6F21-6F22 - 262~1 63~24 6G30-6G37 - 262~1 63~32 6I34-6I35 - 262~1 63~64 6L29-6L60 - 262.4.1~1 63~84 6L123-6R172 - - 320~1 71~101 7B85-7D28 - 320~1 71~266 7F54-7F56 - 320~1 71~288 7F112 - 320~1 71~289 7F113 - 320.1.3~1 71.1.1~29 7H60-7H105 - 320.1.3~1 71.1.1~30 7H110-7H113 - 320.1.3~1 71.1.1~31 7H114 - - That's a big table! It would be insane to try to keep track of - every little detail, so we just read the code itself and do what - it would do. - */ - - for (;;) - { - uint32_t ins = *pc++; - - if ((ins & 0xFC000003) == 0x48000000) /* b instruction */ - { - pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4; - continue; - } - if ((ins & 0xFC600000) == 0x2C000000) /* cmpwi */ - { - int32_t val1 = (int16_t) ins; - int32_t val2 = gprs[ins >> 16 & 0x1F]; - /* Only beq and bne instructions are supported, so we only - need to set the EQ bit. */ - uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C); - if (val1 == val2) - cr |= mask; - else - cr &= ~mask; - continue; - } - if ((ins & 0xFEC38003) == 0x40820000) /* forwards beq/bne */ - { - if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1)) - pc += (ins & 0x7FFC) / 4 - 1; - continue; - } - if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */ - { - gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F] - | gprs [ins >> 21 & 0x1F]); - continue; - } - if (ins >> 26 == 0x0E) /* addi, including li */ - { - reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; - gprs [ins >> 21 & 0x1F] = src + (int16_t) ins; - continue; - } - if (ins >> 26 == 0x0F) /* addis, including lis */ - { - reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; - gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16); - continue; - } - if (ins >> 26 == 0x20) /* lwz */ - { - reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; - uint32_t *p = (uint32_t *)(src + (int16_t) ins); - if (p == invalid_address) - return false; - gprs [ins >> 21 & 0x1F] = *p; - continue; - } - if (ins >> 26 == 0x21) /* lwzu */ - { - uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins); - if (p == invalid_address) - return false; - gprs [ins >> 21 & 0x1F] = *p; - continue; - } - if (ins >> 26 == 0x24) /* stw */ - /* What we hope this is doing is '--in_sigtramp'. We don't want - to actually store to memory, so just make a note of the - address and refuse to load from it. */ - { - reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; - uint32_t *p = (uint32_t *)(src + (int16_t) ins); - if (p == NULL || invalid_address != NULL) - return false; - invalid_address = p; - continue; - } - if (ins >> 26 == 0x2E) /* lmw */ - { - reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; - uint32_t *p = (uint32_t *)(src + (int16_t) ins); - int i; - - for (i = (ins >> 21 & 0x1F); i < 32; i++) - { - if (p == invalid_address) - return false; - gprs[i] = *p++; - } - continue; - } - if ((ins & 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */ - { - lr = gprs [ins >> 21 & 0x1F]; - continue; - } - if ((ins & 0xFC1FFFFF) == 0x7c0802a6) /* mflr */ - { - gprs [ins >> 21 & 0x1F] = lr; - continue; - } - if ((ins & 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */ - { - ctr = gprs [ins >> 21 & 0x1F]; - continue; - } - /* The PowerPC User's Manual says that bit 11 of the mtcrf - instruction is reserved and should be set to zero, but it - looks like the Darwin assembler doesn't do that... */ - if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */ - { - int i; - uint32_t mask = 0; - for (i = 0; i < 8; i++) - mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i; - cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask); - continue; - } - if (ins == 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */ - { - lr = (reg_unit) pc; - continue; - } - if (ins == 0x4e800420) /* bctr */ - { - pc = (uint32_t *) ctr; - continue; - } - if (ins == 0x44000002) /* sc */ - return true; - - return false; - } -} - -/* We used to include and , - but they change so much between different Darwin system versions - that it's much easier to just write the structures involved here - directly. */ - -/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */ -#define UC_TRAD 1 -#define UC_TRAD_VEC 6 -#define UC_TRAD64 20 -#define UC_TRAD64_VEC 25 -#define UC_FLAVOR 30 -#define UC_FLAVOR_VEC 35 -#define UC_FLAVOR64 40 -#define UC_FLAVOR64_VEC 45 -#define UC_DUAL 50 -#define UC_DUAL_VEC 55 - -struct gcc_ucontext -{ - int onstack; - sigset_t sigmask; - void * stack_sp; - size_t stack_sz; - int stack_flags; - struct gcc_ucontext *link; - size_t mcsize; - struct gcc_mcontext32 *mcontext; -}; - -struct gcc_float_vector_state -{ - double fpregs[32]; - uint32_t fpscr_pad; - uint32_t fpscr; - uint32_t save_vr[32][4]; - uint32_t save_vscr[4]; -}; - -struct gcc_mcontext32 { - uint32_t dar; - uint32_t dsisr; - uint32_t exception; - uint32_t padding1[5]; - uint32_t srr0; - uint32_t srr1; - uint32_t gpr[32]; - uint32_t cr; - uint32_t xer; - uint32_t lr; - uint32_t ctr; - uint32_t mq; - uint32_t vrsave; - struct gcc_float_vector_state fvs; -}; - -/* These are based on /usr/include/ppc/ucontext.h and - /usr/include/mach/ppc/thread_status.h, but rewritten to be more - convenient, to compile on Jaguar, and to work around Radar 3712064 - on Panther, which is that the 'es' field of 'struct mcontext64' has - the wrong type (doh!). */ - -struct gcc_mcontext64 { - uint64_t dar; - uint32_t dsisr; - uint32_t exception; - uint32_t padding1[4]; - uint64_t srr0; - uint64_t srr1; - uint32_t gpr[32][2]; - uint32_t cr; - uint32_t xer[2]; /* These are arrays because the original structure has them misaligned. */ - uint32_t lr[2]; - uint32_t ctr[2]; - uint32_t vrsave; - struct gcc_float_vector_state fvs; -}; - -#define UC_FLAVOR_SIZE \ - (sizeof (struct gcc_mcontext32) - 33*16) - -#define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32)) - -#define UC_FLAVOR64_SIZE \ - (sizeof (struct gcc_mcontext64) - 33*16) - -#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64)) - -/* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS - to represent the execution of a signal return; or, if not a signal - return, return false. */ - -static bool -handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32], - _Unwind_Ptr old_cfa) -{ - struct gcc_ucontext *uctx; - bool is_64, is_vector; - struct gcc_float_vector_state * float_vector_state; - _Unwind_Ptr new_cfa; - int i; - static _Unwind_Ptr return_addr; - - /* Yay! We're in a Libc that we understand, and it's made a - system call. In Jaguar, this is a direct system call with value 103; - in Panther and Tiger it is a SYS_syscall call for system call number 184, - and in Leopard it is a direct syscall with number 184. */ - - if (gprs[0] == 0x67 /* SYS_SIGRETURN */) - { - uctx = (struct gcc_ucontext *) gprs[3]; - is_vector = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE - || uctx->mcsize == UC_FLAVOR_VEC_SIZE); - is_64 = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE - || uctx->mcsize == UC_FLAVOR64_SIZE); - } - else if (gprs[0] == 0 /* SYS_syscall */ && gprs[3] == 184) - { - int ctxstyle = gprs[5]; - uctx = (struct gcc_ucontext *) gprs[4]; - is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC - || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC); - is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC - || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64); - } - else if (gprs[0] == 184 /* SYS_sigreturn */) - { - int ctxstyle = gprs[4]; - uctx = (struct gcc_ucontext *) gprs[3]; - is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC - || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC); - is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC - || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64); - } - else - return false; - -#define set_offset(r, addr) \ - (fs->regs.reg[r].how = REG_SAVED_OFFSET, \ - fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa) - - /* Restore even the registers that are not call-saved, since they - might be being used in the prologue to save other registers, - for instance GPR0 is sometimes used to save LR. */ - - /* Handle the GPRs, and produce the information needed to do the rest. */ - if (is_64) - { - /* The context is 64-bit, but it doesn't carry any extra information - for us because only the low 32 bits of the registers are - call-saved. */ - struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext; - int i; - - float_vector_state = &m64->fvs; - - new_cfa = m64->gpr[1][1]; - - set_offset (R_CR2, &m64->cr); - for (i = 0; i < 32; i++) - set_offset (i, m64->gpr[i] + 1); - set_offset (R_XER, m64->xer + 1); - set_offset (R_LR, m64->lr + 1); - set_offset (R_CTR, m64->ctr + 1); - if (is_vector) - set_offset (R_VRSAVE, &m64->vrsave); - - /* Sometimes, srr0 points to the instruction that caused the exception, - and sometimes to the next instruction to be executed; we want - the latter. */ - if (m64->exception == 3 || m64->exception == 4 - || m64->exception == 6 - || (m64->exception == 7 && !(m64->srr1 & 0x10000))) - return_addr = m64->srr0 + 4; - else - return_addr = m64->srr0; - } - else - { - struct gcc_mcontext32 *m = uctx->mcontext; - int i; - - float_vector_state = &m->fvs; - - new_cfa = m->gpr[1]; - - set_offset (R_CR2, &m->cr); - for (i = 0; i < 32; i++) - set_offset (i, m->gpr + i); - set_offset (R_XER, &m->xer); - set_offset (R_LR, &m->lr); - set_offset (R_CTR, &m->ctr); - - if (is_vector) - set_offset (R_VRSAVE, &m->vrsave); - - /* Sometimes, srr0 points to the instruction that caused the exception, - and sometimes to the next instruction to be executed; we want - the latter. */ - if (m->exception == 3 || m->exception == 4 - || m->exception == 6 - || (m->exception == 7 && !(m->srr1 & 0x10000))) - return_addr = m->srr0 + 4; - else - return_addr = m->srr0; - } - - fs->regs.cfa_how = CFA_REG_OFFSET; - fs->regs.cfa_reg = STACK_POINTER_REGNUM; - fs->regs.cfa_offset = new_cfa - old_cfa;; - - /* The choice of column for the return address is somewhat tricky. - Fortunately, the actual choice is private to this file, and - the space it's reserved from is the GCC register space, not the - DWARF2 numbering. So any free element of the right size is an OK - choice. Thus: */ - fs->retaddr_column = ARG_POINTER_REGNUM; - /* FIXME: this should really be done using a DWARF2 location expression, - not using a static variable. In fact, this entire file should - be implemented in DWARF2 expressions. */ - set_offset (ARG_POINTER_REGNUM, &return_addr); - - for (i = 0; i < 32; i++) - set_offset (32 + i, float_vector_state->fpregs + i); - set_offset (R_SPEFSCR, &float_vector_state->fpscr); - - if (is_vector) - { - for (i = 0; i < 32; i++) - set_offset (R_VR0 + i, float_vector_state->save_vr + i); - set_offset (R_VSCR, float_vector_state->save_vscr); - } - - return true; -} - -/* This is also prototyped in rs6000/darwin.h, inside the - MD_FALLBACK_FRAME_STATE_FOR macro. */ -extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context, - _Unwind_FrameState *fs); - -/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro, - returning true iff the frame was a sigreturn() frame that we - can understand. */ - -bool -_Unwind_fallback_frame_state_for (struct _Unwind_Context *context, - _Unwind_FrameState *fs) -{ - reg_unit gprs[32]; - - if (!interpret_libc (gprs, context)) - return false; - return handle_syscall (fs, gprs, _Unwind_GetCFA (context)); -} -#endif diff --git a/gcc/config/rs6000/t-darwin b/gcc/config/rs6000/t-darwin index 8113b9ecbcb..27fc07b69b3 100644 --- a/gcc/config/rs6000/t-darwin +++ b/gcc/config/rs6000/t-darwin @@ -1,5 +1,5 @@ # Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, -# 2007 Free Software Foundation, Inc. +# 2007, 2011 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -40,7 +40,5 @@ TARGET_LIBGCC2_CFLAGS = -Wa,-force_cpusubtype_ALL -pipe -mmacosx-version-min=10. # Export the _xlq* symbols from darwin-ldouble.c. SHLIB_MAPFILES += $(srcdir)/config/rs6000/libgcc-ppc64.ver -LIB2ADDEH += $(srcdir)/config/rs6000/darwin-fallback.c - darwin-fpsave.o: $(srcdir)/config/rs6000/darwin-asm.h darwin-tramp.o: $(srcdir)/config/rs6000/darwin-asm.h diff --git a/gcc/config/sh/t-sh b/gcc/config/sh/t-sh index a897bfffb47..27cbd3d3e88 100644 --- a/gcc/config/sh/t-sh +++ b/gcc/config/sh/t-sh @@ -1,5 +1,5 @@ # Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2006, 2008, 2009 Free Software Foundation, Inc. +# 2003, 2004, 2006, 2008, 2009, 2011 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -149,7 +149,7 @@ $(T)sdivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PAS $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_sdivsi3_i4i -x assembler-with-cpp $< $(T)udivsi3_i4i-Os-4-200.o: $(srcdir)/config/sh/lib1funcs-Os-4-200.asm $(GCC_PASSES) $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -c -o $@ -DL_udivsi3_i4i -x assembler-with-cpp $< -$(T)unwind-dw2-Os-4-200.o: $(srcdir)/unwind-dw2.c $(srcdir)/unwind-generic.h unwind-pe.h unwind.inc unwind-dw2-fde.h unwind-dw2.h $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h config.status stmp-int-hdrs tsystem.h $(GCC_PASSES) +$(T)unwind-dw2-Os-4-200.o: $(srcdir)/../libgcc/unwind-dw2.c $(srcdir)/../libgcc/unwind-generic.h $(srcdir)/../libgcc/unwind-pe.h $(srcdir)/../libgcc/unwind.inc $(srcdir)/../libgcc/unwind-dw2-fde.h $(srcdir)/../libgcc/unwind-dw2.h $(CONFIG_H) coretypes.h $(TM_H) $(MACHMODE_H) longlong.h config.status stmp-int-hdrs tsystem.h $(GCC_PASSES) $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) $(LIBGCC2_CFLAGS) $(INCLUDES) $(vis_hide) -fexceptions -Os -c -o $@ $< OBJS_Os_4_200=$(T)sdivsi3_i4i-Os-4-200.o $(T)udivsi3_i4i-Os-4-200.o $(T)unwind-dw2-Os-4-200.o $(T)libgcc-Os-4-200.a: $(OBJS_Os_4_200) $(GCC_PASSES) diff --git a/gcc/config/spu/t-spu-elf b/gcc/config/spu/t-spu-elf index 5189f28584d..ab680f5be88 100644 --- a/gcc/config/spu/t-spu-elf +++ b/gcc/config/spu/t-spu-elf @@ -47,9 +47,6 @@ LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/spu/float_unssidf.c \ $(srcdir)/config/spu/divmodti4.c \ $(srcdir)/config/spu/divv2df3.c -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c - # We want fine grained libraries, so use the new code to build the # floating point emulation libraries. FPBIT = fp-bit.c diff --git a/gcc/config/t-darwin b/gcc/config/t-darwin index 9e77395998d..d952bd39273 100644 --- a/gcc/config/t-darwin +++ b/gcc/config/t-darwin @@ -42,10 +42,6 @@ darwin-driver.o: $(srcdir)/config/darwin-driver.c \ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/darwin-driver.c -# Use unwind-dw2-fde-darwin -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-darwin.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c - # -pipe because there's an assembler bug, 4077127, which causes # it to not properly process the first # directive, causing temporary # file names to appear in stabs, causing the bootstrap to fail. Using -pipe diff --git a/gcc/config/t-freebsd b/gcc/config/t-freebsd index af2df24f105..0680618a6ec 100644 --- a/gcc/config/t-freebsd +++ b/gcc/config/t-freebsd @@ -3,7 +3,3 @@ CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC # Compile libgcc.a with pic. TARGET_LIBGCC2_CFLAGS += -fPIC - -# Use unwind-dw2-fde-glibc -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/gcc/config/t-libunwind b/gcc/config/t-libunwind index 6fdaf676b37..6b8d2dd1292 100644 --- a/gcc/config/t-libunwind +++ b/gcc/config/t-libunwind @@ -1,4 +1,4 @@ -# Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2004, 2011 Free Software Foundation, Inc. # # This file is part of GCC. # @@ -22,9 +22,6 @@ # so that the resulting libgcc_s.so has the necessary DT_NEEDED entry for # libunwind. SHLIB_LC = -lunwind -lc -LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ - $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c -LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c T_CFLAGS += -DUSE_LIBUNWIND_EXCEPTIONS TARGET_LIBGCC2_CFLAGS += -DUSE_GAS_SYMVER diff --git a/gcc/config/t-libunwind-elf b/gcc/config/t-libunwind-elf deleted file mode 100644 index 5ae0d62de25..00000000000 --- a/gcc/config/t-libunwind-elf +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2004, 2005 Free Software Foundation, Inc. -# -# This file is part of GCC. -# -# GCC 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 3, or (at your option) -# any later version. -# -# GCC 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 GCC; see the file COPYING3. If not see -# . - -# Build libunwind for ELF with the GNU linker. - -# Use unwind-dw2-fde-glibc -LIBUNWIND = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c -LIBUNWINDDEP = unwind.inc unwind-dw2-fde.h unwind-dw2-fde.c - -SHLIBUNWIND_SOVERSION = 7 -SHLIBUNWIND_SONAME = @shlib_base_name@.so.$(SHLIBUNWIND_SOVERSION) - -SHLIBUNWIND_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared \ - -nodefaultlibs -Wl,-h,$(SHLIBUNWIND_SONAME) \ - -Wl,-z,text -Wl,-z,defs -o $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).tmp \ - @multilib_flags@ $(SHLIB_OBJS) -lc && \ - rm -f $(SHLIB_DIR)/$(SHLIB_SOLINK) && \ - if [ -f $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) ]; then \ - mv -f $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) \ - $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).backup; \ - else true; fi && \ - mv $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).tmp \ - $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) && \ - $(LN_S) $(SHLIBUNWIND_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK) - -# $(slibdir) double quoted to protect it from expansion while building -# libgcc.mk. We want this delayed until actual install time. -SHLIBUNWIND_INSTALL = \ - $$(SHELL) $$(srcdir)/mkinstalldirs $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL); \ - $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) \ - $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIBUNWIND_SONAME); \ - rm -f $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK); \ - $(LN_S) $(SHLIBUNWIND_SONAME) \ - $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK) diff --git a/gcc/config/t-linux b/gcc/config/t-linux index 039fa27ae82..64d19ca8dd7 100644 --- a/gcc/config/t-linux +++ b/gcc/config/t-linux @@ -25,7 +25,3 @@ TARGET_LIBGCC2_CFLAGS = -fPIC # Override t-slibgcc-elf-ver to export some libgcc symbols with # the symbol versions that glibc used. SHLIB_MAPFILES += $(srcdir)/config/libgcc-glibc.ver - -# Use unwind-dw2-fde-glibc -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/gcc/config/t-sol2 b/gcc/config/t-sol2 index 73fd8eb3667..f53da4d3ca6 100644 --- a/gcc/config/t-sol2 +++ b/gcc/config/t-sol2 @@ -31,8 +31,3 @@ sol2.o: $(srcdir)/config/sol2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ # This is required by gcc/ada/gcc-interface/Makefile.in. TARGET_LIBGCC2_CFLAGS = -fPIC - -# Use unwind-dw2-fde-glibc.c. Unless linker support and dl_iterate_phdr -# are present, automatically falls back to unwind-dw2-fde.c. -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/gcc/config/xtensa/t-xtensa b/gcc/config/xtensa/t-xtensa index c3d98ae30b5..641e6fe7620 100644 --- a/gcc/config/xtensa/t-xtensa +++ b/gcc/config/xtensa/t-xtensa @@ -1,4 +1,5 @@ -# Copyright (C) 2002, 2003, 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2006, 2007, 2008, 2011 +# Free Software Foundation, Inc. # # This file is part of GCC. # @@ -29,8 +30,6 @@ LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3 _udivsi3 _umodsi3 \ _truncdfsf2 _extendsfdf2 LIB2FUNCS_EXTRA = $(srcdir)/config/xtensa/lib2funcs.S -LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \ - $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c $(T)crti.o: $(srcdir)/config/xtensa/crti.asm $(GCC_PASSES) $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.c b/gcc/config/xtensa/unwind-dw2-xtensa.c deleted file mode 100644 index 54daf7637ce..00000000000 --- a/gcc/config/xtensa/unwind-dw2-xtensa.c +++ /dev/null @@ -1,544 +0,0 @@ -/* DWARF2 exception handling and frame unwinding for Xtensa. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2011 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "dwarf2.h" -#include "unwind.h" -#ifdef __USING_SJLJ_EXCEPTIONS__ -# define NO_SIZE_OF_ENCODED_VALUE -#endif -#include "unwind-pe.h" -#include "unwind-dw2-fde.h" -#include "unwind-dw2-xtensa.h" - -#ifndef __USING_SJLJ_EXCEPTIONS__ - -/* The standard CIE and FDE structures work fine for Xtensa but the - variable-size register window save areas are not a good fit for the rest - of the standard DWARF unwinding mechanism. Nor is that mechanism - necessary, since the register save areas are always in fixed locations - in each stack frame. This file is a stripped down and customized version - of the standard DWARF unwinding code. It needs to be customized to have - builtin logic for finding the save areas and also to track the stack - pointer value (besides the CFA) while unwinding since the primary save - area is located below the stack pointer. It is stripped down to reduce - code size and ease the maintenance burden of tracking changes in the - standard version of the code. */ - -#ifndef DWARF_REG_TO_UNWIND_COLUMN -#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) -#endif - -#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF - -/* This is the register and unwind state for a particular frame. This - provides the information necessary to unwind up past a frame and return - to its caller. */ -struct _Unwind_Context -{ - /* Track register window save areas of 4 registers each, instead of - keeping separate addresses for the individual registers. */ - _Unwind_Word *reg[4]; - - void *cfa; - void *sp; - void *ra; - - /* Cache the 2 high bits to replace the window size in return addresses. */ - _Unwind_Word ra_high_bits; - - void *lsda; - struct dwarf_eh_bases bases; - /* Signal frame context. */ -#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) - _Unwind_Word flags; - /* 0 for now, can be increased when further fields are added to - struct _Unwind_Context. */ - _Unwind_Word version; -}; - - -/* Read unaligned data from the instruction buffer. */ - -union unaligned -{ - void *p; -} __attribute__ ((packed)); - -static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); -static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, - _Unwind_FrameState *); - -static inline void * -read_pointer (const void *p) { const union unaligned *up = p; return up->p; } - -static inline _Unwind_Word -_Unwind_IsSignalFrame (struct _Unwind_Context *context) -{ - return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0; -} - -static inline void -_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) -{ - if (val) - context->flags |= SIGNAL_FRAME_BIT; - else - context->flags &= ~SIGNAL_FRAME_BIT; -} - -/* Get the value of register INDEX as saved in CONTEXT. */ - -inline _Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) -{ - _Unwind_Word *ptr; - - index = DWARF_REG_TO_UNWIND_COLUMN (index); - ptr = context->reg[index >> 2] + (index & 3); - - return *ptr; -} - -/* Get the value of the CFA as saved in CONTEXT. */ - -_Unwind_Word -_Unwind_GetCFA (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->cfa; -} - -/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ - -inline void -_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) -{ - _Unwind_Word *ptr; - - index = DWARF_REG_TO_UNWIND_COLUMN (index); - ptr = context->reg[index >> 2] + (index & 3); - - *ptr = val; -} - -/* Retrieve the return address for CONTEXT. */ - -inline _Unwind_Ptr -_Unwind_GetIP (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->ra; -} - -/* Retrieve the return address and flag whether that IP is before - or after first not yet fully executed instruction. */ - -inline _Unwind_Ptr -_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) -{ - *ip_before_insn = _Unwind_IsSignalFrame (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; -} - -void * -_Unwind_FindEnclosingFunction (void *pc) -{ - struct dwarf_eh_bases bases; - const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); - if (fde) - return bases.func; - else - return NULL; -} - -_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; -} - -#include "md-unwind-support.h" - -/* 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 (const struct dwarf_cie *cie, struct _Unwind_Context *context, - _Unwind_FrameState *fs) -{ - const unsigned char *aug = cie->augmentation; - const unsigned char *p = aug + strlen ((const char *)aug) + 1; - const unsigned char *ret = NULL; - _uleb128_t utmp; - _sleb128_t stmp; - - /* g++ v2 "eh" has pointer immediately following augmentation string, - so it must be handled first. */ - if (aug[0] == 'e' && aug[1] == 'h') - { - fs->eh_ptr = read_pointer (p); - p += sizeof (void *); - aug += 2; - } - - /* Immediately following the augmentation are the code and - data alignment and return address column. */ - p = read_uleb128 (p, &utmp); - p = read_sleb128 (p, &stmp); - if (cie->version == 1) - fs->retaddr_column = *p++; - else - { - p = read_uleb128 (p, &utmp); - fs->retaddr_column = (_Unwind_Word)utmp; - } - 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, &utmp); - ret = p + utmp; - - fs->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') - { - 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') - { - _Unwind_Ptr personality; - - p = read_encoded_value (context, *p, p + 1, &personality); - fs->personality = (_Unwind_Personality_Fn) personality; - aug += 1; - } - - /* "S" indicates a signal frame. */ - else if (aug[0] == 'S') - { - fs->signal_frame = 1; - aug += 1; - } - - /* Otherwise we have an unknown augmentation string. - Bail unless we saw a 'z' prefix. */ - else - return ret; - } - - return ret ? ret : p; -} - -/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for - its caller and decode it into FS. This function also sets the - lsda member of CONTEXT, as it is really information - about the caller's frame. */ - -static _Unwind_Reason_Code -uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - const struct dwarf_fde *fde; - const struct dwarf_cie *cie; - const unsigned char *aug; - int window_size; - _Unwind_Word *ra_ptr; - - memset (fs, 0, sizeof (*fs)); - context->lsda = 0; - - fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, - &context->bases); - if (fde == NULL) - { -#ifdef MD_FALLBACK_FRAME_STATE_FOR - _Unwind_Reason_Code reason; - /* Couldn't find frame unwind info for this function. Try a - target-specific fallback mechanism. This will necessarily - not provide a personality routine or LSDA. */ - reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs); - if (reason != _URC_END_OF_STACK) - return reason; -#endif - /* The frame was not recognized and handled by the fallback function, - but it is not really the end of the stack. Fall through here and - unwind it anyway. */ - } - else - { - cie = get_cie (fde); - if (extract_cie_info (cie, context, fs) == NULL) - /* CIE contained unknown augmentation. */ - return _URC_FATAL_PHASE1_ERROR; - - /* Locate augmentation for the fde. */ - aug = (const unsigned char *) fde + sizeof (*fde); - aug += 2 * size_of_encoded_value (fs->fde_encoding); - if (fs->saw_z) - { - _uleb128_t i; - aug = read_uleb128 (aug, &i); - } - if (fs->lsda_encoding != DW_EH_PE_omit) - { - _Unwind_Ptr lsda; - - aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); - context->lsda = (void *) lsda; - } - } - - /* Check for the end of the stack. This needs to be checked after - the MD_FALLBACK_FRAME_STATE_FOR check for signal frames because - the contents of context->reg[0] are undefined at a signal frame, - and register a0 may appear to be zero. (The return address in - context->ra comes from register a4 or a8). */ - ra_ptr = context->reg[0]; - if (ra_ptr && *ra_ptr == 0) - return _URC_END_OF_STACK; - - /* Find the window size from the high bits of the return address. */ - if (ra_ptr) - window_size = (*ra_ptr >> 30) * 4; - else - window_size = 8; - - fs->retaddr_column = window_size; - - return _URC_NO_REASON; -} - -static void -uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - struct _Unwind_Context orig_context = *context; - _Unwind_Word *sp, *cfa, *next_cfa; - int i; - - if (fs->signal_regs) - { - cfa = (_Unwind_Word *) fs->signal_regs[1]; - next_cfa = (_Unwind_Word *) cfa[-3]; - - for (i = 0; i < 4; i++) - context->reg[i] = fs->signal_regs + (i << 2); - } - else - { - int window_size = fs->retaddr_column >> 2; - - sp = (_Unwind_Word *) orig_context.sp; - cfa = (_Unwind_Word *) orig_context.cfa; - next_cfa = (_Unwind_Word *) cfa[-3]; - - /* Registers a0-a3 are in the save area below sp. */ - context->reg[0] = sp - 4; - - /* Find the extra save area below next_cfa. */ - for (i = 1; i < window_size; i++) - context->reg[i] = next_cfa - 4 * (1 + window_size - i); - - /* Remaining registers rotate from previous save areas. */ - for (i = window_size; i < 4; i++) - context->reg[i] = orig_context.reg[i - window_size]; - } - - context->sp = cfa; - context->cfa = next_cfa; - - _Unwind_SetSignalFrame (context, fs->signal_frame); -} - -/* CONTEXT describes the unwind state for a frame, and FS describes the FDE - of its caller. Update CONTEXT to refer to the caller as well. Note - that the lsda member is not updated here, but later in - uw_frame_state_for. */ - -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. */ - if (fs->signal_ra != 0) - context->ra = (void *) fs->signal_ra; - else - context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column) - & XTENSA_RA_FIELD_MASK) | context->ra_high_bits); -} - -static void -uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - uw_update_context (context, fs); -} - -/* 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 \ - { \ - __builtin_unwind_init (); \ - uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ - __builtin_return_address (0)); \ - } \ - while (0) - -static void __attribute__((noinline)) -uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa, - void *outer_ra) -{ - void *ra = __builtin_return_address (0); - void *cfa = __builtin_dwarf_cfa (); - _Unwind_FrameState fs; - - memset (context, 0, sizeof (struct _Unwind_Context)); - context->ra = ra; - - memset (&fs, 0, sizeof (fs)); - fs.retaddr_column = 8; - context->sp = cfa; - context->cfa = outer_cfa; - context->ra_high_bits = - ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK; - uw_update_context_1 (context, &fs); - - context->ra = 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 long -uw_install_context_1 (struct _Unwind_Context *current, - struct _Unwind_Context *target) -{ - long i; - - /* The eh_return insn assumes a window size of 8, so don't bother copying - the save areas for registers a8-a15 since they won't be reloaded. */ - for (i = 0; i < 2; ++i) - { - void *c = current->reg[i]; - void *t = target->reg[i]; - - if (t && c && t != c) - memcpy (c, t, 4 * sizeof (_Unwind_Word)); - } - - return 0; -} - -static inline _Unwind_Ptr -uw_identify_context (struct _Unwind_Context *context) -{ - return _Unwind_GetCFA (context); -} - - -#include "unwind.inc" - -#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) -alias (_Unwind_Backtrace); -alias (_Unwind_DeleteException); -alias (_Unwind_FindEnclosingFunction); -alias (_Unwind_ForcedUnwind); -alias (_Unwind_GetDataRelBase); -alias (_Unwind_GetTextRelBase); -alias (_Unwind_GetCFA); -alias (_Unwind_GetGR); -alias (_Unwind_GetIP); -alias (_Unwind_GetLanguageSpecificData); -alias (_Unwind_GetRegionStart); -alias (_Unwind_RaiseException); -alias (_Unwind_Resume); -alias (_Unwind_Resume_or_Rethrow); -alias (_Unwind_SetGR); -alias (_Unwind_SetIP); -#endif - -#endif /* !USING_SJLJ_EXCEPTIONS */ diff --git a/gcc/config/xtensa/unwind-dw2-xtensa.h b/gcc/config/xtensa/unwind-dw2-xtensa.h deleted file mode 100644 index d13b3264c99..00000000000 --- a/gcc/config/xtensa/unwind-dw2-xtensa.h +++ /dev/null @@ -1,50 +0,0 @@ -/* DWARF2 frame unwind data structure for Xtensa. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, - 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* 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 - -/* Xtensa's variable-size register window save areas can be unwound without - any unwind info. This is a stripped down version of the standard DWARF - _Unwind_FrameState. */ -typedef struct -{ - /* The information we care about from the CIE/FDE. */ - _Unwind_Personality_Fn personality; - _Unwind_Word retaddr_column; - unsigned char fde_encoding; - unsigned char lsda_encoding; - unsigned char saw_z; - unsigned char signal_frame; - void *eh_ptr; - - /* Saved registers for a signal frame. */ - _Unwind_Word *signal_regs; - _Unwind_Word signal_ra; -} _Unwind_FrameState; - diff --git a/gcc/configure b/gcc/configure index 63e44c5e43d..88bb116dc1f 100755 --- a/gcc/configure +++ b/gcc/configure @@ -894,7 +894,6 @@ enable_rpath with_libiconv_prefix enable_initfini_array enable_sjlj_exceptions -with_system_libunwind enable_secureplt enable_leading_mingw64_underscores enable_cld @@ -1659,7 +1658,6 @@ Optional Packages: --with-gnu-ld assume the C compiler uses GNU ld default=no --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib --without-libiconv-prefix don't search for libiconv in includedir and libdir - --with-system-libunwind use installed libunwind --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] @@ -10855,46 +10853,6 @@ _ACEOF fi -# For platforms with the unwind ABI which includes an unwind library, -# libunwind, we can choose to use the system libunwind. -# config.gcc also contains tests of with_system_libunwind. - - -# Check whether --with-system-libunwind was given. -if test "${with_system_libunwind+set}" = set; then : - withval=$with_system_libunwind; -fi - - # If system-libunwind was not specifically set, pick a default setting. - if test x$with_system_libunwind = x; then - case ${target} in - ia64-*-hpux*) with_system_libunwind=yes ;; - *) with_system_libunwind=no ;; - esac - fi - # Based on system-libunwind and target, do we have ipinfo? - if test x$with_system_libunwind = xyes; then - case ${target} in - ia64-*-*) have_unwind_getipinfo=no ;; - *) have_unwind_getipinfo=yes ;; - esac - else - # Darwin before version 9 does not have _Unwind_GetIPInfo. - - case ${target} in - *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;; - *) have_unwind_getipinfo=yes ;; - esac - - fi - - if test x$have_unwind_getipinfo = xyes; then - -$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h - - fi - - # -------------------------------------------------------- # Build, host, and target specific configuration fragments # -------------------------------------------------------- @@ -17805,7 +17763,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17808 "configure" +#line 17766 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17911,7 +17869,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17914 "configure" +#line 17872 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/gcc/configure.ac b/gcc/configure.ac index c71281cbeb2..81345d6f328 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -1184,11 +1184,6 @@ if test $force_sjlj_exceptions = yes; then [Define 0/1 to force the choice for exception handling model.]) fi -# For platforms with the unwind ABI which includes an unwind library, -# libunwind, we can choose to use the system libunwind. -# config.gcc also contains tests of with_system_libunwind. -GCC_CHECK_UNWIND_GETIPINFO - # -------------------------------------------------------- # Build, host, and target specific configuration fragments # -------------------------------------------------------- diff --git a/gcc/emutls.c b/gcc/emutls.c deleted file mode 100644 index b7ee3bdfa7c..00000000000 --- a/gcc/emutls.c +++ /dev/null @@ -1,202 +0,0 @@ -/* TLS emulation. - Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc. - Contributed by Jakub Jelinek . - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "gthr.h" - -typedef unsigned int word __attribute__((mode(word))); -typedef unsigned int pointer __attribute__((mode(pointer))); - -struct __emutls_object -{ - word size; - word align; - union { - pointer offset; - void *ptr; - } loc; - void *templ; -}; - -struct __emutls_array -{ - pointer size; - void **data[]; -}; - -void *__emutls_get_address (struct __emutls_object *); -void __emutls_register_common (struct __emutls_object *, word, word, void *); - -#ifdef __GTHREADS -#ifdef __GTHREAD_MUTEX_INIT -static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT; -#else -static __gthread_mutex_t emutls_mutex; -#endif -static __gthread_key_t emutls_key; -static pointer emutls_size; - -static void -emutls_destroy (void *ptr) -{ - struct __emutls_array *arr = ptr; - pointer size = arr->size; - pointer i; - - for (i = 0; i < size; ++i) - { - if (arr->data[i]) - free (arr->data[i][-1]); - } - - free (ptr); -} - -static void -emutls_init (void) -{ -#ifndef __GTHREAD_MUTEX_INIT - __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex); -#endif - if (__gthread_key_create (&emutls_key, emutls_destroy) != 0) - abort (); -} -#endif - -static void * -emutls_alloc (struct __emutls_object *obj) -{ - void *ptr; - void *ret; - - /* We could use here posix_memalign if available and adjust - emutls_destroy accordingly. */ - if (obj->align <= sizeof (void *)) - { - ptr = malloc (obj->size + sizeof (void *)); - if (ptr == NULL) - abort (); - ((void **) ptr)[0] = ptr; - ret = ptr + sizeof (void *); - } - else - { - ptr = malloc (obj->size + sizeof (void *) + obj->align - 1); - if (ptr == NULL) - abort (); - ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1)) - & ~(pointer)(obj->align - 1)); - ((void **) ret)[-1] = ptr; - } - - if (obj->templ) - memcpy (ret, obj->templ, obj->size); - else - memset (ret, 0, obj->size); - - return ret; -} - -void * -__emutls_get_address (struct __emutls_object *obj) -{ - if (! __gthread_active_p ()) - { - if (__builtin_expect (obj->loc.ptr == NULL, 0)) - obj->loc.ptr = emutls_alloc (obj); - return obj->loc.ptr; - } - -#ifndef __GTHREADS - abort (); -#else - pointer offset = obj->loc.offset; - - if (__builtin_expect (offset == 0, 0)) - { - static __gthread_once_t once = __GTHREAD_ONCE_INIT; - __gthread_once (&once, emutls_init); - __gthread_mutex_lock (&emutls_mutex); - offset = obj->loc.offset; - if (offset == 0) - { - offset = ++emutls_size; - obj->loc.offset = offset; - } - __gthread_mutex_unlock (&emutls_mutex); - } - - struct __emutls_array *arr = __gthread_getspecific (emutls_key); - if (__builtin_expect (arr == NULL, 0)) - { - pointer size = offset + 32; - arr = calloc (size + 1, sizeof (void *)); - if (arr == NULL) - abort (); - arr->size = size; - __gthread_setspecific (emutls_key, (void *) arr); - } - else if (__builtin_expect (offset > arr->size, 0)) - { - pointer orig_size = arr->size; - pointer size = orig_size * 2; - if (offset > size) - size = offset + 32; - arr = realloc (arr, (size + 1) * sizeof (void *)); - if (arr == NULL) - abort (); - arr->size = size; - memset (arr->data + orig_size, 0, - (size - orig_size) * sizeof (void *)); - __gthread_setspecific (emutls_key, (void *) arr); - } - - void *ret = arr->data[offset - 1]; - if (__builtin_expect (ret == NULL, 0)) - { - ret = emutls_alloc (obj); - arr->data[offset - 1] = ret; - } - return ret; -#endif -} - -void -__emutls_register_common (struct __emutls_object *obj, - word size, word align, void *templ) -{ - if (obj->size < size) - { - obj->size = size; - obj->templ = NULL; - } - if (obj->align < align) - obj->align = align; - if (templ && size == obj->size) - obj->templ = templ; -} diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index 1123a00424d..610ca9ba7d0 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,9 @@ +2011-08-05 Rainer Orth + + * EXCLUDES (unwind-c.c, unwind-dw2-fde-darwin.c) + (unwind-dw2-fde-glibc.c, unwind-dw2-fde.c, unwind-dw2-fde.h) + (unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h): Remove. + 2011-07-31 Joseph Myers * de.po: Update. diff --git a/gcc/po/EXCLUDES b/gcc/po/EXCLUDES index cc29a2bd1ac..12fced15f72 100644 --- a/gcc/po/EXCLUDES +++ b/gcc/po/EXCLUDES @@ -44,15 +44,6 @@ libgcc2.h limitx.h limity.h longlong.h -unwind-c.c -unwind-dw2-fde-darwin.c -unwind-dw2-fde-glibc.c -unwind-dw2-fde.c -unwind-dw2-fde.h -unwind-dw2.c -unwind-pe.h -unwind-sjlj.c -unwind.h # These programs are meant to be executed only by GCC maintainers or # installers. Such files do not need to be translated, as these diff --git a/gcc/system.h b/gcc/system.h index 7ac98596bc7..a7db6f58f85 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -802,7 +802,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; /* Target macros only used for code built for the target, that have moved to libgcc-tm.h or have never been present elsewhere. */ #pragma GCC poison DECLARE_LIBRARY_RENAMES LIBGCC2_GNU_PREFIX \ - MD_UNWIND_SUPPORT ENABLE_EXECUTE_STACK + MD_UNWIND_SUPPORT MD_FROB_UPDATE_CONTEXT ENABLE_EXECUTE_STACK /* Other obsolete target macros, or macros that used to be in target headers and were not used, and may be obsolete or may never have diff --git a/gcc/unwind-c.c b/gcc/unwind-c.c deleted file mode 100644 index 86b9f557048..00000000000 --- a/gcc/unwind-c.c +++ /dev/null @@ -1,229 +0,0 @@ -/* Supporting functions for C exception handling. - Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc. - Contributed by Aldy Hernandez . - Shamelessly stolen from the Java front end. - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#include "tconfig.h" -#include "tsystem.h" -#include "unwind.h" -#define NO_SIZE_OF_ENCODED_VALUE -#include "unwind-pe.h" - -typedef struct -{ - _Unwind_Ptr Start; - _Unwind_Ptr LPStart; - _Unwind_Ptr ttype_base; - const unsigned char *TType; - const unsigned char *action_table; - unsigned char ttype_encoding; - unsigned char call_site_encoding; -} lsda_header_info; - -static const unsigned char * -parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, - lsda_header_info *info) -{ - _uleb128_t tmp; - unsigned char lpstart_encoding; - - info->Start = (context ? _Unwind_GetRegionStart (context) : 0); - - /* Find @LPStart, the base to which landing pad offsets are relative. */ - lpstart_encoding = *p++; - if (lpstart_encoding != DW_EH_PE_omit) - p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); - else - info->LPStart = info->Start; - - /* Find @TType, the base of the handler and exception spec type data. */ - info->ttype_encoding = *p++; - if (info->ttype_encoding != DW_EH_PE_omit) - { - p = read_uleb128 (p, &tmp); - info->TType = p + tmp; - } - else - info->TType = 0; - - /* The encoding and length of the call-site table; the action table - immediately follows. */ - info->call_site_encoding = *p++; - p = read_uleb128 (p, &tmp); - info->action_table = p + tmp; - - return p; -} - -#ifdef __ARM_EABI_UNWINDER__ -/* ARM EABI personality routines must also unwind the stack. */ -#define CONTINUE_UNWINDING \ - do \ - { \ - if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ - return _URC_FAILURE; \ - return _URC_CONTINUE_UNWIND; \ - } \ - while (0) -#else -#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND -#endif - -#ifdef __USING_SJLJ_EXCEPTIONS__ -#define PERSONALITY_FUNCTION __gcc_personality_sj0 -#define __builtin_eh_return_data_regno(x) x -#else -#define PERSONALITY_FUNCTION __gcc_personality_v0 -#endif - -#ifdef __ARM_EABI_UNWINDER__ -_Unwind_Reason_Code -PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, - struct _Unwind_Context *); - -_Unwind_Reason_Code -PERSONALITY_FUNCTION (_Unwind_State state, - struct _Unwind_Exception * ue_header, - struct _Unwind_Context * context) -#else -_Unwind_Reason_Code -PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, - struct _Unwind_Exception *, struct _Unwind_Context *); - -_Unwind_Reason_Code -PERSONALITY_FUNCTION (int version, - _Unwind_Action actions, - _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, - struct _Unwind_Exception *ue_header, - struct _Unwind_Context *context) -#endif -{ - lsda_header_info info; - const unsigned char *language_specific_data, *p; - _Unwind_Ptr landing_pad, ip; - int ip_before_insn = 0; - -#ifdef __ARM_EABI_UNWINDER__ - if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) - CONTINUE_UNWINDING; - - /* The dwarf unwinder assumes the context structure holds things like the - function and LSDA pointers. The ARM implementation caches these in - the exception header (UCB). To avoid rewriting everything we make the - virtual IP register point at the UCB. */ - ip = (_Unwind_Ptr) ue_header; - _Unwind_SetGR (context, 12, ip); -#else - if (version != 1) - return _URC_FATAL_PHASE1_ERROR; - - /* Currently we only support cleanups for C. */ - if ((actions & _UA_CLEANUP_PHASE) == 0) - CONTINUE_UNWINDING; -#endif - - language_specific_data = (const unsigned char *) - _Unwind_GetLanguageSpecificData (context); - - /* If no LSDA, then there are no handlers or cleanups. */ - if (! language_specific_data) - CONTINUE_UNWINDING; - - /* Parse the LSDA header. */ - p = parse_lsda_header (context, language_specific_data, &info); -#ifdef HAVE_GETIPINFO - ip = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - ip = _Unwind_GetIP (context); -#endif - if (! ip_before_insn) - --ip; - landing_pad = 0; - -#ifdef __USING_SJLJ_EXCEPTIONS__ - /* The given "IP" is an index into the call-site table, with two - exceptions -- -1 means no-action, and 0 means terminate. But - since we're using uleb128 values, we've not got random access - to the array. */ - if ((int) ip <= 0) - return _URC_CONTINUE_UNWIND; - else - { - _uleb128_t cs_lp, cs_action; - do - { - p = read_uleb128 (p, &cs_lp); - p = read_uleb128 (p, &cs_action); - } - while (--ip); - - /* Can never have null landing pad for sjlj -- that would have - been indicated by a -1 call site index. */ - landing_pad = (_Unwind_Ptr)cs_lp + 1; - goto found_something; - } -#else - /* Search the call-site table for the action associated with this IP. */ - while (p < info.action_table) - { - _Unwind_Ptr cs_start, cs_len, cs_lp; - _uleb128_t cs_action; - - /* Note that all call-site encodings are "absolute" displacements. */ - p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); - p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); - p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); - p = read_uleb128 (p, &cs_action); - - /* The table is sorted, so if we've passed the ip, stop. */ - if (ip < info.Start + cs_start) - p = info.action_table; - else if (ip < info.Start + cs_start + cs_len) - { - if (cs_lp) - landing_pad = info.LPStart + cs_lp; - goto found_something; - } - } -#endif - - /* IP is not in table. No associated cleanups. */ - /* ??? This is where C++ calls std::terminate to catch throw - from a destructor. */ - CONTINUE_UNWINDING; - - found_something: - if (landing_pad == 0) - { - /* IP is present, but has a null landing pad. - No handler to be run. */ - CONTINUE_UNWINDING; - } - - _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), - (_Unwind_Ptr) ue_header); - _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); - _Unwind_SetIP (context, landing_pad); - return _URC_INSTALL_CONTEXT; -} diff --git a/gcc/unwind-compat.c b/gcc/unwind-compat.c deleted file mode 100644 index 5b41f24688d..00000000000 --- a/gcc/unwind-compat.c +++ /dev/null @@ -1,210 +0,0 @@ -/* Backward compatibility unwind routines. - Copyright (C) 2004, 2005, 2006, 2009 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#if defined (USE_GAS_SYMVER) && defined (USE_LIBUNWIND_EXCEPTIONS) -#include "tconfig.h" -#include "tsystem.h" -#include "unwind.h" -#include "unwind-dw2-fde.h" -#include "unwind-compat.h" - -extern _Unwind_Reason_Code __libunwind_Unwind_Backtrace - (_Unwind_Trace_Fn, void *); - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Backtrace (_Unwind_Trace_Fn trace, void *trace_argument) -{ - return __libunwind_Unwind_Backtrace (trace, trace_argument); -} -symver (_Unwind_Backtrace, GCC_3.3); - -extern void __libunwind_Unwind_DeleteException - (struct _Unwind_Exception *); - -void -_Unwind_DeleteException (struct _Unwind_Exception *exc) -{ - return __libunwind_Unwind_DeleteException (exc); -} -symver (_Unwind_DeleteException, GCC_3.0); - -extern void * __libunwind_Unwind_FindEnclosingFunction (void *); - -void * -_Unwind_FindEnclosingFunction (void *pc) -{ - return __libunwind_Unwind_FindEnclosingFunction (pc); -} -symver (_Unwind_FindEnclosingFunction, GCC_3.3); - -extern _Unwind_Reason_Code __libunwind_Unwind_ForcedUnwind - (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, - _Unwind_Stop_Fn stop, void * stop_argument) -{ - return __libunwind_Unwind_ForcedUnwind (exc, stop, stop_argument); -} -symver (_Unwind_ForcedUnwind, GCC_3.0); - -extern _Unwind_Word __libunwind_Unwind_GetCFA - (struct _Unwind_Context *); - -_Unwind_Word -_Unwind_GetCFA (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetCFA (context); -} -symver (_Unwind_GetCFA, GCC_3.3); - -#ifdef __ia64__ -extern _Unwind_Word __libunwind_Unwind_GetBSP - (struct _Unwind_Context *); - -_Unwind_Word -_Unwind_GetBSP (struct _Unwind_Context * context) -{ - return __libunwind_Unwind_GetBSP (context); -} -symver (_Unwind_GetBSP, GCC_3.3.2); -#else -extern _Unwind_Ptr __libunwind_Unwind_GetDataRelBase - (struct _Unwind_Context *); - -_Unwind_Ptr -_Unwind_GetDataRelBase (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetDataRelBase (context); -} -symver (_Unwind_GetDataRelBase, GCC_3.0); - -extern _Unwind_Ptr __libunwind_Unwind_GetTextRelBase - (struct _Unwind_Context *); - -_Unwind_Ptr -_Unwind_GetTextRelBase (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetTextRelBase (context); -} -symver (_Unwind_GetTextRelBase, GCC_3.0); -#endif - -extern _Unwind_Word __libunwind_Unwind_GetGR - (struct _Unwind_Context *, int ); - -_Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) -{ - return __libunwind_Unwind_GetGR (context, index); -} -symver (_Unwind_GetGR, GCC_3.0); - -extern _Unwind_Ptr __libunwind_Unwind_GetIP (struct _Unwind_Context *); - -_Unwind_Ptr -_Unwind_GetIP (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetIP (context); -} -symver (_Unwind_GetIP, GCC_3.0); - -_Unwind_Ptr -_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) -{ - *ip_before_insn = 0; - return __libunwind_Unwind_GetIP (context); -} - -extern void *__libunwind_Unwind_GetLanguageSpecificData - (struct _Unwind_Context *); - -void * -_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetLanguageSpecificData (context); -} -symver (_Unwind_GetLanguageSpecificData, GCC_3.0); - -extern _Unwind_Ptr __libunwind_Unwind_GetRegionStart - (struct _Unwind_Context *); - -_Unwind_Ptr -_Unwind_GetRegionStart (struct _Unwind_Context *context) -{ - return __libunwind_Unwind_GetRegionStart (context); -} -symver (_Unwind_GetRegionStart, GCC_3.0); - -extern _Unwind_Reason_Code __libunwind_Unwind_RaiseException - (struct _Unwind_Exception *); - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_RaiseException(struct _Unwind_Exception *exc) -{ - return __libunwind_Unwind_RaiseException (exc); -} -symver (_Unwind_RaiseException, GCC_3.0); - -extern void __libunwind_Unwind_Resume (struct _Unwind_Exception *); - -void LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume (struct _Unwind_Exception *exc) -{ - __libunwind_Unwind_Resume (exc); -} -symver (_Unwind_Resume, GCC_3.0); - -extern _Unwind_Reason_Code __libunwind_Unwind_Resume_or_Rethrow - (struct _Unwind_Exception *); - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) -{ - return __libunwind_Unwind_Resume_or_Rethrow (exc); -} -symver (_Unwind_Resume_or_Rethrow, GCC_3.3); - -extern void __libunwind_Unwind_SetGR - (struct _Unwind_Context *, int, _Unwind_Word); - -void -_Unwind_SetGR (struct _Unwind_Context *context, int index, - _Unwind_Word val) -{ - __libunwind_Unwind_SetGR (context, index, val); -} -symver (_Unwind_SetGR, GCC_3.0); - -extern void __libunwind_Unwind_SetIP - (struct _Unwind_Context *, _Unwind_Ptr); - -void -_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) -{ - return __libunwind_Unwind_SetIP (context, val); -} -symver (_Unwind_SetIP, GCC_3.0); -#endif diff --git a/gcc/unwind-compat.h b/gcc/unwind-compat.h deleted file mode 100644 index 24c8de11801..00000000000 --- a/gcc/unwind-compat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Backward compatibility unwind routines. - Copyright (C) 2004, 2009 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#define symver(name, version) \ - __asm__ (".symver " #name"," #name "@" #version) - -#define alias(name) \ - __typeof(name) __libunwind##name __attribute__ ((alias (#name))) diff --git a/gcc/unwind-dw2-fde-compat.c b/gcc/unwind-dw2-fde-compat.c deleted file mode 100644 index f305a5501a0..00000000000 --- a/gcc/unwind-dw2-fde-compat.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Backward compatibility unwind routines. - Copyright (C) 2004, 2005, 2009 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#if defined (USE_GAS_SYMVER) && defined (USE_LIBUNWIND_EXCEPTIONS) -#include "tconfig.h" -#include "tsystem.h" -#include "unwind.h" -#include "unwind-dw2-fde.h" -#include "unwind-compat.h" - -extern const fde * __libunwind__Unwind_Find_FDE - (void *, struct dwarf_eh_bases *); - -const fde * -_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) -{ - __libunwind__Unwind_Find_FDE (pc, bases); -} - -symver (_Unwind_Find_FDE, GCC_3.0); -#endif diff --git a/gcc/unwind-dw2-fde-darwin.c b/gcc/unwind-dw2-fde-darwin.c deleted file mode 100644 index 75b404e09e9..00000000000 --- a/gcc/unwind-dw2-fde-darwin.c +++ /dev/null @@ -1,289 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2005, 2009, 2010 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* Locate the FDE entry for a given address, using Darwin's keymgr support. */ - -#include "tconfig.h" -#include "tsystem.h" -#include -#include -#include "dwarf2.h" -#include "unwind.h" -#define NO_BASE_OF_ENCODED_VALUE -#define DWARF2_OBJECT_END_PTR_EXTENSION -#include "unwind-pe.h" -#include "unwind-dw2-fde.h" -/* Carefully don't include gthr.h. */ - -typedef int __gthread_mutex_t; -#define __gthread_mutex_lock(x) (void)(x) -#define __gthread_mutex_unlock(x) (void)(x) - -static const fde * _Unwind_Find_registered_FDE (void *pc, - struct dwarf_eh_bases *bases); - -#define _Unwind_Find_FDE _Unwind_Find_registered_FDE -#include "unwind-dw2-fde.c" -#undef _Unwind_Find_FDE - -/* KeyMgr stuff. */ -#define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */ -#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */ - -extern void *_keymgr_get_and_lock_processwide_ptr (int); -extern void _keymgr_set_and_unlock_processwide_ptr (int, void *); -extern void _keymgr_unlock_processwide_ptr (int); - -struct mach_header; -struct mach_header_64; -extern char *getsectdatafromheader (struct mach_header*, const char*, - const char *, unsigned long *); -extern char *getsectdatafromheader_64 (struct mach_header_64*, const char*, - const char *, unsigned long *); - -/* This is referenced from KEYMGR_GCC3_DW2_OBJ_LIST. */ -struct km_object_info { - struct object *seen_objects; - struct object *unseen_objects; - unsigned spare[2]; -}; - -/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */ -struct live_images { - unsigned long this_size; /* sizeof (live_images) */ - struct mach_header *mh; /* the image info */ - unsigned long vm_slide; - void (*destructor)(struct live_images *); /* destructor for this */ - struct live_images *next; - unsigned int examined_p; - void *fde; - void *object_info; - unsigned long info[2]; /* Future use. */ -}; - -/* Bits in the examined_p field of struct live_images. */ -enum { - EXAMINED_IMAGE_MASK = 1, /* We've seen this one. */ - ALLOCED_IMAGE_MASK = 2, /* The FDE entries were allocated by - malloc, and must be freed. This isn't - used by newer libgcc versions. */ - IMAGE_IS_TEXT_MASK = 4, /* This image is in the TEXT segment. */ - DESTRUCTOR_MAY_BE_CALLED_LIVE = 8 /* The destructor may be called on an - object that's part of the live - image list. */ -}; - -/* Delete any data we allocated on a live_images structure. Either - IMAGE has already been removed from the - KEYMGR_GCC3_LIVE_IMAGE_LIST and the struct will be deleted - after we return, or that list is locked and we're being called - because this object might be about to be unloaded. Called by - KeyMgr. */ - -static void -live_image_destructor (struct live_images *image) -{ - if (image->object_info) - { - struct km_object_info *the_obj_info; - - the_obj_info = - _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST); - if (the_obj_info) - { - seen_objects = the_obj_info->seen_objects; - unseen_objects = the_obj_info->unseen_objects; - - /* Free any sorted arrays. */ - __deregister_frame_info_bases (image->fde); - - the_obj_info->seen_objects = seen_objects; - the_obj_info->unseen_objects = unseen_objects; - } - _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST, - the_obj_info); - - free (image->object_info); - image->object_info = NULL; - if (image->examined_p & ALLOCED_IMAGE_MASK) - free (image->fde); - image->fde = NULL; - } - image->examined_p = 0; - image->destructor = NULL; -} - -/* Run through the list of live images. If we can allocate memory, - give each unseen image a new `struct object'. Even if we can't, - check whether the PC is inside the FDE of each unseen image. - */ - -static inline const fde * -examine_objects (void *pc, struct dwarf_eh_bases *bases, int dont_alloc) -{ - const fde *result = NULL; - struct live_images *image; - - image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST); - - for (; image != NULL; image = image->next) - if ((image->examined_p & EXAMINED_IMAGE_MASK) == 0) - { - char *fde = NULL; - unsigned long sz; - - /* For ppc only check whether or not we have __DATA eh frames. */ -#ifdef __ppc__ - fde = getsectdatafromheader (image->mh, "__DATA", "__eh_frame", &sz); -#endif - - if (fde == NULL) - { -#if __LP64__ - fde = getsectdatafromheader_64 ((struct mach_header_64 *) image->mh, - "__TEXT", "__eh_frame", &sz); -#else - fde = getsectdatafromheader (image->mh, "__TEXT", - "__eh_frame", &sz); -#endif - if (fde != NULL) - image->examined_p |= IMAGE_IS_TEXT_MASK; - } - - /* If .eh_frame is empty, don't register at all. */ - if (fde != NULL && sz > 0) - { - char *real_fde = (fde + image->vm_slide); - struct object *ob = NULL; - struct object panicob; - - if (! dont_alloc) - ob = calloc (1, sizeof (struct object)); - dont_alloc |= ob == NULL; - if (dont_alloc) - ob = &panicob; - - ob->pc_begin = (void *)-1; - ob->tbase = 0; - ob->dbase = 0; - ob->u.single = (struct dwarf_fde *)real_fde; - ob->s.i = 0; - ob->s.b.encoding = DW_EH_PE_omit; - ob->fde_end = real_fde + sz; - - image->fde = real_fde; - - result = search_object (ob, pc); - - if (! dont_alloc) - { - struct object **p; - - image->destructor = live_image_destructor; - image->object_info = ob; - - image->examined_p |= (EXAMINED_IMAGE_MASK - | DESTRUCTOR_MAY_BE_CALLED_LIVE); - - /* 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 (result) - { - int encoding; - _Unwind_Ptr func; - - bases->tbase = ob->tbase; - bases->dbase = ob->dbase; - - encoding = ob->s.b.encoding; - if (ob->s.b.mixed_encoding) - encoding = get_fde_encoding (result); - read_encoded_value_with_base (encoding, - base_from_object (encoding, ob), - result->pc_begin, &func); - bases->func = (void *) func; - break; - } - } - else - image->examined_p |= EXAMINED_IMAGE_MASK; - } - - _keymgr_unlock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST); - - return result; -} - -const fde * -_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) -{ - struct km_object_info *the_obj_info; - const fde *ret = NULL; - - the_obj_info = - _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST); - if (! the_obj_info) - the_obj_info = calloc (1, sizeof (*the_obj_info)); - - if (the_obj_info != NULL) - { - seen_objects = the_obj_info->seen_objects; - unseen_objects = the_obj_info->unseen_objects; - - ret = _Unwind_Find_registered_FDE (pc, bases); - } - - /* OK, didn't find it in the list of FDEs we've seen before, - so go through and look at the new ones. */ - if (ret == NULL) - ret = examine_objects (pc, bases, the_obj_info == NULL); - - if (the_obj_info != NULL) - { - the_obj_info->seen_objects = seen_objects; - the_obj_info->unseen_objects = unseen_objects; - } - _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST, - the_obj_info); - return ret; -} - -void * -_darwin10_Unwind_FindEnclosingFunction (void *pc ATTRIBUTE_UNUSED) -{ -#if __MACH__ && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060) - struct dwarf_eh_bases bases; - const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); - if (fde) - return bases.func; -#endif - return NULL; -} - diff --git a/gcc/unwind-dw2-fde-glibc.c b/gcc/unwind-dw2-fde-glibc.c deleted file mode 100644 index d8e3c0e934b..00000000000 --- a/gcc/unwind-dw2-fde-glibc.c +++ /dev/null @@ -1,470 +0,0 @@ -/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2010 - Free Software Foundation, Inc. - Contributed by Jakub Jelinek . - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF - segment and dl_iterate_phdr to avoid register/deregister calls at - DSO load/unload. */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 -#endif - -#include "tconfig.h" -#include "tsystem.h" -#ifndef inhibit_libc -#include /* Get DT_CONFIG. */ -#endif -#include "coretypes.h" -#include "tm.h" -#include "dwarf2.h" -#include "unwind.h" -#define NO_BASE_OF_ENCODED_VALUE -#include "unwind-pe.h" -#include "unwind-dw2-fde.h" -#include "unwind-compat.h" -#include "gthr.h" - -#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ - && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \ - || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) -# define USE_PT_GNU_EH_FRAME -#endif - -#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ - && defined(__FreeBSD__) && __FreeBSD__ >= 7 -# define ElfW __ElfN -# define USE_PT_GNU_EH_FRAME -#endif - -#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ - && defined(TARGET_DL_ITERATE_PHDR) \ - && defined(__sun__) && defined(__svr4__) -# define USE_PT_GNU_EH_FRAME -#endif - -#if defined(USE_PT_GNU_EH_FRAME) - -#include - -#ifndef __RELOC_POINTER -# define __RELOC_POINTER(ptr, base) ((ptr) + (base)) -#endif - -static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases); - -#define _Unwind_Find_FDE _Unwind_Find_registered_FDE -#include "unwind-dw2-fde.c" -#undef _Unwind_Find_FDE - -#ifndef PT_GNU_EH_FRAME -#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550) -#endif - -struct unw_eh_callback_data -{ - _Unwind_Ptr pc; - void *tbase; - void *dbase; - void *func; - const fde *ret; - int check_cache; -}; - -struct unw_eh_frame_hdr -{ - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; -}; - -#define FRAME_HDR_CACHE_SIZE 8 - -static struct frame_hdr_cache_element -{ - _Unwind_Ptr pc_low; - _Unwind_Ptr pc_high; - _Unwind_Ptr load_base; - const ElfW(Phdr) *p_eh_frame_hdr; - const ElfW(Phdr) *p_dynamic; - struct frame_hdr_cache_element *link; -} frame_hdr_cache[FRAME_HDR_CACHE_SIZE]; - -static struct frame_hdr_cache_element *frame_hdr_cache_head; - -/* Like base_of_encoded_value, but take the base from a struct - unw_eh_callback_data instead of an _Unwind_Context. */ - -static _Unwind_Ptr -base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data) -{ - 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) data->tbase; - case DW_EH_PE_datarel: - return (_Unwind_Ptr) data->dbase; - default: - gcc_unreachable (); - } -} - -static int -_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) -{ - struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr; - const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic; - long n, match; -#ifdef __FRV_FDPIC__ - struct elf32_fdpic_loadaddr load_base; -#else - _Unwind_Ptr load_base; -#endif - const unsigned char *p; - const struct unw_eh_frame_hdr *hdr; - _Unwind_Ptr eh_frame; - struct object ob; - _Unwind_Ptr pc_low = 0, pc_high = 0; - - struct ext_dl_phdr_info - { - ElfW(Addr) dlpi_addr; - const char *dlpi_name; - const ElfW(Phdr) *dlpi_phdr; - ElfW(Half) dlpi_phnum; - unsigned long long int dlpi_adds; - unsigned long long int dlpi_subs; - }; - - match = 0; - phdr = info->dlpi_phdr; - load_base = info->dlpi_addr; - p_eh_frame_hdr = NULL; - p_dynamic = NULL; - - struct frame_hdr_cache_element *prev_cache_entry = NULL, - *last_cache_entry = NULL; - - if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info)) - { - static unsigned long long adds = -1ULL, subs; - struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info; - - /* We use a least recently used cache replacement policy. Also, - the most recently used cache entries are placed at the head - of the search chain. */ - - if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs) - { - /* Find data->pc in shared library cache. - Set load_base, p_eh_frame_hdr and p_dynamic - plus match from the cache and goto - "Read .eh_frame_hdr header." below. */ - - struct frame_hdr_cache_element *cache_entry; - - for (cache_entry = frame_hdr_cache_head; - cache_entry; - cache_entry = cache_entry->link) - { - if (data->pc >= cache_entry->pc_low - && data->pc < cache_entry->pc_high) - { - load_base = cache_entry->load_base; - p_eh_frame_hdr = cache_entry->p_eh_frame_hdr; - p_dynamic = cache_entry->p_dynamic; - - /* And move the entry we're using to the head. */ - if (cache_entry != frame_hdr_cache_head) - { - prev_cache_entry->link = cache_entry->link; - cache_entry->link = frame_hdr_cache_head; - frame_hdr_cache_head = cache_entry; - } - goto found; - } - - last_cache_entry = cache_entry; - /* Exit early if we found an unused entry. */ - if ((cache_entry->pc_low | cache_entry->pc_high) == 0) - break; - if (cache_entry->link != NULL) - prev_cache_entry = cache_entry; - } - } - else - { - adds = einfo->dlpi_adds; - subs = einfo->dlpi_subs; - /* Initialize the cache. Create a chain of cache entries, - with the final one terminated by a NULL link. */ - int i; - for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++) - { - frame_hdr_cache[i].pc_low = 0; - frame_hdr_cache[i].pc_high = 0; - frame_hdr_cache[i].link = &frame_hdr_cache[i+1]; - } - frame_hdr_cache[i-1].link = NULL; - frame_hdr_cache_head = &frame_hdr_cache[0]; - data->check_cache = 0; - } - } - - /* Make sure struct dl_phdr_info is at least as big as we need. */ - if (size < offsetof (struct dl_phdr_info, dlpi_phnum) - + sizeof (info->dlpi_phnum)) - return -1; - - /* See if PC falls into one of the loaded segments. Find the eh_frame - segment at the same time. */ - for (n = info->dlpi_phnum; --n >= 0; phdr++) - { - if (phdr->p_type == PT_LOAD) - { - _Unwind_Ptr vaddr = (_Unwind_Ptr) - __RELOC_POINTER (phdr->p_vaddr, load_base); - if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) - { - match = 1; - pc_low = vaddr; - pc_high = vaddr + phdr->p_memsz; - } - } - else if (phdr->p_type == PT_GNU_EH_FRAME) - p_eh_frame_hdr = phdr; -#ifdef PT_SUNW_UNWIND - /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of - PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well. */ - else if (phdr->p_type == PT_SUNW_UNWIND) - p_eh_frame_hdr = phdr; -#endif - else if (phdr->p_type == PT_DYNAMIC) - p_dynamic = phdr; - } - - if (!match) - return 0; - - if (size >= sizeof (struct ext_dl_phdr_info)) - { - /* Move the cache entry we're about to overwrite to the head of - the list. If either last_cache_entry or prev_cache_entry are - NULL, that cache entry is already at the head. */ - if (last_cache_entry != NULL && prev_cache_entry != NULL) - { - prev_cache_entry->link = last_cache_entry->link; - last_cache_entry->link = frame_hdr_cache_head; - frame_hdr_cache_head = last_cache_entry; - } - - frame_hdr_cache_head->load_base = load_base; - frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr; - frame_hdr_cache_head->p_dynamic = p_dynamic; - frame_hdr_cache_head->pc_low = pc_low; - frame_hdr_cache_head->pc_high = pc_high; - } - - found: - - if (!p_eh_frame_hdr) - return 0; - - /* Read .eh_frame_hdr header. */ - hdr = (const struct unw_eh_frame_hdr *) - __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base); - if (hdr->version != 1) - return 1; - -#ifdef CRT_GET_RFIB_DATA -# ifdef __i386__ - data->dbase = NULL; - if (p_dynamic) - { - /* For dynamically linked executables and shared libraries, - DT_PLTGOT is the gp value for that object. */ - ElfW(Dyn) *dyn = (ElfW(Dyn) *) - __RELOC_POINTER (p_dynamic->p_vaddr, load_base); - for (; dyn->d_tag != DT_NULL ; dyn++) - if (dyn->d_tag == DT_PLTGOT) - { - data->dbase = (void *) dyn->d_un.d_ptr; -#if defined __linux__ - /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has - relocated it. */ -#elif defined __sun__ && defined __svr4__ - /* On Solaris 2/x86, we need to do this ourselves. */ - data->dbase += load_base; -#endif - break; - } - } -# elif defined __FRV_FDPIC__ && defined __linux__ - data->dbase = load_base.got_value; -# elif defined __x86_64__ && defined __sun__ && defined __svr4__ - /* While CRT_GET_RFIB_DATA is also defined for 64-bit Solaris 10+/x86, it - doesn't apply since it uses DW_EH_PE_pcrel encoding. */ -# else -# error What is DW_EH_PE_datarel base on this platform? -# endif -#endif - - p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc, - base_from_cb_data (hdr->eh_frame_ptr_enc, - data), - (const unsigned char *) (hdr + 1), - &eh_frame); - - /* We require here specific table encoding to speed things up. - Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start - as base, not the processor specific DW_EH_PE_datarel. */ - if (hdr->fde_count_enc != DW_EH_PE_omit - && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4)) - { - _Unwind_Ptr fde_count; - - p = read_encoded_value_with_base (hdr->fde_count_enc, - base_from_cb_data (hdr->fde_count_enc, - data), - p, &fde_count); - /* Shouldn't happen. */ - if (fde_count == 0) - return 1; - if ((((_Unwind_Ptr) p) & 3) == 0) - { - struct fde_table { - signed initial_loc __attribute__ ((mode (SI))); - signed fde __attribute__ ((mode (SI))); - }; - const struct fde_table *table = (const struct fde_table *) p; - size_t lo, hi, mid; - _Unwind_Ptr data_base = (_Unwind_Ptr) hdr; - fde *f; - unsigned int f_enc, f_enc_size; - _Unwind_Ptr range; - - mid = fde_count - 1; - if (data->pc < table[0].initial_loc + data_base) - return 1; - else if (data->pc < table[mid].initial_loc + data_base) - { - lo = 0; - hi = mid; - - while (lo < hi) - { - mid = (lo + hi) / 2; - if (data->pc < table[mid].initial_loc + data_base) - hi = mid; - else if (data->pc >= table[mid + 1].initial_loc + data_base) - lo = mid + 1; - else - break; - } - - gcc_assert (lo < hi); - } - - f = (fde *) (table[mid].fde + data_base); - f_enc = get_fde_encoding (f); - f_enc_size = size_of_encoded_value (f_enc); - read_encoded_value_with_base (f_enc & 0x0f, 0, - &f->pc_begin[f_enc_size], &range); - if (data->pc < table[mid].initial_loc + data_base + range) - data->ret = f; - data->func = (void *) (table[mid].initial_loc + data_base); - return 1; - } - } - - /* We have no sorted search table, so need to go the slow way. - As soon as GLIBC will provide API so to notify that a library has been - removed, we could cache this (and thus use search_object). */ - ob.pc_begin = NULL; - ob.tbase = data->tbase; - ob.dbase = data->dbase; - ob.u.single = (fde *) eh_frame; - ob.s.i = 0; - ob.s.b.mixed_encoding = 1; /* Need to assume worst case. */ - data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc); - if (data->ret != NULL) - { - _Unwind_Ptr func; - unsigned int encoding = get_fde_encoding (data->ret); - - read_encoded_value_with_base (encoding, - base_from_cb_data (encoding, data), - data->ret->pc_begin, &func); - data->func = (void *) func; - } - return 1; -} - -const fde * -_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) -{ - struct unw_eh_callback_data data; - const fde *ret; - - ret = _Unwind_Find_registered_FDE (pc, bases); - if (ret != NULL) - return ret; - - data.pc = (_Unwind_Ptr) pc; - data.tbase = NULL; - data.dbase = NULL; - data.func = NULL; - data.ret = NULL; - data.check_cache = 1; - - if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) - return NULL; - - if (data.ret) - { - bases->tbase = data.tbase; - bases->dbase = data.dbase; - bases->func = data.func; - } - return data.ret; -} - -#else -/* Prevent multiple include of header files. */ -#define _Unwind_Find_FDE _Unwind_Find_FDE -#include "unwind-dw2-fde.c" -#endif - -#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) -alias (_Unwind_Find_FDE); -#endif diff --git a/gcc/unwind-dw2-fde.c b/gcc/unwind-dw2-fde.c deleted file mode 100644 index 93d427165c4..00000000000 --- a/gcc/unwind-dw2-fde.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* Subroutines needed for unwinding stack frames for exception handling. */ -/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, - 2009, 2010 Free Software Foundation, Inc. - Contributed by Jason Merrill . - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#ifndef _Unwind_Find_FDE -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "dwarf2.h" -#include "unwind.h" -#define NO_BASE_OF_ENCODED_VALUE -#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 - its 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 __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 - -/* Called from crtbegin.o to register the unwind info for an object. */ - -void -__register_frame_info_bases (const void *begin, struct object *ob, - void *tbase, void *dbase) -{ - /* If .eh_frame is empty, don't register at all. */ - if ((const uword *) begin == 0 || *(const uword *) begin == 0) - return; - - 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; -#ifdef DWARF2_OBJECT_END_PTR_EXTENSION - ob->fde_end = NULL; -#endif - - init_object_mutex_once (); - __gthread_mutex_lock (&object_mutex); - - ob->next = unseen_objects; - unseen_objects = ob; - - __gthread_mutex_unlock (&object_mutex); -} - -void -__register_frame_info (const void *begin, struct object *ob) -{ - __register_frame_info_bases (begin, ob, 0, 0); -} - -void -__register_frame (void *begin) -{ - struct object *ob; - - /* If .eh_frame is empty, don't register at all. */ - if (*(uword *) begin == 0) - return; - - ob = 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 (); - __gthread_mutex_lock (&object_mutex); - - ob->next = unseen_objects; - unseen_objects = ob; - - __gthread_mutex_unlock (&object_mutex); -} - -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 = 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 die. - - 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 (const void *begin) -{ - struct object **p; - struct object *ob = 0; - - /* If .eh_frame is empty, we haven't registered. */ - if ((const uword *) begin == 0 || *(const uword *) begin == 0) - return ob; - - init_object_mutex_once (); - __gthread_mutex_lock (&object_mutex); - - 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; - } - } - - out: - __gthread_mutex_unlock (&object_mutex); - gcc_assert (ob); - return (void *) ob; -} - -void * -__deregister_frame_info (const void *begin) -{ - return __deregister_frame_info_bases (begin); -} - -void -__deregister_frame (void *begin) -{ - /* If .eh_frame is empty, we haven't registered. */ - if (*(uword *) begin != 0) - 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; - default: - gcc_unreachable (); - } -} - -/* 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 (const struct dwarf_cie *cie) -{ - const unsigned char *aug, *p; - _Unwind_Ptr dummy; - _uleb128_t utmp; - _sleb128_t stmp; - - aug = cie->augmentation; - p = aug + strlen ((const char *)aug) + 1; /* Skip the augmentation string. */ - if (__builtin_expect (cie->version >= 4, 0)) - { - if (p[0] != sizeof (void *) || p[1] != 0) - return DW_EH_PE_omit; /* We are not prepared to handle unexpected - address sizes or segment selectors. */ - p += 2; /* Skip address size and segment size. */ - } - - if (aug[0] != 'z') - return DW_EH_PE_absptr; - - p = read_uleb128 (p, &utmp); /* Skip code alignment. */ - p = read_sleb128 (p, &stmp); /* Skip data alignment. */ - if (cie->version == 1) /* Skip return address column. */ - p++; - else - p = read_uleb128 (p, &utmp); - - aug++; /* Skip 'z' */ - p = read_uleb128 (p, &utmp); /* 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 (const 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 int -fde_unencoded_compare (struct object *ob __attribute__((unused)), - const fde *x, const fde *y) -{ - _Unwind_Ptr x_ptr, y_ptr; - memcpy (&x_ptr, x->pc_begin, sizeof (_Unwind_Ptr)); - memcpy (&y_ptr, y->pc_begin, sizeof (_Unwind_Ptr)); - - if (x_ptr > y_ptr) - return 1; - if (x_ptr < y_ptr) - return -1; - return 0; -} - -static int -fde_single_encoding_compare (struct object *ob, const fde *x, const 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); - - if (x_ptr > y_ptr) - return 1; - if (x_ptr < y_ptr) - return -1; - return 0; -} - -static int -fde_mixed_encoding_compare (struct object *ob, const fde *x, const 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); - - if (x_ptr > y_ptr) - return 1; - if (x_ptr < y_ptr) - return -1; - return 0; -} - -typedef int (*fde_compare_t) (struct object *, const fde *, const 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 (const fde *) * count; - if ((accu->linear = malloc (size))) - { - accu->linear->count = 0; - if ((accu->erratic = malloc (size))) - accu->erratic->count = 0; - return 1; - } - else - return 0; -} - -static inline void -fde_insert (struct fde_accumulator *accu, const 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 const fde *marker; - size_t count = linear->count; - const fde *const *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. */ - gcc_assert (sizeof (const fde *) == sizeof (const fde **)); - - for (i = 0; i < count; i++) - { - const fde *const *probe; - - for (probe = chain_end; - probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0; - probe = chain_end) - { - chain_end = (const fde *const*) erratic->array[probe - linear->array]; - erratic->array[probe - linear->array] = NULL; - } - erratic->array[i] = (const 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; -} - -#define SWAP(x,y) do { const fde * tmp = x; x = y; y = tmp; } while (0) - -/* Convert a semi-heap to a heap. A semi-heap is a heap except possibly - for the first (root) node; push it down to its rightful place. */ - -static void -frame_downheap (struct object *ob, fde_compare_t fde_compare, const fde **a, - int lo, int hi) -{ - int i, j; - - for (i = lo, j = 2*i+1; - j < hi; - j = 2*i+1) - { - if (j+1 < hi && fde_compare (ob, a[j], a[j+1]) < 0) - ++j; - - if (fde_compare (ob, a[i], a[j]) < 0) - { - SWAP (a[i], a[j]); - i = j; - } - else - break; - } -} - -/* 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. */ - const 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]. */ - size_t n = erratic->count; - int m; - - /* Expand our heap incrementally from the end of the array, heapifying - each resulting semi-heap as we go. After each step, a[m] is the top - of a heap. */ - for (m = n/2-1; m >= 0; --m) - frame_downheap (ob, fde_compare, a, m, n); - - /* Shrink our heap incrementally from the end of the array, first - swapping out the largest element a[0] and then re-heapifying the - resulting semi-heap. After each step, a[0..m) is a heap. */ - for (m = n-1; m >= 1; --m) - { - SWAP (a[0], a[m]); - frame_downheap (ob, fde_compare, a, 0, m); - } -#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; - const 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; - - gcc_assert (!accu->linear || accu->linear->count == count); - - 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); - gcc_assert (accu->linear->count + accu->erratic->count == count); - 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, const fde *this_fde) -{ - const struct dwarf_cie *last_cie = 0; - size_t count = 0; - int encoding = DW_EH_PE_absptr; - _Unwind_Ptr base = 0; - - for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) - { - const 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); - if (encoding == DW_EH_PE_omit) - return -1; - 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 = (((_Unwind_Ptr) 1) << (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, const fde *this_fde) -{ - const struct dwarf_cie *last_cie = 0; - int encoding = ob->s.b.encoding; - _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob); - - for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) - { - const 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) - { - _Unwind_Ptr ptr; - memcpy (&ptr, this_fde->pc_begin, sizeof (_Unwind_Ptr)); - if (ptr == 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 = (((_Unwind_Ptr) 1) << (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) - { - size_t cur_count = classify_object_over_fdes (ob, *p); - if (cur_count == (size_t) -1) - goto unhandled_fdes; - count += cur_count; - } - } - else - { - count = classify_object_over_fdes (ob, ob->u.single); - if (count == (size_t) -1) - { - static const fde terminator; - unhandled_fdes: - ob->s.i = 0; - ob->s.b.encoding = DW_EH_PE_omit; - ob->u.single = &terminator; - return; - } - } - - /* 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 const fde * -linear_search_fdes (struct object *ob, const fde *this_fde, void *pc) -{ - const struct dwarf_cie *last_cie = 0; - int encoding = ob->s.b.encoding; - _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob); - - for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) - { - const 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) - { - const _Unwind_Ptr *pc_array = (const _Unwind_Ptr *) this_fde->pc_begin; - pc_begin = pc_array[0]; - pc_range = pc_array[1]; - if (pc_begin == 0) - continue; - } - else - { - _Unwind_Ptr mask; - const unsigned 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 = (((_Unwind_Ptr) 1) << (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 const 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; - const fde *const f = vec->array[i]; - void *pc_begin; - uaddr pc_range; - memcpy (&pc_begin, (const void * const *) f->pc_begin, sizeof (void *)); - memcpy (&pc_range, (const uaddr *) f->pc_begin + 1, sizeof (uaddr)); - - if (pc < pc_begin) - hi = i; - else if (pc >= pc_begin + pc_range) - lo = i + 1; - else - return f; - } - - return NULL; -} - -static inline const 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; - const fde *f = vec->array[i]; - _Unwind_Ptr pc_begin, pc_range; - const unsigned 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 const 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; - const fde *f = vec->array[i]; - _Unwind_Ptr pc_begin, pc_range; - const unsigned 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 const 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 laborious linear search, cos we've no memory. */ - if (ob->s.b.from_array) - { - fde **p; - for (p = ob->u.array; *p ; p++) - { - const fde *f = linear_search_fdes (ob, *p, pc); - if (f) - return f; - } - return NULL; - } - else - return linear_search_fdes (ob, ob->u.single, pc); - } -} - -const fde * -_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) -{ - struct object *ob; - const fde *f = NULL; - - init_object_mutex_once (); - __gthread_mutex_lock (&object_mutex); - - /* Linear search through the classified objects, to find the one - containing the pc. Note that pc_begin is sorted descending, 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: - __gthread_mutex_unlock (&object_mutex); - - if (f) - { - int encoding; - _Unwind_Ptr func; - - 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, &func); - bases->func = (void *) func; - } - - return f; -} diff --git a/gcc/unwind-dw2-fde.h b/gcc/unwind-dw2-fde.h deleted file mode 100644 index 6d7a8dee2cf..00000000000 --- a/gcc/unwind-dw2-fde.h +++ /dev/null @@ -1,183 +0,0 @@ -/* Subroutines needed for unwinding stack frames for exception handling. */ -/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2009 - Free Software Foundation, Inc. - Contributed by Jason Merrill . - -This file is part of GCC. - -GCC 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 3, or (at your option) any later -version. - -GCC 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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -. */ - -#ifndef GCC_UNWIND_DW2_FDE_H -#define GCC_UNWIND_DW2_FDE_H - -#ifndef HIDE_EXPORTS -#pragma GCC visibility push(default) -#endif - -struct fde_vector -{ - const void *orig_data; - size_t count; - const struct dwarf_fde *array[]; -}; - -struct object -{ - void *pc_begin; - void *tbase; - void *dbase; - union { - const 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; - -#ifdef DWARF2_OBJECT_END_PTR_EXTENSION - char *fde_end; -#endif - - struct object *next; -}; - -/* 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; -}; - -struct dwarf_eh_bases -{ - void *tbase; - void *dbase; - void *func; -}; - - -extern void __register_frame_info_bases (const void *, struct object *, - void *, void *); -extern void __register_frame_info (const 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 (const void *); -extern void *__deregister_frame_info_bases (const 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 specification, 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[]; -} __attribute__ ((packed, aligned (__alignof__ (void *)))); - -/* The first few fields of an FDE. */ -struct dwarf_fde -{ - uword length; - sword CIE_delta; - unsigned char pc_begin[]; -} __attribute__ ((packed, aligned (__alignof__ (void *)))); - -typedef struct dwarf_fde fde; - -/* Locate the CIE for a given FDE. */ - -static inline const struct dwarf_cie * -get_cie (const struct dwarf_fde *f) -{ - return (const void *)&f->CIE_delta - f->CIE_delta; -} - -static inline const fde * -next_fde (const fde *f) -{ - return (const fde *) ((const char *) f + f->length + sizeof (f->length)); -} - -extern const fde * _Unwind_Find_FDE (void *, struct dwarf_eh_bases *); - -static inline int -last_fde (struct object *obj __attribute__ ((__unused__)), const fde *f) -{ -#ifdef DWARF2_OBJECT_END_PTR_EXTENSION - return (char *)f == obj->fde_end || f->length == 0; -#else - return f->length == 0; -#endif -} - -#ifndef HIDE_EXPORTS -#pragma GCC visibility pop -#endif - -#endif /* unwind-dw2-fde.h */ diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c deleted file mode 100644 index 19da29982b6..00000000000 --- a/gcc/unwind-dw2.c +++ /dev/null @@ -1,1611 +0,0 @@ -/* DWARF2 exception handling and frame unwind runtime interface routines. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2008, 2009, 2010, 2011 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "dwarf2.h" -#include "unwind.h" -#ifdef __USING_SJLJ_EXCEPTIONS__ -# define NO_SIZE_OF_ENCODED_VALUE -#endif -#include "unwind-pe.h" -#include "unwind-dw2-fde.h" -#include "gthr.h" -#include "unwind-dw2.h" - -#ifdef HAVE_SYS_SDT_H -#include -#endif - -#ifndef __USING_SJLJ_EXCEPTIONS__ - -#ifndef STACK_GROWS_DOWNWARD -#define STACK_GROWS_DOWNWARD 0 -#else -#undef STACK_GROWS_DOWNWARD -#define STACK_GROWS_DOWNWARD 1 -#endif - -/* Dwarf frame registers used for pre gcc 3.0 compiled glibc. */ -#ifndef PRE_GCC3_DWARF_FRAME_REGISTERS -#define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS -#endif - -#ifndef DWARF_REG_TO_UNWIND_COLUMN -#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) -#endif - -/* This is the register and unwind state for a particular frame. This - provides the information necessary to unwind up past a frame and return - to its caller. */ -struct _Unwind_Context -{ - void *reg[DWARF_FRAME_REGISTERS+1]; - void *cfa; - void *ra; - void *lsda; - struct dwarf_eh_bases bases; - /* Signal frame context. */ -#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) - /* Context which has version/args_size/by_value fields. */ -#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1) - _Unwind_Word flags; - /* 0 for now, can be increased when further fields are added to - struct _Unwind_Context. */ - _Unwind_Word version; - _Unwind_Word args_size; - char by_value[DWARF_FRAME_REGISTERS+1]; -}; - -/* Byte size of every register managed by these routines. */ -static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1]; - - -/* 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 void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); -static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, - _Unwind_FrameState *); - -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; } - -static inline _Unwind_Word -_Unwind_IsSignalFrame (struct _Unwind_Context *context) -{ - return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0; -} - -static inline void -_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) -{ - if (val) - context->flags |= SIGNAL_FRAME_BIT; - else - context->flags &= ~SIGNAL_FRAME_BIT; -} - -static inline _Unwind_Word -_Unwind_IsExtendedContext (struct _Unwind_Context *context) -{ - return context->flags & EXTENDED_CONTEXT_BIT; -} - -/* Get the value of register INDEX as saved in CONTEXT. */ - -inline _Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) -{ - int size; - void *ptr; - -#ifdef DWARF_ZERO_REG - if (index == DWARF_ZERO_REG) - return 0; -#endif - - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - size = dwarf_reg_size_table[index]; - ptr = context->reg[index]; - - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) - return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr; - - /* This will segfault if the register hasn't been saved. */ - if (size == sizeof(_Unwind_Ptr)) - return * (_Unwind_Ptr *) ptr; - else - { - gcc_assert (size == sizeof(_Unwind_Word)); - return * (_Unwind_Word *) ptr; - } -} - -static inline void * -_Unwind_GetPtr (struct _Unwind_Context *context, int index) -{ - return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index); -} - -/* Get the value of the CFA as saved in CONTEXT. */ - -_Unwind_Word -_Unwind_GetCFA (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->cfa; -} - -/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ - -inline void -_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) -{ - int size; - void *ptr; - - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - size = dwarf_reg_size_table[index]; - - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) - { - context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; - return; - } - - ptr = context->reg[index]; - - if (size == sizeof(_Unwind_Ptr)) - * (_Unwind_Ptr *) ptr = val; - else - { - gcc_assert (size == sizeof(_Unwind_Word)); - * (_Unwind_Word *) ptr = val; - } -} - -/* Get the pointer to a register INDEX as saved in CONTEXT. */ - -static inline void * -_Unwind_GetGRPtr (struct _Unwind_Context *context, int index) -{ - index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) - return &context->reg[index]; - return context->reg[index]; -} - -/* Set the pointer to a register INDEX as saved in CONTEXT. */ - -static inline void -_Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) -{ - index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (_Unwind_IsExtendedContext (context)) - context->by_value[index] = 0; - context->reg[index] = p; -} - -/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ - -static inline void -_Unwind_SetGRValue (struct _Unwind_Context *context, int index, - _Unwind_Word val) -{ - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr)); - - context->by_value[index] = 1; - context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; -} - -/* Return nonzero if register INDEX is stored by value rather than - by reference. */ - -static inline int -_Unwind_GRByValue (struct _Unwind_Context *context, int index) -{ - index = DWARF_REG_TO_UNWIND_COLUMN (index); - return context->by_value[index]; -} - -/* Retrieve the return address for CONTEXT. */ - -inline _Unwind_Ptr -_Unwind_GetIP (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->ra; -} - -/* Retrieve the return address and flag whether that IP is before - or after first not yet fully executed instruction. */ - -inline _Unwind_Ptr -_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) -{ - *ip_before_insn = _Unwind_IsSignalFrame (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; -} - -void * -_Unwind_FindEnclosingFunction (void *pc) -{ - struct dwarf_eh_bases bases; - const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); - if (fde) - return bases.func; - else - return NULL; -} - -#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 - -#include "md-unwind-support.h" - -/* 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 (const struct dwarf_cie *cie, struct _Unwind_Context *context, - _Unwind_FrameState *fs) -{ - const unsigned char *aug = cie->augmentation; - const unsigned char *p = aug + strlen ((const char *)aug) + 1; - const unsigned char *ret = NULL; - _uleb128_t utmp; - _sleb128_t stmp; - - /* g++ v2 "eh" has pointer immediately following augmentation string, - so it must be handled first. */ - if (aug[0] == 'e' && aug[1] == 'h') - { - fs->eh_ptr = read_pointer (p); - p += sizeof (void *); - aug += 2; - } - - /* After the augmentation resp. pointer for "eh" augmentation - follows for CIE version >= 4 address size byte and - segment size byte. */ - if (__builtin_expect (cie->version >= 4, 0)) - { - if (p[0] != sizeof (void *) || p[1] != 0) - return NULL; - p += 2; - } - /* Immediately following this are the code and - data alignment and return address column. */ - p = read_uleb128 (p, &utmp); - fs->code_align = (_Unwind_Word)utmp; - p = read_sleb128 (p, &stmp); - fs->data_align = (_Unwind_Sword)stmp; - if (cie->version == 1) - fs->retaddr_column = *p++; - else - { - p = read_uleb128 (p, &utmp); - fs->retaddr_column = (_Unwind_Word)utmp; - } - 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, &utmp); - ret = p + utmp; - - fs->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') - { - 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') - { - _Unwind_Ptr personality; - - p = read_encoded_value (context, *p, p + 1, &personality); - fs->personality = (_Unwind_Personality_Fn) personality; - aug += 1; - } - - /* "S" indicates a signal frame. */ - else if (aug[0] == 'S') - { - fs->signal_frame = 1; - 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; - _uleb128_t reg, utmp; - _sleb128_t offset, stmp; - - 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_GNU_encoded_addr: - { - _Unwind_Ptr presult; - op_ptr = read_encoded_value (context, *op_ptr, op_ptr+1, &presult); - result = presult; - } - 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, &utmp); - result = (_Unwind_Word)utmp; - break; - case DW_OP_consts: - op_ptr = read_sleb128 (op_ptr, &stmp); - result = (_Unwind_Sword)stmp; - 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, ®); - 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, &offset); - result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset; - break; - case DW_OP_bregx: - op_ptr = read_uleb128 (op_ptr, ®); - op_ptr = read_sleb128 (op_ptr, &offset); - result = _Unwind_GetGR (context, reg) + (_Unwind_Word)offset; - break; - - case DW_OP_dup: - gcc_assert (stack_elt); - result = stack[stack_elt - 1]; - break; - - case DW_OP_drop: - gcc_assert (stack_elt); - stack_elt -= 1; - goto no_push; - - case DW_OP_pick: - offset = *op_ptr++; - gcc_assert (offset < stack_elt - 1); - result = stack[stack_elt - 1 - offset]; - break; - - case DW_OP_over: - gcc_assert (stack_elt >= 2); - result = stack[stack_elt - 2]; - break; - - case DW_OP_swap: - { - _Unwind_Word t; - gcc_assert (stack_elt >= 2); - t = stack[stack_elt - 1]; - stack[stack_elt - 1] = stack[stack_elt - 2]; - stack[stack_elt - 2] = t; - goto no_push; - } - - case DW_OP_rot: - { - _Unwind_Word t1, t2, t3; - - gcc_assert (stack_elt >= 3); - 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. */ - gcc_assert (stack_elt); - stack_elt -= 1; - - 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: - gcc_unreachable (); - } - } - 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, &utmp); - result += (_Unwind_Word)utmp; - break; - - default: - gcc_unreachable (); - } - 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_shl: - case DW_OP_shr: - case DW_OP_shra: - case DW_OP_xor: - 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; - gcc_assert (stack_elt >= 2); - stack_elt -= 2; - - 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 = second % 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) second <= (_Unwind_Sword) first; - break; - case DW_OP_ge: - result = (_Unwind_Sword) second >= (_Unwind_Sword) first; - break; - case DW_OP_eq: - result = (_Unwind_Sword) second == (_Unwind_Sword) first; - break; - case DW_OP_lt: - result = (_Unwind_Sword) second < (_Unwind_Sword) first; - break; - case DW_OP_gt: - result = (_Unwind_Sword) second > (_Unwind_Sword) first; - break; - case DW_OP_ne: - result = (_Unwind_Sword) second != (_Unwind_Sword) first; - break; - - default: - gcc_unreachable (); - } - } - break; - - case DW_OP_skip: - offset = read_2s (op_ptr); - op_ptr += 2; - op_ptr += offset; - goto no_push; - - case DW_OP_bra: - gcc_assert (stack_elt); - stack_elt -= 1; - - 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: - gcc_unreachable (); - } - - /* Most things push a result value. */ - gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack)); - stack[stack_elt++] = result; - no_push:; - } - - /* We were executing this program to get a value. It should be - at top of stack. */ - gcc_assert (stack_elt); - stack_elt -= 1; - return stack[stack_elt]; -} - - -/* 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; - - /* The comparison with the return address uses < rather than <= because - we are only interested in the effects of code before the call; for a - noreturn function, the return address may point to unrelated code with - a different stack configuration that we are not interested in. We - assume that the call itself is unwind info-neutral; if not, or if - there are delay instructions that adjust the stack, these must be - reflected at the point immediately before the call insn. - In signal frames, return address is after last completed instruction, - so we add 1 to return address to make the comparison <=. */ - while (insn_ptr < insn_end - && fs->pc < context->ra + _Unwind_IsSignalFrame (context)) - { - unsigned char insn = *insn_ptr++; - _uleb128_t reg, utmp; - _sleb128_t offset, stmp; - - if ((insn & 0xc0) == DW_CFA_advance_loc) - fs->pc += (insn & 0x3f) * fs->code_align; - else if ((insn & 0xc0) == DW_CFA_offset) - { - reg = insn & 0x3f; - insn_ptr = read_uleb128 (insn_ptr, &utmp); - offset = (_Unwind_Sword) utmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; - } - else if ((insn & 0xc0) == DW_CFA_restore) - { - reg = insn & 0x3f; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED; - } - else switch (insn) - { - case DW_CFA_set_loc: - { - _Unwind_Ptr pc; - - insn_ptr = read_encoded_value (context, fs->fde_encoding, - insn_ptr, &pc); - fs->pc = (void *) 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, ®); - insn_ptr = read_uleb128 (insn_ptr, &utmp); - offset = (_Unwind_Sword) utmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; - break; - - case DW_CFA_restore_extended: - insn_ptr = read_uleb128 (insn_ptr, ®); - /* FIXME, this is wrong; the CIE might have said that the - register was saved somewhere. */ - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; - break; - - case DW_CFA_same_value: - insn_ptr = read_uleb128 (insn_ptr, ®); - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; - break; - - case DW_CFA_undefined: - insn_ptr = read_uleb128 (insn_ptr, ®); - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNDEFINED; - break; - - case DW_CFA_nop: - break; - - case DW_CFA_register: - { - _uleb128_t reg2; - insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_uleb128 (insn_ptr, ®2); - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg = - (_Unwind_Word)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, &utmp); - fs->regs.cfa_reg = (_Unwind_Word)utmp; - insn_ptr = read_uleb128 (insn_ptr, &utmp); - fs->regs.cfa_offset = (_Unwind_Word)utmp; - fs->regs.cfa_how = CFA_REG_OFFSET; - break; - - case DW_CFA_def_cfa_register: - insn_ptr = read_uleb128 (insn_ptr, &utmp); - fs->regs.cfa_reg = (_Unwind_Word)utmp; - fs->regs.cfa_how = CFA_REG_OFFSET; - break; - - case DW_CFA_def_cfa_offset: - insn_ptr = read_uleb128 (insn_ptr, &utmp); - fs->regs.cfa_offset = utmp; - /* cfa_how deliberately not set. */ - break; - - case DW_CFA_def_cfa_expression: - fs->regs.cfa_exp = insn_ptr; - fs->regs.cfa_how = CFA_EXP; - insn_ptr = read_uleb128 (insn_ptr, &utmp); - insn_ptr += utmp; - break; - - case DW_CFA_expression: - insn_ptr = read_uleb128 (insn_ptr, ®); - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; - insn_ptr = read_uleb128 (insn_ptr, &utmp); - insn_ptr += utmp; - break; - - /* Dwarf3. */ - case DW_CFA_offset_extended_sf: - insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_sleb128 (insn_ptr, &stmp); - offset = stmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; - break; - - case DW_CFA_def_cfa_sf: - insn_ptr = read_uleb128 (insn_ptr, &utmp); - fs->regs.cfa_reg = (_Unwind_Word)utmp; - insn_ptr = read_sleb128 (insn_ptr, &stmp); - fs->regs.cfa_offset = (_Unwind_Sword)stmp; - fs->regs.cfa_how = CFA_REG_OFFSET; - fs->regs.cfa_offset *= fs->data_align; - break; - - case DW_CFA_def_cfa_offset_sf: - insn_ptr = read_sleb128 (insn_ptr, &stmp); - fs->regs.cfa_offset = (_Unwind_Sword)stmp; - fs->regs.cfa_offset *= fs->data_align; - /* cfa_how deliberately not set. */ - break; - - case DW_CFA_val_offset: - insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_uleb128 (insn_ptr, &utmp); - offset = (_Unwind_Sword) utmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_VAL_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; - break; - - case DW_CFA_val_offset_sf: - insn_ptr = read_uleb128 (insn_ptr, ®); - insn_ptr = read_sleb128 (insn_ptr, &stmp); - offset = stmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_VAL_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; - break; - - case DW_CFA_val_expression: - insn_ptr = read_uleb128 (insn_ptr, ®); - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_VAL_EXP; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; - insn_ptr = read_uleb128 (insn_ptr, &utmp); - insn_ptr += utmp; - 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, &utmp); - context->args_size = (_Unwind_Word)utmp; - 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, ®); - insn_ptr = read_uleb128 (insn_ptr, &utmp); - offset = (_Unwind_Word) utmp * fs->data_align; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how - = REG_SAVED_OFFSET; - fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset; - break; - - default: - gcc_unreachable (); - } - } -} - -/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for - its caller and decode it into FS. This function also sets the - args_size and lsda members of CONTEXT, as they are really information - about the caller's frame. */ - -static _Unwind_Reason_Code -uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - const struct dwarf_fde *fde; - const struct dwarf_cie *cie; - const unsigned char *aug, *insn, *end; - - memset (fs, 0, sizeof (*fs)); - context->args_size = 0; - context->lsda = 0; - - if (context->ra == 0) - return _URC_END_OF_STACK; - - fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, - &context->bases); - if (fde == NULL) - { -#ifdef MD_FALLBACK_FRAME_STATE_FOR - /* Couldn't find frame unwind info for this function. Try a - target-specific fallback mechanism. This will necessarily - not provide a personality routine or LSDA. */ - return MD_FALLBACK_FRAME_STATE_FOR (context, fs); -#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 = (const unsigned char *) next_fde ((const struct dwarf_fde *) cie); - execute_cfa_program (insn, end, context, fs); - - /* Locate augmentation for the fde. */ - aug = (const unsigned char *) fde + sizeof (*fde); - aug += 2 * size_of_encoded_value (fs->fde_encoding); - insn = NULL; - if (fs->saw_z) - { - _uleb128_t i; - aug = read_uleb128 (aug, &i); - insn = aug + i; - } - if (fs->lsda_encoding != DW_EH_PE_omit) - { - _Unwind_Ptr lsda; - - aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); - context->lsda = (void *) lsda; - } - - /* Then the insns in the FDE up to our target PC. */ - if (insn == NULL) - insn = aug; - end = (const unsigned char *) next_fde (fde); - execute_cfa_program (insn, end, context, fs); - - return _URC_NO_REASON; -} - -typedef struct frame_state -{ - void *cfa; - void *eh_ptr; - long cfa_offset; - long args_size; - long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; - unsigned short cfa_reg; - unsigned short retaddr_column; - char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; -} frame_state; - -struct frame_state * __frame_state_for (void *, struct frame_state *); - -/* Called from pre-G++ 3.0 __throw to find the registers to restore for - a given PC_TARGET. The caller should allocate a local variable of - `struct frame_state' and pass its address to STATE_IN. */ - -struct frame_state * -__frame_state_for (void *pc_target, struct frame_state *state_in) -{ - struct _Unwind_Context context; - _Unwind_FrameState fs; - int reg; - - memset (&context, 0, sizeof (struct _Unwind_Context)); - context.flags = EXTENDED_CONTEXT_BIT; - context.ra = pc_target + 1; - - if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON) - return 0; - - /* We have no way to pass a location expression for the CFA to our - caller. It wouldn't understand it anyway. */ - if (fs.regs.cfa_how == CFA_EXP) - return 0; - - for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++) - { - state_in->saved[reg] = fs.regs.reg[reg].how; - switch (state_in->saved[reg]) - { - case REG_SAVED_REG: - state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg; - break; - case REG_SAVED_OFFSET: - state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset; - break; - default: - state_in->reg_or_offset[reg] = 0; - break; - } - } - - state_in->cfa_offset = fs.regs.cfa_offset; - state_in->cfa_reg = fs.regs.cfa_reg; - state_in->retaddr_column = fs.retaddr_column; - state_in->args_size = context.args_size; - state_in->eh_ptr = fs.eh_ptr; - - return state_in; -} - -typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp; - -static inline void -_Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa, - _Unwind_SpTmp *tmp_sp) -{ - int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()]; - - if (size == sizeof(_Unwind_Ptr)) - tmp_sp->ptr = (_Unwind_Ptr) cfa; - else - { - gcc_assert (size == sizeof(_Unwind_Word)); - tmp_sp->word = (_Unwind_Ptr) cfa; - } - _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp); -} - -static void -uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - struct _Unwind_Context orig_context = *context; - void *cfa; - long i; - -#ifdef EH_RETURN_STACKADJ_RTX - /* 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. - - In very special situations (such as unwind info for signal return), - there may be location expressions that use the stack pointer as well. - - Do this conditionally for one frame. This allows the unwind info - for one frame to save a copy of the stack pointer from the previous - frame, and be able to use much easier CFA mechanisms to do it. - Always zap the saved stack pointer value for the next frame; carrying - the value over from one frame to another doesn't make sense. */ - - _Unwind_SpTmp tmp_sp; - - if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ())) - _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp); - _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL); -#endif - - /* Compute this frame's CFA. */ - switch (fs->regs.cfa_how) - { - case CFA_REG_OFFSET: - cfa = _Unwind_GetPtr (&orig_context, fs->regs.cfa_reg); - cfa += fs->regs.cfa_offset; - break; - - case CFA_EXP: - { - const unsigned char *exp = fs->regs.cfa_exp; - _uleb128_t len; - - exp = read_uleb128 (exp, &len); - cfa = (void *) (_Unwind_Ptr) - execute_stack_op (exp, exp + len, &orig_context, 0); - break; - } - - default: - gcc_unreachable (); - } - 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: - case REG_UNDEFINED: - break; - - case REG_SAVED_OFFSET: - _Unwind_SetGRPtr (context, i, - (void *) (cfa + fs->regs.reg[i].loc.offset)); - break; - - case REG_SAVED_REG: - if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg)) - _Unwind_SetGRValue (context, i, - _Unwind_GetGR (&orig_context, - fs->regs.reg[i].loc.reg)); - else - _Unwind_SetGRPtr (context, i, - _Unwind_GetGRPtr (&orig_context, - fs->regs.reg[i].loc.reg)); - break; - - case REG_SAVED_EXP: - { - const unsigned char *exp = fs->regs.reg[i].loc.exp; - _uleb128_t len; - _Unwind_Ptr val; - - exp = read_uleb128 (exp, &len); - val = execute_stack_op (exp, exp + len, &orig_context, - (_Unwind_Ptr) cfa); - _Unwind_SetGRPtr (context, i, (void *) val); - } - break; - - case REG_SAVED_VAL_OFFSET: - _Unwind_SetGRValue (context, i, - (_Unwind_Internal_Ptr) - (cfa + fs->regs.reg[i].loc.offset)); - break; - - case REG_SAVED_VAL_EXP: - { - const unsigned char *exp = fs->regs.reg[i].loc.exp; - _uleb128_t len; - _Unwind_Ptr val; - - exp = read_uleb128 (exp, &len); - val = execute_stack_op (exp, exp + len, &orig_context, - (_Unwind_Ptr) cfa); - _Unwind_SetGRValue (context, i, val); - } - break; - } - - _Unwind_SetSignalFrame (context, fs->signal_frame); - -#ifdef MD_FROB_UPDATE_CONTEXT - MD_FROB_UPDATE_CONTEXT (context, fs); -#endif -} - -/* CONTEXT describes the unwind state for a frame, and FS describes the FDE - of its caller. Update CONTEXT to refer to the caller as well. Note - that the args_size and lsda members are not updated here, but later in - uw_frame_state_for. */ - -static void -uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - uw_update_context_1 (context, fs); - - /* In general this unwinder doesn't make any distinction between - undefined and same_value rule. Call-saved registers are assumed - to have same_value rule by default and explicit undefined - rule is handled like same_value. The only exception is - DW_CFA_undefined on retaddr_column which is supposed to - mark outermost frame in DWARF 3. */ - if (fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (fs->retaddr_column)].how - == REG_UNDEFINED) - /* uw_frame_state_for uses context->ra == 0 check to find outermost - stack frame. */ - context->ra = 0; - else - /* Compute the return address now, since the return address column - can change from frame to frame. */ - context->ra = __builtin_extract_return_addr - (_Unwind_GetPtr (context, fs->retaddr_column)); -} - -static void -uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - uw_update_context (context, fs); -} - -/* 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 inline void -init_dwarf_reg_size_table (void) -{ - __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table); -} - -static void __attribute__((noinline)) -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; - _Unwind_SpTmp sp_slot; - _Unwind_Reason_Code code; - - memset (context, 0, sizeof (struct _Unwind_Context)); - context->ra = ra; - context->flags = EXTENDED_CONTEXT_BIT; - - code = uw_frame_state_for (context, &fs); - gcc_assert (code == _URC_NO_REASON); - -#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 - - /* Force the frame state to use the known cfa value. */ - _Unwind_SetSpColumn (context, outer_cfa, &sp_slot); - fs.regs.cfa_how = CFA_REG_OFFSET; - fs.regs.cfa_reg = __builtin_dwarf_sp_column (); - fs.regs.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); -} - -static void _Unwind_DebugHook (void *, void *) - __attribute__ ((__noinline__, __used__, __noclone__)); - -/* This function is called during unwinding. It is intended as a hook - for a debugger to intercept exceptions. CFA is the CFA of the - target frame. HANDLER is the PC to which control will be - transferred. */ -static void -_Unwind_DebugHook (void *cfa __attribute__ ((__unused__)), - void *handler __attribute__ ((__unused__))) -{ - /* We only want to use stap probes starting with v3. Earlier - versions added too much startup cost. */ -#if defined (HAVE_SYS_SDT_H) && defined (STAP_PROBE2) && _SDT_NOTE_TYPE >= 3 - STAP_PROBE2 (libgcc, unwind, cfa, handler); -#else - asm (""); -#endif -} - -/* 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); \ - _Unwind_DebugHook ((TARGET)->cfa, handler); \ - __builtin_eh_return (offset, handler); \ - } \ - while (0) - -static long -uw_install_context_1 (struct _Unwind_Context *current, - struct _Unwind_Context *target) -{ - long i; - _Unwind_SpTmp sp_slot; - - /* If the target frame does not have a saved stack pointer, - then set up the target's CFA. */ - if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ())) - _Unwind_SetSpColumn (target, target->cfa, &sp_slot); - - for (i = 0; i < DWARF_FRAME_REGISTERS; ++i) - { - void *c = current->reg[i]; - void *t = target->reg[i]; - - gcc_assert (current->by_value[i] == 0); - if (target->by_value[i] && c) - { - _Unwind_Word w; - _Unwind_Ptr p; - if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word)) - { - w = (_Unwind_Internal_Ptr) t; - memcpy (c, &w, sizeof (_Unwind_Word)); - } - else - { - gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr)); - p = (_Unwind_Internal_Ptr) t; - memcpy (c, &p, sizeof (_Unwind_Ptr)); - } - } - else if (t && c && t != c) - memcpy (c, t, dwarf_reg_size_table[i]); - } - - /* If the current frame doesn't have a saved stack pointer, then we - need to rely on EH_RETURN_STACKADJ_RTX to get our target stack - pointer value reloaded. */ - if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ())) - { - void *target_cfa; - - target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ()); - - /* 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; - } - return 0; -} - -static inline _Unwind_Ptr -uw_identify_context (struct _Unwind_Context *context) -{ - /* The CFA is not sufficient to disambiguate the context of a function - interrupted by a signal before establishing its frame and the context - of the signal itself. */ - if (STACK_GROWS_DOWNWARD) - return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context); - else - return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context); -} - - -#include "unwind.inc" - -#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) -alias (_Unwind_Backtrace); -alias (_Unwind_DeleteException); -alias (_Unwind_FindEnclosingFunction); -alias (_Unwind_ForcedUnwind); -alias (_Unwind_GetDataRelBase); -alias (_Unwind_GetTextRelBase); -alias (_Unwind_GetCFA); -alias (_Unwind_GetGR); -alias (_Unwind_GetIP); -alias (_Unwind_GetLanguageSpecificData); -alias (_Unwind_GetRegionStart); -alias (_Unwind_RaiseException); -alias (_Unwind_Resume); -alias (_Unwind_Resume_or_Rethrow); -alias (_Unwind_SetGR); -alias (_Unwind_SetIP); -#endif - -#endif /* !USING_SJLJ_EXCEPTIONS */ diff --git a/gcc/unwind-dw2.h b/gcc/unwind-dw2.h deleted file mode 100644 index 2c558b4962a..00000000000 --- a/gcc/unwind-dw2.h +++ /dev/null @@ -1,87 +0,0 @@ -/* DWARF2 frame unwind data structure. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2009 - Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* 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 - -/* 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 { - _Unwind_Word reg; - _Unwind_Sword offset; - const unsigned char *exp; - } loc; - enum { - REG_UNSAVED, - REG_SAVED_OFFSET, - REG_SAVED_REG, - REG_SAVED_EXP, - REG_SAVED_VAL_OFFSET, - REG_SAVED_VAL_EXP, - REG_UNDEFINED - } how; - } reg[DWARF_FRAME_REGISTERS+1]; - - /* Used to implement DW_CFA_remember_state. */ - struct frame_state_reg_info *prev; - - /* 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; - } regs; - - /* The PC described by the current frame state. */ - void *pc; - - /* The information we care about from the CIE/FDE. */ - _Unwind_Personality_Fn personality; - _Unwind_Sword data_align; - _Unwind_Word code_align; - _Unwind_Word retaddr_column; - unsigned char fde_encoding; - unsigned char lsda_encoding; - unsigned char saw_z; - unsigned char signal_frame; - void *eh_ptr; -} _Unwind_FrameState; - diff --git a/gcc/unwind-generic.h b/gcc/unwind-generic.h deleted file mode 100644 index 4ff9017b88b..00000000000 --- a/gcc/unwind-generic.h +++ /dev/null @@ -1,276 +0,0 @@ -/* Exception handling and frame unwind runtime interface routines. - Copyright (C) 2001, 2003, 2004, 2006, 2008, 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* This is derived from the C++ ABI for IA-64. Where we diverge - for cross-architecture compatibility are noted with "@@@". */ - -#ifndef _UNWIND_H -#define _UNWIND_H - -#ifndef HIDE_EXPORTS -#pragma GCC visibility push(default) -#endif - -#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__(__unwind_word__))); -typedef signed _Unwind_Sword __attribute__((__mode__(__unwind_word__))); -#if defined(__ia64__) && defined(__hpux__) -typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__))); -#else -typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); -#endif -typedef unsigned _Unwind_Internal_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 -#define _UA_END_OF_STACK 16 - -/* The target can override this macro to define any back-end-specific - attributes required for the lowest-level stack frame. */ -#ifndef LIBGCC2_UNWIND_ATTRIBUTE -#define LIBGCC2_UNWIND_ATTRIBUTE -#endif - -/* 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 LIBGCC2_UNWIND_ATTRIBUTE -_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 LIBGCC2_UNWIND_ATTRIBUTE -_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 LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume (struct _Unwind_Exception *); - -/* @@@ Resume propagation of a FORCE_UNWIND exception, or to rethrow - a normal exception that was handled. */ -extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *); - -/* @@@ Use unwind data to perform a stack backtrace. The trace callback - is called for every stack frame in the call chain, but no cleanup - actions are performed. */ -typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) - (struct _Unwind_Context *, void *); - -extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Backtrace (_Unwind_Trace_Fn, void *); - -/* 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 may be 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 _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *); -extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr); - -/* @@@ Retrieve the CFA of the given context. */ -extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); - -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 LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_SjLj_RaiseException (struct _Unwind_Exception *); -extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_SjLj_ForcedUnwind (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); -extern void LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_SjLj_Resume (struct _Unwind_Exception *); -extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_SjLj_Resume_or_Rethrow (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 - -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 __attribute__ ((__unused__))) -{ - abort (); - return 0; -} - -/* @@@ Retrieve the Backing Store Pointer of the given context. */ -extern _Unwind_Word _Unwind_GetBSP (struct _Unwind_Context *); -#else -extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *); -extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *); -#endif - -/* @@@ Given an address, return the entry point of the function that - contains it. */ -extern void * _Unwind_FindEnclosingFunction (void *pc); - -#ifndef __SIZEOF_LONG__ - #error "__SIZEOF_LONG__ macro not defined" -#endif - -#ifndef __SIZEOF_POINTER__ - #error "__SIZEOF_POINTER__ macro not defined" -#endif - - -/* leb128 type numbers have a potentially unlimited size. - The target of the following definitions of _sleb128_t and _uleb128_t - is to have efficient data types large enough to hold the leb128 type - numbers used in the unwind code. - Mostly these types will simply be defined to long and unsigned long - except when a unsigned long data type on the target machine is not - capable of storing a pointer. */ - -#if __SIZEOF_LONG__ >= __SIZEOF_POINTER__ - typedef long _sleb128_t; - typedef unsigned long _uleb128_t; -#elif __SIZEOF_LONG_LONG__ >= __SIZEOF_POINTER__ - typedef long long _sleb128_t; - typedef unsigned long long _uleb128_t; -#else -# error "What type shall we use for _sleb128_t?" -#endif - -#ifdef __cplusplus -} -#endif - -#ifndef HIDE_EXPORTS -#pragma GCC visibility pop -#endif - -#endif /* unwind.h */ diff --git a/gcc/unwind-pe.h b/gcc/unwind-pe.h deleted file mode 100644 index 121f8776721..00000000000 --- a/gcc/unwind-pe.h +++ /dev/null @@ -1,289 +0,0 @@ -/* Exception handling and frame unwind runtime interface routines. - Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* @@@ 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. */ - -#ifndef GCC_UNWIND_PE_H -#define GCC_UNWIND_PE_H - -/* 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 - - -#ifndef NO_SIZE_OF_ENCODED_VALUE - -/* 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) __attribute__ ((unused)); - -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 (); -} - -#endif - -#ifndef NO_BASE_OF_ENCODED_VALUE - -/* 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 (); -} - -#endif - -/* Read an unsigned leb128 value from P, store the value in VAL, return - P incremented past the value. We assume that a word is large enough to - hold any value so encoded; if it is smaller than a pointer on some target, - pointers should not be leb128 encoded on that target. */ - -static const unsigned char * -read_uleb128 (const unsigned char *p, _uleb128_t *val) -{ - unsigned int shift = 0; - unsigned char byte; - _uleb128_t result; - - result = 0; - do - { - byte = *p++; - result |= ((_uleb128_t)byte & 0x7f) << shift; - shift += 7; - } - while (byte & 0x80); - - *val = result; - return p; -} - -/* Similar, but read a signed leb128 value. */ - -static const unsigned char * -read_sleb128 (const unsigned char *p, _sleb128_t *val) -{ - unsigned int shift = 0; - unsigned char byte; - _uleb128_t result; - - result = 0; - do - { - byte = *p++; - result |= ((_uleb128_t)byte & 0x7f) << shift; - shift += 7; - } - while (byte & 0x80); - - /* Sign-extend a negative value. */ - if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) - result |= -(((_uleb128_t)1L) << shift); - - *val = (_sleb128_t) result; - return p; -} - -/* 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__)); - - const union unaligned *u = (const union unaligned *) p; - _Unwind_Internal_Ptr result; - - if (encoding == DW_EH_PE_aligned) - { - _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; - a = (a + sizeof (void *) - 1) & - sizeof(void *); - result = *(_Unwind_Internal_Ptr *) a; - p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *)); - } - else - { - switch (encoding & 0x0f) - { - case DW_EH_PE_absptr: - result = (_Unwind_Internal_Ptr) u->ptr; - p += sizeof (void *); - break; - - case DW_EH_PE_uleb128: - { - _uleb128_t tmp; - p = read_uleb128 (p, &tmp); - result = (_Unwind_Internal_Ptr) tmp; - } - break; - - case DW_EH_PE_sleb128: - { - _sleb128_t tmp; - p = read_sleb128 (p, &tmp); - result = (_Unwind_Internal_Ptr) tmp; - } - 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_Internal_Ptr) u : base); - if (encoding & DW_EH_PE_indirect) - result = *(_Unwind_Internal_Ptr *) result; - } - } - - *val = result; - return p; -} - -#ifndef NO_BASE_OF_ENCODED_VALUE - -/* 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); -} - -#endif - -#endif /* unwind-pe.h */ diff --git a/gcc/unwind-sjlj.c b/gcc/unwind-sjlj.c deleted file mode 100644 index c71e79858ee..00000000000 --- a/gcc/unwind-sjlj.c +++ /dev/null @@ -1,326 +0,0 @@ -/* SJLJ exception handling and frame unwind runtime interface routines. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, - 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -#include "tconfig.h" -#include "tsystem.h" -#include "coretypes.h" -#include "tm.h" -#include "unwind.h" -#include "gthr.h" - -#ifdef __USING_SJLJ_EXCEPTIONS__ - -#ifdef DONT_USE_BUILTIN_SETJMP -#ifndef inhibit_libc -#include -#else -typedef void *jmp_buf[JMP_BUF_SIZE]; -extern void longjmp(jmp_buf, int) __attribute__((noreturn)); -#endif -#else -#define longjmp __builtin_longjmp -#endif - -/* The setjmp side is dealt with in the except.c file. */ -#undef setjmp -#define setjmp setjmp_should_not_be_used_in_this_file - - -/* This structure is allocated on the stack of the target function. - This must match the definition created in except.c:init_eh. */ -struct SjLj_Function_Context -{ - /* This is the chain through all registered contexts. It is - filled in by _Unwind_SjLj_Register. */ - struct SjLj_Function_Context *prev; - - /* This is assigned in by the target function before every call - to the index of the call site in the lsda. It is assigned by - the personality routine to the landing pad index. */ - int call_site; - - /* This is how data is returned from the personality routine to - the target function's handler. */ - _Unwind_Word data[4]; - - /* These are filled in once by the target function before any - exceptions are expected to be handled. */ - _Unwind_Personality_Fn personality; - void *lsda; - -#ifdef DONT_USE_BUILTIN_SETJMP - /* We don't know what sort of alignment requirements the system - jmp_buf has. We over estimated in except.c, and now we have - to match that here just in case the system *didn't* have more - restrictive requirements. */ - jmp_buf jbuf __attribute__((aligned)); -#else - void *jbuf[]; -#endif -}; - -struct _Unwind_Context -{ - struct SjLj_Function_Context *fc; -}; - -typedef struct -{ - _Unwind_Personality_Fn personality; -} _Unwind_FrameState; - - -/* Manage the chain of registered function contexts. */ - -/* Single threaded fallback chain. */ -static struct SjLj_Function_Context *fc_static; - -#if __GTHREADS -static __gthread_key_t fc_key; -static int use_fc_key = -1; - -static void -fc_key_init (void) -{ - use_fc_key = __gthread_key_create (&fc_key, 0) == 0; -} - -static void -fc_key_init_once (void) -{ - static __gthread_once_t once = __GTHREAD_ONCE_INIT; - if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0) - use_fc_key = 0; -} -#endif - -void -_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) -{ -#if __GTHREADS - if (use_fc_key < 0) - fc_key_init_once (); - - if (use_fc_key) - { - fc->prev = __gthread_getspecific (fc_key); - __gthread_setspecific (fc_key, fc); - } - else -#endif - { - fc->prev = fc_static; - fc_static = fc; - } -} - -static inline struct SjLj_Function_Context * -_Unwind_SjLj_GetContext (void) -{ -#if __GTHREADS - if (use_fc_key < 0) - fc_key_init_once (); - - if (use_fc_key) - return __gthread_getspecific (fc_key); -#endif - return fc_static; -} - -static inline void -_Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc) -{ -#if __GTHREADS - if (use_fc_key < 0) - fc_key_init_once (); - - if (use_fc_key) - __gthread_setspecific (fc_key, fc); - else -#endif - fc_static = fc; -} - -void -_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) -{ - _Unwind_SjLj_SetContext (fc->prev); -} - - -/* Get/set the return data value at INDEX in CONTEXT. */ - -_Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) -{ - return context->fc->data[index]; -} - -/* Get the value of the CFA as saved in CONTEXT. */ - -_Unwind_Word -_Unwind_GetCFA (struct _Unwind_Context *context __attribute__((unused))) -{ - /* ??? Ideally __builtin_setjmp places the CFA in the jmpbuf. */ - -#ifndef DONT_USE_BUILTIN_SETJMP - /* This is a crude imitation of the CFA: the saved stack pointer. - This is roughly the CFA of the frame before CONTEXT. When using the - DWARF-2 unwinder _Unwind_GetCFA returns the CFA of the frame described - by CONTEXT instead; but for DWARF-2 the cleanups associated with - CONTEXT have already been run, and for SJLJ they have not yet been. */ - if (context->fc != NULL) - return (_Unwind_Word) context->fc->jbuf[2]; -#endif - - /* Otherwise we're out of luck for now. */ - return (_Unwind_Word) 0; -} - -void -_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) -{ - context->fc->data[index] = val; -} - -/* Get the call-site index as saved in CONTEXT. */ - -_Unwind_Ptr -_Unwind_GetIP (struct _Unwind_Context *context) -{ - return context->fc->call_site + 1; -} - -_Unwind_Ptr -_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) -{ - *ip_before_insn = 0; - if (context->fc != NULL) - return context->fc->call_site + 1; - else - return 0; -} - -/* Set the return landing pad index in CONTEXT. */ - -void -_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) -{ - context->fc->call_site = val - 1; -} - -void * -_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) -{ - return context->fc->lsda; -} - -_Unwind_Ptr -_Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) ) -{ - return 0; -} - -void * -_Unwind_FindEnclosingFunction (void *pc __attribute__((unused))) -{ - return NULL; -} - -#ifndef __ia64__ -_Unwind_Ptr -_Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) ) -{ - return 0; -} - -_Unwind_Ptr -_Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) ) -{ - return 0; -} -#endif - -static inline _Unwind_Reason_Code -uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - if (context->fc == NULL) - { - fs->personality = NULL; - return _URC_END_OF_STACK; - } - else - { - fs->personality = context->fc->personality; - return _URC_NO_REASON; - } -} - -static inline void -uw_update_context (struct _Unwind_Context *context, - _Unwind_FrameState *fs __attribute__((unused)) ) -{ - context->fc = context->fc->prev; -} - -static void -uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) -{ - _Unwind_SjLj_Unregister (context->fc); - uw_update_context (context, fs); -} - -static inline void -uw_init_context (struct _Unwind_Context *context) -{ - context->fc = _Unwind_SjLj_GetContext (); -} - -static void __attribute__((noreturn)) -uw_install_context (struct _Unwind_Context *current __attribute__((unused)), - struct _Unwind_Context *target) -{ - _Unwind_SjLj_SetContext (target->fc); - longjmp (target->fc->jbuf, 1); -} - -static inline _Unwind_Ptr -uw_identify_context (struct _Unwind_Context *context) -{ - return (_Unwind_Ptr) context->fc; -} - - -/* Play games with unwind symbols so that we can have call frame - and sjlj symbols in the same shared library. Not that you can - use them simultaneously... */ -#define _Unwind_RaiseException _Unwind_SjLj_RaiseException -#define _Unwind_ForcedUnwind _Unwind_SjLj_ForcedUnwind -#define _Unwind_Resume _Unwind_SjLj_Resume -#define _Unwind_Resume_or_Rethrow _Unwind_SjLj_Resume_or_Rethrow - -#include "unwind.inc" - -#endif /* USING_SJLJ_EXCEPTIONS */ diff --git a/gcc/unwind.inc b/gcc/unwind.inc deleted file mode 100644 index 5e2ec29c79a..00000000000 --- a/gcc/unwind.inc +++ /dev/null @@ -1,307 +0,0 @@ -/* Exception handling and frame unwind runtime interface routines. -*- C -*- - Copyright (C) 2001, 2003, 2008, 2009 Free Software Foundation, Inc. - - This file is part of GCC. - - GCC 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 3, or (at your option) - any later version. - - GCC 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. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* This is derived from the C++ ABI for IA-64. Where we diverge - for cross-architecture compatibility are noted with "@@@". - This file is included from unwind-dw2.c, unwind-sjlj.c or - unwind-ia64.c. */ - -/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. - - Unwind the stack calling the personality routine to find both the - exception handler and intermediary cleanup code. We'll only locate - the first such frame here. Cleanup code will call back into - _Unwind_Resume and we'll continue Phase 2 there. */ - -static _Unwind_Reason_Code -_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, - struct _Unwind_Context *context) -{ - _Unwind_Reason_Code code; - - while (1) - { - _Unwind_FrameState fs; - int match_handler; - - code = uw_frame_state_for (context, &fs); - - /* Identify when we've reached the designated handler context. */ - match_handler = (uw_identify_context (context) == exc->private_2 - ? _UA_HANDLER_FRAME : 0); - - if (code != _URC_NO_REASON) - /* Some error encountered. Usually the unwinder doesn't - diagnose these and merely crashes. */ - return _URC_FATAL_PHASE2_ERROR; - - /* Unwind successful. Run the personality routine, if any. */ - if (fs.personality) - { - code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, - exc->exception_class, exc, context); - if (code == _URC_INSTALL_CONTEXT) - break; - if (code != _URC_CONTINUE_UNWIND) - return _URC_FATAL_PHASE2_ERROR; - } - - /* Don't let us unwind past the handler context. */ - gcc_assert (!match_handler); - - uw_update_context (context, &fs); - } - - return code; -} - -/* Raise an exception, passing along the given exception object. */ - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_RaiseException(struct _Unwind_Exception *exc) -{ - struct _Unwind_Context this_context, cur_context; - _Unwind_Reason_Code code; - - /* Set up this_context to describe the current stack frame. */ - uw_init_context (&this_context); - cur_context = this_context; - - /* Phase 1: Search. Unwind the stack, calling the personality routine - with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ - while (1) - { - _Unwind_FrameState fs; - - /* Set up fs to describe the FDE for the caller of cur_context. The - first time through the loop, that means __cxa_throw. */ - code = uw_frame_state_for (&cur_context, &fs); - - if (code == _URC_END_OF_STACK) - /* Hit end of stack with no handler found. */ - return _URC_END_OF_STACK; - - if (code != _URC_NO_REASON) - /* Some error encountered. Usually the unwinder doesn't - diagnose these and merely crashes. */ - return _URC_FATAL_PHASE1_ERROR; - - /* Unwind successful. Run the personality routine, if any. */ - if (fs.personality) - { - code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, - exc, &cur_context); - if (code == _URC_HANDLER_FOUND) - break; - else if (code != _URC_CONTINUE_UNWIND) - return _URC_FATAL_PHASE1_ERROR; - } - - /* Update cur_context to describe the same frame as fs. */ - uw_update_context (&cur_context, &fs); - } - - /* Indicate to _Unwind_Resume and associated subroutines that this - is not a forced unwind. Further, note where we found a handler. */ - exc->private_1 = 0; - exc->private_2 = uw_identify_context (&cur_context); - - cur_context = this_context; - code = _Unwind_RaiseException_Phase2 (exc, &cur_context); - if (code != _URC_INSTALL_CONTEXT) - return code; - - uw_install_context (&this_context, &cur_context); -} - - -/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ - -static _Unwind_Reason_Code -_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, - struct _Unwind_Context *context) -{ - _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; - void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; - _Unwind_Reason_Code code, stop_code; - - while (1) - { - _Unwind_FrameState fs; - int action; - - /* Set up fs to describe the FDE for the caller of cur_context. */ - code = uw_frame_state_for (context, &fs); - if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) - return _URC_FATAL_PHASE2_ERROR; - - /* Unwind successful. */ - action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; - if (code == _URC_END_OF_STACK) - action |= _UA_END_OF_STACK; - stop_code = (*stop) (1, action, exc->exception_class, exc, - context, stop_argument); - if (stop_code != _URC_NO_REASON) - return _URC_FATAL_PHASE2_ERROR; - - /* Stop didn't want to do anything. Invoke the personality - handler, if applicable, to run cleanups. */ - if (code == _URC_END_OF_STACK) - break; - - if (fs.personality) - { - code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, - exc->exception_class, exc, context); - if (code == _URC_INSTALL_CONTEXT) - break; - if (code != _URC_CONTINUE_UNWIND) - return _URC_FATAL_PHASE2_ERROR; - } - - /* Update cur_context to describe the same frame as fs, and discard - the previous context if necessary. */ - uw_advance_context (context, &fs); - } - - return code; -} - - -/* Raise an exception for forced unwinding. */ - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, - _Unwind_Stop_Fn stop, void * stop_argument) -{ - struct _Unwind_Context this_context, cur_context; - _Unwind_Reason_Code code; - - uw_init_context (&this_context); - cur_context = this_context; - - exc->private_1 = (_Unwind_Ptr) stop; - exc->private_2 = (_Unwind_Ptr) stop_argument; - - code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); - if (code != _URC_INSTALL_CONTEXT) - return code; - - uw_install_context (&this_context, &cur_context); -} - - -/* Resume propagation of an existing exception. This is used after - e.g. executing cleanup code, and not to implement rethrowing. */ - -void LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume (struct _Unwind_Exception *exc) -{ - struct _Unwind_Context this_context, cur_context; - _Unwind_Reason_Code code; - - uw_init_context (&this_context); - cur_context = this_context; - - /* Choose between continuing to process _Unwind_RaiseException - or _Unwind_ForcedUnwind. */ - if (exc->private_1 == 0) - code = _Unwind_RaiseException_Phase2 (exc, &cur_context); - else - code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); - - gcc_assert (code == _URC_INSTALL_CONTEXT); - - uw_install_context (&this_context, &cur_context); -} - - -/* Resume propagation of an FORCE_UNWIND exception, or to rethrow - a normal exception that was handled. */ - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) -{ - struct _Unwind_Context this_context, cur_context; - _Unwind_Reason_Code code; - - /* Choose between continuing to process _Unwind_RaiseException - or _Unwind_ForcedUnwind. */ - if (exc->private_1 == 0) - return _Unwind_RaiseException (exc); - - uw_init_context (&this_context); - cur_context = this_context; - - code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); - - gcc_assert (code == _URC_INSTALL_CONTEXT); - - uw_install_context (&this_context, &cur_context); -} - - -/* A convenience function that calls the exception_cleanup field. */ - -void -_Unwind_DeleteException (struct _Unwind_Exception *exc) -{ - if (exc->exception_cleanup) - (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); -} - - -/* Perform stack backtrace through unwind data. */ - -_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE -_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) -{ - struct _Unwind_Context context; - _Unwind_Reason_Code code; - - uw_init_context (&context); - - while (1) - { - _Unwind_FrameState fs; - - /* Set up fs to describe the FDE for the caller of context. */ - code = uw_frame_state_for (&context, &fs); - if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) - return _URC_FATAL_PHASE1_ERROR; - - /* Call trace function. */ - if ((*trace) (&context, trace_argument) != _URC_NO_REASON) - return _URC_FATAL_PHASE1_ERROR; - - /* We're done at end of stack. */ - if (code == _URC_END_OF_STACK) - break; - - /* Update context to describe the same frame as fs. */ - uw_update_context (&context, &fs); - } - - return code; -} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 322b93ec861..65d47a80278 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,68 @@ +2011-08-05 Rainer Orth + + * Makefile.in (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): New + variables. + (LIBUNWIND, SHLIBUNWIND_LINK, SHLIBUNWIND_INSTALL): New variables. + (LIB2ADDEH, LIB2ADDEHSTATIC, LIB2ADDEHSHARED): Add $(srcdir)/emutls.c. + (install-unwind_h): New target. + (all): Depend on it. + * config.host (unwind_header): New variable. + (*-*-freebsd*): Set tmake_file to t-eh-dw2-dip. + (*-*-linux*, frv-*-*linux*, *-*-kfreebsd*-gnu, *-*-knetbsd*-gnu, + *-*-gnu*): Likewise, also for *-*-kopensolaris*-gnu. + (*-*-solaris2*): Add t-eh-dw2-dip to tmake_file. + (arm*-*-linux*): Add arm/t-bpabi for arm*-*-linux-*eabi. + Set unwind_header. + (arm*-*-uclinux*): Add arm/t-bpabi for arm*-*-uclinux*eabi. + Set unwind_header. + (arm*-*-eabi*, arm*-*-symbianelf*): Add arm/t-bpabi for + arm*-*-eabi*. + Add arm/t-symbian to tmake_file for arm*-*-symbianelf*. + Set unwind_header. + (ia64*-*-elf*): Add ia64/t-eh-ia64 to tmake_file. + (ia64*-*-freebsd*): Likewise. + (ia64*-*-linux*): Add ia64/t-glibc, ia64/t-eh-ia64, t-libunwind to + tmake_file. + Add t-libunwind-elf, ia64/t-glibc-libunwind unless + $with_system_libunwind. + (ia64*-*-hpux*): Set tmake_file. + (ia64-hp-*vms*): Add ia64/t-eh-ia64 to tmake_file. + (picochip-*-*): Set tmake_file. + (rs6000-ibm-aix4.[3456789]*, powerpc-ibm-aix4.[3456789]*): Set + md_unwind_header. + (rs6000-ibm-aix5.1.*, powerpc-ibm-aix5.1.*): Likewise. + (rs6000-ibm-aix[56789].*, powerpc-ibm-aix[56789].*): Likewise. + (s390x-ibm-tpf*): Add t-eh-dw2-dip to tmake_file. + (xtensa*-*-elf*): Set tmake_file. + (xtensa*-*-linux*): Likewise. + * configure.ac: Include ../config/unwind_ipinfo.m4. + Call GCC_CHECK_UNWIND_GETIPINFO. + Link unwind.h to $unwind_header. + * configure: Regenerate. + * emutls.c, unwind-c.c, unwind-compat.c, unwind-compat.h, + unwind-dw2-fde-compat.c, unwind-dw2-fde-dip.c, unwind-dw2-fde.c, + unwind-dw2-fde.h, unwind-dw2.c, unwind-dw2.h, unwind-generic.h, + unwind-pe.h, unwind-sjlj.c, unwind.inc: New files. + * config/unwind-dw2-fde-darwin.c: New file. + * config/arm/libunwind.S, config/arm/pr-support.c, + config/arm/t-bpabi, config/arm/t-symbian, config/arm/unwind-arm.c, + config/arm/unwind-arm.h,: New files. + * config/ia64/fde-glibc.c, config/ia64/fde-vms.c, + config/ia64/t-eh-ia64, config/ia64/t-glibc, + config/ia64/t-glibc-libunwind, config/ia64/t-hpux, + config/ia64/t-vms, config/ia64/unwind-ia64.c, + config/ia64/unwind-ia64.h: New files. + * config/picochip/t-picochip: New file. + * config/rs6000/aix-unwind.h, config/rs6000/darwin-fallback.c: New + files. + * config/rs6000/t-darwin (LIB2ADDEH): Set. + * config/s390/t-tpf (LIB2ADDEH): Remove. + * config/t-darwin (LIB2ADDEH): Set. + * config/t-eh-dw2-dip: New file. + * config/t-libunwind, config/t-libunwind-elf: New files. + * config/t-sol2 (LIB2ADDEH): Remove. + * config/xtensa/t-xtensa: New file. + 2011-08-02 H.J. Lu * config/i386/linux-unwind.h (RT_SIGRETURN_SYSCALL): New. diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index 5f7cd629fc2..c252d9a2217 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -256,6 +256,17 @@ LIBGCC_VER_GNU_PREFIX = __ LIBGCC_VER_FIXEDPOINT_GNU_PREFIX = __ LIBGCC_VER_SYMBOLS_PREFIX = +# Additional sources to handle exceptions; overridden by targets as needed. +LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c +LIB2ADDEHSTATIC = $(LIB2ADDEH) +LIB2ADDEHSHARED = $(LIB2ADDEH) + +# Don't build libunwind by default. +LIBUNWIND = +SHLIBUNWIND_LINK = +SHLIBUNWIND_INSTALL = + tmake_file = @tmake_file@ include $(srcdir)/empty.mk $(tmake_file) @@ -316,6 +327,10 @@ endif LIB2ADD += enable-execute-stack.c +LIB2ADDEH += $(srcdir)/emutls.c +LIB2ADDEHSTATIC += $(srcdir)/emutls.c +LIB2ADDEHSHARED += $(srcdir)/emutls.c + # Library members defined in libgcc2.c. lib2funcs = _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 _cmpdi2 _ucmpdi2 \ _clear_cache _trampoline __main _absvsi2 \ @@ -967,6 +982,12 @@ gcc-extra-parts: all: $(extra-parts) +install-unwind_h: + cp unwind.h $(gcc_objdir)/include/unwind.h + chmod a+r $(gcc_objdir)/include/unwind.h + +all: install-unwind_h + # Documentation targets (empty). .PHONY: info html dvi pdf install-info install-html install-pdf diff --git a/libgcc/config.host b/libgcc/config.host index f7c1b3bd035..db00c4c2d8c 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -57,12 +57,15 @@ # tmake_file A list of machine-description-specific # makefile-fragments, if different from # "$cpu_type/t-$cpu_type". +# unwind_header The name of the header file declaring the unwind +# runtime interface routines. asm_hidden_op=.hidden enable_execute_stack= extra_parts= tmake_file= md_unwind_header=no-unwind.h +unwind_header=unwind-generic.h # Set default cpu_type so it can be updated in each machine entry. cpu_type=`echo ${host} | sed 's/-.*$//'` @@ -171,8 +174,10 @@ case ${host} in # This is the generic ELF configuration of FreeBSD. Later # machine-specific sections may refine and add to this # configuration. + tmake_file=t-eh-dw2-dip ;; -*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu*) +*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu) + tmake_file=t-eh-dw2-dip extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o" ;; *-*-netbsd*) @@ -182,7 +187,9 @@ case ${host} in *-*-rtems*) ;; *-*-solaris2*) - tmake_file="$tmake_file t-sol2 t-slibgcc t-slibgcc-elf-ver" + # Unless linker support and dl_iterate_phdr are present, + # unwind-dw2-fde-dip.c automatically falls back to unwind-dw2-fde.c. + tmake_file="$tmake_file t-sol2 t-eh-dw2-dip t-slibgcc t-slibgcc-elf-ver" if test $with_gnu_ld = yes; then tmake_file="$tmake_file t-slibgcc-gld" else @@ -265,14 +272,35 @@ arm*-*-netbsdelf*) ;; arm*-*-linux*) # ARM GNU/Linux with ELF tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" + case ${host} in + arm*-*-linux-*eabi) + tmake_file="${tmake_file} arm/t-bpabi" + unwind_header=config/arm/unwind-arm.h + ;; + esac ;; arm*-*-uclinux*) # ARM ucLinux tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" + case ${host} in + arm*-*-uclinux*eabi) + tmake_file="${tmake_file} arm/t-bpabi" + unwind_header=config/arm/unwind-arm.h + ;; + esac ;; arm*-*-ecos-elf) ;; arm*-*-eabi* | arm*-*-symbianelf* ) tmake_file="${tmake_file} t-fixedpoint-gnu-prefix" + case ${host} in + arm*-*-eabi*) + tmake_file="${tmake_file} arm/t-bpabi" + ;; + arm*-*-symbianelf*) + tmake_file="${tmake_file} arm/t-symbian" + ;; + esac + unwind_header=config/arm/unwind-arm.h ;; arm*-*-rtems*) ;; @@ -408,21 +436,25 @@ i[34567]86-*-interix3*) ;; ia64*-*-elf*) extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" - tmake_file="ia64/t-ia64 t-crtfm" + tmake_file="ia64/t-ia64 ia64/t-eh-ia64 t-crtfm" ;; ia64*-*-freebsd*) extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" - tmake_file="ia64/t-ia64 t-crtfm" + tmake_file="ia64/t-ia64 ia64/t-eh-ia64 t-crtfm" ;; ia64*-*-linux*) extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtfastmath.o" - tmake_file="ia64/t-ia64 t-crtfm t-softfp ia64/t-fprules-softfp ia64/t-softfp-compat" + tmake_file="ia64/t-ia64 t-crtfm t-softfp ia64/t-fprules-softfp ia64/t-softfp-compat ia64/t-glibc ia64/t-eh-ia64 t-libunwind" + if test x$with_system_libunwind != xyes ; then + tmake_file="${tmake_file} t-libunwind-elf ia64/t-glibc-libunwind" + fi md_unwind_header=ia64/linux-unwind.h ;; ia64*-*-hpux*) + tmake_file="ia64/t-hpux" ;; ia64-hp-*vms*) - tmake_file="vms/t-vms vms/t-vms64 ia64/t-vms" + tmake_file="vms/t-vms vms/t-vms64 ia64/t-eh-ia64 ia64/t-vms" md_unwind_header=ia64/vms-unwind.h ;; iq2000*-*-elf*) @@ -522,6 +554,7 @@ moxie-*-*) pdp11-*-*) ;; picochip-*-*) + tmake_file=picochip/t-picochip ;; powerpc-*-darwin*) case ${host} in @@ -574,10 +607,13 @@ powerpcle-*-eabisim*) powerpcle-*-eabi*) ;; rs6000-ibm-aix4.[3456789]* | powerpc-ibm-aix4.[3456789]*) + md_unwind_header=rs6000/aix-unwind.h ;; rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*) + md_unwind_header=rs6000/aix-unwind.h ;; rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*) + md_unwind_header=rs6000/aix-unwind.h ;; rx-*-elf) extra_parts="crtbegin.o crtend.o" @@ -592,7 +628,7 @@ s390x-*-linux*) md_unwind_header=s390/linux-unwind.h ;; s390x-ibm-tpf*) - tmake_file="${tmake_file} s390/t-crtstuff s390/t-tpf" + tmake_file="${tmake_file} s390/t-crtstuff s390/t-tpf t-eh-dw2-dip" md_unwind_header=s390/tpf-unwind.h ;; score-*-elf) @@ -674,8 +710,10 @@ vax-*-openbsd*) xstormy16-*-elf) ;; xtensa*-*-elf*) + tmake_file=xtensa/t-xtensa ;; xtensa*-*-linux*) + tmake_file=xtensa/t-xtensa md_unwind_header=xtensa/linux-unwind.h ;; am33_2.0-*-linux*) diff --git a/libgcc/config/arm/libunwind.S b/libgcc/config/arm/libunwind.S new file mode 100644 index 00000000000..a3a19daab4b --- /dev/null +++ b/libgcc/config/arm/libunwind.S @@ -0,0 +1,363 @@ +/* Support functions for the unwinder. + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. + Contributed by Paul Brook + + This file 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 3, or (at your option) any + later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* An executable stack is *not* required for these functions. */ +#if defined(__ELF__) && defined(__linux__) +.section .note.GNU-stack,"",%progbits +.previous +#endif + +#ifdef __ARM_EABI__ +/* Some attributes that are common to all routines in this file. */ + /* Tag_ABI_align_needed: This code does not require 8-byte + alignment from the caller. */ + /* .eabi_attribute 24, 0 -- default setting. */ + /* Tag_ABI_align_preserved: This code preserves 8-byte + alignment in any callee. */ + .eabi_attribute 25, 1 +#endif /* __ARM_EABI__ */ + +#ifndef __symbian__ + +#include "config/arm/lib1funcs.asm" + +.macro UNPREFIX name + .global SYM (\name) + EQUIV SYM (\name), SYM (__\name) +.endm + +#if (__ARM_ARCH__ == 4) +/* Some coprocessors require armv5. We know this code will never be run on + other cpus. Tell gas to allow armv5, but only mark the objects as armv4. + */ +.arch armv5t +#ifdef __ARM_ARCH_4T__ +.object_arch armv4t +#else +.object_arch armv4 +#endif +#endif + +#ifdef __ARM_ARCH_6M__ + +/* r0 points to a 16-word block. Upload these values to the actual core + state. */ +FUNC_START restore_core_regs + mov r1, r0 + add r1, r1, #52 + ldmia r1!, {r3, r4, r5} + sub r3, r3, #4 + mov ip, r3 + str r5, [r3] + mov lr, r4 + /* Restore r8-r11. */ + mov r1, r0 + add r1, r1, #32 + ldmia r1!, {r2, r3, r4, r5} + mov r8, r2 + mov r9, r3 + mov sl, r4 + mov fp, r5 + mov r1, r0 + add r1, r1, #8 + ldmia r1!, {r2, r3, r4, r5, r6, r7} + ldr r1, [r0, #4] + ldr r0, [r0] + mov sp, ip + pop {pc} + FUNC_END restore_core_regs + UNPREFIX restore_core_regs + +/* ARMV6M does not have coprocessors, so these should never be used. */ +FUNC_START gnu_Unwind_Restore_VFP + RET + +/* Store VFR regsters d0-d15 to the address in r0. */ +FUNC_START gnu_Unwind_Save_VFP + RET + +/* Load VFP registers d0-d15 from the address in r0. + Use this to load from FSTMD format. */ +FUNC_START gnu_Unwind_Restore_VFP_D + RET + +/* Store VFP registers d0-d15 to the address in r0. + Use this to store in FLDMD format. */ +FUNC_START gnu_Unwind_Save_VFP_D + RET + +/* Load VFP registers d16-d31 from the address in r0. + Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ +FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 + RET + +/* Store VFP registers d16-d31 to the address in r0. + Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ +FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 + RET + +FUNC_START gnu_Unwind_Restore_WMMXD + RET + +FUNC_START gnu_Unwind_Save_WMMXD + RET + +FUNC_START gnu_Unwind_Restore_WMMXC + RET + +FUNC_START gnu_Unwind_Save_WMMXC + RET + +.macro UNWIND_WRAPPER name nargs + FUNC_START \name + /* Create a phase2_vrs structure. */ + /* Save r0 in the PC slot so we can use it as a scratch register. */ + push {r0} + add r0, sp, #4 + push {r0, lr} /* Push original SP and LR. */ + /* Make space for r8-r12. */ + sub sp, sp, #20 + /* Save low registers. */ + push {r0, r1, r2, r3, r4, r5, r6, r7} + /* Save high registers. */ + add r0, sp, #32 + mov r1, r8 + mov r2, r9 + mov r3, sl + mov r4, fp + mov r5, ip + stmia r0!, {r1, r2, r3, r4, r5} + /* Restore original low register values. */ + add r0, sp, #4 + ldmia r0!, {r1, r2, r3, r4, r5} + /* Restore orginial r0. */ + ldr r0, [sp, #60] + str r0, [sp] + /* Demand-save flags, plus an extra word for alignment. */ + mov r3, #0 + push {r2, r3} + /* Point r1 at the block. Pass r[0..nargs) unchanged. */ + add r\nargs, sp, #4 + + bl SYM (__gnu\name) + + ldr r3, [sp, #64] + add sp, sp, #72 + bx r3 + + FUNC_END \name + UNPREFIX \name +.endm + +#else /* !__ARM_ARCH_6M__ */ + +/* r0 points to a 16-word block. Upload these values to the actual core + state. */ +ARM_FUNC_START restore_core_regs + /* We must use sp as the base register when restoring sp. Push the + last 3 registers onto the top of the current stack to achieve + this. */ + add r1, r0, #52 + ldmia r1, {r3, r4, r5} /* {sp, lr, pc}. */ +#if defined(__thumb2__) + /* Thumb-2 doesn't allow sp in a load-multiple instruction, so push + the target address onto the target stack. This is safe as + we're always returning to somewhere further up the call stack. */ + mov ip, r3 + mov lr, r4 + str r5, [ip, #-4]! +#elif defined(__INTERWORKING__) + /* Restore pc into ip. */ + mov r2, r5 + stmfd sp!, {r2, r3, r4} +#else + stmfd sp!, {r3, r4, r5} +#endif + /* Don't bother restoring ip. */ + ldmia r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp} +#if defined(__thumb2__) + /* Pop the return address off the target stack. */ + mov sp, ip + pop {pc} +#elif defined(__INTERWORKING__) + /* Pop the three registers we pushed earlier. */ + ldmfd sp, {ip, sp, lr} + bx ip +#else + ldmfd sp, {sp, lr, pc} +#endif + FUNC_END restore_core_regs + UNPREFIX restore_core_regs + +/* Load VFP registers d0-d15 from the address in r0. + Use this to load from FSTMX format. */ +ARM_FUNC_START gnu_Unwind_Restore_VFP + /* Use the generic coprocessor form so that gas doesn't complain + on soft-float targets. */ + ldc p11,cr0,[r0],{0x21} /* fldmiax r0, {d0-d15} */ + RET + +/* Store VFP registers d0-d15 to the address in r0. + Use this to store in FSTMX format. */ +ARM_FUNC_START gnu_Unwind_Save_VFP + /* Use the generic coprocessor form so that gas doesn't complain + on soft-float targets. */ + stc p11,cr0,[r0],{0x21} /* fstmiax r0, {d0-d15} */ + RET + +/* Load VFP registers d0-d15 from the address in r0. + Use this to load from FSTMD format. */ +ARM_FUNC_START gnu_Unwind_Restore_VFP_D + ldc p11,cr0,[r0],{0x20} /* fldmiad r0, {d0-d15} */ + RET + +/* Store VFP registers d0-d15 to the address in r0. + Use this to store in FLDMD format. */ +ARM_FUNC_START gnu_Unwind_Save_VFP_D + stc p11,cr0,[r0],{0x20} /* fstmiad r0, {d0-d15} */ + RET + +/* Load VFP registers d16-d31 from the address in r0. + Use this to load from FSTMD (=VSTM) format. Needs VFPv3. */ +ARM_FUNC_START gnu_Unwind_Restore_VFP_D_16_to_31 + ldcl p11,cr0,[r0],{0x20} /* vldm r0, {d16-d31} */ + RET + +/* Store VFP registers d16-d31 to the address in r0. + Use this to store in FLDMD (=VLDM) format. Needs VFPv3. */ +ARM_FUNC_START gnu_Unwind_Save_VFP_D_16_to_31 + stcl p11,cr0,[r0],{0x20} /* vstm r0, {d16-d31} */ + RET + +ARM_FUNC_START gnu_Unwind_Restore_WMMXD + /* Use the generic coprocessor form so that gas doesn't complain + on non-iWMMXt targets. */ + ldcl p1, cr0, [r0], #8 /* wldrd wr0, [r0], #8 */ + ldcl p1, cr1, [r0], #8 /* wldrd wr1, [r0], #8 */ + ldcl p1, cr2, [r0], #8 /* wldrd wr2, [r0], #8 */ + ldcl p1, cr3, [r0], #8 /* wldrd wr3, [r0], #8 */ + ldcl p1, cr4, [r0], #8 /* wldrd wr4, [r0], #8 */ + ldcl p1, cr5, [r0], #8 /* wldrd wr5, [r0], #8 */ + ldcl p1, cr6, [r0], #8 /* wldrd wr6, [r0], #8 */ + ldcl p1, cr7, [r0], #8 /* wldrd wr7, [r0], #8 */ + ldcl p1, cr8, [r0], #8 /* wldrd wr8, [r0], #8 */ + ldcl p1, cr9, [r0], #8 /* wldrd wr9, [r0], #8 */ + ldcl p1, cr10, [r0], #8 /* wldrd wr10, [r0], #8 */ + ldcl p1, cr11, [r0], #8 /* wldrd wr11, [r0], #8 */ + ldcl p1, cr12, [r0], #8 /* wldrd wr12, [r0], #8 */ + ldcl p1, cr13, [r0], #8 /* wldrd wr13, [r0], #8 */ + ldcl p1, cr14, [r0], #8 /* wldrd wr14, [r0], #8 */ + ldcl p1, cr15, [r0], #8 /* wldrd wr15, [r0], #8 */ + RET + +ARM_FUNC_START gnu_Unwind_Save_WMMXD + /* Use the generic coprocessor form so that gas doesn't complain + on non-iWMMXt targets. */ + stcl p1, cr0, [r0], #8 /* wstrd wr0, [r0], #8 */ + stcl p1, cr1, [r0], #8 /* wstrd wr1, [r0], #8 */ + stcl p1, cr2, [r0], #8 /* wstrd wr2, [r0], #8 */ + stcl p1, cr3, [r0], #8 /* wstrd wr3, [r0], #8 */ + stcl p1, cr4, [r0], #8 /* wstrd wr4, [r0], #8 */ + stcl p1, cr5, [r0], #8 /* wstrd wr5, [r0], #8 */ + stcl p1, cr6, [r0], #8 /* wstrd wr6, [r0], #8 */ + stcl p1, cr7, [r0], #8 /* wstrd wr7, [r0], #8 */ + stcl p1, cr8, [r0], #8 /* wstrd wr8, [r0], #8 */ + stcl p1, cr9, [r0], #8 /* wstrd wr9, [r0], #8 */ + stcl p1, cr10, [r0], #8 /* wstrd wr10, [r0], #8 */ + stcl p1, cr11, [r0], #8 /* wstrd wr11, [r0], #8 */ + stcl p1, cr12, [r0], #8 /* wstrd wr12, [r0], #8 */ + stcl p1, cr13, [r0], #8 /* wstrd wr13, [r0], #8 */ + stcl p1, cr14, [r0], #8 /* wstrd wr14, [r0], #8 */ + stcl p1, cr15, [r0], #8 /* wstrd wr15, [r0], #8 */ + RET + +ARM_FUNC_START gnu_Unwind_Restore_WMMXC + /* Use the generic coprocessor form so that gas doesn't complain + on non-iWMMXt targets. */ + ldc2 p1, cr8, [r0], #4 /* wldrw wcgr0, [r0], #4 */ + ldc2 p1, cr9, [r0], #4 /* wldrw wcgr1, [r0], #4 */ + ldc2 p1, cr10, [r0], #4 /* wldrw wcgr2, [r0], #4 */ + ldc2 p1, cr11, [r0], #4 /* wldrw wcgr3, [r0], #4 */ + RET + +ARM_FUNC_START gnu_Unwind_Save_WMMXC + /* Use the generic coprocessor form so that gas doesn't complain + on non-iWMMXt targets. */ + stc2 p1, cr8, [r0], #4 /* wstrw wcgr0, [r0], #4 */ + stc2 p1, cr9, [r0], #4 /* wstrw wcgr1, [r0], #4 */ + stc2 p1, cr10, [r0], #4 /* wstrw wcgr2, [r0], #4 */ + stc2 p1, cr11, [r0], #4 /* wstrw wcgr3, [r0], #4 */ + RET + +/* Wrappers to save core registers, then call the real routine. */ + +.macro UNWIND_WRAPPER name nargs + ARM_FUNC_START \name + /* Create a phase2_vrs structure. */ + /* Split reg push in two to ensure the correct value for sp. */ +#if defined(__thumb2__) + mov ip, sp + push {lr} /* PC is ignored. */ + push {ip, lr} /* Push original SP and LR. */ +#else + stmfd sp!, {sp, lr, pc} +#endif + stmfd sp!, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip} + + /* Demand-save flags, plus an extra word for alignment. */ + mov r3, #0 + stmfd sp!, {r2, r3} + + /* Point r1 at the block. Pass r[0..nargs) unchanged. */ + add r\nargs, sp, #4 +#if defined(__thumb__) && !defined(__thumb2__) + /* Switch back to thumb mode to avoid interworking hassle. */ + adr ip, .L1_\name + orr ip, ip, #1 + bx ip + .thumb +.L1_\name: + bl SYM (__gnu\name) __PLT__ + ldr r3, [sp, #64] + add sp, #72 + bx r3 +#else + bl SYM (__gnu\name) __PLT__ + ldr lr, [sp, #64] + add sp, sp, #72 + RET +#endif + FUNC_END \name + UNPREFIX \name +.endm + +#endif /* !__ARM_ARCH_6M__ */ + +UNWIND_WRAPPER _Unwind_RaiseException 1 +UNWIND_WRAPPER _Unwind_Resume 1 +UNWIND_WRAPPER _Unwind_Resume_or_Rethrow 1 +UNWIND_WRAPPER _Unwind_ForcedUnwind 3 +UNWIND_WRAPPER _Unwind_Backtrace 2 + +#endif /* ndef __symbian__ */ diff --git a/libgcc/config/arm/pr-support.c b/libgcc/config/arm/pr-support.c new file mode 100644 index 00000000000..deee661e264 --- /dev/null +++ b/libgcc/config/arm/pr-support.c @@ -0,0 +1,401 @@ +/* ARM EABI compliant unwinding routines + Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. + Contributed by Paul Brook + + This file 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 3, or (at your option) any + later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "unwind.h" + +/* We add a prototype for abort here to avoid creating a dependency on + target headers. */ +extern void abort (void); + +typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ + +/* Misc constants. */ +#define R_IP 12 +#define R_SP 13 +#define R_LR 14 +#define R_PC 15 + +#define uint32_highbit (((_uw) 1) << 31) + +void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); + +/* Unwind descriptors. */ + +typedef struct +{ + _uw16 length; + _uw16 offset; +} EHT16; + +typedef struct +{ + _uw length; + _uw offset; +} EHT32; + +/* Calculate the address encoded by a 31-bit self-relative offset at address + P. Copy of routine in unwind-arm.c. */ + +static inline _uw +selfrel_offset31 (const _uw *p) +{ + _uw offset; + + offset = *p; + /* Sign extend to 32 bits. */ + if (offset & (1 << 30)) + offset |= 1u << 31; + + return offset + (_uw) p; +} + + +/* Personality routine helper functions. */ + +#define CODE_FINISH (0xb0) + +/* Return the next byte of unwinding information, or CODE_FINISH if there is + no data remaining. */ +static inline _uw8 +next_unwind_byte (__gnu_unwind_state * uws) +{ + _uw8 b; + + if (uws->bytes_left == 0) + { + /* Load another word */ + if (uws->words_left == 0) + return CODE_FINISH; /* Nothing left. */ + uws->words_left--; + uws->data = *(uws->next++); + uws->bytes_left = 3; + } + else + uws->bytes_left--; + + /* Extract the most significant byte. */ + b = (uws->data >> 24) & 0xff; + uws->data <<= 8; + return b; +} + +/* Execute the unwinding instructions described by UWS. */ +_Unwind_Reason_Code +__gnu_unwind_execute (_Unwind_Context * context, __gnu_unwind_state * uws) +{ + _uw op; + int set_pc; + _uw reg; + + set_pc = 0; + for (;;) + { + op = next_unwind_byte (uws); + if (op == CODE_FINISH) + { + /* If we haven't already set pc then copy it from lr. */ + if (!set_pc) + { + _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, + ®); + _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, + ®); + set_pc = 1; + } + /* Drop out of the loop. */ + break; + } + if ((op & 0x80) == 0) + { + /* vsp = vsp +- (imm6 << 2 + 4). */ + _uw offset; + + offset = ((op & 0x3f) << 2) + 4; + _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); + if (op & 0x40) + reg -= offset; + else + reg += offset; + _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); + continue; + } + + if ((op & 0xf0) == 0x80) + { + op = (op << 8) | next_unwind_byte (uws); + if (op == 0x8000) + { + /* Refuse to unwind. */ + return _URC_FAILURE; + } + /* Pop r4-r15 under mask. */ + op = (op << 4) & 0xfff0; + if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) + != _UVRSR_OK) + return _URC_FAILURE; + if (op & (1 << R_PC)) + set_pc = 1; + continue; + } + if ((op & 0xf0) == 0x90) + { + op &= 0xf; + if (op == 13 || op == 15) + /* Reserved. */ + return _URC_FAILURE; + /* vsp = r[nnnn]. */ + _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®); + _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); + continue; + } + if ((op & 0xf0) == 0xa0) + { + /* Pop r4-r[4+nnn], [lr]. */ + _uw mask; + + mask = (0xff0 >> (7 - (op & 7))) & 0xff0; + if (op & 8) + mask |= (1 << R_LR); + if (_Unwind_VRS_Pop (context, _UVRSC_CORE, mask, _UVRSD_UINT32) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if ((op & 0xf0) == 0xb0) + { + /* op == 0xb0 already handled. */ + if (op == 0xb1) + { + op = next_unwind_byte (uws); + if (op == 0 || ((op & 0xf0) != 0)) + /* Spare. */ + return _URC_FAILURE; + /* Pop r0-r4 under mask. */ + if (_Unwind_VRS_Pop (context, _UVRSC_CORE, op, _UVRSD_UINT32) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if (op == 0xb2) + { + /* vsp = vsp + 0x204 + (uleb128 << 2). */ + int shift; + + _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, + ®); + op = next_unwind_byte (uws); + shift = 2; + while (op & 0x80) + { + reg += ((op & 0x7f) << shift); + shift += 7; + op = next_unwind_byte (uws); + } + reg += ((op & 0x7f) << shift) + 0x204; + _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, + ®); + continue; + } + if (op == 0xb3) + { + /* Pop VFP registers with fldmx. */ + op = next_unwind_byte (uws); + op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if ((op & 0xfc) == 0xb4) + { + /* Pop FPA E[4]-E[4+nn]. */ + op = 0x40000 | ((op & 3) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + /* op & 0xf8 == 0xb8. */ + /* Pop VFP D[8]-D[8+nnn] with fldmx. */ + op = 0x80000 | ((op & 7) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_VFPX) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if ((op & 0xf0) == 0xc0) + { + if (op == 0xc6) + { + /* Pop iWMMXt D registers. */ + op = next_unwind_byte (uws); + op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if (op == 0xc7) + { + op = next_unwind_byte (uws); + if (op == 0 || (op & 0xf0) != 0) + /* Spare. */ + return _URC_FAILURE; + /* Pop iWMMXt wCGR{3,2,1,0} under mask. */ + if (_Unwind_VRS_Pop (context, _UVRSC_WMMXC, op, _UVRSD_UINT32) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if ((op & 0xf8) == 0xc0) + { + /* Pop iWMMXt wR[10]-wR[10+nnn]. */ + op = 0xa0000 | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_WMMXD, op, _UVRSD_UINT64) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + if (op == 0xc8) + { +#ifndef __VFP_FP__ + /* Pop FPA registers. */ + op = next_unwind_byte (uws); + op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_FPA, op, _UVRSD_FPAX) + != _UVRSR_OK) + return _URC_FAILURE; + continue; +#else + /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */ + op = next_unwind_byte (uws); + op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) + != _UVRSR_OK) + return _URC_FAILURE; + continue; +#endif + } + if (op == 0xc9) + { + /* Pop VFP registers with fldmd. */ + op = next_unwind_byte (uws); + op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + /* Spare. */ + return _URC_FAILURE; + } + if ((op & 0xf8) == 0xd0) + { + /* Pop VFP D[8]-D[8+nnn] with fldmd. */ + op = 0x80000 | ((op & 7) + 1); + if (_Unwind_VRS_Pop (context, _UVRSC_VFP, op, _UVRSD_DOUBLE) + != _UVRSR_OK) + return _URC_FAILURE; + continue; + } + /* Spare. */ + return _URC_FAILURE; + } + return _URC_OK; +} + + +/* Execute the unwinding instructions associated with a frame. UCBP and + CONTEXT are the current exception object and virtual CPU state + respectively. */ + +_Unwind_Reason_Code +__gnu_unwind_frame (_Unwind_Control_Block * ucbp, _Unwind_Context * context) +{ + _uw *ptr; + __gnu_unwind_state uws; + + ptr = (_uw *) ucbp->pr_cache.ehtp; + /* Skip over the personality routine address. */ + ptr++; + /* Setup the unwinder state. */ + uws.data = (*ptr) << 8; + uws.next = ptr + 1; + uws.bytes_left = 3; + uws.words_left = ((*ptr) >> 24) & 0xff; + + return __gnu_unwind_execute (context, &uws); +} + +/* Get the _Unwind_Control_Block from an _Unwind_Context. */ + +static inline _Unwind_Control_Block * +unwind_UCB_from_context (_Unwind_Context * context) +{ + return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP); +} + +/* Get the start address of the function being unwound. */ + +_Unwind_Ptr +_Unwind_GetRegionStart (_Unwind_Context * context) +{ + _Unwind_Control_Block *ucbp; + + ucbp = unwind_UCB_from_context (context); + return (_Unwind_Ptr) ucbp->pr_cache.fnstart; +} + +/* Find the Language specific exception data. */ + +void * +_Unwind_GetLanguageSpecificData (_Unwind_Context * context) +{ + _Unwind_Control_Block *ucbp; + _uw *ptr; + + /* Get a pointer to the exception table entry. */ + ucbp = unwind_UCB_from_context (context); + ptr = (_uw *) ucbp->pr_cache.ehtp; + /* Skip the personality routine address. */ + ptr++; + /* Skip the unwind opcodes. */ + ptr += (((*ptr) >> 24) & 0xff) + 1; + + return ptr; +} + + +/* These two should never be used. */ + +_Unwind_Ptr +_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused))) +{ + abort (); +} + +_Unwind_Ptr +_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused))) +{ + abort (); +} diff --git a/libgcc/config/arm/t-bpabi b/libgcc/config/arm/t-bpabi new file mode 100644 index 00000000000..a3b23dcd20c --- /dev/null +++ b/libgcc/config/arm/t-bpabi @@ -0,0 +1,3 @@ +LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \ + $(srcdir)/config/arm/libunwind.S \ + $(srcdir)/config/arm/pr-support.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/arm/t-symbian b/libgcc/config/arm/t-symbian new file mode 100644 index 00000000000..6788d5f40b3 --- /dev/null +++ b/libgcc/config/arm/t-symbian @@ -0,0 +1,2 @@ +# Include the gcc personality routine +LIB2ADDEH = $(srcdir)/unwind-c.c $(srcdir)/config/arm/pr-support.c diff --git a/libgcc/config/arm/unwind-arm.c b/libgcc/config/arm/unwind-arm.c new file mode 100644 index 00000000000..90d258d3c80 --- /dev/null +++ b/libgcc/config/arm/unwind-arm.c @@ -0,0 +1,1283 @@ +/* ARM EABI compliant unwinding routines. + Copyright (C) 2004, 2005, 2009 Free Software Foundation, Inc. + Contributed by Paul Brook + + This file 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 3, or (at your option) any + later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "unwind.h" + +/* We add a prototype for abort here to avoid creating a dependency on + target headers. */ +extern void abort (void); + +/* Definitions for C++ runtime support routines. We make these weak + declarations to avoid pulling in libsupc++ unnecessarily. */ +typedef unsigned char bool; + +typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ +enum __cxa_type_match_result + { + ctm_failed = 0, + ctm_succeeded = 1, + ctm_succeeded_with_ptr_to_base = 2 + }; + +void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); +bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp); +enum __cxa_type_match_result __attribute__((weak)) __cxa_type_match + (_Unwind_Control_Block *ucbp, const type_info *rttip, + bool is_reference, void **matched_object); + +_Unwind_Ptr __attribute__((weak)) +__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *); + +/* Misc constants. */ +#define R_IP 12 +#define R_SP 13 +#define R_LR 14 +#define R_PC 15 + +#define EXIDX_CANTUNWIND 1 +#define uint32_highbit (((_uw) 1) << 31) + +#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1) +#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) +#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) +#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) + +struct core_regs +{ + _uw r[16]; +}; + +/* We use normal integer types here to avoid the compiler generating + coprocessor instructions. */ +struct vfp_regs +{ + _uw64 d[16]; + _uw pad; +}; + +struct vfpv3_regs +{ + /* Always populated via VSTM, so no need for the "pad" field from + vfp_regs (which is used to store the format word for FSTMX). */ + _uw64 d[16]; +}; + +struct fpa_reg +{ + _uw w[3]; +}; + +struct fpa_regs +{ + struct fpa_reg f[8]; +}; + +struct wmmxd_regs +{ + _uw64 wd[16]; +}; + +struct wmmxc_regs +{ + _uw wc[4]; +}; + +/* Unwind descriptors. */ + +typedef struct +{ + _uw16 length; + _uw16 offset; +} EHT16; + +typedef struct +{ + _uw length; + _uw offset; +} EHT32; + +/* The ABI specifies that the unwind routines may only use core registers, + except when actually manipulating coprocessor state. This allows + us to write one implementation that works on all platforms by + demand-saving coprocessor registers. + + During unwinding we hold the coprocessor state in the actual hardware + registers and allocate demand-save areas for use during phase1 + unwinding. */ + +typedef struct +{ + /* The first fields must be the same as a phase2_vrs. */ + _uw demand_save_flags; + struct core_regs core; + _uw prev_sp; /* Only valid during forced unwinding. */ + struct vfp_regs vfp; + struct vfpv3_regs vfp_regs_16_to_31; + struct fpa_regs fpa; + struct wmmxd_regs wmmxd; + struct wmmxc_regs wmmxc; +} phase1_vrs; + +#define DEMAND_SAVE_VFP 1 /* VFP state has been saved if not set */ +#define DEMAND_SAVE_VFP_D 2 /* VFP state is for FLDMD/FSTMD if set */ +#define DEMAND_SAVE_VFP_V3 4 /* VFPv3 state for regs 16 .. 31 has + been saved if not set */ +#define DEMAND_SAVE_WMMXD 8 /* iWMMXt data registers have been + saved if not set. */ +#define DEMAND_SAVE_WMMXC 16 /* iWMMXt control registers have been + saved if not set. */ + +/* This must match the structure created by the assembly wrappers. */ +typedef struct +{ + _uw demand_save_flags; + struct core_regs core; +} phase2_vrs; + + +/* An exception index table entry. */ + +typedef struct __EIT_entry +{ + _uw fnoffset; + _uw content; +} __EIT_entry; + +/* Assembly helper functions. */ + +/* Restore core register state. Never returns. */ +void __attribute__((noreturn)) restore_core_regs (struct core_regs *); + + +/* Coprocessor register state manipulation functions. */ + +/* Routines for FLDMX/FSTMX format... */ +void __gnu_Unwind_Save_VFP (struct vfp_regs * p); +void __gnu_Unwind_Restore_VFP (struct vfp_regs * p); +void __gnu_Unwind_Save_WMMXD (struct wmmxd_regs * p); +void __gnu_Unwind_Restore_WMMXD (struct wmmxd_regs * p); +void __gnu_Unwind_Save_WMMXC (struct wmmxc_regs * p); +void __gnu_Unwind_Restore_WMMXC (struct wmmxc_regs * p); + +/* ...and those for FLDMD/FSTMD format... */ +void __gnu_Unwind_Save_VFP_D (struct vfp_regs * p); +void __gnu_Unwind_Restore_VFP_D (struct vfp_regs * p); + +/* ...and those for VLDM/VSTM format, saving/restoring only registers + 16 through 31. */ +void __gnu_Unwind_Save_VFP_D_16_to_31 (struct vfpv3_regs * p); +void __gnu_Unwind_Restore_VFP_D_16_to_31 (struct vfpv3_regs * p); + +/* Restore coprocessor state after phase1 unwinding. */ +static void +restore_non_core_regs (phase1_vrs * vrs) +{ + if ((vrs->demand_save_flags & DEMAND_SAVE_VFP) == 0) + { + if (vrs->demand_save_flags & DEMAND_SAVE_VFP_D) + __gnu_Unwind_Restore_VFP_D (&vrs->vfp); + else + __gnu_Unwind_Restore_VFP (&vrs->vfp); + } + + if ((vrs->demand_save_flags & DEMAND_SAVE_VFP_V3) == 0) + __gnu_Unwind_Restore_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31); + + if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXD) == 0) + __gnu_Unwind_Restore_WMMXD (&vrs->wmmxd); + if ((vrs->demand_save_flags & DEMAND_SAVE_WMMXC) == 0) + __gnu_Unwind_Restore_WMMXC (&vrs->wmmxc); +} + +/* A better way to do this would probably be to compare the absolute address + with a segment relative relocation of the same symbol. */ + +extern int __text_start; +extern int __data_start; + +/* The exception index table location. */ +extern __EIT_entry __exidx_start; +extern __EIT_entry __exidx_end; + +/* ABI defined personality routines. */ +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0 (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *);// __attribute__((weak)); +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1 (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak)); +extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2 (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *) __attribute__((weak)); + +/* ABI defined routine to store a virtual register to memory. */ + +_Unwind_VRS_Result _Unwind_VRS_Get (_Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + _uw regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) +{ + phase1_vrs *vrs = (phase1_vrs *) context; + + switch (regclass) + { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 + || regno > 15) + return _UVRSR_FAILED; + *(_uw *) valuep = vrs->core.r[regno]; + return _UVRSR_OK; + + case _UVRSC_VFP: + case _UVRSC_FPA: + case _UVRSC_WMMXD: + case _UVRSC_WMMXC: + return _UVRSR_NOT_IMPLEMENTED; + + default: + return _UVRSR_FAILED; + } +} + + +/* ABI defined function to load a virtual register from memory. */ + +_Unwind_VRS_Result _Unwind_VRS_Set (_Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + _uw regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep) +{ + phase1_vrs *vrs = (phase1_vrs *) context; + + switch (regclass) + { + case _UVRSC_CORE: + if (representation != _UVRSD_UINT32 + || regno > 15) + return _UVRSR_FAILED; + + vrs->core.r[regno] = *(_uw *) valuep; + return _UVRSR_OK; + + case _UVRSC_VFP: + case _UVRSC_FPA: + case _UVRSC_WMMXD: + case _UVRSC_WMMXC: + return _UVRSR_NOT_IMPLEMENTED; + + default: + return _UVRSR_FAILED; + } +} + + +/* ABI defined function to pop registers off the stack. */ + +_Unwind_VRS_Result _Unwind_VRS_Pop (_Unwind_Context *context, + _Unwind_VRS_RegClass regclass, + _uw discriminator, + _Unwind_VRS_DataRepresentation representation) +{ + phase1_vrs *vrs = (phase1_vrs *) context; + + switch (regclass) + { + case _UVRSC_CORE: + { + _uw *ptr; + _uw mask; + int i; + + if (representation != _UVRSD_UINT32) + return _UVRSR_FAILED; + + mask = discriminator & 0xffff; + ptr = (_uw *) vrs->core.r[R_SP]; + /* Pop the requested registers. */ + for (i = 0; i < 16; i++) + { + if (mask & (1 << i)) + vrs->core.r[i] = *(ptr++); + } + /* Writeback the stack pointer value if it wasn't restored. */ + if ((mask & (1 << R_SP)) == 0) + vrs->core.r[R_SP] = (_uw) ptr; + } + return _UVRSR_OK; + + case _UVRSC_VFP: + { + _uw start = discriminator >> 16; + _uw count = discriminator & 0xffff; + struct vfp_regs tmp; + struct vfpv3_regs tmp_16_to_31; + int tmp_count; + _uw *sp; + _uw *dest; + int num_vfpv3_regs = 0; + + /* We use an approximation here by bounding _UVRSD_DOUBLE + register numbers at 32 always, since we can't detect if + VFPv3 isn't present (in such a case the upper limit is 16). */ + if ((representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE) + || start + count > (representation == _UVRSD_VFPX ? 16 : 32) + || (representation == _UVRSD_VFPX && start >= 16)) + return _UVRSR_FAILED; + + /* Check if we're being asked to pop VFPv3-only registers + (numbers 16 through 31). */ + if (start >= 16) + num_vfpv3_regs = count; + else if (start + count > 16) + num_vfpv3_regs = start + count - 16; + + if (num_vfpv3_regs && representation != _UVRSD_DOUBLE) + return _UVRSR_FAILED; + + /* Demand-save coprocessor registers for stage1. */ + if (start < 16 && (vrs->demand_save_flags & DEMAND_SAVE_VFP)) + { + vrs->demand_save_flags &= ~DEMAND_SAVE_VFP; + + if (representation == _UVRSD_DOUBLE) + { + /* Save in FLDMD/FSTMD format. */ + vrs->demand_save_flags |= DEMAND_SAVE_VFP_D; + __gnu_Unwind_Save_VFP_D (&vrs->vfp); + } + else + { + /* Save in FLDMX/FSTMX format. */ + vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_D; + __gnu_Unwind_Save_VFP (&vrs->vfp); + } + } + + if (num_vfpv3_regs > 0 + && (vrs->demand_save_flags & DEMAND_SAVE_VFP_V3)) + { + vrs->demand_save_flags &= ~DEMAND_SAVE_VFP_V3; + __gnu_Unwind_Save_VFP_D_16_to_31 (&vrs->vfp_regs_16_to_31); + } + + /* Restore the registers from the stack. Do this by saving the + current VFP registers to a memory area, moving the in-memory + values into that area, and restoring from the whole area. + For _UVRSD_VFPX we assume FSTMX standard format 1. */ + if (representation == _UVRSD_VFPX) + __gnu_Unwind_Save_VFP (&tmp); + else + { + /* Save registers 0 .. 15 if required. */ + if (start < 16) + __gnu_Unwind_Save_VFP_D (&tmp); + + /* Save VFPv3 registers 16 .. 31 if required. */ + if (num_vfpv3_regs) + __gnu_Unwind_Save_VFP_D_16_to_31 (&tmp_16_to_31); + } + + /* Work out how many registers below register 16 need popping. */ + tmp_count = num_vfpv3_regs > 0 ? 16 - start : count; + + /* Copy registers below 16, if needed. + The stack address is only guaranteed to be word aligned, so + we can't use doubleword copies. */ + sp = (_uw *) vrs->core.r[R_SP]; + if (tmp_count > 0) + { + tmp_count *= 2; + dest = (_uw *) &tmp.d[start]; + while (tmp_count--) + *(dest++) = *(sp++); + } + + /* Copy VFPv3 registers numbered >= 16, if needed. */ + if (num_vfpv3_regs > 0) + { + /* num_vfpv3_regs is needed below, so copy it. */ + int tmp_count_2 = num_vfpv3_regs * 2; + int vfpv3_start = start < 16 ? 16 : start; + + dest = (_uw *) &tmp_16_to_31.d[vfpv3_start - 16]; + while (tmp_count_2--) + *(dest++) = *(sp++); + } + + /* Skip the format word space if using FLDMX/FSTMX format. */ + if (representation == _UVRSD_VFPX) + sp++; + + /* Set the new stack pointer. */ + vrs->core.r[R_SP] = (_uw) sp; + + /* Reload the registers. */ + if (representation == _UVRSD_VFPX) + __gnu_Unwind_Restore_VFP (&tmp); + else + { + /* Restore registers 0 .. 15 if required. */ + if (start < 16) + __gnu_Unwind_Restore_VFP_D (&tmp); + + /* Restore VFPv3 registers 16 .. 31 if required. */ + if (num_vfpv3_regs > 0) + __gnu_Unwind_Restore_VFP_D_16_to_31 (&tmp_16_to_31); + } + } + return _UVRSR_OK; + + case _UVRSC_FPA: + return _UVRSR_NOT_IMPLEMENTED; + + case _UVRSC_WMMXD: + { + _uw start = discriminator >> 16; + _uw count = discriminator & 0xffff; + struct wmmxd_regs tmp; + _uw *sp; + _uw *dest; + + if ((representation != _UVRSD_UINT64) || start + count > 16) + return _UVRSR_FAILED; + + if (vrs->demand_save_flags & DEMAND_SAVE_WMMXD) + { + /* Demand-save resisters for stage1. */ + vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXD; + __gnu_Unwind_Save_WMMXD (&vrs->wmmxd); + } + + /* Restore the registers from the stack. Do this by saving the + current WMMXD registers to a memory area, moving the in-memory + values into that area, and restoring from the whole area. */ + __gnu_Unwind_Save_WMMXD (&tmp); + + /* The stack address is only guaranteed to be word aligned, so + we can't use doubleword copies. */ + sp = (_uw *) vrs->core.r[R_SP]; + dest = (_uw *) &tmp.wd[start]; + count *= 2; + while (count--) + *(dest++) = *(sp++); + + /* Set the new stack pointer. */ + vrs->core.r[R_SP] = (_uw) sp; + + /* Reload the registers. */ + __gnu_Unwind_Restore_WMMXD (&tmp); + } + return _UVRSR_OK; + + case _UVRSC_WMMXC: + { + int i; + struct wmmxc_regs tmp; + _uw *sp; + + if ((representation != _UVRSD_UINT32) || discriminator > 16) + return _UVRSR_FAILED; + + if (vrs->demand_save_flags & DEMAND_SAVE_WMMXC) + { + /* Demand-save resisters for stage1. */ + vrs->demand_save_flags &= ~DEMAND_SAVE_WMMXC; + __gnu_Unwind_Save_WMMXC (&vrs->wmmxc); + } + + /* Restore the registers from the stack. Do this by saving the + current WMMXC registers to a memory area, moving the in-memory + values into that area, and restoring from the whole area. */ + __gnu_Unwind_Save_WMMXC (&tmp); + + sp = (_uw *) vrs->core.r[R_SP]; + for (i = 0; i < 4; i++) + if (discriminator & (1 << i)) + tmp.wc[i] = *(sp++); + + /* Set the new stack pointer. */ + vrs->core.r[R_SP] = (_uw) sp; + + /* Reload the registers. */ + __gnu_Unwind_Restore_WMMXC (&tmp); + } + return _UVRSR_OK; + + default: + return _UVRSR_FAILED; + } +} + + +/* Core unwinding functions. */ + +/* Calculate the address encoded by a 31-bit self-relative offset at address + P. */ +static inline _uw +selfrel_offset31 (const _uw *p) +{ + _uw offset; + + offset = *p; + /* Sign extend to 32 bits. */ + if (offset & (1 << 30)) + offset |= 1u << 31; + else + offset &= ~(1u << 31); + + return offset + (_uw) p; +} + + +/* Perform a binary search for RETURN_ADDRESS in TABLE. The table contains + NREC entries. */ + +static const __EIT_entry * +search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) +{ + _uw next_fn; + _uw this_fn; + int n, left, right; + + if (nrec == 0) + return (__EIT_entry *) 0; + + left = 0; + right = nrec - 1; + + while (1) + { + n = (left + right) / 2; + this_fn = selfrel_offset31 (&table[n].fnoffset); + if (n != nrec - 1) + next_fn = selfrel_offset31 (&table[n + 1].fnoffset) - 1; + else + next_fn = (_uw)0 - 1; + + if (return_address < this_fn) + { + if (n == left) + return (__EIT_entry *) 0; + right = n - 1; + } + else if (return_address <= next_fn) + return &table[n]; + else + left = n + 1; + } +} + +/* Find the exception index table eintry for the given address. + Fill in the relevant fields of the UCB. + Returns _URC_FAILURE if an error occurred, _URC_OK on success. */ + +static _Unwind_Reason_Code +get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) +{ + const __EIT_entry * eitp; + int nrec; + + /* The return address is the address of the instruction following the + call instruction (plus one in thumb mode). If this was the last + instruction in the function the address will lie in the following + function. Subtract 2 from the address so that it points within the call + instruction itself. */ + return_address -= 2; + + if (__gnu_Unwind_Find_exidx) + { + eitp = (const __EIT_entry *) __gnu_Unwind_Find_exidx (return_address, + &nrec); + if (!eitp) + { + UCB_PR_ADDR (ucbp) = 0; + return _URC_FAILURE; + } + } + else + { + eitp = &__exidx_start; + nrec = &__exidx_end - &__exidx_start; + } + + eitp = search_EIT_table (eitp, nrec, return_address); + + if (!eitp) + { + UCB_PR_ADDR (ucbp) = 0; + return _URC_FAILURE; + } + ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset); + + /* Can this frame be unwound at all? */ + if (eitp->content == EXIDX_CANTUNWIND) + { + UCB_PR_ADDR (ucbp) = 0; + return _URC_END_OF_STACK; + } + + /* Obtain the address of the "real" __EHT_Header word. */ + + if (eitp->content & uint32_highbit) + { + /* It is immediate data. */ + ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; + ucbp->pr_cache.additional = 1; + } + else + { + /* The low 31 bits of the content field are a self-relative + offset to an _Unwind_EHT_Entry structure. */ + ucbp->pr_cache.ehtp = + (_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content); + ucbp->pr_cache.additional = 0; + } + + /* Discover the personality routine address. */ + if (*ucbp->pr_cache.ehtp & (1u << 31)) + { + /* One of the predefined standard routines. */ + _uw idx = (*(_uw *) ucbp->pr_cache.ehtp >> 24) & 0xf; + if (idx == 0) + UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr0; + else if (idx == 1) + UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr1; + else if (idx == 2) + UCB_PR_ADDR (ucbp) = (_uw) &__aeabi_unwind_cpp_pr2; + else + { /* Failed */ + UCB_PR_ADDR (ucbp) = 0; + return _URC_FAILURE; + } + } + else + { + /* Execute region offset to PR */ + UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp); + } + return _URC_OK; +} + + +/* Perform phase2 unwinding. VRS is the initial virtual register state. */ + +static void __attribute__((noreturn)) +unwind_phase2 (_Unwind_Control_Block * ucbp, phase2_vrs * vrs) +{ + _Unwind_Reason_Code pr_result; + + do + { + /* Find the entry for this routine. */ + if (get_eit_entry (ucbp, vrs->core.r[R_PC]) != _URC_OK) + abort (); + + UCB_SAVED_CALLSITE_ADDR (ucbp) = vrs->core.r[R_PC]; + + /* Call the pr to decide what to do. */ + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) + (_US_UNWIND_FRAME_STARTING, ucbp, (_Unwind_Context *) vrs); + } + while (pr_result == _URC_CONTINUE_UNWIND); + + if (pr_result != _URC_INSTALL_CONTEXT) + abort(); + + restore_core_regs (&vrs->core); +} + +/* Perform phase2 forced unwinding. */ + +static _Unwind_Reason_Code +unwind_phase2_forced (_Unwind_Control_Block *ucbp, phase2_vrs *entry_vrs, + int resuming) +{ + _Unwind_Stop_Fn stop_fn = (_Unwind_Stop_Fn) UCB_FORCED_STOP_FN (ucbp); + void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp); + _Unwind_Reason_Code pr_result = 0; + /* We use phase1_vrs here even though we do not demand save, for the + prev_sp field. */ + phase1_vrs saved_vrs, next_vrs; + + /* Save the core registers. */ + saved_vrs.core = entry_vrs->core; + /* We don't need to demand-save the non-core registers, because we + unwind in a single pass. */ + saved_vrs.demand_save_flags = 0; + + /* Unwind until we reach a propagation barrier. */ + do + { + _Unwind_State action; + _Unwind_Reason_Code entry_code; + _Unwind_Reason_Code stop_code; + + /* Find the entry for this routine. */ + entry_code = get_eit_entry (ucbp, saved_vrs.core.r[R_PC]); + + if (resuming) + { + action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND; + resuming = 0; + } + else + action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND; + + if (entry_code == _URC_OK) + { + UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC]; + + next_vrs = saved_vrs; + + /* Call the pr to decide what to do. */ + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) + (action, ucbp, (void *) &next_vrs); + + saved_vrs.prev_sp = next_vrs.core.r[R_SP]; + } + else + { + /* Treat any failure as the end of unwinding, to cope more + gracefully with missing EH information. Mixed EH and + non-EH within one object will usually result in failure, + because the .ARM.exidx tables do not indicate the end + of the code to which they apply; but mixed EH and non-EH + shared objects should return an unwind failure at the + entry of a non-EH shared object. */ + action |= _US_END_OF_STACK; + + saved_vrs.prev_sp = saved_vrs.core.r[R_SP]; + } + + stop_code = stop_fn (1, action, ucbp->exception_class, ucbp, + (void *)&saved_vrs, stop_arg); + if (stop_code != _URC_NO_REASON) + return _URC_FAILURE; + + if (entry_code != _URC_OK) + return entry_code; + + saved_vrs = next_vrs; + } + while (pr_result == _URC_CONTINUE_UNWIND); + + if (pr_result != _URC_INSTALL_CONTEXT) + { + /* Some sort of failure has occurred in the pr and probably the + pr returned _URC_FAILURE. */ + return _URC_FAILURE; + } + + restore_core_regs (&saved_vrs.core); +} + +/* This is a very limited implementation of _Unwind_GetCFA. It returns + the stack pointer as it is about to be unwound, and is only valid + while calling the stop function during forced unwinding. If the + current personality routine result is going to run a cleanup, this + will not be the CFA; but when the frame is really unwound, it will + be. */ + +_Unwind_Word +_Unwind_GetCFA (_Unwind_Context *context) +{ + return ((phase1_vrs *) context)->prev_sp; +} + +/* Perform phase1 unwinding. UCBP is the exception being thrown, and + entry_VRS is the register state on entry to _Unwind_RaiseException. */ + +_Unwind_Reason_Code +__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, + phase2_vrs * entry_vrs) +{ + phase1_vrs saved_vrs; + _Unwind_Reason_Code pr_result; + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + + /* Save the core registers. */ + saved_vrs.core = entry_vrs->core; + /* Set demand-save flags. */ + saved_vrs.demand_save_flags = ~(_uw) 0; + + /* Unwind until we reach a propagation barrier. */ + do + { + /* Find the entry for this routine. */ + if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) + return _URC_FAILURE; + + /* Call the pr to decide what to do. */ + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) + (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); + } + while (pr_result == _URC_CONTINUE_UNWIND); + + /* We've unwound as far as we want to go, so restore the original + register state. */ + restore_non_core_regs (&saved_vrs); + if (pr_result != _URC_HANDLER_FOUND) + { + /* Some sort of failure has occurred in the pr and probably the + pr returned _URC_FAILURE. */ + return _URC_FAILURE; + } + + unwind_phase2 (ucbp, entry_vrs); +} + +/* Resume unwinding after a cleanup has been run. UCBP is the exception + being thrown and ENTRY_VRS is the register state on entry to + _Unwind_Resume. */ +_Unwind_Reason_Code +__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp, + _Unwind_Stop_Fn stop_fn, void *stop_arg, + phase2_vrs *entry_vrs) +{ + UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn; + UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg; + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + + return unwind_phase2_forced (ucbp, entry_vrs, 0); +} + +_Unwind_Reason_Code +__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs) +{ + _Unwind_Reason_Code pr_result; + + /* Recover the saved address. */ + entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp); + + if (UCB_FORCED_STOP_FN (ucbp)) + { + unwind_phase2_forced (ucbp, entry_vrs, 1); + + /* We can't return failure at this point. */ + abort (); + } + + /* Call the cached PR. */ + pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) + (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); + + switch (pr_result) + { + case _URC_INSTALL_CONTEXT: + /* Upload the registers to enter the landing pad. */ + restore_core_regs (&entry_vrs->core); + + case _URC_CONTINUE_UNWIND: + /* Continue unwinding the next frame. */ + unwind_phase2 (ucbp, entry_vrs); + + default: + abort (); + } +} + +_Unwind_Reason_Code +__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *); + +_Unwind_Reason_Code +__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp, + phase2_vrs * entry_vrs) +{ + if (!UCB_FORCED_STOP_FN (ucbp)) + return __gnu_Unwind_RaiseException (ucbp, entry_vrs); + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + /* Continue unwinding the next frame. */ + return unwind_phase2_forced (ucbp, entry_vrs, 0); +} + +/* Clean up an exception object when unwinding is complete. */ +void +_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused))) +{ +} + + +/* Get the _Unwind_Control_Block from an _Unwind_Context. */ + +static inline _Unwind_Control_Block * +unwind_UCB_from_context (_Unwind_Context * context) +{ + return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP); +} + + +/* Free an exception. */ + +void +_Unwind_DeleteException (_Unwind_Exception * exc) +{ + if (exc->exception_cleanup) + (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); +} + + +/* Perform stack backtrace through unwind data. */ +_Unwind_Reason_Code +__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, + phase2_vrs * entry_vrs); +_Unwind_Reason_Code +__gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, + phase2_vrs * entry_vrs) +{ + phase1_vrs saved_vrs; + _Unwind_Reason_Code code; + + _Unwind_Control_Block ucb; + _Unwind_Control_Block *ucbp = &ucb; + + /* Set the pc to the call site. */ + entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; + + /* Save the core registers. */ + saved_vrs.core = entry_vrs->core; + /* Set demand-save flags. */ + saved_vrs.demand_save_flags = ~(_uw) 0; + + do + { + /* Find the entry for this routine. */ + if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) + { + code = _URC_FAILURE; + break; + } + + /* The dwarf unwinder assumes the context structure holds things + like the function and LSDA pointers. The ARM implementation + caches these in the exception header (UCB). To avoid + rewriting everything we make the virtual IP register point at + the UCB. */ + _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp); + + /* Call trace function. */ + if ((*trace) ((_Unwind_Context *) &saved_vrs, trace_argument) + != _URC_NO_REASON) + { + code = _URC_FAILURE; + break; + } + + /* Call the pr to decide what to do. */ + code = ((personality_routine) UCB_PR_ADDR (ucbp)) + (_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, + ucbp, (void *) &saved_vrs); + } + while (code != _URC_END_OF_STACK + && code != _URC_FAILURE); + + restore_non_core_regs (&saved_vrs); + return code; +} + + +/* Common implementation for ARM ABI defined personality routines. + ID is the index of the personality routine, other arguments are as defined + by __aeabi_unwind_cpp_pr{0,1,2}. */ + +static _Unwind_Reason_Code +__gnu_unwind_pr_common (_Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context, + int id) +{ + __gnu_unwind_state uws; + _uw *data; + _uw offset; + _uw len; + _uw rtti_count; + int phase2_call_unexpected_after_unwind = 0; + int in_range = 0; + int forced_unwind = state & _US_FORCE_UNWIND; + + state &= _US_ACTION_MASK; + + data = (_uw *) ucbp->pr_cache.ehtp; + uws.data = *(data++); + uws.next = data; + if (id == 0) + { + uws.data <<= 8; + uws.words_left = 0; + uws.bytes_left = 3; + } + else + { + uws.words_left = (uws.data >> 16) & 0xff; + uws.data <<= 16; + uws.bytes_left = 2; + data += uws.words_left; + } + + /* Restore the saved pointer. */ + if (state == _US_UNWIND_FRAME_RESUME) + data = (_uw *) ucbp->cleanup_cache.bitpattern[0]; + + if ((ucbp->pr_cache.additional & 1) == 0) + { + /* Process descriptors. */ + while (*data) + { + _uw addr; + _uw fnstart; + + if (id == 2) + { + len = ((EHT32 *) data)->length; + offset = ((EHT32 *) data)->offset; + data += 2; + } + else + { + len = ((EHT16 *) data)->length; + offset = ((EHT16 *) data)->offset; + data++; + } + + fnstart = ucbp->pr_cache.fnstart + (offset & ~1); + addr = _Unwind_GetGR (context, R_PC); + in_range = (fnstart <= addr && addr < fnstart + (len & ~1)); + + switch (((offset & 1) << 1) | (len & 1)) + { + case 0: + /* Cleanup. */ + if (state != _US_VIRTUAL_UNWIND_FRAME + && in_range) + { + /* Cleanup in range, and we are running cleanups. */ + _uw lp; + + /* Landing pad address is 31-bit pc-relative offset. */ + lp = selfrel_offset31 (data); + data++; + /* Save the exception data pointer. */ + ucbp->cleanup_cache.bitpattern[0] = (_uw) data; + if (!__cxa_begin_cleanup (ucbp)) + return _URC_FAILURE; + /* Setup the VRS to enter the landing pad. */ + _Unwind_SetGR (context, R_PC, lp); + return _URC_INSTALL_CONTEXT; + } + /* Cleanup not in range, or we are in stage 1. */ + data++; + break; + + case 1: + /* Catch handler. */ + if (state == _US_VIRTUAL_UNWIND_FRAME) + { + if (in_range) + { + /* Check for a barrier. */ + _uw rtti; + bool is_reference = (data[0] & uint32_highbit) != 0; + void *matched; + enum __cxa_type_match_result match_type; + + /* Check for no-throw areas. */ + if (data[1] == (_uw) -2) + return _URC_FAILURE; + + /* The thrown object immediately follows the ECB. */ + matched = (void *)(ucbp + 1); + if (data[1] != (_uw) -1) + { + /* Match a catch specification. */ + rtti = _Unwind_decode_target2 ((_uw) &data[1]); + match_type = __cxa_type_match (ucbp, + (type_info *) rtti, + is_reference, + &matched); + } + else + match_type = ctm_succeeded; + + if (match_type) + { + ucbp->barrier_cache.sp = + _Unwind_GetGR (context, R_SP); + // ctm_succeeded_with_ptr_to_base really + // means _c_t_m indirected the pointer + // object. We have to reconstruct the + // additional pointer layer by using a temporary. + if (match_type == ctm_succeeded_with_ptr_to_base) + { + ucbp->barrier_cache.bitpattern[2] + = (_uw) matched; + ucbp->barrier_cache.bitpattern[0] + = (_uw) &ucbp->barrier_cache.bitpattern[2]; + } + else + ucbp->barrier_cache.bitpattern[0] = (_uw) matched; + ucbp->barrier_cache.bitpattern[1] = (_uw) data; + return _URC_HANDLER_FOUND; + } + } + /* Handler out of range, or not matched. */ + } + else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) + && ucbp->barrier_cache.bitpattern[1] == (_uw) data) + { + /* Matched a previous propagation barrier. */ + _uw lp; + + /* Setup for entry to the handler. */ + lp = selfrel_offset31 (data); + _Unwind_SetGR (context, R_PC, lp); + _Unwind_SetGR (context, 0, (_uw) ucbp); + return _URC_INSTALL_CONTEXT; + } + /* Catch handler not matched. Advance to the next descriptor. */ + data += 2; + break; + + case 2: + rtti_count = data[0] & 0x7fffffff; + /* Exception specification. */ + if (state == _US_VIRTUAL_UNWIND_FRAME) + { + if (in_range && (!forced_unwind || !rtti_count)) + { + /* Match against the exception specification. */ + _uw i; + _uw rtti; + void *matched; + + for (i = 0; i < rtti_count; i++) + { + matched = (void *)(ucbp + 1); + rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]); + if (__cxa_type_match (ucbp, (type_info *) rtti, 0, + &matched)) + break; + } + + if (i == rtti_count) + { + /* Exception does not match the spec. */ + ucbp->barrier_cache.sp = + _Unwind_GetGR (context, R_SP); + ucbp->barrier_cache.bitpattern[0] = (_uw) matched; + ucbp->barrier_cache.bitpattern[1] = (_uw) data; + return _URC_HANDLER_FOUND; + } + } + /* Handler out of range, or exception is permitted. */ + } + else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) + && ucbp->barrier_cache.bitpattern[1] == (_uw) data) + { + /* Matched a previous propagation barrier. */ + _uw lp; + /* Record the RTTI list for __cxa_call_unexpected. */ + ucbp->barrier_cache.bitpattern[1] = rtti_count; + ucbp->barrier_cache.bitpattern[2] = 0; + ucbp->barrier_cache.bitpattern[3] = 4; + ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1]; + + if (data[0] & uint32_highbit) + { + data += rtti_count + 1; + /* Setup for entry to the handler. */ + lp = selfrel_offset31 (data); + data++; + _Unwind_SetGR (context, R_PC, lp); + _Unwind_SetGR (context, 0, (_uw) ucbp); + return _URC_INSTALL_CONTEXT; + } + else + phase2_call_unexpected_after_unwind = 1; + } + if (data[0] & uint32_highbit) + data++; + data += rtti_count + 1; + break; + + default: + /* Should never happen. */ + return _URC_FAILURE; + } + /* Finished processing this descriptor. */ + } + } + + if (__gnu_unwind_execute (context, &uws) != _URC_OK) + return _URC_FAILURE; + + if (phase2_call_unexpected_after_unwind) + { + /* Enter __cxa_unexpected as if called from the call site. */ + _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC)); + _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected); + return _URC_INSTALL_CONTEXT; + } + + return _URC_CONTINUE_UNWIND; +} + + +/* ABI defined personality routine entry points. */ + +_Unwind_Reason_Code +__aeabi_unwind_cpp_pr0 (_Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) +{ + return __gnu_unwind_pr_common (state, ucbp, context, 0); +} + +_Unwind_Reason_Code +__aeabi_unwind_cpp_pr1 (_Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) +{ + return __gnu_unwind_pr_common (state, ucbp, context, 1); +} + +_Unwind_Reason_Code +__aeabi_unwind_cpp_pr2 (_Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) +{ + return __gnu_unwind_pr_common (state, ucbp, context, 2); +} diff --git a/libgcc/config/arm/unwind-arm.h b/libgcc/config/arm/unwind-arm.h new file mode 100644 index 00000000000..1a51d8d4824 --- /dev/null +++ b/libgcc/config/arm/unwind-arm.h @@ -0,0 +1,281 @@ +/* Header file for the ARM EABI unwinder + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 + Free Software Foundation, Inc. + Contributed by Paul Brook + + This file 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 3, or (at your option) any + later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Language-independent unwinder header public defines. This contains both + ABI defined objects, and GNU support routines. */ + +#ifndef UNWIND_ARM_H +#define UNWIND_ARM_H + +#define __ARM_EABI_UNWINDER__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); + typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); + typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); + typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); + typedef _Unwind_Word _uw; + typedef unsigned _uw64 __attribute__((mode(__DI__))); + typedef unsigned _uw16 __attribute__((mode(__HI__))); + typedef unsigned _uw8 __attribute__((mode(__QI__))); + + typedef enum + { + _URC_OK = 0, /* operation completed successfully */ + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9 /* unspecified failure of some kind */ + } + _Unwind_Reason_Code; + + typedef enum + { + _US_VIRTUAL_UNWIND_FRAME = 0, + _US_UNWIND_FRAME_STARTING = 1, + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16 + } + _Unwind_State; + + /* Provided only for compatibility with existing code. */ + typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE 1 +#define _UA_CLEANUP_PHASE 2 +#define _UA_HANDLER_FRAME 4 +#define _UA_FORCE_UNWIND 8 +#define _UA_END_OF_STACK 16 +#define _URC_NO_REASON _URC_OK + + typedef struct _Unwind_Control_Block _Unwind_Control_Block; + typedef struct _Unwind_Context _Unwind_Context; + typedef _uw _Unwind_EHT_Header; + + + /* UCB: */ + + struct _Unwind_Control_Block + { + char exception_class[8]; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); + /* Unwinder cache, private fields for the unwinder's use */ + struct + { + _uw reserved1; /* Forced unwind stop fn, 0 if not forced */ + _uw reserved2; /* Personality routine address */ + _uw reserved3; /* Saved callsite address */ + _uw reserved4; /* Forced unwind stop arg */ + _uw reserved5; + } + unwinder_cache; + /* Propagation barrier cache (valid after phase 1): */ + struct + { + _uw sp; + _uw bitpattern[5]; + } + barrier_cache; + /* Cleanup cache (preserved over cleanup): */ + struct + { + _uw bitpattern[4]; + } + cleanup_cache; + /* Pr cache (for pr's benefit): */ + struct + { + _uw fnstart; /* function start address */ + _Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */ + _uw additional; /* additional data */ + _uw reserved1; + } + pr_cache; + long long int :0; /* Force alignment to 8-byte boundary */ + }; + + /* Virtual Register Set*/ + + typedef enum + { + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ + _UVRSC_FPA = 2, /* fpa */ + _UVRSC_WMMXD = 3, /* Intel WMMX data register */ + _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + } + _Unwind_VRS_RegClass; + + typedef enum + { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 + } + _Unwind_VRS_DataRepresentation; + + typedef enum + { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 + } + _Unwind_VRS_Result; + + /* Frame unwinding state. */ + typedef struct + { + /* The current word (bytes packed msb first). */ + _uw data; + /* Pointer to the next word of data. */ + _uw *next; + /* The number of bytes left in this word. */ + _uw8 bytes_left; + /* The number of words pointed to by ptr. */ + _uw8 words_left; + } + __gnu_unwind_state; + + typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, + _Unwind_Control_Block *, _Unwind_Context *); + + _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation, + void *); + + _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, + _uw, _Unwind_VRS_DataRepresentation); + + + /* Support functions for the PR. */ +#define _Unwind_Exception _Unwind_Control_Block + typedef char _Unwind_Exception_Class[8]; + + void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); + + /* These two should never be used. */ + _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); + _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); + + /* Interface functions: */ + _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); + void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); + _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + + typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int, _Unwind_Action, _Unwind_Exception_Class, + _Unwind_Control_Block *, struct _Unwind_Context *, void *); + _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, + _Unwind_Stop_Fn, void *); + /* @@@ Use unwind data to perform a stack backtrace. The trace callback + is called for every stack frame in the call chain, but no cleanup + actions are performed. */ + typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *); + _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, + void*); + + _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); + void _Unwind_Complete(_Unwind_Control_Block *ucbp); + void _Unwind_DeleteException (_Unwind_Exception *); + + _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, + _Unwind_Context *); + _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, + __gnu_unwind_state *); + + /* Decode an R_ARM_TARGET2 relocation. */ + static inline _Unwind_Word + _Unwind_decode_target2 (_Unwind_Word ptr) + { + _Unwind_Word tmp; + + tmp = *(_Unwind_Word *) ptr; + /* Zero values are always NULL. */ + if (!tmp) + return 0; + +#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) + /* Pc-relative indirect. */ + tmp += ptr; + tmp = *(_Unwind_Word *) tmp; +#elif defined(__symbian__) || defined(__uClinux__) + /* Absolute pointer. Nothing more to do. */ +#else + /* Pc-relative pointer. */ + tmp += ptr; +#endif + return tmp; + } + + static inline _Unwind_Word + _Unwind_GetGR (_Unwind_Context *context, int regno) + { + _uw val; + _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + return val; + } + + /* Return the address of the instruction, not the actual IP value. */ +#define _Unwind_GetIP(context) \ + (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + +#define _Unwind_GetIPInfo(context, ip_before_insn) \ + (*ip_before_insn = 0, _Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + + static inline void + _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) + { + _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); + } + + /* The dwarf unwinder doesn't understand arm/thumb state. We assume the + landing pad uses the same instruction set as the call site. */ +#define _Unwind_SetIP(context, val) \ + _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) + +/* leb128 type numbers have a potentially unlimited size. + The target of the following definitions of _sleb128_t and _uleb128_t + is to have efficient data types large enough to hold the leb128 type + numbers used in the unwind code. */ +typedef long _sleb128_t; +typedef unsigned long _uleb128_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* defined UNWIND_ARM_H */ diff --git a/libgcc/config/ia64/fde-glibc.c b/libgcc/config/ia64/fde-glibc.c new file mode 100644 index 00000000000..12760b96eda --- /dev/null +++ b/libgcc/config/ia64/fde-glibc.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2000, 2001, 2003, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Locate the FDE entry for a given address, using glibc ld.so routines + to avoid register/deregister calls at DSO load/unload. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#include "config.h" +#include +#include +#include +#include "unwind-ia64.h" + +#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 2) \ + || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && !defined(DT_CONFIG)) +# error You need GLIBC 2.2.4 or later on IA-64 Linux +#endif + +struct unw_ia64_callback_data +{ + Elf64_Addr pc; + unsigned long *segment_base; + unsigned long *gp; + struct unw_table_entry *ret; +}; + +static int +_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) +{ + struct unw_ia64_callback_data *data = (struct unw_ia64_callback_data *) ptr; + const Elf64_Phdr *phdr, *p_unwind, *p_dynamic; + long n, match; + Elf64_Addr load_base, seg_base; + struct unw_table_entry *f_base, *f; + size_t lo, hi; + + /* Make sure struct dl_phdr_info is at least as big as we need. */ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + + sizeof (info->dlpi_phnum)) + return -1; + + match = 0; + phdr = info->dlpi_phdr; + load_base = info->dlpi_addr; + p_unwind = NULL; + p_dynamic = NULL; + seg_base = ~(Elf64_Addr) 0; + + /* See if PC falls into one of the loaded segments. Find the unwind + segment at the same time. */ + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + if (phdr->p_type == PT_LOAD) + { + Elf64_Addr vaddr = phdr->p_vaddr + load_base; + if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) + match = 1; + if (vaddr < seg_base) + seg_base = vaddr; + } + else if (phdr->p_type == PT_IA_64_UNWIND) + p_unwind = phdr; + else if (phdr->p_type == PT_DYNAMIC) + p_dynamic = phdr; + } + if (!match || !p_unwind) + return 0; + + /* Search for the FDE within the unwind segment. */ + + f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base); + lo = 0; + hi = p_unwind->p_memsz / sizeof (struct unw_table_entry); + + while (lo < hi) + { + size_t mid = (lo + hi) / 2; + + f = f_base + mid; + if (data->pc < f->start_offset + seg_base) + hi = mid; + else if (data->pc >= f->end_offset + seg_base) + lo = mid + 1; + else + goto found; + } + /* No need to search for further libraries when we know pc is contained + in this library. */ + return 1; + + found: + *data->segment_base = seg_base; + *data->gp = 0; + data->ret = f; + + if (p_dynamic) + { + /* For dynamically linked executables and shared libraries, + DT_PLTGOT is the gp value for that object. */ + Elf64_Dyn *dyn = (Elf64_Dyn *)(p_dynamic->p_vaddr + load_base); + for (; dyn->d_tag != DT_NULL ; dyn++) + if (dyn->d_tag == DT_PLTGOT) + { + /* On IA-64, _DYNAMIC is writable and GLIBC has relocated it. */ + *data->gp = dyn->d_un.d_ptr; + break; + } + } + else + { + /* Otherwise this is a static executable with no _DYNAMIC. + The gp is constant program-wide. */ + register unsigned long gp __asm__("gp"); + *data->gp = gp; + } + + return 1; +} + +/* Return a pointer to the unwind table entry for the function + containing PC. */ + +struct unw_table_entry * +_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, + unsigned long *gp, + struct unw_table_entry *ent ATTRIBUTE_UNUSED) +{ + struct unw_ia64_callback_data data; + + data.pc = (Elf64_Addr) pc; + data.segment_base = segment_base; + data.gp = gp; + data.ret = NULL; + + if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) + return NULL; + + return data.ret; +} diff --git a/libgcc/config/ia64/fde-vms.c b/libgcc/config/ia64/fde-vms.c new file mode 100644 index 00000000000..c9ac5d28076 --- /dev/null +++ b/libgcc/config/ia64/fde-vms.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc. + Contributed by Douglas B Rupp + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Locate the FDE entry for a given address, using VMS Starlet routines + to avoid register/deregister calls at DSO load/unload. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include +#include +#include +#include "md-unwind-support.h" +#include "unwind-ia64.h" + +#define __int64 long +#include +#ifndef SS$_NORMAL +#define SS$_NORMAL 1 +#endif + +typedef struct +{ + unsigned long start_offset; + unsigned long end_offset; + unsigned long info_offset; + unsigned long gp_value; +} vms_unw_table_entry; + +typedef unsigned long long uqword; + +/* ENTRY is the unwind table entry found for a PC part of call chain we're + unwinding through. Return whether we should force the generic unwinder + to resort to "fallback" processing. */ + +static int +force_fallback_processing_for (void * pc, vms_unw_table_entry * entry) +{ + static int eh_debug = -1; + + uqword * unw_info_block = (uqword *)entry->info_offset; + uqword header = *unw_info_block; + + /* We need to force fallback processing in two cases: + + 1/ The exception dispatch frame, since only our fallback + processing knows how to properly unwind through it, and + + 2/ A bottom of stack frame, since only our fallback processing + will ensure we don't try to unwind further past it, which + would get us into unknown territory and likely cause a severe + crash along the way. + + The two cases are indicated by non-default values for specific + bits in the OS Specific Data (OSSD) General Information block + associated with such frames. */ + + ossddef * ossd; + + if (eh_debug == -1) + { + char * EH_DEBUG = getenv ("EH_DEBUG"); + eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0; + } + + if (eh_debug) + { + printf ("pc @ 0x%p, block @ 0x%p, header = 0x%016llx\n", + pc, unw_info_block, header); + printf ("mode = %d, length = %ld, handler = %d\n", + (int)UNW_IVMS_MODE (header), UNW_LENGTH (header), + UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header)); + } + + /* An OSSD block is there for IVMS_MODE == 3 only. */ + if (UNW_IVMS_MODE (header) != 3) + return 0; + + /* The OSSD block is found past the header, unwind descriptor area + and condition handler pointer, if any. */ + ossd = (ossddef *) + /* Beware: uqword pointer arithmetic below. */ + (unw_info_block + + 1 + + UNW_LENGTH (header) + + (UNW_FLAG_EHANDLER (header) || UNW_FLAG_EHANDLER (header))); + + /* "A General Information segment may be omitted if all of its fields + would have their default values. If a General Information segment + is present, it must be the first in the OSSD area." So ... */ + + if (eh_debug) + printf ("ossd @ 0x%p\n", ossd); + + if (eh_debug && ossd->ossd$v_type == OSSD$K_GENERAL_INFO) + printf ("exc_frame = %d - bot_frame = %d - base_frame = %d\n", + ossd->ossd$v_exception_frame, + ossd->ossd$v_bottom_of_stack, + ossd->ossd$v_base_frame); + + return + ossd->ossd$v_type == OSSD$K_GENERAL_INFO + && (ossd->ossd$v_exception_frame + || ossd->ossd$v_bottom_of_stack || ossd->ossd$v_base_frame); +} + +/* Return a pointer to the unwind table entry for the function + containing PC, 0 if we cannot find an entry or if the one we find + calls for fallback processing. */ + +struct unw_table_entry * +_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, + unsigned long *gp, struct unw_table_entry *ent) +{ + vms_unw_table_entry vueblock; + + if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL) + return 0; + + /* If there is no unwind information, use fallback. */ + if (vueblock.info_offset == 0) + return 0; + + /* If we need to force fallback processing, just pretend there is + no entry. */ + if (force_fallback_processing_for (pc, &vueblock)) + return 0; + + *segment_base = 0; /* ??? Fixme. ??? */ + *gp = vueblock.gp_value; + ent->start_offset = vueblock.start_offset; + ent->end_offset = vueblock.end_offset; + ent->info_offset = vueblock.info_offset; + + return ent; +} diff --git a/libgcc/config/ia64/t-eh-ia64 b/libgcc/config/ia64/t-eh-ia64 new file mode 100644 index 00000000000..6aa4bb930b8 --- /dev/null +++ b/libgcc/config/ia64/t-eh-ia64 @@ -0,0 +1,2 @@ +LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \ + $(srcdir)/unwind-c.c diff --git a/libgcc/config/ia64/t-glibc b/libgcc/config/ia64/t-glibc new file mode 100644 index 00000000000..df4fe9c4404 --- /dev/null +++ b/libgcc/config/ia64/t-glibc @@ -0,0 +1,3 @@ +# Use system libunwind library on IA-64 GLIBC based system. +LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ + $(srcdir)/unwind-compat.c diff --git a/libgcc/config/ia64/t-glibc-libunwind b/libgcc/config/ia64/t-glibc-libunwind new file mode 100644 index 00000000000..8b1736a2d67 --- /dev/null +++ b/libgcc/config/ia64/t-glibc-libunwind @@ -0,0 +1,3 @@ +# Build libunwind for IA-64 GLIBC based system. +LIBUNWIND = $(srcdir)/config/ia64/fde-glibc.c \ + $(srcdir)/config/ia64/unwind-ia64.c diff --git a/libgcc/config/ia64/t-hpux b/libgcc/config/ia64/t-hpux new file mode 100644 index 00000000000..ef3387e7a61 --- /dev/null +++ b/libgcc/config/ia64/t-hpux @@ -0,0 +1 @@ +LIB2ADDEH = $(srcdir)/unwind-c.c diff --git a/libgcc/config/ia64/t-vms b/libgcc/config/ia64/t-vms new file mode 100644 index 00000000000..9bc933adfe0 --- /dev/null +++ b/libgcc/config/ia64/t-vms @@ -0,0 +1 @@ +LIB2ADDEH += $(srcdir)/config/ia64/fde-vms.c diff --git a/libgcc/config/ia64/unwind-ia64.c b/libgcc/config/ia64/unwind-ia64.c new file mode 100644 index 00000000000..e9ddfca8864 --- /dev/null +++ b/libgcc/config/ia64/unwind-ia64.c @@ -0,0 +1,2458 @@ +/* Subroutines needed for unwinding IA-64 standard format stack frame + info for exception handling. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, + 2009, 2011 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + Andrew Haley + David Mosberger-Tang + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "unwind.h" +#include "unwind-ia64.h" +#include "unwind-compat.h" +#include "ia64intrin.h" + +/* This isn't thread safe, but nice for occasional tests. */ +#undef ENABLE_MALLOC_CHECKING + +#ifndef __USING_SJLJ_EXCEPTIONS__ + +enum unw_application_register +{ + UNW_AR_BSP, + UNW_AR_BSPSTORE, + UNW_AR_PFS, + UNW_AR_RNAT, + UNW_AR_UNAT, + UNW_AR_LC, + UNW_AR_EC, + UNW_AR_FPSR, + UNW_AR_RSC, + UNW_AR_CCV +}; + +enum unw_register_index +{ + /* Primary UNAT. */ + UNW_REG_PRI_UNAT_GR, + UNW_REG_PRI_UNAT_MEM, + + /* Memory Stack. */ + UNW_REG_PSP, /* previous memory stack pointer */ + + /* Register Stack. */ + UNW_REG_BSP, /* register stack pointer */ + UNW_REG_BSPSTORE, + UNW_REG_PFS, /* previous function state */ + UNW_REG_RNAT, + /* Return Pointer. */ + UNW_REG_RP, + + /* Special preserved registers. */ + UNW_REG_UNAT, UNW_REG_PR, UNW_REG_LC, UNW_REG_FPSR, + + /* Non-stacked general registers. */ + UNW_REG_R2, + UNW_REG_R4 = UNW_REG_R2 + 2, + UNW_REG_R7 = UNW_REG_R2 + 5, + UNW_REG_R31 = UNW_REG_R2 + 29, + + /* Non-stacked floating point registers. */ + UNW_REG_F2, + UNW_REG_F5 = UNW_REG_F2 + 3, + UNW_REG_F16 = UNW_REG_F2 + 14, + UNW_REG_F31 = UNW_REG_F2 + 29, + + /* Branch registers. */ + UNW_REG_B0, UNW_REG_B1, + UNW_REG_B5 = UNW_REG_B1 + 4, + + UNW_NUM_REGS +}; + +enum unw_where +{ + UNW_WHERE_NONE, /* register isn't saved at all */ + UNW_WHERE_GR, /* register is saved in a general register */ + UNW_WHERE_FR, /* register is saved in a floating-point register */ + UNW_WHERE_BR, /* register is saved in a branch register */ + UNW_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ + UNW_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ + + /* At the end of each prologue these locations get resolved to + UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively. */ + UNW_WHERE_SPILL_HOME, /* register is saved in its spill home */ + UNW_WHERE_GR_SAVE /* register is saved in next general register */ +}; + +#define UNW_WHEN_NEVER 0x7fffffff + +struct unw_reg_info +{ + unsigned long val; /* save location: register number or offset */ + enum unw_where where; /* where the register gets saved */ + int when; /* when the register gets saved */ +}; + +struct unw_reg_state { + struct unw_reg_state *next; /* next (outer) element on state stack */ + struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */ +}; + +struct unw_labeled_state { + struct unw_labeled_state *next; /* next labeled state (or NULL) */ + unsigned long label; /* label for this state */ + struct unw_reg_state saved_state; +}; + +typedef struct unw_state_record +{ + unsigned int first_region : 1; /* is this the first region? */ + unsigned int done : 1; /* are we done scanning descriptors? */ + unsigned int any_spills : 1; /* got any register spills? */ + unsigned int in_body : 1; /* are we inside a body? */ + unsigned int no_reg_stack_frame : 1; /* Don't adjust bsp for i&l regs */ + unsigned char *imask; /* imask of spill_mask record or NULL */ + unsigned long pr_val; /* predicate values */ + unsigned long pr_mask; /* predicate mask */ + long spill_offset; /* psp-relative offset for spill base */ + int region_start; + int region_len; + int epilogue_start; + int epilogue_count; + int when_target; + + unsigned char gr_save_loc; /* next general register to use for saving */ + unsigned char return_link_reg; /* branch register for return link */ + unsigned short unwabi; + + struct unw_labeled_state *labeled_states; /* list of all labeled states */ + struct unw_reg_state curr; /* current state */ + + _Unwind_Personality_Fn personality; + +} _Unwind_FrameState; + +enum unw_nat_type +{ + UNW_NAT_NONE, /* NaT not represented */ + UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */ + UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */ + UNW_NAT_REGSTK /* NaT is in rnat */ +}; + +struct unw_stack +{ + unsigned long limit; + unsigned long top; +}; + +struct _Unwind_Context +{ + /* Initial frame info. */ + unsigned long rnat; /* rse nat collection */ + unsigned long regstk_top; /* lowest address of rbs stored register + which uses context->rnat collection */ + + /* Current frame info. */ + unsigned long bsp; /* backing store pointer value + corresponding to psp. */ + unsigned long sp; /* stack pointer value */ + unsigned long psp; /* previous sp value */ + unsigned long rp; /* return pointer */ + unsigned long pr; /* predicate collection */ + + unsigned long region_start; /* start of unwind region */ + unsigned long gp; /* global pointer value */ + void *lsda; /* language specific data area */ + + /* Preserved state. */ + unsigned long *bsp_loc; /* previous bsp save location + Appears to be write-only? */ + unsigned long *bspstore_loc; + unsigned long *pfs_loc; /* Save location for pfs in current + (corr. to sp) frame. Target + contains cfm for caller. */ + unsigned long *signal_pfs_loc;/* Save location for pfs in current + signal frame. Target contains + pfs for caller. */ + unsigned long *pri_unat_loc; + unsigned long *unat_loc; + unsigned long *lc_loc; + unsigned long *fpsr_loc; + + unsigned long eh_data[4]; + + struct unw_ireg + { + unsigned long *loc; + struct unw_ireg_nat + { + enum unw_nat_type type : 3; + signed long off : 61; /* NaT word is at loc+nat.off */ + } nat; + } ireg[32 - 2]; /* Indexed by - 2 */ + + unsigned long *br_loc[8]; + void *fr_loc[32 - 2]; + + /* ??? We initially point pri_unat_loc here. The entire NAT bit + logic needs work. */ + unsigned long initial_unat; +}; + +typedef unsigned long unw_word; + +/* Implicit register save order. See section 11.4.2.3 Rules for Using + Unwind Descriptors, rule 3. */ + +static unsigned char const save_order[] = +{ + UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR, + UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR +}; + + +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) + +/* MASK is a bitmap describing the allocation state of emergency buffers, + with bit set indicating free. Return >= 0 if allocation is successful; + < 0 if failure. */ + +static inline int +atomic_alloc (unsigned int *mask) +{ + unsigned int old = *mask, ret, new; + + while (1) + { + if (old == 0) + return -1; + ret = old & -old; + new = old & ~ret; + new = __sync_val_compare_and_swap (mask, old, new); + if (old == new) + break; + old = new; + } + + return __builtin_ffs (ret) - 1; +} + +/* Similarly, free an emergency buffer. */ + +static inline void +atomic_free (unsigned int *mask, int bit) +{ + __sync_xor_and_fetch (mask, 1 << bit); +} + + +#define SIZE(X) (sizeof(X) / sizeof(*(X))) +#define MASK_FOR(X) ((2U << (SIZE (X) - 1)) - 1) +#define PTR_IN(X, P) ((P) >= (X) && (P) < (X) + SIZE (X)) + +static struct unw_reg_state emergency_reg_state[32]; +static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state); + +static struct unw_labeled_state emergency_labeled_state[8]; +static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state); + +#ifdef ENABLE_MALLOC_CHECKING +static int reg_state_alloced; +static int labeled_state_alloced; +#endif + +/* Allocation and deallocation of structures. */ + +static struct unw_reg_state * +alloc_reg_state (void) +{ + struct unw_reg_state *rs; + +#ifdef ENABLE_MALLOC_CHECKING + reg_state_alloced++; +#endif + + rs = malloc (sizeof (struct unw_reg_state)); + if (!rs) + { + int n = atomic_alloc (&emergency_reg_state_free); + if (n >= 0) + rs = &emergency_reg_state[n]; + } + + return rs; +} + +static void +free_reg_state (struct unw_reg_state *rs) +{ +#ifdef ENABLE_MALLOC_CHECKING + reg_state_alloced--; +#endif + + if (PTR_IN (emergency_reg_state, rs)) + atomic_free (&emergency_reg_state_free, rs - emergency_reg_state); + else + free (rs); +} + +static struct unw_labeled_state * +alloc_label_state (void) +{ + struct unw_labeled_state *ls; + +#ifdef ENABLE_MALLOC_CHECKING + labeled_state_alloced++; +#endif + + ls = malloc(sizeof(struct unw_labeled_state)); + if (!ls) + { + int n = atomic_alloc (&emergency_labeled_state_free); + if (n >= 0) + ls = &emergency_labeled_state[n]; + } + + return ls; +} + +static void +free_label_state (struct unw_labeled_state *ls) +{ +#ifdef ENABLE_MALLOC_CHECKING + labeled_state_alloced--; +#endif + + if (PTR_IN (emergency_labeled_state, ls)) + atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls); + else + free (ls); +} + +/* Routines to manipulate the state stack. */ + +static void +push (struct unw_state_record *sr) +{ + struct unw_reg_state *rs = alloc_reg_state (); + memcpy (rs, &sr->curr, sizeof (*rs)); + sr->curr.next = rs; +} + +static void +pop (struct unw_state_record *sr) +{ + struct unw_reg_state *rs = sr->curr.next; + + if (!rs) + abort (); + memcpy (&sr->curr, rs, sizeof(*rs)); + free_reg_state (rs); +} + +/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */ + +static struct unw_reg_state * +dup_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *copy, *prev = NULL, *first = NULL; + + while (rs) + { + copy = alloc_reg_state (); + memcpy (copy, rs, sizeof(*copy)); + if (first) + prev->next = copy; + else + first = copy; + rs = rs->next; + prev = copy; + } + + return first; +} + +/* Free all stacked register states (but not RS itself). */ +static void +free_state_stack (struct unw_reg_state *rs) +{ + struct unw_reg_state *p, *next; + + for (p = rs->next; p != NULL; p = next) + { + next = p->next; + free_reg_state (p); + } + rs->next = NULL; +} + +/* Free all labeled states. */ + +static void +free_label_states (struct unw_labeled_state *ls) +{ + struct unw_labeled_state *next; + + for (; ls ; ls = next) + { + next = ls->next; + + free_state_stack (&ls->saved_state); + free_label_state (ls); + } +} + +/* Unwind decoder routines */ + +static enum unw_register_index __attribute__((const)) +decode_abreg (unsigned char abreg, int memory) +{ + switch (abreg) + { +#if TARGET_ABI_OPEN_VMS + /* OpenVMS Calling Standard specifies R3 - R31. */ + case 0x03 ... 0x1f: return UNW_REG_R2 + (abreg - 0x02); +#else + /* Standard Intel ABI specifies GR 4 - 7. */ + case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04); +#endif + case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22); + case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30); + case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41); + case 0x60: return UNW_REG_PR; + case 0x61: return UNW_REG_PSP; + case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR; + case 0x63: return UNW_REG_RP; + case 0x64: return UNW_REG_BSP; + case 0x65: return UNW_REG_BSPSTORE; + case 0x66: return UNW_REG_RNAT; + case 0x67: return UNW_REG_UNAT; + case 0x68: return UNW_REG_FPSR; + case 0x69: return UNW_REG_PFS; + case 0x6a: return UNW_REG_LC; + default: + abort (); + } +} + +static void +set_reg (struct unw_reg_info *reg, enum unw_where where, + int when, unsigned long val) +{ + reg->val = val; + reg->where = where; + if (reg->when == UNW_WHEN_NEVER) + reg->when = when; +} + +static void +alloc_spill_area (unsigned long *offp, unsigned long regsize, + struct unw_reg_info *lo, struct unw_reg_info *hi) +{ + struct unw_reg_info *reg; + + for (reg = hi; reg >= lo; --reg) + { + if (reg->where == UNW_WHERE_SPILL_HOME) + { + reg->where = UNW_WHERE_PSPREL; + *offp -= regsize; + reg->val = *offp; + } + } +} + +static inline void +spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, + unw_word t) +{ + struct unw_reg_info *reg; + + for (reg = *regp; reg <= lim; ++reg) + { + if (reg->where == UNW_WHERE_SPILL_HOME) + { + reg->when = t; + *regp = reg + 1; + return; + } + } + /* Excess spill. */ + abort (); +} + +static void +finish_prologue (struct unw_state_record *sr) +{ + struct unw_reg_info *reg; + unsigned long off; + int i; + + /* First, resolve implicit register save locations + (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */ + + for (i = 0; i < (int) sizeof (save_order); ++i) + { + reg = sr->curr.reg + save_order[i]; + if (reg->where == UNW_WHERE_GR_SAVE) + { + reg->where = UNW_WHERE_GR; + reg->val = sr->gr_save_loc++; + } + } + + /* Next, compute when the fp, general, and branch registers get saved. + This must come before alloc_spill_area() because we need to know + which registers are spilled to their home locations. */ + if (sr->imask) + { + static unsigned char const limit[3] = { + UNW_REG_F31, UNW_REG_R7, UNW_REG_B5 + }; + + unsigned char kind, mask = 0, *cp = sr->imask; + int t; + struct unw_reg_info *(regs[3]); + + regs[0] = sr->curr.reg + UNW_REG_F2; + regs[1] = sr->curr.reg + UNW_REG_R4; + regs[2] = sr->curr.reg + UNW_REG_B1; + + for (t = 0; t < sr->region_len; ++t) + { + if ((t & 3) == 0) + mask = *cp++; + kind = (mask >> 2*(3-(t & 3))) & 3; + if (kind > 0) + spill_next_when (®s[kind - 1], sr->curr.reg + limit[kind - 1], + sr->region_start + t); + } + } + + /* Next, lay out the memory stack spill area. */ + if (sr->any_spills) + { + off = sr->spill_offset; + alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2, + sr->curr.reg + UNW_REG_F31); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_B1, + sr->curr.reg + UNW_REG_B5); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_R4, + sr->curr.reg + UNW_REG_R7); + } +} + +/* + * Region header descriptors. + */ + +static void +desc_prologue (int body, unw_word rlen, unsigned char mask, + unsigned char grsave, struct unw_state_record *sr) +{ + int i; + + if (!(sr->in_body || sr->first_region)) + finish_prologue (sr); + sr->first_region = 0; + + /* Check if we're done. */ + if (sr->when_target < sr->region_start + sr->region_len) + { + sr->done = 1; + return; + } + + for (i = 0; i < sr->epilogue_count; ++i) + pop (sr); + + sr->epilogue_count = 0; + sr->epilogue_start = UNW_WHEN_NEVER; + + if (!body) + push (sr); + + sr->region_start += sr->region_len; + sr->region_len = rlen; + sr->in_body = body; + + if (!body) + { + for (i = 0; i < 4; ++i) + { + if (mask & 0x8) + set_reg (sr->curr.reg + save_order[i], UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, grsave++); + mask <<= 1; + } + sr->gr_save_loc = grsave; + sr->any_spills = 0; + sr->imask = 0; + sr->spill_offset = 0x10; /* default to psp+16 */ + } +} + +/* + * Prologue descriptors. + */ + +static inline void +desc_abi (unsigned char abi, + unsigned char context, + struct unw_state_record *sr) +{ + sr->unwabi = (abi << 8) | context; +} + +static inline void +desc_br_gr (unsigned char brmask, unsigned char gr, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + brmask >>= 1; + } +} + +static inline void +desc_br_mem (unsigned char brmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + { + set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + brmask >>= 1; + } +} + +static inline void +desc_frgr_mem (unsigned char grmask, unw_word frmask, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } + for (i = 0; i < 20; ++i) + { + if ((frmask & 1) != 0) + { + enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4; + set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_fr_mem (unsigned char frmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((frmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_gr_gr (unsigned char grmask, unsigned char gr, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + grmask >>= 1; + } +} + +static inline void +desc_gr_mem (unsigned char grmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } +} + +static inline void +desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, + sr->region_start + MIN ((int)t, sr->region_len - 1), 16*size); +} + +static inline void +desc_mem_stack_v (unw_word t, struct unw_state_record *sr) +{ + sr->curr.reg[UNW_REG_PSP].when + = sr->region_start + MIN ((int)t, sr->region_len - 1); +} + +static inline void +desc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, dst); +} + +static inline void +desc_reg_psprel (unsigned char reg, unw_word pspoff, + struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_PSPREL, + sr->region_start + sr->region_len - 1, + 0x10 - 4*pspoff); +} + +static inline void +desc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_SPREL, + sr->region_start + sr->region_len - 1, + 4*spoff); +} + +static inline void +desc_rp_br (unsigned char dst, struct unw_state_record *sr) +{ + sr->return_link_reg = dst; +} + +static inline void +desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) +{ + struct unw_reg_info *reg = sr->curr.reg + regnum; + + if (reg->where == UNW_WHERE_NONE) + reg->where = UNW_WHERE_GR_SAVE; + reg->when = sr->region_start + MIN ((int)t, sr->region_len - 1); +} + +static inline void +desc_spill_base (unw_word pspoff, struct unw_state_record *sr) +{ + sr->spill_offset = 0x10 - 4*pspoff; +} + +static inline unsigned char * +desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr) +{ + sr->imask = imaskp; + return imaskp + (2*sr->region_len + 7)/8; +} + +/* + * Body descriptors. + */ +static inline void +desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) +{ + sr->epilogue_start = sr->region_start + sr->region_len - 1 - t; + sr->epilogue_count = ecount + 1; +} + +static inline void +desc_copy_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_labeled_state *ls; + + for (ls = sr->labeled_states; ls; ls = ls->next) + { + if (ls->label == label) + { + free_state_stack (&sr->curr); + memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr)); + sr->curr.next = dup_state_stack (ls->saved_state.next); + return; + } + } + abort (); +} + +static inline void +desc_label_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_labeled_state *ls = alloc_label_state (); + + ls->label = label; + memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state)); + ls->saved_state.next = dup_state_stack (sr->curr.next); + + /* Insert into list of labeled states. */ + ls->next = sr->labeled_states; + sr->labeled_states = ls; +} + +/* + * General descriptors. + */ + +static inline int +desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) +{ + if (sr->when_target <= sr->region_start + MIN ((int)t, sr->region_len - 1)) + return 0; + if (qp > 0) + { + if ((sr->pr_val & (1UL << qp)) == 0) + return 0; + sr->pr_mask |= (1UL << qp); + } + return 1; +} + +static inline void +desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, + struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = UNW_WHERE_NONE; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = 0; +} + +static inline void +desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, + unsigned char x, unsigned char ytreg, + struct unw_state_record *sr) +{ + enum unw_where where = UNW_WHERE_GR; + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + if (x) + where = UNW_WHERE_BR; + else if (ytreg & 0x80) + where = UNW_WHERE_FR; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = where; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = ytreg & 0x7f; +} + +static inline void +desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word pspoff, struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = UNW_WHERE_PSPREL; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = 0x10 - 4*pspoff; +} + +static inline void +desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word spoff, struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = UNW_WHERE_SPREL; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = 4*spoff; +} + + +#define UNW_DEC_BAD_CODE(code) abort (); + +/* Region headers. */ +#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg) +#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg) + +/* Prologue descriptors. */ +#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg) +#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg) +#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg) +#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg) +#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg) +#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg) +#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg) +#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg) +#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg) +#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg) +#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg) +#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg) +#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg) +#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg) +#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg) +#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg) +#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg)) + +/* Body descriptors. */ +#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg) +#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg) +#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg) + +/* General unwind descriptors. */ +#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg) +#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg) +#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg) +#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg) +#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) + + +/* + * Generic IA-64 unwind info decoder. + * + * This file is used both by the Linux kernel and objdump. Please keep + * the copies of this file in sync. + * + * You need to customize the decoder by defining the following + * macros/constants before including this file: + * + * Types: + * unw_word Unsigned integer type with at least 64 bits + * + * Register names: + * UNW_REG_BSP + * UNW_REG_BSPSTORE + * UNW_REG_FPSR + * UNW_REG_LC + * UNW_REG_PFS + * UNW_REG_PR + * UNW_REG_RNAT + * UNW_REG_PSP + * UNW_REG_RP + * UNW_REG_UNAT + * + * Decoder action macros: + * UNW_DEC_BAD_CODE(code) + * UNW_DEC_ABI(fmt,abi,context,arg) + * UNW_DEC_BR_GR(fmt,brmask,gr,arg) + * UNW_DEC_BR_MEM(fmt,brmask,arg) + * UNW_DEC_COPY_STATE(fmt,label,arg) + * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) + * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) + * UNW_DEC_FR_MEM(fmt,frmask,arg) + * UNW_DEC_GR_GR(fmt,grmask,gr,arg) + * UNW_DEC_GR_MEM(fmt,grmask,arg) + * UNW_DEC_LABEL_STATE(fmt,label,arg) + * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) + * UNW_DEC_MEM_STACK_V(fmt,t,arg) + * UNW_DEC_PRIUNAT_GR(fmt,r,arg) + * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) + * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) + * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) + * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) + * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) + * UNW_DEC_REG_REG(fmt,src,dst,arg) + * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) + * UNW_DEC_REG_WHEN(fmt,reg,t,arg) + * UNW_DEC_RESTORE(fmt,t,abreg,arg) + * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) + * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) + * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) + * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) + * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) + */ + +static unw_word +unw_decode_uleb128 (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *dpp = bp; + return result; +} + +static unsigned char * +unw_decode_x1 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, abreg; + unw_word t, off; + + byte1 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x2 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + ytreg = byte2; + x = (byte1 >> 7) & 1; + if ((byte1 & 0x80) == 0 && ytreg == 0) + UNW_DEC_RESTORE(X2, t, abreg, arg); + else + UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_x3 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, abreg, qp; + unw_word t, off; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x4 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + t = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + x = (byte2 >> 7) & 1; + ytreg = byte3; + + if ((byte2 & 0x80) == 0 && byte3 == 0) + UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); + else + UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) +{ + int body = (code & 0x20) != 0; + unw_word rlen; + + rlen = (code & 0x1f); + UNW_DEC_PROLOGUE(R1, body, rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, mask, grsave; + unw_word rlen; + + byte1 = *dp++; + + mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + grsave = (byte1 & 0x7f); + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); + return dp; +} + +static unsigned char * +unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word rlen; + + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char brmask = (code & 0x1f); + + UNW_DEC_BR_MEM(P1, brmask, arg); + return dp; +} + +static unsigned char * +unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) +{ + if ((code & 0x10) == 0) + { + unsigned char byte1 = *dp++; + + UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), + (byte1 & 0x7f), arg); + } + else if ((code & 0x08) == 0) + { + unsigned char byte1 = *dp++, r, dst; + + r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + dst = (byte1 & 0x7f); + switch (r) + { + case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; + case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; + case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; + case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; + case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; + case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; + case 6: UNW_DEC_RP_BR(P3, dst, arg); break; + case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; + case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; + case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; + case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; + case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else if ((code & 0x7) == 0) + UNW_DEC_SPILL_MASK(P4, dp, arg); + else if ((code & 0x7) == 1) + { + unw_word grmask, frmask, byte1, byte2, byte3; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + grmask = ((byte1 >> 4) & 0xf); + frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; + UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); + } + else + UNW_DEC_BAD_CODE(code); + return dp; +} + +static unsigned char * +unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) +{ + int gregs = (code & 0x10) != 0; + unsigned char mask = (code & 0x0f); + + if (gregs) + UNW_DEC_GR_MEM(P6, mask, arg); + else + UNW_DEC_FR_MEM(P6, mask, arg); + return dp; +} + +static unsigned char * +unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char r, byte1, byte2; + unw_word t, size; + + if ((code & 0x10) == 0) + { + r = (code & 0xf); + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 0: + size = unw_decode_uleb128 (&dp); + UNW_DEC_MEM_STACK_F(P7, t, size, arg); + break; + + case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; + case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; + case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; + case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; + case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; + case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; + case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; + case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; + case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; + case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; + case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; + case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else + { + switch (code & 0xf) + { + case 0x0: /* p8 */ + { + r = *dp++; + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; + case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; + case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; + case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; + case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; + case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; + case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; + case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; + case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; + case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; + case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; + case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; + case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; + case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + break; + + case 0x1: + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); + break; + + case 0xf: /* p10 */ + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_ABI(P10, byte1, byte2, arg); + break; + + case 0x9: + return unw_decode_x1 (dp, code, arg); + + case 0xa: + return unw_decode_x2 (dp, code, arg); + + case 0xb: + return unw_decode_x3 (dp, code, arg); + + case 0xc: + return unw_decode_x4 (dp, code, arg); + + default: + UNW_DEC_BAD_CODE(code); + break; + } + } + return dp; +} + +static unsigned char * +unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word label = (code & 0x1f); + + if ((code & 0x20) != 0) + UNW_DEC_COPY_STATE(B1, label, arg); + else + UNW_DEC_LABEL_STATE(B1, label, arg); + return dp; +} + +static unsigned char * +unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t; + + t = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); + return dp; +} + +static unsigned char * +unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t, ecount, label; + + if ((code & 0x10) == 0) + { + t = unw_decode_uleb128 (&dp); + ecount = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B3, t, ecount, arg); + } + else if ((code & 0x07) == 0) + { + label = unw_decode_uleb128 (&dp); + if ((code & 0x08) != 0) + UNW_DEC_COPY_STATE(B4, label, arg); + else + UNW_DEC_LABEL_STATE(B4, label, arg); + } + else + switch (code & 0x7) + { + case 1: return unw_decode_x1 (dp, code, arg); + case 2: return unw_decode_x2 (dp, code, arg); + case 3: return unw_decode_x3 (dp, code, arg); + case 4: return unw_decode_x4 (dp, code, arg); + default: UNW_DEC_BAD_CODE(code); break; + } + return dp; +} + +typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); + +static const unw_decoder unw_decode_table[2][8] = +{ + /* prologue table: */ + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_p1, /* 4 */ + unw_decode_p2_p5, + unw_decode_p6, + unw_decode_p7_p10 + }, + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_b1, /* 4 */ + unw_decode_b1, + unw_decode_b2, + unw_decode_b3_x4 + } +}; + +/* + * Decode one descriptor and return address of next descriptor. + */ +static inline unsigned char * +unw_decode (unsigned char *dp, int inside_body, void *arg) +{ + unw_decoder decoder; + unsigned char code; + + code = *dp++; + decoder = unw_decode_table[inside_body][code >> 5]; + dp = (*decoder) (dp, code, arg); + return dp; +} + + +/* RSE helper functions. */ + +static inline unsigned long +ia64_rse_slot_num (unsigned long *addr) +{ + return (((unsigned long) addr) >> 3) & 0x3f; +} + +/* Return TRUE if ADDR is the address of an RNAT slot. */ +static inline unsigned long +ia64_rse_is_rnat_slot (unsigned long *addr) +{ + return ia64_rse_slot_num (addr) == 0x3f; +} + +/* Returns the address of the RNAT slot that covers the slot at + address SLOT_ADDR. */ +static inline unsigned long * +ia64_rse_rnat_addr (unsigned long *slot_addr) +{ + return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3)); +} + +/* Calculate the number of registers in the dirty partition starting at + BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY + divided by eight because the 64th slot is used to store ar.rnat. */ +static inline unsigned long +ia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp) +{ + unsigned long slots = (bsp - bspstore); + + return slots - (ia64_rse_slot_num (bspstore) + slots)/0x40; +} + +/* The inverse of the above: given bspstore and the number of + registers, calculate ar.bsp. */ +static inline unsigned long * +ia64_rse_skip_regs (unsigned long *addr, long num_regs) +{ + long delta = ia64_rse_slot_num (addr) + num_regs; + + if (num_regs < 0) + delta -= 0x3e; + return addr + num_regs + delta/0x3f; +} + + +/* Copy register backing store from SRC to DST, LEN words + (which include both saved registers and nat collections). + DST_RNAT is a partial nat collection for DST. SRC and DST + don't have to be equal modulo 64 slots, so it cannot be + done with a simple memcpy as the nat collections will be + at different relative offsets and need to be combined together. */ +static void +ia64_copy_rbs (struct _Unwind_Context *info, unsigned long dst, + unsigned long src, long len, unsigned long dst_rnat) +{ + long count; + unsigned long src_rnat; + unsigned long shift1, shift2; + + len <<= 3; + dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1; + src_rnat = src >= info->regstk_top + ? info->rnat : *(unsigned long *) (src | 0x1f8); + src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1); + /* Just to make sure. */ + src_rnat &= ~(1UL << 63); + shift1 = ((dst - src) >> 3) & 0x3f; + if ((dst & 0x1f8) < (src & 0x1f8)) + shift1--; + shift2 = 0x3f - shift1; + if ((dst & 0x1f8) >= (src & 0x1f8)) + { + count = ~dst & 0x1f8; + goto first; + } + count = ~src & 0x1f8; + goto second; + while (len > 0) + { + src_rnat = src >= info->regstk_top + ? info->rnat : *(unsigned long *) (src | 0x1f8); + /* Just to make sure. */ + src_rnat &= ~(1UL << 63); + count = shift2 << 3; +first: + if (count > len) + count = len; + memcpy ((char *) dst, (char *) src, count); + dst += count; + src += count; + len -= count; + dst_rnat |= (src_rnat << shift1) & ~(1UL << 63); + if (len <= 0) + break; + *(long *) dst = dst_rnat; + dst += 8; + dst_rnat = 0; + count = shift1 << 3; +second: + if (count > len) + count = len; + memcpy ((char *) dst, (char *) src, count); + dst += count; + src += count + 8; + len -= count + 8; + dst_rnat |= (src_rnat >> shift2); + } + if ((dst & 0x1f8) == 0x1f8) + { + *(long *) dst = dst_rnat; + dst += 8; + dst_rnat = 0; + } + /* Set info->regstk_top to lowest rbs address which will use + info->rnat collection. */ + info->regstk_top = dst & ~0x1ffUL; + info->rnat = dst_rnat; +} + +/* Unwind accessors. */ + +static void +unw_access_gr (struct _Unwind_Context *info, int regnum, + unsigned long *val, char *nat, int write) +{ + unsigned long *addr, *nat_addr = 0, nat_mask = 0, dummy_nat; + struct unw_ireg *ireg; + + if ((unsigned) regnum - 1 >= 127) + abort (); + + if (regnum < 1) + { + nat_addr = addr = &dummy_nat; + dummy_nat = 0; + } + else if (regnum < 32) + { + /* Access a non-stacked register. */ + ireg = &info->ireg[regnum - 2]; + addr = ireg->loc; + if (addr) + { + nat_addr = addr + ireg->nat.off; + switch (ireg->nat.type) + { + case UNW_NAT_VAL: + /* Simulate getf.sig/setf.sig. */ + if (write) + { + if (*nat) + { + /* Write NaTVal and be done with it. */ + addr[0] = 0; + addr[1] = 0x1fffe; + return; + } + addr[1] = 0x1003e; + } + else if (addr[0] == 0 && addr[1] == 0x1ffe) + { + /* Return NaT and be done with it. */ + *val = 0; + *nat = 1; + return; + } + /* FALLTHRU */ + + case UNW_NAT_NONE: + dummy_nat = 0; + nat_addr = &dummy_nat; + break; + + case UNW_NAT_MEMSTK: + nat_mask = 1UL << ((long) addr & 0x1f8)/8; + break; + + case UNW_NAT_REGSTK: + if ((unsigned long) addr >= info->regstk_top) + nat_addr = &info->rnat; + else + nat_addr = ia64_rse_rnat_addr (addr); + nat_mask = 1UL << ia64_rse_slot_num (addr); + break; + } + } + } + else + { + /* Access a stacked register. */ + addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32); + if ((unsigned long) addr >= info->regstk_top) + nat_addr = &info->rnat; + else + nat_addr = ia64_rse_rnat_addr (addr); + nat_mask = 1UL << ia64_rse_slot_num (addr); + } + + if (write) + { + *addr = *val; + if (*nat) + *nat_addr |= nat_mask; + else + *nat_addr &= ~nat_mask; + } + else + { + *val = *addr; + *nat = (*nat_addr & nat_mask) != 0; + } +} + +/* Get the value of register REG as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + _Unwind_Word ret; + char nat; + + if (index == 1) + return context->gp; + else if (index >= 15 && index <= 18) + return context->eh_data[index - 15]; + else + unw_access_gr (context, index, &ret, &nat, 0); + + return ret; +} + +/* Overwrite the saved value for register REG in CONTEXT with VAL. */ + +void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + char nat = 0; + + if (index == 1) + context->gp = val; + else if (index >= 15 && index <= 18) + context->eh_data[index - 15] = val; + else + unw_access_gr (context, index, &val, &nat, 1); +} + +/* Retrieve the return address for CONTEXT. */ + +inline _Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return context->rp; +} + +inline _Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + return context->rp; +} + +/* Overwrite the return address for CONTEXT with VAL. */ + +inline void +_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) +{ + context->rp = val; +} + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) +{ + return context->lsda; +} + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *context) +{ + return context->region_start; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + struct unw_table_entry *entp, ent; + unsigned long segment_base, gp; + + entp = _Unwind_FindTableEntry (pc, &segment_base, &gp, &ent); + if (entp == NULL) + return NULL; + else + return (void *)(segment_base + entp->start_offset); +} + +/* Get the value of the CFA as saved in CONTEXT. In GCC/Dwarf2 parlance, + the CFA is the value of the stack pointer on entry; In IA-64 unwind + parlance, this is the PSP. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->psp; +} + +/* Get the value of the Backing Store Pointer as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetBSP (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->bsp; +} + +#include "md-unwind-support.h" + +/* By default, assume personality routine interface compatibility with + our expectations. */ +#ifndef MD_UNW_COMPATIBLE_PERSONALITY_P +#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) 1 +#endif + + +static _Unwind_Reason_Code +uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + struct unw_table_entry *entp, ent; + unsigned long *unw, header, length; + unsigned char *insn, *insn_end; + unsigned long segment_base; + struct unw_reg_info *r; + + memset (fs, 0, sizeof (*fs)); + for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) + r->when = UNW_WHEN_NEVER; + context->lsda = 0; + + entp = _Unwind_FindTableEntry ((void *) context->rp, + &segment_base, &context->gp, &ent); + if (entp == NULL) + { + /* Couldn't find unwind info for this function. Try an + os-specific fallback mechanism. This will necessarily + not provide a personality routine or LSDA. */ +#ifdef MD_FALLBACK_FRAME_STATE_FOR + if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON) + return _URC_NO_REASON; +#endif + + /* [SCRA 11.4.1] A leaf function with no memory stack, no exception + handlers, and which keeps the return value in B0 does not need + an unwind table entry. + + This can only happen in the frame after unwinding through a signal + handler. Avoid infinite looping by requiring that B0 != RP. + RP == 0 terminates the chain. */ + if (context->br_loc[0] + && *context->br_loc[0] != context->rp + && context->rp != 0) + goto skip_unwind_info; + + return _URC_END_OF_STACK; + } + + context->region_start = entp->start_offset + segment_base; + fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3 + + (context->rp & 15); + + unw = (unsigned long *) (entp->info_offset + segment_base); + header = *unw; + length = UNW_LENGTH (header); + + /* Some operating systems use the personality routine slot in way not + compatible with what we expect. For instance, OpenVMS uses this slot to + designate "condition handlers" with very different arguments than what we + would be providing. Such cases are typically identified from OS specific + bits in the unwind information block header, and checked by the target + MD_UNW_COMPATIBLE_PERSONALITY_P macro. + + We just pretend there is no personality from our standpoint in such + situations, and expect GCC not to set the identifying bits itself so that + compatible personalities for GCC compiled code are called. + + Of course, this raises the question of what combinations of native/GCC + calls can be expected to behave properly exception handling-wise. We are + not to provide a magic answer here, merely to prevent crashes assuming + users know what they are doing. + + ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK as well. */ + + if (MD_UNW_COMPATIBLE_PERSONALITY_P (header) + && (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header))) + { + fs->personality = + *(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp); + context->lsda = unw + length + 2; + } + + insn = (unsigned char *) (unw + 1); + insn_end = (unsigned char *) (unw + 1 + length); + while (!fs->done && insn < insn_end) + insn = unw_decode (insn, fs->in_body, fs); + + free_label_states (fs->labeled_states); + free_state_stack (&fs->curr); + +#ifdef ENABLE_MALLOC_CHECKING + if (reg_state_alloced || labeled_state_alloced) + abort (); +#endif + + /* If we're in the epilogue, sp has been restored and all values + on the memory stack below psp also have been restored. */ + if (fs->when_target > fs->epilogue_start) + { + struct unw_reg_info *r; + + fs->curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; + fs->curr.reg[UNW_REG_PSP].val = 0; + for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) + if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) + || r->where == UNW_WHERE_SPREL) + r->where = UNW_WHERE_NONE; + } + +skip_unwind_info: + /* If RP didn't get saved, generate entry for the return link register. */ + if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target) + { + fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; + fs->curr.reg[UNW_REG_RP].when = -1; + fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg; + } + + /* There is a subtlety for the frame after unwinding through a signal + handler: should we restore the cfm as usual or the pfs? We can't + restore both because we use br.ret to resume execution of user code. + For other frames the procedure is by definition non-leaf so the pfs + is saved and restored and thus effectively dead in the body; only + the cfm need therefore be restored. + + Here we have 2 cases: + - either the pfs is saved and restored and thus effectively dead + like in regular frames; then we do nothing special and restore + the cfm. + - or the pfs is not saved and thus live; but in that case the + procedure is necessarily leaf so the cfm is effectively dead + and we restore the pfs. */ + if (context->signal_pfs_loc) + { + if (fs->curr.reg[UNW_REG_PFS].when >= fs->when_target) + context->pfs_loc = context->signal_pfs_loc; + context->signal_pfs_loc = NULL; + } + + return _URC_NO_REASON; +} + +static void +uw_update_reg_address (struct _Unwind_Context *context, + _Unwind_FrameState *fs, + enum unw_register_index regno) +{ + struct unw_reg_info *r = fs->curr.reg + regno; + void *addr; + unsigned long rval; + + if (r->where == UNW_WHERE_NONE || r->when >= fs->when_target) + return; + + rval = r->val; + switch (r->where) + { + case UNW_WHERE_GR: + if (rval >= 32) + addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32); + else if (rval >= 2) + addr = context->ireg[rval - 2].loc; + else if (rval == 0) + { + static const unsigned long dummy; + addr = (void *) &dummy; + } + else + abort (); + break; + + case UNW_WHERE_FR: + if (rval >= 2 && rval < 32) + addr = context->fr_loc[rval - 2]; + else + abort (); + break; + + case UNW_WHERE_BR: + /* Note that while RVAL can only be 1-5 from normal descriptors, + we can want to look at B0, B6 and B7 due to having manually unwound a + signal frame. */ + if (rval < 8) + addr = context->br_loc[rval]; + else + abort (); + break; + + case UNW_WHERE_SPREL: + addr = (void *)(context->sp + rval); + break; + + case UNW_WHERE_PSPREL: + addr = (void *)(context->psp + rval); + break; + + default: + abort (); + } + + switch (regno) + { + case UNW_REG_R2 ... UNW_REG_R31: + context->ireg[regno - UNW_REG_R2].loc = addr; + switch (r->where) + { + case UNW_WHERE_GR: + if (rval >= 32) + { + context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK; + context->ireg[regno - UNW_REG_R2].nat.off + = context->pri_unat_loc - (unsigned long *) addr; + } + else if (rval >= 2) + { + context->ireg[regno - UNW_REG_R2].nat + = context->ireg[rval - 2].nat; + } + else if (rval == 0) + { + context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE; + context->ireg[regno - UNW_REG_R2].nat.off = 0; + } + else + abort (); + break; + + case UNW_WHERE_FR: + context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_VAL; + context->ireg[regno - UNW_REG_R2].nat.off = 0; + break; + + case UNW_WHERE_BR: + context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE; + context->ireg[regno - UNW_REG_R2].nat.off = 0; + break; + + case UNW_WHERE_PSPREL: + case UNW_WHERE_SPREL: + context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK; + context->ireg[regno - UNW_REG_R2].nat.off + = context->pri_unat_loc - (unsigned long *) addr; + break; + + default: + abort (); + } + break; + + case UNW_REG_F2 ... UNW_REG_F31: + context->fr_loc[regno - UNW_REG_F2] = addr; + break; + + case UNW_REG_B1 ... UNW_REG_B5: + context->br_loc[regno - UNW_REG_B0] = addr; + break; + + case UNW_REG_BSP: + context->bsp_loc = addr; + break; + case UNW_REG_BSPSTORE: + context->bspstore_loc = addr; + break; + case UNW_REG_PFS: + context->pfs_loc = addr; + break; + case UNW_REG_RP: + context->rp = *(unsigned long *)addr; + break; + case UNW_REG_UNAT: + context->unat_loc = addr; + break; + case UNW_REG_PR: + context->pr = *(unsigned long *) addr; + break; + case UNW_REG_LC: + context->lc_loc = addr; + break; + case UNW_REG_FPSR: + context->fpsr_loc = addr; + break; + + case UNW_REG_PSP: + context->psp = *(unsigned long *)addr; + break; + + default: + abort (); + } +} + +static void +uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + long i; + +#ifdef MD_HANDLE_UNWABI + MD_HANDLE_UNWABI (context, fs); +#endif + + context->sp = context->psp; + + /* First, set PSP. Subsequent instructions may depend on this value. */ + if (fs->when_target > fs->curr.reg[UNW_REG_PSP].when) + { + if (fs->curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE) + context->psp = context->psp + fs->curr.reg[UNW_REG_PSP].val; + else + uw_update_reg_address (context, fs, UNW_REG_PSP); + } + + /* Determine the location of the primary UNaT. */ + { + int i; + if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_GR].when) + i = UNW_REG_PRI_UNAT_MEM; + else if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when) + i = UNW_REG_PRI_UNAT_GR; + else if (fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when + > fs->curr.reg[UNW_REG_PRI_UNAT_GR].when) + i = UNW_REG_PRI_UNAT_MEM; + else + i = UNW_REG_PRI_UNAT_GR; + uw_update_reg_address (context, fs, i); + } + + /* Compute the addresses of all registers saved in this frame. */ + for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i) + uw_update_reg_address (context, fs, i); + + /* Unwind BSP for the local registers allocated this frame. */ + /* ??? What to do with stored BSP or BSPSTORE registers. */ + /* We assert that we are either at a call site, or we have + just unwound through a signal frame. In either case + pfs_loc is valid. */ + if (!(fs -> no_reg_stack_frame)) + { + unsigned long pfs = *context->pfs_loc; + unsigned long sol = (pfs >> 7) & 0x7f; + context->bsp = (unsigned long) + ia64_rse_skip_regs ((unsigned long *) context->bsp, -sol); + } +} + +static void +uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context (context, fs); +} + +/* Fill in CONTEXT for top-of-stack. The only valid registers at this + level will be the return address and the CFA. Note that CFA = SP+16. */ + +#define uw_init_context(CONTEXT) \ + do { \ + /* ??? There is a whole lot o code in uw_install_context that \ + tries to avoid spilling the entire machine state here. We \ + should try to make that work again. */ \ + __builtin_unwind_init(); \ + uw_init_context_1 (CONTEXT, __builtin_ia64_bsp ()); \ + } while (0) + +static void __attribute__((noinline)) +uw_init_context_1 (struct _Unwind_Context *context, void *bsp) +{ + void *rp = __builtin_extract_return_addr (__builtin_return_address (0)); + /* Set psp to the caller's stack pointer. */ + void *psp = __builtin_dwarf_cfa () - 16; + _Unwind_FrameState fs; + unsigned long rnat, tmp1, tmp2; + + /* Flush the register stack to memory so that we can access it. + Get rse nat collection for the last incomplete rbs chunk of + registers at the same time. For this RSE needs to be turned + into the mandatory only mode. */ + asm ("mov.m %1 = ar.rsc;;\n\t" + "and %2 = 0x1c, %1;;\n\t" + "mov.m ar.rsc = %2;;\n\t" + "flushrs;;\n\t" + "mov.m %0 = ar.rnat;;\n\t" + "mov.m ar.rsc = %1\n\t" + : "=r" (rnat), "=r" (tmp1), "=r" (tmp2)); + + memset (context, 0, sizeof (struct _Unwind_Context)); + context->bsp = (unsigned long) bsp; + /* Set context->regstk_top to lowest rbs address which will use + context->rnat collection. */ + context->regstk_top = context->bsp & ~0x1ffULL; + context->rnat = rnat; + context->psp = (unsigned long) psp; + context->rp = (unsigned long) rp; + asm ("mov %0 = sp" : "=r" (context->sp)); + asm ("mov %0 = pr" : "=r" (context->pr)); + context->pri_unat_loc = &context->initial_unat; /* ??? */ + + if (uw_frame_state_for (context, &fs) != _URC_NO_REASON) + abort (); + + uw_update_context (context, &fs); +} + +/* Install (i.e. longjmp to) the contents of TARGET. */ + +static void __attribute__((noreturn)) +uw_install_context (struct _Unwind_Context *current __attribute__((unused)), + struct _Unwind_Context *target) +{ + unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0; + long i; + + /* Copy integer register data from the target context to a + temporary buffer. Do this so that we can frob AR.UNAT + to get the NaT bits for these registers set properly. */ + for (i = 4; i <= 7; ++i) + { + char nat; + void *t = target->ireg[i - 2].loc; + if (t) + { + unw_access_gr (target, i, &ireg_buf[i - 4], &nat, 0); + ireg_nat |= (long)nat << (((size_t)&ireg_buf[i - 4] >> 3) & 0x3f); + /* Set p6 - p9. */ + ireg_pr |= 4L << i; + } + } + + /* The value in uc_bsp that we've computed is that for the + target function. The value that we install below will be + adjusted by the BR.RET instruction based on the contents + of AR.PFS. So we must unadjust that here. */ + target->bsp = (unsigned long) + ia64_rse_skip_regs ((unsigned long *)target->bsp, + (*target->pfs_loc >> 7) & 0x7f); + + if (target->bsp < target->regstk_top) + target->rnat = *ia64_rse_rnat_addr ((unsigned long *) target->bsp); + + /* Provide assembly with the offsets into the _Unwind_Context. */ + asm volatile ("uc_rnat = %0" + : : "i"(offsetof (struct _Unwind_Context, rnat))); + asm volatile ("uc_bsp = %0" + : : "i"(offsetof (struct _Unwind_Context, bsp))); + asm volatile ("uc_psp = %0" + : : "i"(offsetof (struct _Unwind_Context, psp))); + asm volatile ("uc_rp = %0" + : : "i"(offsetof (struct _Unwind_Context, rp))); + asm volatile ("uc_pr = %0" + : : "i"(offsetof (struct _Unwind_Context, pr))); + asm volatile ("uc_gp = %0" + : : "i"(offsetof (struct _Unwind_Context, gp))); + asm volatile ("uc_pfs_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, pfs_loc))); + asm volatile ("uc_unat_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, unat_loc))); + asm volatile ("uc_lc_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, lc_loc))); + asm volatile ("uc_fpsr_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, fpsr_loc))); + asm volatile ("uc_eh_data = %0" + : : "i"(offsetof (struct _Unwind_Context, eh_data))); + asm volatile ("uc_br_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, br_loc))); + asm volatile ("uc_fr_loc = %0" + : : "i"(offsetof (struct _Unwind_Context, fr_loc))); + + asm volatile ( + /* Load up call-saved non-window integer registers from ireg_buf. */ + "add r20 = 8, %1 \n\t" + "mov ar.unat = %2 \n\t" + "mov pr = %3, 0x3c0 \n\t" + ";; \n\t" + "(p6) ld8.fill r4 = [%1] \n\t" + "(p7) ld8.fill r5 = [r20] \n\t" + "add r21 = uc_br_loc + 16, %0 \n\t" + "adds %1 = 16, %1 \n\t" + "adds r20 = 16, r20 \n\t" + ";; \n\t" + "(p8) ld8.fill r6 = [%1] \n\t" + "(p9) ld8.fill r7 = [r20] \n\t" + "add r20 = uc_br_loc + 8, %0 \n\t" + ";; \n\t" + /* Load up call-saved branch registers. */ + "ld8 r22 = [r20], 16 \n\t" + "ld8 r23 = [r21], 16 \n\t" + ";; \n\t" + "ld8 r24 = [r20], 16 \n\t" + "ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 32)\n\t" + ";; \n\t" + "ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 40)\n\t" + "ld8 r27 = [r21], 24 \n\t" + "cmp.ne p6, p0 = r0, r22 \n\t" + ";; \n\t" + "ld8 r28 = [r20], 8 \n\t" + "(p6) ld8 r22 = [r22] \n\t" + "cmp.ne p7, p0 = r0, r23 \n\t" + ";; \n\t" + "(p7) ld8 r23 = [r23] \n\t" + "cmp.ne p8, p0 = r0, r24 \n\t" + ";; \n\t" + "(p8) ld8 r24 = [r24] \n\t" + "(p6) mov b1 = r22 \n\t" + "cmp.ne p9, p0 = r0, r25 \n\t" + ";; \n\t" + "(p9) ld8 r25 = [r25] \n\t" + "(p7) mov b2 = r23 \n\t" + "cmp.ne p6, p0 = r0, r26 \n\t" + ";; \n\t" + "(p6) ld8 r26 = [r26] \n\t" + "(p8) mov b3 = r24 \n\t" + "cmp.ne p7, p0 = r0, r27 \n\t" + ";; \n\t" + /* Load up call-saved fp registers. */ + "(p7) ldf.fill f2 = [r27] \n\t" + "(p9) mov b4 = r25 \n\t" + "cmp.ne p8, p0 = r0, r28 \n\t" + ";; \n\t" + "(p8) ldf.fill f3 = [r28] \n\t" + "(p6) mov b5 = r26 \n\t" + ";; \n\t" + "ld8 r29 = [r20], 16*8 - 4*8 \n\t" + "ld8 r30 = [r21], 17*8 - 5*8 \n\t" + ";; \n\t" + "ld8 r22 = [r20], 16 \n\t" + "ld8 r23 = [r21], 16 \n\t" + ";; \n\t" + "ld8 r24 = [r20], 16 \n\t" + "ld8 r25 = [r21] \n\t" + "cmp.ne p6, p0 = r0, r29 \n\t" + ";; \n\t" + "ld8 r26 = [r20], 8 \n\t" + "(p6) ldf.fill f4 = [r29] \n\t" + "cmp.ne p7, p0 = r0, r30 \n\t" + ";; \n\t" + "ld8 r27 = [r20], 8 \n\t" + "(p7) ldf.fill f5 = [r30] \n\t" + "cmp.ne p6, p0 = r0, r22 \n\t" + ";; \n\t" + "ld8 r28 = [r20], 8 \n\t" + "(p6) ldf.fill f16 = [r22] \n\t" + "cmp.ne p7, p0 = r0, r23 \n\t" + ";; \n\t" + "ld8 r29 = [r20], 8 \n\t" + "(p7) ldf.fill f17 = [r23] \n\t" + "cmp.ne p6, p0 = r0, r24 \n\t" + ";; \n\t" + "ld8 r22 = [r20], 8 \n\t" + "(p6) ldf.fill f18 = [r24] \n\t" + "cmp.ne p7, p0 = r0, r25 \n\t" + ";; \n\t" + "ld8 r23 = [r20], 8 \n\t" + "(p7) ldf.fill f19 = [r25] \n\t" + "cmp.ne p6, p0 = r0, r26 \n\t" + ";; \n\t" + "ld8 r24 = [r20], 8 \n\t" + "(p6) ldf.fill f20 = [r26] \n\t" + "cmp.ne p7, p0 = r0, r27 \n\t" + ";; \n\t" + "ld8 r25 = [r20], 8 \n\t" + "(p7) ldf.fill f21 = [r27] \n\t" + "cmp.ne p6, p0 = r0, r28 \n\t" + ";; \n\t" + "ld8 r26 = [r20], 8 \n\t" + "(p6) ldf.fill f22 = [r28] \n\t" + "cmp.ne p7, p0 = r0, r29 \n\t" + ";; \n\t" + "ld8 r27 = [r20], 8 \n\t" + ";; \n\t" + "ld8 r28 = [r20], 8 \n\t" + "(p7) ldf.fill f23 = [r29] \n\t" + "cmp.ne p6, p0 = r0, r22 \n\t" + ";; \n\t" + "ld8 r29 = [r20], 8 \n\t" + "(p6) ldf.fill f24 = [r22] \n\t" + "cmp.ne p7, p0 = r0, r23 \n\t" + ";; \n\t" + "(p7) ldf.fill f25 = [r23] \n\t" + "cmp.ne p6, p0 = r0, r24 \n\t" + "cmp.ne p7, p0 = r0, r25 \n\t" + ";; \n\t" + "(p6) ldf.fill f26 = [r24] \n\t" + "(p7) ldf.fill f27 = [r25] \n\t" + "cmp.ne p6, p0 = r0, r26 \n\t" + ";; \n\t" + "(p6) ldf.fill f28 = [r26] \n\t" + "cmp.ne p7, p0 = r0, r27 \n\t" + "cmp.ne p6, p0 = r0, r28 \n\t" + ";; \n\t" + "(p7) ldf.fill f29 = [r27] \n\t" + "(p6) ldf.fill f30 = [r28] \n\t" + "cmp.ne p7, p0 = r0, r29 \n\t" + ";; \n\t" + "(p7) ldf.fill f31 = [r29] \n\t" + "add r20 = uc_rnat, %0 \n\t" + "add r21 = uc_bsp, %0 \n\t" + ";; \n\t" + /* Load the balance of the thread state from the context. */ + "ld8 r22 = [r20], uc_psp - uc_rnat \n\t" + "ld8 r23 = [r21], uc_gp - uc_bsp \n\t" + ";; \n\t" + "ld8 r24 = [r20], uc_pfs_loc - uc_psp \n\t" + "ld8 r1 = [r21], uc_rp - uc_gp \n\t" + ";; \n\t" + "ld8 r25 = [r20], uc_unat_loc - uc_pfs_loc\n\t" + "ld8 r26 = [r21], uc_pr - uc_rp \n\t" + ";; \n\t" + "ld8 r27 = [r20], uc_lc_loc - uc_unat_loc\n\t" + "ld8 r28 = [r21], uc_fpsr_loc - uc_pr \n\t" + ";; \n\t" + "ld8 r29 = [r20], uc_eh_data - uc_lc_loc\n\t" + "ld8 r30 = [r21], uc_eh_data + 8 - uc_fpsr_loc\n\t" + ";; \n\t" + /* Load data for the exception handler. */ + "ld8 r15 = [r20], 16 \n\t" + "ld8 r16 = [r21], 16 \n\t" + ";; \n\t" + "ld8 r17 = [r20] \n\t" + "ld8 r18 = [r21] \n\t" + ";; \n\t" + /* Install the balance of the thread state loaded above. */ + "cmp.ne p6, p0 = r0, r25 \n\t" + "cmp.ne p7, p0 = r0, r27 \n\t" + ";; \n\t" + "(p6) ld8 r25 = [r25] \n\t" + "(p7) ld8 r27 = [r27] \n\t" + ";; \n\t" + "(p7) mov.m ar.unat = r27 \n\t" + "(p6) mov.i ar.pfs = r25 \n\t" + "cmp.ne p9, p0 = r0, r29 \n\t" + ";; \n\t" + "(p9) ld8 r29 = [r29] \n\t" + "cmp.ne p6, p0 = r0, r30 \n\t" + ";; \n\t" + "(p6) ld8 r30 = [r30] \n\t" + /* Don't clobber p6-p9, which are in use at present. */ + "mov pr = r28, ~0x3c0 \n\t" + "(p9) mov.i ar.lc = r29 \n\t" + ";; \n\t" + "mov.m r25 = ar.rsc \n\t" + "(p6) mov.m ar.fpsr = r30 \n\t" + ";; \n\t" + "and r29 = 0x1c, r25 \n\t" + "mov b0 = r26 \n\t" + ";; \n\t" + "mov.m ar.rsc = r29 \n\t" + ";; \n\t" + /* This must be done before setting AR.BSPSTORE, otherwise + AR.BSP will be initialized with a random displacement + below the value we want, based on the current number of + dirty stacked registers. */ + "loadrs \n\t" + "invala \n\t" + ";; \n\t" + "mov.m ar.bspstore = r23 \n\t" + ";; \n\t" + "mov.m ar.rnat = r22 \n\t" + ";; \n\t" + "mov.m ar.rsc = r25 \n\t" + "mov sp = r24 \n\t" + "br.ret.sptk.few b0" + : : "r"(target), "r"(ireg_buf), "r"(ireg_nat), "r"(ireg_pr) + : "r15", "r16", "r17", "r18", "r20", "r21", "r22", + "r23", "r24", "r25", "r26", "r27", "r28", "r29", + "r30", "r31"); + /* NOTREACHED */ + while (1); +} + +static inline _Unwind_Ptr +uw_identify_context (struct _Unwind_Context *context) +{ + return _Unwind_GetIP (context); +} + +#include "unwind.inc" + +#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) +alias (_Unwind_Backtrace); +alias (_Unwind_DeleteException); +alias (_Unwind_FindEnclosingFunction); +alias (_Unwind_ForcedUnwind); +alias (_Unwind_GetBSP); +alias (_Unwind_GetCFA); +alias (_Unwind_GetGR); +alias (_Unwind_GetIP); +alias (_Unwind_GetLanguageSpecificData); +alias (_Unwind_GetRegionStart); +alias (_Unwind_RaiseException); +alias (_Unwind_Resume); +alias (_Unwind_Resume_or_Rethrow); +alias (_Unwind_SetGR); +alias (_Unwind_SetIP); +#endif + +#endif diff --git a/libgcc/config/ia64/unwind-ia64.h b/libgcc/config/ia64/unwind-ia64.h new file mode 100644 index 00000000000..b98f048fdb5 --- /dev/null +++ b/libgcc/config/ia64/unwind-ia64.h @@ -0,0 +1,43 @@ +/* Copyright (C) 1999, 2000, 2001, 2007, 2009 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + Andrew Haley + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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 GCC; see the file COPYING3. If not see + . */ + +struct unw_table_entry +{ + unsigned long start_offset; + unsigned long end_offset; + unsigned long info_offset; +}; + +/* Accessors to fields of an unwind info block header. In this common file to + be visible from all the units involved in a target implementation. */ + +#ifndef __USING_SJLJ_EXCEPTIONS__ +#define UNW_VER(x) ((x) >> 48) +#define UNW_FLAG_MASK 0x0000ffff00000000 +#define UNW_FLAG_OSMASK 0x0000f00000000000 +#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L) +#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L) +#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffL) +#endif + +extern struct unw_table_entry * +_Unwind_FindTableEntry (void *pc, unsigned long *segment_base, + unsigned long *gp, struct unw_table_entry *ent) + __attribute__ ((__visibility__ ("hidden"))); diff --git a/libgcc/config/ia64/vms-unwind.h b/libgcc/config/ia64/vms-unwind.h index 41c76ae768c..48bdc6884ea 100644 --- a/libgcc/config/ia64/vms-unwind.h +++ b/libgcc/config/ia64/vms-unwind.h @@ -1,5 +1,5 @@ /* DWARF2 EH unwinding support for IA64 VMS. - Copyright (C) 2005-2009 Free Software Foundation, Inc. + Copyright (C) 2005-2011 Free Software Foundation, Inc. This file is part of GCC. @@ -32,6 +32,9 @@ #include #include +#define UNW_IVMS_MODE(HEADER) (((HEADER) >> 44) & 0x3L) +#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) (!UNW_IVMS_MODE (HEADER)) + #define DYN$C_SSENTRY 66 /* ??? would rather get the proper header file. */ diff --git a/libgcc/config/picochip/t-picochip b/libgcc/config/picochip/t-picochip new file mode 100644 index 00000000000..5135d500cbb --- /dev/null +++ b/libgcc/config/picochip/t-picochip @@ -0,0 +1,2 @@ +# Turn off the building of exception handling libraries. +LIB2ADDEH = diff --git a/libgcc/config/rs6000/aix-unwind.h b/libgcc/config/rs6000/aix-unwind.h new file mode 100644 index 00000000000..9e126595edb --- /dev/null +++ b/libgcc/config/rs6000/aix-unwind.h @@ -0,0 +1,57 @@ +/* DWARF2 EH unwinding support for AIX. + Copyright (C) 2011 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* If the current unwind info (FS) does not contain explicit info + saving R2, then we have to do a minor amount of code reading to + figure out if it was saved. The big problem here is that the + code that does the save/restore is generated by the linker, so + we have no good way to determine at compile time what to do. */ + +#define R_LR 65 + +#ifdef __64BIT__ +#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \ + do { \ + if ((FS)->regs.reg[2].how == REG_UNSAVED) \ + { \ + unsigned int *insn \ + = (unsigned int *) \ + _Unwind_GetGR ((CTX), R_LR); \ + if (*insn == 0xE8410028) \ + _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 40); \ + } \ + } while (0) +#else +#define MD_FROB_UPDATE_CONTEXT(CTX, FS) \ + do { \ + if ((FS)->regs.reg[2].how == REG_UNSAVED) \ + { \ + unsigned int *insn \ + = (unsigned int *) \ + _Unwind_GetGR ((CTX), R_LR); \ + if (*insn == 0x80410014) \ + _Unwind_SetGRPtr ((CTX), 2, (CTX)->cfa + 20); \ + } \ + } while (0) +#endif diff --git a/libgcc/config/rs6000/darwin-fallback.c b/libgcc/config/rs6000/darwin-fallback.c new file mode 100644 index 00000000000..4591071ea74 --- /dev/null +++ b/libgcc/config/rs6000/darwin-fallback.c @@ -0,0 +1,487 @@ +/* Fallback frame-state unwinder for Darwin. + Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifdef __ppc__ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#include "unwind-dw2.h" +#include +#include +#include +#include + +#define R_LR 65 +#define R_CTR 66 +#define R_CR2 70 +#define R_XER 76 +#define R_VR0 77 +#define R_VRSAVE 109 +#define R_VSCR 110 +#define R_SPEFSCR 112 + +typedef unsigned long reg_unit; + +/* Place in GPRS the parameters to the first 'sc' instruction that would + have been executed if we were returning from this CONTEXT, or + return false if an unexpected instruction is encountered. */ + +static bool +interpret_libc (reg_unit gprs[32], struct _Unwind_Context *context) +{ + uint32_t *pc = (uint32_t *)_Unwind_GetIP (context); + uint32_t cr; + reg_unit lr = (reg_unit) pc; + reg_unit ctr = 0; + uint32_t *invalid_address = NULL; + + int i; + + for (i = 0; i < 13; i++) + gprs[i] = 1; + gprs[1] = _Unwind_GetCFA (context); + for (; i < 32; i++) + gprs[i] = _Unwind_GetGR (context, i); + cr = _Unwind_GetGR (context, R_CR2); + + /* For each supported Libc, we have to track the code flow + all the way back into the kernel. + + This code is believed to support all released Libc/Libsystem builds since + Jaguar 6C115, including all the security updates. To be precise, + + Libc Libsystem Build(s) + 262~1 60~37 6C115 + 262~1 60.2~4 6D52 + 262~1 61~3 6F21-6F22 + 262~1 63~24 6G30-6G37 + 262~1 63~32 6I34-6I35 + 262~1 63~64 6L29-6L60 + 262.4.1~1 63~84 6L123-6R172 + + 320~1 71~101 7B85-7D28 + 320~1 71~266 7F54-7F56 + 320~1 71~288 7F112 + 320~1 71~289 7F113 + 320.1.3~1 71.1.1~29 7H60-7H105 + 320.1.3~1 71.1.1~30 7H110-7H113 + 320.1.3~1 71.1.1~31 7H114 + + That's a big table! It would be insane to try to keep track of + every little detail, so we just read the code itself and do what + it would do. + */ + + for (;;) + { + uint32_t ins = *pc++; + + if ((ins & 0xFC000003) == 0x48000000) /* b instruction */ + { + pc += ((((int32_t) ins & 0x3FFFFFC) ^ 0x2000000) - 0x2000004) / 4; + continue; + } + if ((ins & 0xFC600000) == 0x2C000000) /* cmpwi */ + { + int32_t val1 = (int16_t) ins; + int32_t val2 = gprs[ins >> 16 & 0x1F]; + /* Only beq and bne instructions are supported, so we only + need to set the EQ bit. */ + uint32_t mask = 0xF << ((ins >> 21 & 0x1C) ^ 0x1C); + if (val1 == val2) + cr |= mask; + else + cr &= ~mask; + continue; + } + if ((ins & 0xFEC38003) == 0x40820000) /* forwards beq/bne */ + { + if ((cr >> ((ins >> 16 & 0x1F) ^ 0x1F) & 1) == (ins >> 24 & 1)) + pc += (ins & 0x7FFC) / 4 - 1; + continue; + } + if ((ins & 0xFC0007FF) == 0x7C000378) /* or, including mr */ + { + gprs [ins >> 16 & 0x1F] = (gprs [ins >> 11 & 0x1F] + | gprs [ins >> 21 & 0x1F]); + continue; + } + if (ins >> 26 == 0x0E) /* addi, including li */ + { + reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; + gprs [ins >> 21 & 0x1F] = src + (int16_t) ins; + continue; + } + if (ins >> 26 == 0x0F) /* addis, including lis */ + { + reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; + gprs [ins >> 21 & 0x1F] = src + ((int16_t) ins << 16); + continue; + } + if (ins >> 26 == 0x20) /* lwz */ + { + reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; + uint32_t *p = (uint32_t *)(src + (int16_t) ins); + if (p == invalid_address) + return false; + gprs [ins >> 21 & 0x1F] = *p; + continue; + } + if (ins >> 26 == 0x21) /* lwzu */ + { + uint32_t *p = (uint32_t *)(gprs [ins >> 16 & 0x1F] += (int16_t) ins); + if (p == invalid_address) + return false; + gprs [ins >> 21 & 0x1F] = *p; + continue; + } + if (ins >> 26 == 0x24) /* stw */ + /* What we hope this is doing is '--in_sigtramp'. We don't want + to actually store to memory, so just make a note of the + address and refuse to load from it. */ + { + reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; + uint32_t *p = (uint32_t *)(src + (int16_t) ins); + if (p == NULL || invalid_address != NULL) + return false; + invalid_address = p; + continue; + } + if (ins >> 26 == 0x2E) /* lmw */ + { + reg_unit src = (ins >> 16 & 0x1F) == 0 ? 0 : gprs [ins >> 16 & 0x1F]; + uint32_t *p = (uint32_t *)(src + (int16_t) ins); + int i; + + for (i = (ins >> 21 & 0x1F); i < 32; i++) + { + if (p == invalid_address) + return false; + gprs[i] = *p++; + } + continue; + } + if ((ins & 0xFC1FFFFF) == 0x7c0803a6) /* mtlr */ + { + lr = gprs [ins >> 21 & 0x1F]; + continue; + } + if ((ins & 0xFC1FFFFF) == 0x7c0802a6) /* mflr */ + { + gprs [ins >> 21 & 0x1F] = lr; + continue; + } + if ((ins & 0xFC1FFFFF) == 0x7c0903a6) /* mtctr */ + { + ctr = gprs [ins >> 21 & 0x1F]; + continue; + } + /* The PowerPC User's Manual says that bit 11 of the mtcrf + instruction is reserved and should be set to zero, but it + looks like the Darwin assembler doesn't do that... */ + if ((ins & 0xFC000FFF) == 0x7c000120) /* mtcrf */ + { + int i; + uint32_t mask = 0; + for (i = 0; i < 8; i++) + mask |= ((-(ins >> (12 + i) & 1)) & 0xF) << 4 * i; + cr = (cr & ~mask) | (gprs [ins >> 21 & 0x1F] & mask); + continue; + } + if (ins == 0x429f0005) /* bcl- 20,4*cr7+so,.+4, loads pc into LR */ + { + lr = (reg_unit) pc; + continue; + } + if (ins == 0x4e800420) /* bctr */ + { + pc = (uint32_t *) ctr; + continue; + } + if (ins == 0x44000002) /* sc */ + return true; + + return false; + } +} + +/* We used to include and , + but they change so much between different Darwin system versions + that it's much easier to just write the structures involved here + directly. */ + +/* These defines are from the kernel's bsd/dev/ppc/unix_signal.c. */ +#define UC_TRAD 1 +#define UC_TRAD_VEC 6 +#define UC_TRAD64 20 +#define UC_TRAD64_VEC 25 +#define UC_FLAVOR 30 +#define UC_FLAVOR_VEC 35 +#define UC_FLAVOR64 40 +#define UC_FLAVOR64_VEC 45 +#define UC_DUAL 50 +#define UC_DUAL_VEC 55 + +struct gcc_ucontext +{ + int onstack; + sigset_t sigmask; + void * stack_sp; + size_t stack_sz; + int stack_flags; + struct gcc_ucontext *link; + size_t mcsize; + struct gcc_mcontext32 *mcontext; +}; + +struct gcc_float_vector_state +{ + double fpregs[32]; + uint32_t fpscr_pad; + uint32_t fpscr; + uint32_t save_vr[32][4]; + uint32_t save_vscr[4]; +}; + +struct gcc_mcontext32 { + uint32_t dar; + uint32_t dsisr; + uint32_t exception; + uint32_t padding1[5]; + uint32_t srr0; + uint32_t srr1; + uint32_t gpr[32]; + uint32_t cr; + uint32_t xer; + uint32_t lr; + uint32_t ctr; + uint32_t mq; + uint32_t vrsave; + struct gcc_float_vector_state fvs; +}; + +/* These are based on /usr/include/ppc/ucontext.h and + /usr/include/mach/ppc/thread_status.h, but rewritten to be more + convenient, to compile on Jaguar, and to work around Radar 3712064 + on Panther, which is that the 'es' field of 'struct mcontext64' has + the wrong type (doh!). */ + +struct gcc_mcontext64 { + uint64_t dar; + uint32_t dsisr; + uint32_t exception; + uint32_t padding1[4]; + uint64_t srr0; + uint64_t srr1; + uint32_t gpr[32][2]; + uint32_t cr; + uint32_t xer[2]; /* These are arrays because the original structure has them misaligned. */ + uint32_t lr[2]; + uint32_t ctr[2]; + uint32_t vrsave; + struct gcc_float_vector_state fvs; +}; + +#define UC_FLAVOR_SIZE \ + (sizeof (struct gcc_mcontext32) - 33*16) + +#define UC_FLAVOR_VEC_SIZE (sizeof (struct gcc_mcontext32)) + +#define UC_FLAVOR64_SIZE \ + (sizeof (struct gcc_mcontext64) - 33*16) + +#define UC_FLAVOR64_VEC_SIZE (sizeof (struct gcc_mcontext64)) + +/* Given GPRS as input to a 'sc' instruction, and OLD_CFA, update FS + to represent the execution of a signal return; or, if not a signal + return, return false. */ + +static bool +handle_syscall (_Unwind_FrameState *fs, const reg_unit gprs[32], + _Unwind_Ptr old_cfa) +{ + struct gcc_ucontext *uctx; + bool is_64, is_vector; + struct gcc_float_vector_state * float_vector_state; + _Unwind_Ptr new_cfa; + int i; + static _Unwind_Ptr return_addr; + + /* Yay! We're in a Libc that we understand, and it's made a + system call. In Jaguar, this is a direct system call with value 103; + in Panther and Tiger it is a SYS_syscall call for system call number 184, + and in Leopard it is a direct syscall with number 184. */ + + if (gprs[0] == 0x67 /* SYS_SIGRETURN */) + { + uctx = (struct gcc_ucontext *) gprs[3]; + is_vector = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE + || uctx->mcsize == UC_FLAVOR_VEC_SIZE); + is_64 = (uctx->mcsize == UC_FLAVOR64_VEC_SIZE + || uctx->mcsize == UC_FLAVOR64_SIZE); + } + else if (gprs[0] == 0 /* SYS_syscall */ && gprs[3] == 184) + { + int ctxstyle = gprs[5]; + uctx = (struct gcc_ucontext *) gprs[4]; + is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC + || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC); + is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC + || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64); + } + else if (gprs[0] == 184 /* SYS_sigreturn */) + { + int ctxstyle = gprs[4]; + uctx = (struct gcc_ucontext *) gprs[3]; + is_vector = (ctxstyle == UC_FLAVOR_VEC || ctxstyle == UC_FLAVOR64_VEC + || ctxstyle == UC_TRAD_VEC || ctxstyle == UC_TRAD64_VEC); + is_64 = (ctxstyle == UC_FLAVOR64_VEC || ctxstyle == UC_TRAD64_VEC + || ctxstyle == UC_FLAVOR64 || ctxstyle == UC_TRAD64); + } + else + return false; + +#define set_offset(r, addr) \ + (fs->regs.reg[r].how = REG_SAVED_OFFSET, \ + fs->regs.reg[r].loc.offset = (_Unwind_Ptr)(addr) - new_cfa) + + /* Restore even the registers that are not call-saved, since they + might be being used in the prologue to save other registers, + for instance GPR0 is sometimes used to save LR. */ + + /* Handle the GPRs, and produce the information needed to do the rest. */ + if (is_64) + { + /* The context is 64-bit, but it doesn't carry any extra information + for us because only the low 32 bits of the registers are + call-saved. */ + struct gcc_mcontext64 *m64 = (struct gcc_mcontext64 *)uctx->mcontext; + int i; + + float_vector_state = &m64->fvs; + + new_cfa = m64->gpr[1][1]; + + set_offset (R_CR2, &m64->cr); + for (i = 0; i < 32; i++) + set_offset (i, m64->gpr[i] + 1); + set_offset (R_XER, m64->xer + 1); + set_offset (R_LR, m64->lr + 1); + set_offset (R_CTR, m64->ctr + 1); + if (is_vector) + set_offset (R_VRSAVE, &m64->vrsave); + + /* Sometimes, srr0 points to the instruction that caused the exception, + and sometimes to the next instruction to be executed; we want + the latter. */ + if (m64->exception == 3 || m64->exception == 4 + || m64->exception == 6 + || (m64->exception == 7 && !(m64->srr1 & 0x10000))) + return_addr = m64->srr0 + 4; + else + return_addr = m64->srr0; + } + else + { + struct gcc_mcontext32 *m = uctx->mcontext; + int i; + + float_vector_state = &m->fvs; + + new_cfa = m->gpr[1]; + + set_offset (R_CR2, &m->cr); + for (i = 0; i < 32; i++) + set_offset (i, m->gpr + i); + set_offset (R_XER, &m->xer); + set_offset (R_LR, &m->lr); + set_offset (R_CTR, &m->ctr); + + if (is_vector) + set_offset (R_VRSAVE, &m->vrsave); + + /* Sometimes, srr0 points to the instruction that caused the exception, + and sometimes to the next instruction to be executed; we want + the latter. */ + if (m->exception == 3 || m->exception == 4 + || m->exception == 6 + || (m->exception == 7 && !(m->srr1 & 0x10000))) + return_addr = m->srr0 + 4; + else + return_addr = m->srr0; + } + + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = STACK_POINTER_REGNUM; + fs->regs.cfa_offset = new_cfa - old_cfa;; + + /* The choice of column for the return address is somewhat tricky. + Fortunately, the actual choice is private to this file, and + the space it's reserved from is the GCC register space, not the + DWARF2 numbering. So any free element of the right size is an OK + choice. Thus: */ + fs->retaddr_column = ARG_POINTER_REGNUM; + /* FIXME: this should really be done using a DWARF2 location expression, + not using a static variable. In fact, this entire file should + be implemented in DWARF2 expressions. */ + set_offset (ARG_POINTER_REGNUM, &return_addr); + + for (i = 0; i < 32; i++) + set_offset (32 + i, float_vector_state->fpregs + i); + set_offset (R_SPEFSCR, &float_vector_state->fpscr); + + if (is_vector) + { + for (i = 0; i < 32; i++) + set_offset (R_VR0 + i, float_vector_state->save_vr + i); + set_offset (R_VSCR, float_vector_state->save_vscr); + } + + return true; +} + +/* This is also prototyped in rs6000/darwin.h, inside the + MD_FALLBACK_FRAME_STATE_FOR macro. */ +extern bool _Unwind_fallback_frame_state_for (struct _Unwind_Context *context, + _Unwind_FrameState *fs); + +/* Implement the MD_FALLBACK_FRAME_STATE_FOR macro, + returning true iff the frame was a sigreturn() frame that we + can understand. */ + +bool +_Unwind_fallback_frame_state_for (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + reg_unit gprs[32]; + + if (!interpret_libc (gprs, context)) + return false; + return handle_syscall (fs, gprs, _Unwind_GetCFA (context)); +} +#endif diff --git a/libgcc/config/rs6000/t-darwin b/libgcc/config/rs6000/t-darwin index 4541e4ed3ed..404df85870f 100644 --- a/libgcc/config/rs6000/t-darwin +++ b/libgcc/config/rs6000/t-darwin @@ -3,4 +3,6 @@ DARWIN_EXTRA_CRT_BUILD_CFLAGS = -mlongcall -mmacosx-version-min=10.4 crt2.o: $(srcdir)/config/rs6000/darwin-crt2.c $(crt_compile) $(DARWIN_EXTRA_CRT_BUILD_CFLAGS) -c $< +LIB2ADDEH += $(srcdir)/config/rs6000/darwin-fallback.c + SHLIB_VERPFX = $(gcc_srcdir)/config/rs6000/darwin-libgcc diff --git a/libgcc/config/s390/t-tpf b/libgcc/config/s390/t-tpf index 2110c688d5f..9d416acc12d 100644 --- a/libgcc/config/s390/t-tpf +++ b/libgcc/config/s390/t-tpf @@ -1,7 +1,2 @@ # Compile libgcc2.a with pic. HOST_LIBGCC2_CFLAGS += -fPIC - -# Use unwind-dw2-fde-glibc. -LIB2ADDEH = $(gcc_srcdir)/unwind-dw2.c $(gcc_srcdir)/unwind-dw2-fde-glibc.c \ - $(gcc_srcdir)/unwind-sjlj.c $(gcc_srcdir)/unwind-c.c \ - $(gcc_srcdir)/emutls.c diff --git a/libgcc/config/t-darwin b/libgcc/config/t-darwin index 548f0e3d469..311b7e2679f 100644 --- a/libgcc/config/t-darwin +++ b/libgcc/config/t-darwin @@ -2,3 +2,7 @@ crt3.o: $(srcdir)/config/darwin-crt3.c $(crt_compile) \ -fno-tree-dominator-opts $(DARWIN_EXTRA_CRT_BUILD_CFLAGS) -c $< + +# Use unwind-dw2-fde-darwin +LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/config/unwind-dw2-fde-darwin.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/t-eh-dw2-dip b/libgcc/config/t-eh-dw2-dip new file mode 100644 index 00000000000..88fa103c4e7 --- /dev/null +++ b/libgcc/config/t-eh-dw2-dip @@ -0,0 +1,3 @@ +# Use unwind-dw2-fde-dip. +LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-dip.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/t-libunwind b/libgcc/config/t-libunwind new file mode 100644 index 00000000000..1c7a898675f --- /dev/null +++ b/libgcc/config/t-libunwind @@ -0,0 +1,3 @@ +LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \ + $(srcdir)/unwind-compat.c $(srcdir)/unwind-dw2-fde-compat.c +LIB2ADDEHSTATIC = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/t-libunwind-elf b/libgcc/config/t-libunwind-elf new file mode 100644 index 00000000000..47a460bdd0e --- /dev/null +++ b/libgcc/config/t-libunwind-elf @@ -0,0 +1,51 @@ +# Copyright (C) 2004, 2005, 2011 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC 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 3, or (at your option) +# any later version. +# +# GCC 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 GCC; see the file COPYING3. If not see +# . + +# Build libunwind for ELF with the GNU linker. + +SHLIB_SOLINK = @shlib_base_name@.so +SHLIB_OBJS = @shlib_objs@ +SHLIB_DIR = @multilib_dir@ +SHLIB_SLIBDIR_QUAL = @shlib_slibdir_qual@ + +# Use unwind-dw2-fde-dip +LIBUNWIND = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-dip.c + +SHLIBUNWIND_SOVERSION = 7 +SHLIBUNWIND_SONAME = @shlib_base_name@.so.$(SHLIBUNWIND_SOVERSION) + +SHLIBUNWIND_LINK = $(CC) $(LIBGCC2_CFLAGS) -shared \ + -nodefaultlibs -Wl,-h,$(SHLIBUNWIND_SONAME) \ + -Wl,-z,text -Wl,-z,defs -o $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).tmp \ + @multilib_flags@ $(SHLIB_OBJS) -lc && \ + rm -f $(SHLIB_DIR)/$(SHLIB_SOLINK) && \ + if [ -f $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) ]; then \ + mv -f $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) \ + $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).backup; \ + else true; fi && \ + mv $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME).tmp \ + $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) && \ + $(LN_S) $(SHLIBUNWIND_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK) + +SHLIBUNWIND_INSTALL = \ + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL); \ + $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIBUNWIND_SONAME) \ + $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIBUNWIND_SONAME); \ + rm -f $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK); \ + $(LN_S) $(SHLIBUNWIND_SONAME) \ + $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK) diff --git a/libgcc/config/t-sol2 b/libgcc/config/t-sol2 index e55c64f646d..bfb8f3b5cc2 100644 --- a/libgcc/config/t-sol2 +++ b/libgcc/config/t-sol2 @@ -16,11 +16,6 @@ # along with GCC; see the file COPYING3. If not see # . -# Use unwind-dw2-fde-glibc.c. Unless linker support and dl_iterate_phdr -# are present, automatically falls back to unwind-dw2-fde.c. -LIB2ADDEH = $(gcc_srcdir)/unwind-dw2.c $(gcc_srcdir)/unwind-dw2-fde-glibc.c \ - $(gcc_srcdir)/unwind-sjlj.c $(gcc_srcdir)/unwind-c.c $(gcc_srcdir)/emutls.c - # gmon build rule: gmon.o: $(srcdir)/config/gmon-sol2.c $(gcc_compile) -c $< diff --git a/libgcc/config/unwind-dw2-fde-darwin.c b/libgcc/config/unwind-dw2-fde-darwin.c new file mode 100644 index 00000000000..75b404e09e9 --- /dev/null +++ b/libgcc/config/unwind-dw2-fde-darwin.c @@ -0,0 +1,289 @@ +/* Copyright (C) 2001, 2002, 2003, 2005, 2009, 2010 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Locate the FDE entry for a given address, using Darwin's keymgr support. */ + +#include "tconfig.h" +#include "tsystem.h" +#include +#include +#include "dwarf2.h" +#include "unwind.h" +#define NO_BASE_OF_ENCODED_VALUE +#define DWARF2_OBJECT_END_PTR_EXTENSION +#include "unwind-pe.h" +#include "unwind-dw2-fde.h" +/* Carefully don't include gthr.h. */ + +typedef int __gthread_mutex_t; +#define __gthread_mutex_lock(x) (void)(x) +#define __gthread_mutex_unlock(x) (void)(x) + +static const fde * _Unwind_Find_registered_FDE (void *pc, + struct dwarf_eh_bases *bases); + +#define _Unwind_Find_FDE _Unwind_Find_registered_FDE +#include "unwind-dw2-fde.c" +#undef _Unwind_Find_FDE + +/* KeyMgr stuff. */ +#define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */ +#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */ + +extern void *_keymgr_get_and_lock_processwide_ptr (int); +extern void _keymgr_set_and_unlock_processwide_ptr (int, void *); +extern void _keymgr_unlock_processwide_ptr (int); + +struct mach_header; +struct mach_header_64; +extern char *getsectdatafromheader (struct mach_header*, const char*, + const char *, unsigned long *); +extern char *getsectdatafromheader_64 (struct mach_header_64*, const char*, + const char *, unsigned long *); + +/* This is referenced from KEYMGR_GCC3_DW2_OBJ_LIST. */ +struct km_object_info { + struct object *seen_objects; + struct object *unseen_objects; + unsigned spare[2]; +}; + +/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */ +struct live_images { + unsigned long this_size; /* sizeof (live_images) */ + struct mach_header *mh; /* the image info */ + unsigned long vm_slide; + void (*destructor)(struct live_images *); /* destructor for this */ + struct live_images *next; + unsigned int examined_p; + void *fde; + void *object_info; + unsigned long info[2]; /* Future use. */ +}; + +/* Bits in the examined_p field of struct live_images. */ +enum { + EXAMINED_IMAGE_MASK = 1, /* We've seen this one. */ + ALLOCED_IMAGE_MASK = 2, /* The FDE entries were allocated by + malloc, and must be freed. This isn't + used by newer libgcc versions. */ + IMAGE_IS_TEXT_MASK = 4, /* This image is in the TEXT segment. */ + DESTRUCTOR_MAY_BE_CALLED_LIVE = 8 /* The destructor may be called on an + object that's part of the live + image list. */ +}; + +/* Delete any data we allocated on a live_images structure. Either + IMAGE has already been removed from the + KEYMGR_GCC3_LIVE_IMAGE_LIST and the struct will be deleted + after we return, or that list is locked and we're being called + because this object might be about to be unloaded. Called by + KeyMgr. */ + +static void +live_image_destructor (struct live_images *image) +{ + if (image->object_info) + { + struct km_object_info *the_obj_info; + + the_obj_info = + _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST); + if (the_obj_info) + { + seen_objects = the_obj_info->seen_objects; + unseen_objects = the_obj_info->unseen_objects; + + /* Free any sorted arrays. */ + __deregister_frame_info_bases (image->fde); + + the_obj_info->seen_objects = seen_objects; + the_obj_info->unseen_objects = unseen_objects; + } + _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST, + the_obj_info); + + free (image->object_info); + image->object_info = NULL; + if (image->examined_p & ALLOCED_IMAGE_MASK) + free (image->fde); + image->fde = NULL; + } + image->examined_p = 0; + image->destructor = NULL; +} + +/* Run through the list of live images. If we can allocate memory, + give each unseen image a new `struct object'. Even if we can't, + check whether the PC is inside the FDE of each unseen image. + */ + +static inline const fde * +examine_objects (void *pc, struct dwarf_eh_bases *bases, int dont_alloc) +{ + const fde *result = NULL; + struct live_images *image; + + image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST); + + for (; image != NULL; image = image->next) + if ((image->examined_p & EXAMINED_IMAGE_MASK) == 0) + { + char *fde = NULL; + unsigned long sz; + + /* For ppc only check whether or not we have __DATA eh frames. */ +#ifdef __ppc__ + fde = getsectdatafromheader (image->mh, "__DATA", "__eh_frame", &sz); +#endif + + if (fde == NULL) + { +#if __LP64__ + fde = getsectdatafromheader_64 ((struct mach_header_64 *) image->mh, + "__TEXT", "__eh_frame", &sz); +#else + fde = getsectdatafromheader (image->mh, "__TEXT", + "__eh_frame", &sz); +#endif + if (fde != NULL) + image->examined_p |= IMAGE_IS_TEXT_MASK; + } + + /* If .eh_frame is empty, don't register at all. */ + if (fde != NULL && sz > 0) + { + char *real_fde = (fde + image->vm_slide); + struct object *ob = NULL; + struct object panicob; + + if (! dont_alloc) + ob = calloc (1, sizeof (struct object)); + dont_alloc |= ob == NULL; + if (dont_alloc) + ob = &panicob; + + ob->pc_begin = (void *)-1; + ob->tbase = 0; + ob->dbase = 0; + ob->u.single = (struct dwarf_fde *)real_fde; + ob->s.i = 0; + ob->s.b.encoding = DW_EH_PE_omit; + ob->fde_end = real_fde + sz; + + image->fde = real_fde; + + result = search_object (ob, pc); + + if (! dont_alloc) + { + struct object **p; + + image->destructor = live_image_destructor; + image->object_info = ob; + + image->examined_p |= (EXAMINED_IMAGE_MASK + | DESTRUCTOR_MAY_BE_CALLED_LIVE); + + /* 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 (result) + { + int encoding; + _Unwind_Ptr func; + + bases->tbase = ob->tbase; + bases->dbase = ob->dbase; + + encoding = ob->s.b.encoding; + if (ob->s.b.mixed_encoding) + encoding = get_fde_encoding (result); + read_encoded_value_with_base (encoding, + base_from_object (encoding, ob), + result->pc_begin, &func); + bases->func = (void *) func; + break; + } + } + else + image->examined_p |= EXAMINED_IMAGE_MASK; + } + + _keymgr_unlock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST); + + return result; +} + +const fde * +_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) +{ + struct km_object_info *the_obj_info; + const fde *ret = NULL; + + the_obj_info = + _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST); + if (! the_obj_info) + the_obj_info = calloc (1, sizeof (*the_obj_info)); + + if (the_obj_info != NULL) + { + seen_objects = the_obj_info->seen_objects; + unseen_objects = the_obj_info->unseen_objects; + + ret = _Unwind_Find_registered_FDE (pc, bases); + } + + /* OK, didn't find it in the list of FDEs we've seen before, + so go through and look at the new ones. */ + if (ret == NULL) + ret = examine_objects (pc, bases, the_obj_info == NULL); + + if (the_obj_info != NULL) + { + the_obj_info->seen_objects = seen_objects; + the_obj_info->unseen_objects = unseen_objects; + } + _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST, + the_obj_info); + return ret; +} + +void * +_darwin10_Unwind_FindEnclosingFunction (void *pc ATTRIBUTE_UNUSED) +{ +#if __MACH__ && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060) + struct dwarf_eh_bases bases; + const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); + if (fde) + return bases.func; +#endif + return NULL; +} + diff --git a/libgcc/config/xtensa/t-xtensa b/libgcc/config/xtensa/t-xtensa new file mode 100644 index 00000000000..7d9e9db0487 --- /dev/null +++ b/libgcc/config/xtensa/t-xtensa @@ -0,0 +1,2 @@ +LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \ + $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c diff --git a/libgcc/config/xtensa/unwind-dw2-xtensa.c b/libgcc/config/xtensa/unwind-dw2-xtensa.c new file mode 100644 index 00000000000..54daf7637ce --- /dev/null +++ b/libgcc/config/xtensa/unwind-dw2-xtensa.c @@ -0,0 +1,544 @@ +/* DWARF2 exception handling and frame unwinding for Xtensa. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007, 2008, 2009, 2011 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#ifdef __USING_SJLJ_EXCEPTIONS__ +# define NO_SIZE_OF_ENCODED_VALUE +#endif +#include "unwind-pe.h" +#include "unwind-dw2-fde.h" +#include "unwind-dw2-xtensa.h" + +#ifndef __USING_SJLJ_EXCEPTIONS__ + +/* The standard CIE and FDE structures work fine for Xtensa but the + variable-size register window save areas are not a good fit for the rest + of the standard DWARF unwinding mechanism. Nor is that mechanism + necessary, since the register save areas are always in fixed locations + in each stack frame. This file is a stripped down and customized version + of the standard DWARF unwinding code. It needs to be customized to have + builtin logic for finding the save areas and also to track the stack + pointer value (besides the CFA) while unwinding since the primary save + area is located below the stack pointer. It is stripped down to reduce + code size and ease the maintenance burden of tracking changes in the + standard version of the code. */ + +#ifndef DWARF_REG_TO_UNWIND_COLUMN +#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) +#endif + +#define XTENSA_RA_FIELD_MASK 0x3FFFFFFF + +/* This is the register and unwind state for a particular frame. This + provides the information necessary to unwind up past a frame and return + to its caller. */ +struct _Unwind_Context +{ + /* Track register window save areas of 4 registers each, instead of + keeping separate addresses for the individual registers. */ + _Unwind_Word *reg[4]; + + void *cfa; + void *sp; + void *ra; + + /* Cache the 2 high bits to replace the window size in return addresses. */ + _Unwind_Word ra_high_bits; + + void *lsda; + struct dwarf_eh_bases bases; + /* Signal frame context. */ +#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) + _Unwind_Word flags; + /* 0 for now, can be increased when further fields are added to + struct _Unwind_Context. */ + _Unwind_Word version; +}; + + +/* Read unaligned data from the instruction buffer. */ + +union unaligned +{ + void *p; +} __attribute__ ((packed)); + +static void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); +static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, + _Unwind_FrameState *); + +static inline void * +read_pointer (const void *p) { const union unaligned *up = p; return up->p; } + +static inline _Unwind_Word +_Unwind_IsSignalFrame (struct _Unwind_Context *context) +{ + return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0; +} + +static inline void +_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) +{ + if (val) + context->flags |= SIGNAL_FRAME_BIT; + else + context->flags &= ~SIGNAL_FRAME_BIT; +} + +/* Get the value of register INDEX as saved in CONTEXT. */ + +inline _Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + _Unwind_Word *ptr; + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + ptr = context->reg[index >> 2] + (index & 3); + + return *ptr; +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->cfa; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +inline void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + _Unwind_Word *ptr; + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + ptr = context->reg[index >> 2] + (index & 3); + + *ptr = val; +} + +/* Retrieve the return address for CONTEXT. */ + +inline _Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->ra; +} + +/* Retrieve the return address and flag whether that IP is before + or after first not yet fully executed instruction. */ + +inline _Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = _Unwind_IsSignalFrame (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; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + struct dwarf_eh_bases bases; + const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); + if (fde) + return bases.func; + else + return NULL; +} + +_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; +} + +#include "md-unwind-support.h" + +/* 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 (const struct dwarf_cie *cie, struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + const unsigned char *aug = cie->augmentation; + const unsigned char *p = aug + strlen ((const char *)aug) + 1; + const unsigned char *ret = NULL; + _uleb128_t utmp; + _sleb128_t stmp; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (aug[0] == 'e' && aug[1] == 'h') + { + fs->eh_ptr = read_pointer (p); + p += sizeof (void *); + aug += 2; + } + + /* Immediately following the augmentation are the code and + data alignment and return address column. */ + p = read_uleb128 (p, &utmp); + p = read_sleb128 (p, &stmp); + if (cie->version == 1) + fs->retaddr_column = *p++; + else + { + p = read_uleb128 (p, &utmp); + fs->retaddr_column = (_Unwind_Word)utmp; + } + 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, &utmp); + ret = p + utmp; + + fs->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') + { + 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') + { + _Unwind_Ptr personality; + + p = read_encoded_value (context, *p, p + 1, &personality); + fs->personality = (_Unwind_Personality_Fn) personality; + aug += 1; + } + + /* "S" indicates a signal frame. */ + else if (aug[0] == 'S') + { + fs->signal_frame = 1; + aug += 1; + } + + /* Otherwise we have an unknown augmentation string. + Bail unless we saw a 'z' prefix. */ + else + return ret; + } + + return ret ? ret : p; +} + +/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for + its caller and decode it into FS. This function also sets the + lsda member of CONTEXT, as it is really information + about the caller's frame. */ + +static _Unwind_Reason_Code +uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + const struct dwarf_fde *fde; + const struct dwarf_cie *cie; + const unsigned char *aug; + int window_size; + _Unwind_Word *ra_ptr; + + memset (fs, 0, sizeof (*fs)); + context->lsda = 0; + + fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, + &context->bases); + if (fde == NULL) + { +#ifdef MD_FALLBACK_FRAME_STATE_FOR + _Unwind_Reason_Code reason; + /* Couldn't find frame unwind info for this function. Try a + target-specific fallback mechanism. This will necessarily + not provide a personality routine or LSDA. */ + reason = MD_FALLBACK_FRAME_STATE_FOR (context, fs); + if (reason != _URC_END_OF_STACK) + return reason; +#endif + /* The frame was not recognized and handled by the fallback function, + but it is not really the end of the stack. Fall through here and + unwind it anyway. */ + } + else + { + cie = get_cie (fde); + if (extract_cie_info (cie, context, fs) == NULL) + /* CIE contained unknown augmentation. */ + return _URC_FATAL_PHASE1_ERROR; + + /* Locate augmentation for the fde. */ + aug = (const unsigned char *) fde + sizeof (*fde); + aug += 2 * size_of_encoded_value (fs->fde_encoding); + if (fs->saw_z) + { + _uleb128_t i; + aug = read_uleb128 (aug, &i); + } + if (fs->lsda_encoding != DW_EH_PE_omit) + { + _Unwind_Ptr lsda; + + aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); + context->lsda = (void *) lsda; + } + } + + /* Check for the end of the stack. This needs to be checked after + the MD_FALLBACK_FRAME_STATE_FOR check for signal frames because + the contents of context->reg[0] are undefined at a signal frame, + and register a0 may appear to be zero. (The return address in + context->ra comes from register a4 or a8). */ + ra_ptr = context->reg[0]; + if (ra_ptr && *ra_ptr == 0) + return _URC_END_OF_STACK; + + /* Find the window size from the high bits of the return address. */ + if (ra_ptr) + window_size = (*ra_ptr >> 30) * 4; + else + window_size = 8; + + fs->retaddr_column = window_size; + + return _URC_NO_REASON; +} + +static void +uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + struct _Unwind_Context orig_context = *context; + _Unwind_Word *sp, *cfa, *next_cfa; + int i; + + if (fs->signal_regs) + { + cfa = (_Unwind_Word *) fs->signal_regs[1]; + next_cfa = (_Unwind_Word *) cfa[-3]; + + for (i = 0; i < 4; i++) + context->reg[i] = fs->signal_regs + (i << 2); + } + else + { + int window_size = fs->retaddr_column >> 2; + + sp = (_Unwind_Word *) orig_context.sp; + cfa = (_Unwind_Word *) orig_context.cfa; + next_cfa = (_Unwind_Word *) cfa[-3]; + + /* Registers a0-a3 are in the save area below sp. */ + context->reg[0] = sp - 4; + + /* Find the extra save area below next_cfa. */ + for (i = 1; i < window_size; i++) + context->reg[i] = next_cfa - 4 * (1 + window_size - i); + + /* Remaining registers rotate from previous save areas. */ + for (i = window_size; i < 4; i++) + context->reg[i] = orig_context.reg[i - window_size]; + } + + context->sp = cfa; + context->cfa = next_cfa; + + _Unwind_SetSignalFrame (context, fs->signal_frame); +} + +/* CONTEXT describes the unwind state for a frame, and FS describes the FDE + of its caller. Update CONTEXT to refer to the caller as well. Note + that the lsda member is not updated here, but later in + uw_frame_state_for. */ + +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. */ + if (fs->signal_ra != 0) + context->ra = (void *) fs->signal_ra; + else + context->ra = (void *) ((_Unwind_GetGR (context, fs->retaddr_column) + & XTENSA_RA_FIELD_MASK) | context->ra_high_bits); +} + +static void +uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context (context, fs); +} + +/* 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 \ + { \ + __builtin_unwind_init (); \ + uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ + __builtin_return_address (0)); \ + } \ + while (0) + +static void __attribute__((noinline)) +uw_init_context_1 (struct _Unwind_Context *context, void *outer_cfa, + void *outer_ra) +{ + void *ra = __builtin_return_address (0); + void *cfa = __builtin_dwarf_cfa (); + _Unwind_FrameState fs; + + memset (context, 0, sizeof (struct _Unwind_Context)); + context->ra = ra; + + memset (&fs, 0, sizeof (fs)); + fs.retaddr_column = 8; + context->sp = cfa; + context->cfa = outer_cfa; + context->ra_high_bits = + ((_Unwind_Word) uw_init_context_1) & ~XTENSA_RA_FIELD_MASK; + uw_update_context_1 (context, &fs); + + context->ra = 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 long +uw_install_context_1 (struct _Unwind_Context *current, + struct _Unwind_Context *target) +{ + long i; + + /* The eh_return insn assumes a window size of 8, so don't bother copying + the save areas for registers a8-a15 since they won't be reloaded. */ + for (i = 0; i < 2; ++i) + { + void *c = current->reg[i]; + void *t = target->reg[i]; + + if (t && c && t != c) + memcpy (c, t, 4 * sizeof (_Unwind_Word)); + } + + return 0; +} + +static inline _Unwind_Ptr +uw_identify_context (struct _Unwind_Context *context) +{ + return _Unwind_GetCFA (context); +} + + +#include "unwind.inc" + +#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) +alias (_Unwind_Backtrace); +alias (_Unwind_DeleteException); +alias (_Unwind_FindEnclosingFunction); +alias (_Unwind_ForcedUnwind); +alias (_Unwind_GetDataRelBase); +alias (_Unwind_GetTextRelBase); +alias (_Unwind_GetCFA); +alias (_Unwind_GetGR); +alias (_Unwind_GetIP); +alias (_Unwind_GetLanguageSpecificData); +alias (_Unwind_GetRegionStart); +alias (_Unwind_RaiseException); +alias (_Unwind_Resume); +alias (_Unwind_Resume_or_Rethrow); +alias (_Unwind_SetGR); +alias (_Unwind_SetIP); +#endif + +#endif /* !USING_SJLJ_EXCEPTIONS */ diff --git a/libgcc/config/xtensa/unwind-dw2-xtensa.h b/libgcc/config/xtensa/unwind-dw2-xtensa.h new file mode 100644 index 00000000000..d13b3264c99 --- /dev/null +++ b/libgcc/config/xtensa/unwind-dw2-xtensa.h @@ -0,0 +1,50 @@ +/* DWARF2 frame unwind data structure for Xtensa. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, + 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* 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 + +/* Xtensa's variable-size register window save areas can be unwound without + any unwind info. This is a stripped down version of the standard DWARF + _Unwind_FrameState. */ +typedef struct +{ + /* The information we care about from the CIE/FDE. */ + _Unwind_Personality_Fn personality; + _Unwind_Word retaddr_column; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char saw_z; + unsigned char signal_frame; + void *eh_ptr; + + /* Saved registers for a signal frame. */ + _Unwind_Word *signal_regs; + _Unwind_Word signal_ra; +} _Unwind_FrameState; + diff --git a/libgcc/configure b/libgcc/configure index 9845eadb65a..60363387312 100644 --- a/libgcc/configure +++ b/libgcc/configure @@ -651,6 +651,7 @@ with_slibdir enable_maintainer_mode with_build_libsubdir enable_decimal_float +with_system_libunwind enable_tls ' ac_precious_vars='build_alias @@ -1295,6 +1296,7 @@ Optional Packages: --with-ld arrange to use the specified ld (full pathname) --with-slibdir=DIR shared libraries in DIR LIBDIR --with-build-libsubdir=DIR Directory where to find libraries for build system + --with-system-libunwind use installed libunwind Some influential environment variables: CC C compiler command @@ -3743,6 +3745,46 @@ $as_echo "$libgcc_cv_fixed_point" >&6; } fixed_point=$libgcc_cv_fixed_point +# For platforms with the unwind ABI which includes an unwind library, +# libunwind, we can choose to use the system libunwind. +# config.gcc also contains tests of with_system_libunwind. + + +# Check whether --with-system-libunwind was given. +if test "${with_system_libunwind+set}" = set; then : + withval=$with_system_libunwind; +fi + + # If system-libunwind was not specifically set, pick a default setting. + if test x$with_system_libunwind = x; then + case ${target} in + ia64-*-hpux*) with_system_libunwind=yes ;; + *) with_system_libunwind=no ;; + esac + fi + # Based on system-libunwind and target, do we have ipinfo? + if test x$with_system_libunwind = xyes; then + case ${target} in + ia64-*-*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + else + # Darwin before version 9 does not have _Unwind_GetIPInfo. + + case ${target} in + *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + + fi + + if test x$have_unwind_getipinfo = xyes; then + +$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if test "${acl_cv_prog_gnu_ld+set}" = set; then : @@ -3962,6 +4004,8 @@ tmake_file="${tmake_file_}" ac_config_links="$ac_config_links enable-execute-stack.c:$enable_execute_stack" +ac_config_links="$ac_config_links unwind.h:$unwind_header" + ac_config_links="$ac_config_links md-unwind-support.h:config/$md_unwind_header" @@ -4690,6 +4734,7 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in "enable-execute-stack.c") CONFIG_LINKS="$CONFIG_LINKS enable-execute-stack.c:$enable_execute_stack" ;; + "unwind.h") CONFIG_LINKS="$CONFIG_LINKS unwind.h:$unwind_header" ;; "md-unwind-support.h") CONFIG_LINKS="$CONFIG_LINKS md-unwind-support.h:config/$md_unwind_header" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; diff --git a/libgcc/configure.ac b/libgcc/configure.ac index 39a2e920ba7..d96bcb4224a 100644 --- a/libgcc/configure.ac +++ b/libgcc/configure.ac @@ -7,6 +7,7 @@ sinclude(../config/no-executables.m4) sinclude(../config/lib-ld.m4) sinclude(../config/override.m4) sinclude(../config/dfp.m4) +sinclude(../config/unwind_ipinfo.m4) AC_PREREQ(2.64) AC_INIT([GNU C Runtime Library], 1.0,,[libgcc]) @@ -167,6 +168,11 @@ AC_CACHE_CHECK([whether fixed-point is supported], [libgcc_cv_fixed_point], fixed_point=$libgcc_cv_fixed_point AC_SUBST(fixed_point) +# For platforms with the unwind ABI which includes an unwind library, +# libunwind, we can choose to use the system libunwind. +# config.gcc also contains tests of with_system_libunwind. +GCC_CHECK_UNWIND_GETIPINFO + AC_LIB_PROG_LD_GNU AC_MSG_CHECKING([for thread model used by GCC]) @@ -277,6 +283,7 @@ AC_SUBST(cpu_type) AC_SUBST(extra_parts) AC_SUBST(asm_hidden_op) AC_CONFIG_LINKS([enable-execute-stack.c:$enable_execute_stack]) +AC_CONFIG_LINKS([unwind.h:$unwind_header]) AC_CONFIG_LINKS([md-unwind-support.h:config/$md_unwind_header]) # We need multilib support. diff --git a/libgcc/emutls.c b/libgcc/emutls.c new file mode 100644 index 00000000000..b7ee3bdfa7c --- /dev/null +++ b/libgcc/emutls.c @@ -0,0 +1,202 @@ +/* TLS emulation. + Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc. + Contributed by Jakub Jelinek . + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "gthr.h" + +typedef unsigned int word __attribute__((mode(word))); +typedef unsigned int pointer __attribute__((mode(pointer))); + +struct __emutls_object +{ + word size; + word align; + union { + pointer offset; + void *ptr; + } loc; + void *templ; +}; + +struct __emutls_array +{ + pointer size; + void **data[]; +}; + +void *__emutls_get_address (struct __emutls_object *); +void __emutls_register_common (struct __emutls_object *, word, word, void *); + +#ifdef __GTHREADS +#ifdef __GTHREAD_MUTEX_INIT +static __gthread_mutex_t emutls_mutex = __GTHREAD_MUTEX_INIT; +#else +static __gthread_mutex_t emutls_mutex; +#endif +static __gthread_key_t emutls_key; +static pointer emutls_size; + +static void +emutls_destroy (void *ptr) +{ + struct __emutls_array *arr = ptr; + pointer size = arr->size; + pointer i; + + for (i = 0; i < size; ++i) + { + if (arr->data[i]) + free (arr->data[i][-1]); + } + + free (ptr); +} + +static void +emutls_init (void) +{ +#ifndef __GTHREAD_MUTEX_INIT + __GTHREAD_MUTEX_INIT_FUNCTION (&emutls_mutex); +#endif + if (__gthread_key_create (&emutls_key, emutls_destroy) != 0) + abort (); +} +#endif + +static void * +emutls_alloc (struct __emutls_object *obj) +{ + void *ptr; + void *ret; + + /* We could use here posix_memalign if available and adjust + emutls_destroy accordingly. */ + if (obj->align <= sizeof (void *)) + { + ptr = malloc (obj->size + sizeof (void *)); + if (ptr == NULL) + abort (); + ((void **) ptr)[0] = ptr; + ret = ptr + sizeof (void *); + } + else + { + ptr = malloc (obj->size + sizeof (void *) + obj->align - 1); + if (ptr == NULL) + abort (); + ret = (void *) (((pointer) (ptr + sizeof (void *) + obj->align - 1)) + & ~(pointer)(obj->align - 1)); + ((void **) ret)[-1] = ptr; + } + + if (obj->templ) + memcpy (ret, obj->templ, obj->size); + else + memset (ret, 0, obj->size); + + return ret; +} + +void * +__emutls_get_address (struct __emutls_object *obj) +{ + if (! __gthread_active_p ()) + { + if (__builtin_expect (obj->loc.ptr == NULL, 0)) + obj->loc.ptr = emutls_alloc (obj); + return obj->loc.ptr; + } + +#ifndef __GTHREADS + abort (); +#else + pointer offset = obj->loc.offset; + + if (__builtin_expect (offset == 0, 0)) + { + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + __gthread_once (&once, emutls_init); + __gthread_mutex_lock (&emutls_mutex); + offset = obj->loc.offset; + if (offset == 0) + { + offset = ++emutls_size; + obj->loc.offset = offset; + } + __gthread_mutex_unlock (&emutls_mutex); + } + + struct __emutls_array *arr = __gthread_getspecific (emutls_key); + if (__builtin_expect (arr == NULL, 0)) + { + pointer size = offset + 32; + arr = calloc (size + 1, sizeof (void *)); + if (arr == NULL) + abort (); + arr->size = size; + __gthread_setspecific (emutls_key, (void *) arr); + } + else if (__builtin_expect (offset > arr->size, 0)) + { + pointer orig_size = arr->size; + pointer size = orig_size * 2; + if (offset > size) + size = offset + 32; + arr = realloc (arr, (size + 1) * sizeof (void *)); + if (arr == NULL) + abort (); + arr->size = size; + memset (arr->data + orig_size, 0, + (size - orig_size) * sizeof (void *)); + __gthread_setspecific (emutls_key, (void *) arr); + } + + void *ret = arr->data[offset - 1]; + if (__builtin_expect (ret == NULL, 0)) + { + ret = emutls_alloc (obj); + arr->data[offset - 1] = ret; + } + return ret; +#endif +} + +void +__emutls_register_common (struct __emutls_object *obj, + word size, word align, void *templ) +{ + if (obj->size < size) + { + obj->size = size; + obj->templ = NULL; + } + if (obj->align < align) + obj->align = align; + if (templ && size == obj->size) + obj->templ = templ; +} diff --git a/libgcc/unwind-c.c b/libgcc/unwind-c.c new file mode 100644 index 00000000000..86b9f557048 --- /dev/null +++ b/libgcc/unwind-c.c @@ -0,0 +1,229 @@ +/* Supporting functions for C exception handling. + Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc. + Contributed by Aldy Hernandez . + Shamelessly stolen from the Java front end. + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#include "tconfig.h" +#include "tsystem.h" +#include "unwind.h" +#define NO_SIZE_OF_ENCODED_VALUE +#include "unwind-pe.h" + +typedef struct +{ + _Unwind_Ptr Start; + _Unwind_Ptr LPStart; + _Unwind_Ptr ttype_base; + const unsigned char *TType; + const unsigned char *action_table; + unsigned char ttype_encoding; + unsigned char call_site_encoding; +} lsda_header_info; + +static const unsigned char * +parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, + lsda_header_info *info) +{ + _uleb128_t tmp; + unsigned char lpstart_encoding; + + info->Start = (context ? _Unwind_GetRegionStart (context) : 0); + + /* Find @LPStart, the base to which landing pad offsets are relative. */ + lpstart_encoding = *p++; + if (lpstart_encoding != DW_EH_PE_omit) + p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); + else + info->LPStart = info->Start; + + /* Find @TType, the base of the handler and exception spec type data. */ + info->ttype_encoding = *p++; + if (info->ttype_encoding != DW_EH_PE_omit) + { + p = read_uleb128 (p, &tmp); + info->TType = p + tmp; + } + else + info->TType = 0; + + /* The encoding and length of the call-site table; the action table + immediately follows. */ + info->call_site_encoding = *p++; + p = read_uleb128 (p, &tmp); + info->action_table = p + tmp; + + return p; +} + +#ifdef __ARM_EABI_UNWINDER__ +/* ARM EABI personality routines must also unwind the stack. */ +#define CONTINUE_UNWINDING \ + do \ + { \ + if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \ + return _URC_FAILURE; \ + return _URC_CONTINUE_UNWIND; \ + } \ + while (0) +#else +#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND +#endif + +#ifdef __USING_SJLJ_EXCEPTIONS__ +#define PERSONALITY_FUNCTION __gcc_personality_sj0 +#define __builtin_eh_return_data_regno(x) x +#else +#define PERSONALITY_FUNCTION __gcc_personality_v0 +#endif + +#ifdef __ARM_EABI_UNWINDER__ +_Unwind_Reason_Code +PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *, + struct _Unwind_Context *); + +_Unwind_Reason_Code +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception * ue_header, + struct _Unwind_Context * context) +#else +_Unwind_Reason_Code +PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class, + struct _Unwind_Exception *, struct _Unwind_Context *); + +_Unwind_Reason_Code +PERSONALITY_FUNCTION (int version, + _Unwind_Action actions, + _Unwind_Exception_Class exception_class ATTRIBUTE_UNUSED, + struct _Unwind_Exception *ue_header, + struct _Unwind_Context *context) +#endif +{ + lsda_header_info info; + const unsigned char *language_specific_data, *p; + _Unwind_Ptr landing_pad, ip; + int ip_before_insn = 0; + +#ifdef __ARM_EABI_UNWINDER__ + if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) + CONTINUE_UNWINDING; + + /* The dwarf unwinder assumes the context structure holds things like the + function and LSDA pointers. The ARM implementation caches these in + the exception header (UCB). To avoid rewriting everything we make the + virtual IP register point at the UCB. */ + ip = (_Unwind_Ptr) ue_header; + _Unwind_SetGR (context, 12, ip); +#else + if (version != 1) + return _URC_FATAL_PHASE1_ERROR; + + /* Currently we only support cleanups for C. */ + if ((actions & _UA_CLEANUP_PHASE) == 0) + CONTINUE_UNWINDING; +#endif + + language_specific_data = (const unsigned char *) + _Unwind_GetLanguageSpecificData (context); + + /* If no LSDA, then there are no handlers or cleanups. */ + if (! language_specific_data) + CONTINUE_UNWINDING; + + /* Parse the LSDA header. */ + p = parse_lsda_header (context, language_specific_data, &info); +#ifdef HAVE_GETIPINFO + ip = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + ip = _Unwind_GetIP (context); +#endif + if (! ip_before_insn) + --ip; + landing_pad = 0; + +#ifdef __USING_SJLJ_EXCEPTIONS__ + /* The given "IP" is an index into the call-site table, with two + exceptions -- -1 means no-action, and 0 means terminate. But + since we're using uleb128 values, we've not got random access + to the array. */ + if ((int) ip <= 0) + return _URC_CONTINUE_UNWIND; + else + { + _uleb128_t cs_lp, cs_action; + do + { + p = read_uleb128 (p, &cs_lp); + p = read_uleb128 (p, &cs_action); + } + while (--ip); + + /* Can never have null landing pad for sjlj -- that would have + been indicated by a -1 call site index. */ + landing_pad = (_Unwind_Ptr)cs_lp + 1; + goto found_something; + } +#else + /* Search the call-site table for the action associated with this IP. */ + while (p < info.action_table) + { + _Unwind_Ptr cs_start, cs_len, cs_lp; + _uleb128_t cs_action; + + /* Note that all call-site encodings are "absolute" displacements. */ + p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); + p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); + p = read_uleb128 (p, &cs_action); + + /* The table is sorted, so if we've passed the ip, stop. */ + if (ip < info.Start + cs_start) + p = info.action_table; + else if (ip < info.Start + cs_start + cs_len) + { + if (cs_lp) + landing_pad = info.LPStart + cs_lp; + goto found_something; + } + } +#endif + + /* IP is not in table. No associated cleanups. */ + /* ??? This is where C++ calls std::terminate to catch throw + from a destructor. */ + CONTINUE_UNWINDING; + + found_something: + if (landing_pad == 0) + { + /* IP is present, but has a null landing pad. + No handler to be run. */ + CONTINUE_UNWINDING; + } + + _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), + (_Unwind_Ptr) ue_header); + _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0); + _Unwind_SetIP (context, landing_pad); + return _URC_INSTALL_CONTEXT; +} diff --git a/libgcc/unwind-compat.c b/libgcc/unwind-compat.c new file mode 100644 index 00000000000..5b41f24688d --- /dev/null +++ b/libgcc/unwind-compat.c @@ -0,0 +1,210 @@ +/* Backward compatibility unwind routines. + Copyright (C) 2004, 2005, 2006, 2009 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#if defined (USE_GAS_SYMVER) && defined (USE_LIBUNWIND_EXCEPTIONS) +#include "tconfig.h" +#include "tsystem.h" +#include "unwind.h" +#include "unwind-dw2-fde.h" +#include "unwind-compat.h" + +extern _Unwind_Reason_Code __libunwind_Unwind_Backtrace + (_Unwind_Trace_Fn, void *); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Backtrace (_Unwind_Trace_Fn trace, void *trace_argument) +{ + return __libunwind_Unwind_Backtrace (trace, trace_argument); +} +symver (_Unwind_Backtrace, GCC_3.3); + +extern void __libunwind_Unwind_DeleteException + (struct _Unwind_Exception *); + +void +_Unwind_DeleteException (struct _Unwind_Exception *exc) +{ + return __libunwind_Unwind_DeleteException (exc); +} +symver (_Unwind_DeleteException, GCC_3.0); + +extern void * __libunwind_Unwind_FindEnclosingFunction (void *); + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + return __libunwind_Unwind_FindEnclosingFunction (pc); +} +symver (_Unwind_FindEnclosingFunction, GCC_3.3); + +extern _Unwind_Reason_Code __libunwind_Unwind_ForcedUnwind + (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument) +{ + return __libunwind_Unwind_ForcedUnwind (exc, stop, stop_argument); +} +symver (_Unwind_ForcedUnwind, GCC_3.0); + +extern _Unwind_Word __libunwind_Unwind_GetCFA + (struct _Unwind_Context *); + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetCFA (context); +} +symver (_Unwind_GetCFA, GCC_3.3); + +#ifdef __ia64__ +extern _Unwind_Word __libunwind_Unwind_GetBSP + (struct _Unwind_Context *); + +_Unwind_Word +_Unwind_GetBSP (struct _Unwind_Context * context) +{ + return __libunwind_Unwind_GetBSP (context); +} +symver (_Unwind_GetBSP, GCC_3.3.2); +#else +extern _Unwind_Ptr __libunwind_Unwind_GetDataRelBase + (struct _Unwind_Context *); + +_Unwind_Ptr +_Unwind_GetDataRelBase (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetDataRelBase (context); +} +symver (_Unwind_GetDataRelBase, GCC_3.0); + +extern _Unwind_Ptr __libunwind_Unwind_GetTextRelBase + (struct _Unwind_Context *); + +_Unwind_Ptr +_Unwind_GetTextRelBase (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetTextRelBase (context); +} +symver (_Unwind_GetTextRelBase, GCC_3.0); +#endif + +extern _Unwind_Word __libunwind_Unwind_GetGR + (struct _Unwind_Context *, int ); + +_Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + return __libunwind_Unwind_GetGR (context, index); +} +symver (_Unwind_GetGR, GCC_3.0); + +extern _Unwind_Ptr __libunwind_Unwind_GetIP (struct _Unwind_Context *); + +_Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetIP (context); +} +symver (_Unwind_GetIP, GCC_3.0); + +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + return __libunwind_Unwind_GetIP (context); +} + +extern void *__libunwind_Unwind_GetLanguageSpecificData + (struct _Unwind_Context *); + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetLanguageSpecificData (context); +} +symver (_Unwind_GetLanguageSpecificData, GCC_3.0); + +extern _Unwind_Ptr __libunwind_Unwind_GetRegionStart + (struct _Unwind_Context *); + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *context) +{ + return __libunwind_Unwind_GetRegionStart (context); +} +symver (_Unwind_GetRegionStart, GCC_3.0); + +extern _Unwind_Reason_Code __libunwind_Unwind_RaiseException + (struct _Unwind_Exception *); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_RaiseException(struct _Unwind_Exception *exc) +{ + return __libunwind_Unwind_RaiseException (exc); +} +symver (_Unwind_RaiseException, GCC_3.0); + +extern void __libunwind_Unwind_Resume (struct _Unwind_Exception *); + +void LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + __libunwind_Unwind_Resume (exc); +} +symver (_Unwind_Resume, GCC_3.0); + +extern _Unwind_Reason_Code __libunwind_Unwind_Resume_or_Rethrow + (struct _Unwind_Exception *); + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) +{ + return __libunwind_Unwind_Resume_or_Rethrow (exc); +} +symver (_Unwind_Resume_or_Rethrow, GCC_3.3); + +extern void __libunwind_Unwind_SetGR + (struct _Unwind_Context *, int, _Unwind_Word); + +void +_Unwind_SetGR (struct _Unwind_Context *context, int index, + _Unwind_Word val) +{ + __libunwind_Unwind_SetGR (context, index, val); +} +symver (_Unwind_SetGR, GCC_3.0); + +extern void __libunwind_Unwind_SetIP + (struct _Unwind_Context *, _Unwind_Ptr); + +void +_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) +{ + return __libunwind_Unwind_SetIP (context, val); +} +symver (_Unwind_SetIP, GCC_3.0); +#endif diff --git a/libgcc/unwind-compat.h b/libgcc/unwind-compat.h new file mode 100644 index 00000000000..24c8de11801 --- /dev/null +++ b/libgcc/unwind-compat.h @@ -0,0 +1,30 @@ +/* Backward compatibility unwind routines. + Copyright (C) 2004, 2009 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#define symver(name, version) \ + __asm__ (".symver " #name"," #name "@" #version) + +#define alias(name) \ + __typeof(name) __libunwind##name __attribute__ ((alias (#name))) diff --git a/libgcc/unwind-dw2-fde-compat.c b/libgcc/unwind-dw2-fde-compat.c new file mode 100644 index 00000000000..f305a5501a0 --- /dev/null +++ b/libgcc/unwind-dw2-fde-compat.c @@ -0,0 +1,43 @@ +/* Backward compatibility unwind routines. + Copyright (C) 2004, 2005, 2009 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#if defined (USE_GAS_SYMVER) && defined (USE_LIBUNWIND_EXCEPTIONS) +#include "tconfig.h" +#include "tsystem.h" +#include "unwind.h" +#include "unwind-dw2-fde.h" +#include "unwind-compat.h" + +extern const fde * __libunwind__Unwind_Find_FDE + (void *, struct dwarf_eh_bases *); + +const fde * +_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) +{ + __libunwind__Unwind_Find_FDE (pc, bases); +} + +symver (_Unwind_Find_FDE, GCC_3.0); +#endif diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c new file mode 100644 index 00000000000..d8e3c0e934b --- /dev/null +++ b/libgcc/unwind-dw2-fde-dip.c @@ -0,0 +1,470 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2010 + Free Software Foundation, Inc. + Contributed by Jakub Jelinek . + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Locate the FDE entry for a given address, using PT_GNU_EH_FRAME ELF + segment and dl_iterate_phdr to avoid register/deregister calls at + DSO load/unload. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include "tconfig.h" +#include "tsystem.h" +#ifndef inhibit_libc +#include /* Get DT_CONFIG. */ +#endif +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#define NO_BASE_OF_ENCODED_VALUE +#include "unwind-pe.h" +#include "unwind-dw2-fde.h" +#include "unwind-compat.h" +#include "gthr.h" + +#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ + && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \ + || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) +# define USE_PT_GNU_EH_FRAME +#endif + +#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ + && defined(__FreeBSD__) && __FreeBSD__ >= 7 +# define ElfW __ElfN +# define USE_PT_GNU_EH_FRAME +#endif + +#if !defined(inhibit_libc) && defined(HAVE_LD_EH_FRAME_HDR) \ + && defined(TARGET_DL_ITERATE_PHDR) \ + && defined(__sun__) && defined(__svr4__) +# define USE_PT_GNU_EH_FRAME +#endif + +#if defined(USE_PT_GNU_EH_FRAME) + +#include + +#ifndef __RELOC_POINTER +# define __RELOC_POINTER(ptr, base) ((ptr) + (base)) +#endif + +static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases); + +#define _Unwind_Find_FDE _Unwind_Find_registered_FDE +#include "unwind-dw2-fde.c" +#undef _Unwind_Find_FDE + +#ifndef PT_GNU_EH_FRAME +#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550) +#endif + +struct unw_eh_callback_data +{ + _Unwind_Ptr pc; + void *tbase; + void *dbase; + void *func; + const fde *ret; + int check_cache; +}; + +struct unw_eh_frame_hdr +{ + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; +}; + +#define FRAME_HDR_CACHE_SIZE 8 + +static struct frame_hdr_cache_element +{ + _Unwind_Ptr pc_low; + _Unwind_Ptr pc_high; + _Unwind_Ptr load_base; + const ElfW(Phdr) *p_eh_frame_hdr; + const ElfW(Phdr) *p_dynamic; + struct frame_hdr_cache_element *link; +} frame_hdr_cache[FRAME_HDR_CACHE_SIZE]; + +static struct frame_hdr_cache_element *frame_hdr_cache_head; + +/* Like base_of_encoded_value, but take the base from a struct + unw_eh_callback_data instead of an _Unwind_Context. */ + +static _Unwind_Ptr +base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data) +{ + 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) data->tbase; + case DW_EH_PE_datarel: + return (_Unwind_Ptr) data->dbase; + default: + gcc_unreachable (); + } +} + +static int +_Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr) +{ + struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr; + const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic; + long n, match; +#ifdef __FRV_FDPIC__ + struct elf32_fdpic_loadaddr load_base; +#else + _Unwind_Ptr load_base; +#endif + const unsigned char *p; + const struct unw_eh_frame_hdr *hdr; + _Unwind_Ptr eh_frame; + struct object ob; + _Unwind_Ptr pc_low = 0, pc_high = 0; + + struct ext_dl_phdr_info + { + ElfW(Addr) dlpi_addr; + const char *dlpi_name; + const ElfW(Phdr) *dlpi_phdr; + ElfW(Half) dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + }; + + match = 0; + phdr = info->dlpi_phdr; + load_base = info->dlpi_addr; + p_eh_frame_hdr = NULL; + p_dynamic = NULL; + + struct frame_hdr_cache_element *prev_cache_entry = NULL, + *last_cache_entry = NULL; + + if (data->check_cache && size >= sizeof (struct ext_dl_phdr_info)) + { + static unsigned long long adds = -1ULL, subs; + struct ext_dl_phdr_info *einfo = (struct ext_dl_phdr_info *) info; + + /* We use a least recently used cache replacement policy. Also, + the most recently used cache entries are placed at the head + of the search chain. */ + + if (einfo->dlpi_adds == adds && einfo->dlpi_subs == subs) + { + /* Find data->pc in shared library cache. + Set load_base, p_eh_frame_hdr and p_dynamic + plus match from the cache and goto + "Read .eh_frame_hdr header." below. */ + + struct frame_hdr_cache_element *cache_entry; + + for (cache_entry = frame_hdr_cache_head; + cache_entry; + cache_entry = cache_entry->link) + { + if (data->pc >= cache_entry->pc_low + && data->pc < cache_entry->pc_high) + { + load_base = cache_entry->load_base; + p_eh_frame_hdr = cache_entry->p_eh_frame_hdr; + p_dynamic = cache_entry->p_dynamic; + + /* And move the entry we're using to the head. */ + if (cache_entry != frame_hdr_cache_head) + { + prev_cache_entry->link = cache_entry->link; + cache_entry->link = frame_hdr_cache_head; + frame_hdr_cache_head = cache_entry; + } + goto found; + } + + last_cache_entry = cache_entry; + /* Exit early if we found an unused entry. */ + if ((cache_entry->pc_low | cache_entry->pc_high) == 0) + break; + if (cache_entry->link != NULL) + prev_cache_entry = cache_entry; + } + } + else + { + adds = einfo->dlpi_adds; + subs = einfo->dlpi_subs; + /* Initialize the cache. Create a chain of cache entries, + with the final one terminated by a NULL link. */ + int i; + for (i = 0; i < FRAME_HDR_CACHE_SIZE; i++) + { + frame_hdr_cache[i].pc_low = 0; + frame_hdr_cache[i].pc_high = 0; + frame_hdr_cache[i].link = &frame_hdr_cache[i+1]; + } + frame_hdr_cache[i-1].link = NULL; + frame_hdr_cache_head = &frame_hdr_cache[0]; + data->check_cache = 0; + } + } + + /* Make sure struct dl_phdr_info is at least as big as we need. */ + if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + + sizeof (info->dlpi_phnum)) + return -1; + + /* See if PC falls into one of the loaded segments. Find the eh_frame + segment at the same time. */ + for (n = info->dlpi_phnum; --n >= 0; phdr++) + { + if (phdr->p_type == PT_LOAD) + { + _Unwind_Ptr vaddr = (_Unwind_Ptr) + __RELOC_POINTER (phdr->p_vaddr, load_base); + if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz) + { + match = 1; + pc_low = vaddr; + pc_high = vaddr + phdr->p_memsz; + } + } + else if (phdr->p_type == PT_GNU_EH_FRAME) + p_eh_frame_hdr = phdr; +#ifdef PT_SUNW_UNWIND + /* Sun ld emits PT_SUNW_UNWIND .eh_frame_hdr sections instead of + PT_SUNW_EH_FRAME/PT_GNU_EH_FRAME, so accept them as well. */ + else if (phdr->p_type == PT_SUNW_UNWIND) + p_eh_frame_hdr = phdr; +#endif + else if (phdr->p_type == PT_DYNAMIC) + p_dynamic = phdr; + } + + if (!match) + return 0; + + if (size >= sizeof (struct ext_dl_phdr_info)) + { + /* Move the cache entry we're about to overwrite to the head of + the list. If either last_cache_entry or prev_cache_entry are + NULL, that cache entry is already at the head. */ + if (last_cache_entry != NULL && prev_cache_entry != NULL) + { + prev_cache_entry->link = last_cache_entry->link; + last_cache_entry->link = frame_hdr_cache_head; + frame_hdr_cache_head = last_cache_entry; + } + + frame_hdr_cache_head->load_base = load_base; + frame_hdr_cache_head->p_eh_frame_hdr = p_eh_frame_hdr; + frame_hdr_cache_head->p_dynamic = p_dynamic; + frame_hdr_cache_head->pc_low = pc_low; + frame_hdr_cache_head->pc_high = pc_high; + } + + found: + + if (!p_eh_frame_hdr) + return 0; + + /* Read .eh_frame_hdr header. */ + hdr = (const struct unw_eh_frame_hdr *) + __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base); + if (hdr->version != 1) + return 1; + +#ifdef CRT_GET_RFIB_DATA +# ifdef __i386__ + data->dbase = NULL; + if (p_dynamic) + { + /* For dynamically linked executables and shared libraries, + DT_PLTGOT is the gp value for that object. */ + ElfW(Dyn) *dyn = (ElfW(Dyn) *) + __RELOC_POINTER (p_dynamic->p_vaddr, load_base); + for (; dyn->d_tag != DT_NULL ; dyn++) + if (dyn->d_tag == DT_PLTGOT) + { + data->dbase = (void *) dyn->d_un.d_ptr; +#if defined __linux__ + /* On IA-32 Linux, _DYNAMIC is writable and GLIBC has + relocated it. */ +#elif defined __sun__ && defined __svr4__ + /* On Solaris 2/x86, we need to do this ourselves. */ + data->dbase += load_base; +#endif + break; + } + } +# elif defined __FRV_FDPIC__ && defined __linux__ + data->dbase = load_base.got_value; +# elif defined __x86_64__ && defined __sun__ && defined __svr4__ + /* While CRT_GET_RFIB_DATA is also defined for 64-bit Solaris 10+/x86, it + doesn't apply since it uses DW_EH_PE_pcrel encoding. */ +# else +# error What is DW_EH_PE_datarel base on this platform? +# endif +#endif + + p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc, + base_from_cb_data (hdr->eh_frame_ptr_enc, + data), + (const unsigned char *) (hdr + 1), + &eh_frame); + + /* We require here specific table encoding to speed things up. + Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start + as base, not the processor specific DW_EH_PE_datarel. */ + if (hdr->fde_count_enc != DW_EH_PE_omit + && hdr->table_enc == (DW_EH_PE_datarel | DW_EH_PE_sdata4)) + { + _Unwind_Ptr fde_count; + + p = read_encoded_value_with_base (hdr->fde_count_enc, + base_from_cb_data (hdr->fde_count_enc, + data), + p, &fde_count); + /* Shouldn't happen. */ + if (fde_count == 0) + return 1; + if ((((_Unwind_Ptr) p) & 3) == 0) + { + struct fde_table { + signed initial_loc __attribute__ ((mode (SI))); + signed fde __attribute__ ((mode (SI))); + }; + const struct fde_table *table = (const struct fde_table *) p; + size_t lo, hi, mid; + _Unwind_Ptr data_base = (_Unwind_Ptr) hdr; + fde *f; + unsigned int f_enc, f_enc_size; + _Unwind_Ptr range; + + mid = fde_count - 1; + if (data->pc < table[0].initial_loc + data_base) + return 1; + else if (data->pc < table[mid].initial_loc + data_base) + { + lo = 0; + hi = mid; + + while (lo < hi) + { + mid = (lo + hi) / 2; + if (data->pc < table[mid].initial_loc + data_base) + hi = mid; + else if (data->pc >= table[mid + 1].initial_loc + data_base) + lo = mid + 1; + else + break; + } + + gcc_assert (lo < hi); + } + + f = (fde *) (table[mid].fde + data_base); + f_enc = get_fde_encoding (f); + f_enc_size = size_of_encoded_value (f_enc); + read_encoded_value_with_base (f_enc & 0x0f, 0, + &f->pc_begin[f_enc_size], &range); + if (data->pc < table[mid].initial_loc + data_base + range) + data->ret = f; + data->func = (void *) (table[mid].initial_loc + data_base); + return 1; + } + } + + /* We have no sorted search table, so need to go the slow way. + As soon as GLIBC will provide API so to notify that a library has been + removed, we could cache this (and thus use search_object). */ + ob.pc_begin = NULL; + ob.tbase = data->tbase; + ob.dbase = data->dbase; + ob.u.single = (fde *) eh_frame; + ob.s.i = 0; + ob.s.b.mixed_encoding = 1; /* Need to assume worst case. */ + data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc); + if (data->ret != NULL) + { + _Unwind_Ptr func; + unsigned int encoding = get_fde_encoding (data->ret); + + read_encoded_value_with_base (encoding, + base_from_cb_data (encoding, data), + data->ret->pc_begin, &func); + data->func = (void *) func; + } + return 1; +} + +const fde * +_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) +{ + struct unw_eh_callback_data data; + const fde *ret; + + ret = _Unwind_Find_registered_FDE (pc, bases); + if (ret != NULL) + return ret; + + data.pc = (_Unwind_Ptr) pc; + data.tbase = NULL; + data.dbase = NULL; + data.func = NULL; + data.ret = NULL; + data.check_cache = 1; + + if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0) + return NULL; + + if (data.ret) + { + bases->tbase = data.tbase; + bases->dbase = data.dbase; + bases->func = data.func; + } + return data.ret; +} + +#else +/* Prevent multiple include of header files. */ +#define _Unwind_Find_FDE _Unwind_Find_FDE +#include "unwind-dw2-fde.c" +#endif + +#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) +alias (_Unwind_Find_FDE); +#endif diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c new file mode 100644 index 00000000000..93d427165c4 --- /dev/null +++ b/libgcc/unwind-dw2-fde.c @@ -0,0 +1,1054 @@ +/* Subroutines needed for unwinding stack frames for exception handling. */ +/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008, + 2009, 2010 Free Software Foundation, Inc. + Contributed by Jason Merrill . + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#ifndef _Unwind_Find_FDE +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#define NO_BASE_OF_ENCODED_VALUE +#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 + its 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 __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 + +/* Called from crtbegin.o to register the unwind info for an object. */ + +void +__register_frame_info_bases (const void *begin, struct object *ob, + void *tbase, void *dbase) +{ + /* If .eh_frame is empty, don't register at all. */ + if ((const uword *) begin == 0 || *(const uword *) begin == 0) + return; + + 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; +#ifdef DWARF2_OBJECT_END_PTR_EXTENSION + ob->fde_end = NULL; +#endif + + init_object_mutex_once (); + __gthread_mutex_lock (&object_mutex); + + ob->next = unseen_objects; + unseen_objects = ob; + + __gthread_mutex_unlock (&object_mutex); +} + +void +__register_frame_info (const void *begin, struct object *ob) +{ + __register_frame_info_bases (begin, ob, 0, 0); +} + +void +__register_frame (void *begin) +{ + struct object *ob; + + /* If .eh_frame is empty, don't register at all. */ + if (*(uword *) begin == 0) + return; + + ob = 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 (); + __gthread_mutex_lock (&object_mutex); + + ob->next = unseen_objects; + unseen_objects = ob; + + __gthread_mutex_unlock (&object_mutex); +} + +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 = 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 die. + + 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 (const void *begin) +{ + struct object **p; + struct object *ob = 0; + + /* If .eh_frame is empty, we haven't registered. */ + if ((const uword *) begin == 0 || *(const uword *) begin == 0) + return ob; + + init_object_mutex_once (); + __gthread_mutex_lock (&object_mutex); + + 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; + } + } + + out: + __gthread_mutex_unlock (&object_mutex); + gcc_assert (ob); + return (void *) ob; +} + +void * +__deregister_frame_info (const void *begin) +{ + return __deregister_frame_info_bases (begin); +} + +void +__deregister_frame (void *begin) +{ + /* If .eh_frame is empty, we haven't registered. */ + if (*(uword *) begin != 0) + 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; + default: + gcc_unreachable (); + } +} + +/* 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 (const struct dwarf_cie *cie) +{ + const unsigned char *aug, *p; + _Unwind_Ptr dummy; + _uleb128_t utmp; + _sleb128_t stmp; + + aug = cie->augmentation; + p = aug + strlen ((const char *)aug) + 1; /* Skip the augmentation string. */ + if (__builtin_expect (cie->version >= 4, 0)) + { + if (p[0] != sizeof (void *) || p[1] != 0) + return DW_EH_PE_omit; /* We are not prepared to handle unexpected + address sizes or segment selectors. */ + p += 2; /* Skip address size and segment size. */ + } + + if (aug[0] != 'z') + return DW_EH_PE_absptr; + + p = read_uleb128 (p, &utmp); /* Skip code alignment. */ + p = read_sleb128 (p, &stmp); /* Skip data alignment. */ + if (cie->version == 1) /* Skip return address column. */ + p++; + else + p = read_uleb128 (p, &utmp); + + aug++; /* Skip 'z' */ + p = read_uleb128 (p, &utmp); /* 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 (const 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 int +fde_unencoded_compare (struct object *ob __attribute__((unused)), + const fde *x, const fde *y) +{ + _Unwind_Ptr x_ptr, y_ptr; + memcpy (&x_ptr, x->pc_begin, sizeof (_Unwind_Ptr)); + memcpy (&y_ptr, y->pc_begin, sizeof (_Unwind_Ptr)); + + if (x_ptr > y_ptr) + return 1; + if (x_ptr < y_ptr) + return -1; + return 0; +} + +static int +fde_single_encoding_compare (struct object *ob, const fde *x, const 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); + + if (x_ptr > y_ptr) + return 1; + if (x_ptr < y_ptr) + return -1; + return 0; +} + +static int +fde_mixed_encoding_compare (struct object *ob, const fde *x, const 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); + + if (x_ptr > y_ptr) + return 1; + if (x_ptr < y_ptr) + return -1; + return 0; +} + +typedef int (*fde_compare_t) (struct object *, const fde *, const 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 (const fde *) * count; + if ((accu->linear = malloc (size))) + { + accu->linear->count = 0; + if ((accu->erratic = malloc (size))) + accu->erratic->count = 0; + return 1; + } + else + return 0; +} + +static inline void +fde_insert (struct fde_accumulator *accu, const 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 const fde *marker; + size_t count = linear->count; + const fde *const *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. */ + gcc_assert (sizeof (const fde *) == sizeof (const fde **)); + + for (i = 0; i < count; i++) + { + const fde *const *probe; + + for (probe = chain_end; + probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0; + probe = chain_end) + { + chain_end = (const fde *const*) erratic->array[probe - linear->array]; + erratic->array[probe - linear->array] = NULL; + } + erratic->array[i] = (const 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; +} + +#define SWAP(x,y) do { const fde * tmp = x; x = y; y = tmp; } while (0) + +/* Convert a semi-heap to a heap. A semi-heap is a heap except possibly + for the first (root) node; push it down to its rightful place. */ + +static void +frame_downheap (struct object *ob, fde_compare_t fde_compare, const fde **a, + int lo, int hi) +{ + int i, j; + + for (i = lo, j = 2*i+1; + j < hi; + j = 2*i+1) + { + if (j+1 < hi && fde_compare (ob, a[j], a[j+1]) < 0) + ++j; + + if (fde_compare (ob, a[i], a[j]) < 0) + { + SWAP (a[i], a[j]); + i = j; + } + else + break; + } +} + +/* 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. */ + const 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]. */ + size_t n = erratic->count; + int m; + + /* Expand our heap incrementally from the end of the array, heapifying + each resulting semi-heap as we go. After each step, a[m] is the top + of a heap. */ + for (m = n/2-1; m >= 0; --m) + frame_downheap (ob, fde_compare, a, m, n); + + /* Shrink our heap incrementally from the end of the array, first + swapping out the largest element a[0] and then re-heapifying the + resulting semi-heap. After each step, a[0..m) is a heap. */ + for (m = n-1; m >= 1; --m) + { + SWAP (a[0], a[m]); + frame_downheap (ob, fde_compare, a, 0, m); + } +#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; + const 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; + + gcc_assert (!accu->linear || accu->linear->count == count); + + 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); + gcc_assert (accu->linear->count + accu->erratic->count == count); + 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, const fde *this_fde) +{ + const struct dwarf_cie *last_cie = 0; + size_t count = 0; + int encoding = DW_EH_PE_absptr; + _Unwind_Ptr base = 0; + + for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) + { + const 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); + if (encoding == DW_EH_PE_omit) + return -1; + 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 = (((_Unwind_Ptr) 1) << (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, const fde *this_fde) +{ + const struct dwarf_cie *last_cie = 0; + int encoding = ob->s.b.encoding; + _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob); + + for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) + { + const 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) + { + _Unwind_Ptr ptr; + memcpy (&ptr, this_fde->pc_begin, sizeof (_Unwind_Ptr)); + if (ptr == 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 = (((_Unwind_Ptr) 1) << (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) + { + size_t cur_count = classify_object_over_fdes (ob, *p); + if (cur_count == (size_t) -1) + goto unhandled_fdes; + count += cur_count; + } + } + else + { + count = classify_object_over_fdes (ob, ob->u.single); + if (count == (size_t) -1) + { + static const fde terminator; + unhandled_fdes: + ob->s.i = 0; + ob->s.b.encoding = DW_EH_PE_omit; + ob->u.single = &terminator; + return; + } + } + + /* 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 const fde * +linear_search_fdes (struct object *ob, const fde *this_fde, void *pc) +{ + const struct dwarf_cie *last_cie = 0; + int encoding = ob->s.b.encoding; + _Unwind_Ptr base = base_from_object (ob->s.b.encoding, ob); + + for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde)) + { + const 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) + { + const _Unwind_Ptr *pc_array = (const _Unwind_Ptr *) this_fde->pc_begin; + pc_begin = pc_array[0]; + pc_range = pc_array[1]; + if (pc_begin == 0) + continue; + } + else + { + _Unwind_Ptr mask; + const unsigned 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 = (((_Unwind_Ptr) 1) << (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 const 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; + const fde *const f = vec->array[i]; + void *pc_begin; + uaddr pc_range; + memcpy (&pc_begin, (const void * const *) f->pc_begin, sizeof (void *)); + memcpy (&pc_range, (const uaddr *) f->pc_begin + 1, sizeof (uaddr)); + + if (pc < pc_begin) + hi = i; + else if (pc >= pc_begin + pc_range) + lo = i + 1; + else + return f; + } + + return NULL; +} + +static inline const 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; + const fde *f = vec->array[i]; + _Unwind_Ptr pc_begin, pc_range; + const unsigned 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 const 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; + const fde *f = vec->array[i]; + _Unwind_Ptr pc_begin, pc_range; + const unsigned 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 const 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 laborious linear search, cos we've no memory. */ + if (ob->s.b.from_array) + { + fde **p; + for (p = ob->u.array; *p ; p++) + { + const fde *f = linear_search_fdes (ob, *p, pc); + if (f) + return f; + } + return NULL; + } + else + return linear_search_fdes (ob, ob->u.single, pc); + } +} + +const fde * +_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) +{ + struct object *ob; + const fde *f = NULL; + + init_object_mutex_once (); + __gthread_mutex_lock (&object_mutex); + + /* Linear search through the classified objects, to find the one + containing the pc. Note that pc_begin is sorted descending, 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: + __gthread_mutex_unlock (&object_mutex); + + if (f) + { + int encoding; + _Unwind_Ptr func; + + 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, &func); + bases->func = (void *) func; + } + + return f; +} diff --git a/libgcc/unwind-dw2-fde.h b/libgcc/unwind-dw2-fde.h new file mode 100644 index 00000000000..6d7a8dee2cf --- /dev/null +++ b/libgcc/unwind-dw2-fde.h @@ -0,0 +1,183 @@ +/* Subroutines needed for unwinding stack frames for exception handling. */ +/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2009 + Free Software Foundation, Inc. + Contributed by Jason Merrill . + +This file is part of GCC. + +GCC 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 3, or (at your option) any later +version. + +GCC 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#ifndef GCC_UNWIND_DW2_FDE_H +#define GCC_UNWIND_DW2_FDE_H + +#ifndef HIDE_EXPORTS +#pragma GCC visibility push(default) +#endif + +struct fde_vector +{ + const void *orig_data; + size_t count; + const struct dwarf_fde *array[]; +}; + +struct object +{ + void *pc_begin; + void *tbase; + void *dbase; + union { + const 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; + +#ifdef DWARF2_OBJECT_END_PTR_EXTENSION + char *fde_end; +#endif + + struct object *next; +}; + +/* 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; +}; + +struct dwarf_eh_bases +{ + void *tbase; + void *dbase; + void *func; +}; + + +extern void __register_frame_info_bases (const void *, struct object *, + void *, void *); +extern void __register_frame_info (const 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 (const void *); +extern void *__deregister_frame_info_bases (const 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 specification, 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[]; +} __attribute__ ((packed, aligned (__alignof__ (void *)))); + +/* The first few fields of an FDE. */ +struct dwarf_fde +{ + uword length; + sword CIE_delta; + unsigned char pc_begin[]; +} __attribute__ ((packed, aligned (__alignof__ (void *)))); + +typedef struct dwarf_fde fde; + +/* Locate the CIE for a given FDE. */ + +static inline const struct dwarf_cie * +get_cie (const struct dwarf_fde *f) +{ + return (const void *)&f->CIE_delta - f->CIE_delta; +} + +static inline const fde * +next_fde (const fde *f) +{ + return (const fde *) ((const char *) f + f->length + sizeof (f->length)); +} + +extern const fde * _Unwind_Find_FDE (void *, struct dwarf_eh_bases *); + +static inline int +last_fde (struct object *obj __attribute__ ((__unused__)), const fde *f) +{ +#ifdef DWARF2_OBJECT_END_PTR_EXTENSION + return (char *)f == obj->fde_end || f->length == 0; +#else + return f->length == 0; +#endif +} + +#ifndef HIDE_EXPORTS +#pragma GCC visibility pop +#endif + +#endif /* unwind-dw2-fde.h */ diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c new file mode 100644 index 00000000000..19da29982b6 --- /dev/null +++ b/libgcc/unwind-dw2.c @@ -0,0 +1,1611 @@ +/* DWARF2 exception handling and frame unwind runtime interface routines. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "dwarf2.h" +#include "unwind.h" +#ifdef __USING_SJLJ_EXCEPTIONS__ +# define NO_SIZE_OF_ENCODED_VALUE +#endif +#include "unwind-pe.h" +#include "unwind-dw2-fde.h" +#include "gthr.h" +#include "unwind-dw2.h" + +#ifdef HAVE_SYS_SDT_H +#include +#endif + +#ifndef __USING_SJLJ_EXCEPTIONS__ + +#ifndef STACK_GROWS_DOWNWARD +#define STACK_GROWS_DOWNWARD 0 +#else +#undef STACK_GROWS_DOWNWARD +#define STACK_GROWS_DOWNWARD 1 +#endif + +/* Dwarf frame registers used for pre gcc 3.0 compiled glibc. */ +#ifndef PRE_GCC3_DWARF_FRAME_REGISTERS +#define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS +#endif + +#ifndef DWARF_REG_TO_UNWIND_COLUMN +#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) +#endif + +/* This is the register and unwind state for a particular frame. This + provides the information necessary to unwind up past a frame and return + to its caller. */ +struct _Unwind_Context +{ + void *reg[DWARF_FRAME_REGISTERS+1]; + void *cfa; + void *ra; + void *lsda; + struct dwarf_eh_bases bases; + /* Signal frame context. */ +#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) + /* Context which has version/args_size/by_value fields. */ +#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1) + _Unwind_Word flags; + /* 0 for now, can be increased when further fields are added to + struct _Unwind_Context. */ + _Unwind_Word version; + _Unwind_Word args_size; + char by_value[DWARF_FRAME_REGISTERS+1]; +}; + +/* Byte size of every register managed by these routines. */ +static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1]; + + +/* 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 void uw_update_context (struct _Unwind_Context *, _Unwind_FrameState *); +static _Unwind_Reason_Code uw_frame_state_for (struct _Unwind_Context *, + _Unwind_FrameState *); + +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; } + +static inline _Unwind_Word +_Unwind_IsSignalFrame (struct _Unwind_Context *context) +{ + return (context->flags & SIGNAL_FRAME_BIT) ? 1 : 0; +} + +static inline void +_Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) +{ + if (val) + context->flags |= SIGNAL_FRAME_BIT; + else + context->flags &= ~SIGNAL_FRAME_BIT; +} + +static inline _Unwind_Word +_Unwind_IsExtendedContext (struct _Unwind_Context *context) +{ + return context->flags & EXTENDED_CONTEXT_BIT; +} + +/* Get the value of register INDEX as saved in CONTEXT. */ + +inline _Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + int size; + void *ptr; + +#ifdef DWARF_ZERO_REG + if (index == DWARF_ZERO_REG) + return 0; +#endif + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); + size = dwarf_reg_size_table[index]; + ptr = context->reg[index]; + + if (_Unwind_IsExtendedContext (context) && context->by_value[index]) + return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr; + + /* This will segfault if the register hasn't been saved. */ + if (size == sizeof(_Unwind_Ptr)) + return * (_Unwind_Ptr *) ptr; + else + { + gcc_assert (size == sizeof(_Unwind_Word)); + return * (_Unwind_Word *) ptr; + } +} + +static inline void * +_Unwind_GetPtr (struct _Unwind_Context *context, int index) +{ + return (void *)(_Unwind_Ptr) _Unwind_GetGR (context, index); +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->cfa; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +inline void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + int size; + void *ptr; + + index = DWARF_REG_TO_UNWIND_COLUMN (index); + gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); + size = dwarf_reg_size_table[index]; + + if (_Unwind_IsExtendedContext (context) && context->by_value[index]) + { + context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; + return; + } + + ptr = context->reg[index]; + + if (size == sizeof(_Unwind_Ptr)) + * (_Unwind_Ptr *) ptr = val; + else + { + gcc_assert (size == sizeof(_Unwind_Word)); + * (_Unwind_Word *) ptr = val; + } +} + +/* Get the pointer to a register INDEX as saved in CONTEXT. */ + +static inline void * +_Unwind_GetGRPtr (struct _Unwind_Context *context, int index) +{ + index = DWARF_REG_TO_UNWIND_COLUMN (index); + if (_Unwind_IsExtendedContext (context) && context->by_value[index]) + return &context->reg[index]; + return context->reg[index]; +} + +/* Set the pointer to a register INDEX as saved in CONTEXT. */ + +static inline void +_Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) +{ + index = DWARF_REG_TO_UNWIND_COLUMN (index); + if (_Unwind_IsExtendedContext (context)) + context->by_value[index] = 0; + context->reg[index] = p; +} + +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +static inline void +_Unwind_SetGRValue (struct _Unwind_Context *context, int index, + _Unwind_Word val) +{ + index = DWARF_REG_TO_UNWIND_COLUMN (index); + gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); + gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr)); + + context->by_value[index] = 1; + context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; +} + +/* Return nonzero if register INDEX is stored by value rather than + by reference. */ + +static inline int +_Unwind_GRByValue (struct _Unwind_Context *context, int index) +{ + index = DWARF_REG_TO_UNWIND_COLUMN (index); + return context->by_value[index]; +} + +/* Retrieve the return address for CONTEXT. */ + +inline _Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->ra; +} + +/* Retrieve the return address and flag whether that IP is before + or after first not yet fully executed instruction. */ + +inline _Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = _Unwind_IsSignalFrame (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; +} + +void * +_Unwind_FindEnclosingFunction (void *pc) +{ + struct dwarf_eh_bases bases; + const struct dwarf_fde *fde = _Unwind_Find_FDE (pc-1, &bases); + if (fde) + return bases.func; + else + return NULL; +} + +#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 + +#include "md-unwind-support.h" + +/* 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 (const struct dwarf_cie *cie, struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + const unsigned char *aug = cie->augmentation; + const unsigned char *p = aug + strlen ((const char *)aug) + 1; + const unsigned char *ret = NULL; + _uleb128_t utmp; + _sleb128_t stmp; + + /* g++ v2 "eh" has pointer immediately following augmentation string, + so it must be handled first. */ + if (aug[0] == 'e' && aug[1] == 'h') + { + fs->eh_ptr = read_pointer (p); + p += sizeof (void *); + aug += 2; + } + + /* After the augmentation resp. pointer for "eh" augmentation + follows for CIE version >= 4 address size byte and + segment size byte. */ + if (__builtin_expect (cie->version >= 4, 0)) + { + if (p[0] != sizeof (void *) || p[1] != 0) + return NULL; + p += 2; + } + /* Immediately following this are the code and + data alignment and return address column. */ + p = read_uleb128 (p, &utmp); + fs->code_align = (_Unwind_Word)utmp; + p = read_sleb128 (p, &stmp); + fs->data_align = (_Unwind_Sword)stmp; + if (cie->version == 1) + fs->retaddr_column = *p++; + else + { + p = read_uleb128 (p, &utmp); + fs->retaddr_column = (_Unwind_Word)utmp; + } + 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, &utmp); + ret = p + utmp; + + fs->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') + { + 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') + { + _Unwind_Ptr personality; + + p = read_encoded_value (context, *p, p + 1, &personality); + fs->personality = (_Unwind_Personality_Fn) personality; + aug += 1; + } + + /* "S" indicates a signal frame. */ + else if (aug[0] == 'S') + { + fs->signal_frame = 1; + 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; + _uleb128_t reg, utmp; + _sleb128_t offset, stmp; + + 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_GNU_encoded_addr: + { + _Unwind_Ptr presult; + op_ptr = read_encoded_value (context, *op_ptr, op_ptr+1, &presult); + result = presult; + } + 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, &utmp); + result = (_Unwind_Word)utmp; + break; + case DW_OP_consts: + op_ptr = read_sleb128 (op_ptr, &stmp); + result = (_Unwind_Sword)stmp; + 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, ®); + 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, &offset); + result = _Unwind_GetGR (context, op - DW_OP_breg0) + offset; + break; + case DW_OP_bregx: + op_ptr = read_uleb128 (op_ptr, ®); + op_ptr = read_sleb128 (op_ptr, &offset); + result = _Unwind_GetGR (context, reg) + (_Unwind_Word)offset; + break; + + case DW_OP_dup: + gcc_assert (stack_elt); + result = stack[stack_elt - 1]; + break; + + case DW_OP_drop: + gcc_assert (stack_elt); + stack_elt -= 1; + goto no_push; + + case DW_OP_pick: + offset = *op_ptr++; + gcc_assert (offset < stack_elt - 1); + result = stack[stack_elt - 1 - offset]; + break; + + case DW_OP_over: + gcc_assert (stack_elt >= 2); + result = stack[stack_elt - 2]; + break; + + case DW_OP_swap: + { + _Unwind_Word t; + gcc_assert (stack_elt >= 2); + t = stack[stack_elt - 1]; + stack[stack_elt - 1] = stack[stack_elt - 2]; + stack[stack_elt - 2] = t; + goto no_push; + } + + case DW_OP_rot: + { + _Unwind_Word t1, t2, t3; + + gcc_assert (stack_elt >= 3); + 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. */ + gcc_assert (stack_elt); + stack_elt -= 1; + + 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: + gcc_unreachable (); + } + } + 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, &utmp); + result += (_Unwind_Word)utmp; + break; + + default: + gcc_unreachable (); + } + 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_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + 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; + gcc_assert (stack_elt >= 2); + stack_elt -= 2; + + 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 = second % 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) second <= (_Unwind_Sword) first; + break; + case DW_OP_ge: + result = (_Unwind_Sword) second >= (_Unwind_Sword) first; + break; + case DW_OP_eq: + result = (_Unwind_Sword) second == (_Unwind_Sword) first; + break; + case DW_OP_lt: + result = (_Unwind_Sword) second < (_Unwind_Sword) first; + break; + case DW_OP_gt: + result = (_Unwind_Sword) second > (_Unwind_Sword) first; + break; + case DW_OP_ne: + result = (_Unwind_Sword) second != (_Unwind_Sword) first; + break; + + default: + gcc_unreachable (); + } + } + break; + + case DW_OP_skip: + offset = read_2s (op_ptr); + op_ptr += 2; + op_ptr += offset; + goto no_push; + + case DW_OP_bra: + gcc_assert (stack_elt); + stack_elt -= 1; + + 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: + gcc_unreachable (); + } + + /* Most things push a result value. */ + gcc_assert ((size_t) stack_elt < sizeof(stack)/sizeof(*stack)); + stack[stack_elt++] = result; + no_push:; + } + + /* We were executing this program to get a value. It should be + at top of stack. */ + gcc_assert (stack_elt); + stack_elt -= 1; + return stack[stack_elt]; +} + + +/* 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; + + /* The comparison with the return address uses < rather than <= because + we are only interested in the effects of code before the call; for a + noreturn function, the return address may point to unrelated code with + a different stack configuration that we are not interested in. We + assume that the call itself is unwind info-neutral; if not, or if + there are delay instructions that adjust the stack, these must be + reflected at the point immediately before the call insn. + In signal frames, return address is after last completed instruction, + so we add 1 to return address to make the comparison <=. */ + while (insn_ptr < insn_end + && fs->pc < context->ra + _Unwind_IsSignalFrame (context)) + { + unsigned char insn = *insn_ptr++; + _uleb128_t reg, utmp; + _sleb128_t offset, stmp; + + if ((insn & 0xc0) == DW_CFA_advance_loc) + fs->pc += (insn & 0x3f) * fs->code_align; + else if ((insn & 0xc0) == DW_CFA_offset) + { + reg = insn & 0x3f; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + offset = (_Unwind_Sword) utmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; + } + else if ((insn & 0xc0) == DW_CFA_restore) + { + reg = insn & 0x3f; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED; + } + else switch (insn) + { + case DW_CFA_set_loc: + { + _Unwind_Ptr pc; + + insn_ptr = read_encoded_value (context, fs->fde_encoding, + insn_ptr, &pc); + fs->pc = (void *) 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, ®); + insn_ptr = read_uleb128 (insn_ptr, &utmp); + offset = (_Unwind_Sword) utmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; + break; + + case DW_CFA_restore_extended: + insn_ptr = read_uleb128 (insn_ptr, ®); + /* FIXME, this is wrong; the CIE might have said that the + register was saved somewhere. */ + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; + break; + + case DW_CFA_same_value: + insn_ptr = read_uleb128 (insn_ptr, ®); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED; + break; + + case DW_CFA_undefined: + insn_ptr = read_uleb128 (insn_ptr, ®); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNDEFINED; + break; + + case DW_CFA_nop: + break; + + case DW_CFA_register: + { + _uleb128_t reg2; + insn_ptr = read_uleb128 (insn_ptr, ®); + insn_ptr = read_uleb128 (insn_ptr, ®2); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg = + (_Unwind_Word)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, &utmp); + fs->regs.cfa_reg = (_Unwind_Word)utmp; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->regs.cfa_offset = (_Unwind_Word)utmp; + fs->regs.cfa_how = CFA_REG_OFFSET; + break; + + case DW_CFA_def_cfa_register: + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->regs.cfa_reg = (_Unwind_Word)utmp; + fs->regs.cfa_how = CFA_REG_OFFSET; + break; + + case DW_CFA_def_cfa_offset: + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->regs.cfa_offset = utmp; + /* cfa_how deliberately not set. */ + break; + + case DW_CFA_def_cfa_expression: + fs->regs.cfa_exp = insn_ptr; + fs->regs.cfa_how = CFA_EXP; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + insn_ptr += utmp; + break; + + case DW_CFA_expression: + insn_ptr = read_uleb128 (insn_ptr, ®); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + insn_ptr += utmp; + break; + + /* Dwarf3. */ + case DW_CFA_offset_extended_sf: + insn_ptr = read_uleb128 (insn_ptr, ®); + insn_ptr = read_sleb128 (insn_ptr, &stmp); + offset = stmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; + break; + + case DW_CFA_def_cfa_sf: + insn_ptr = read_uleb128 (insn_ptr, &utmp); + fs->regs.cfa_reg = (_Unwind_Word)utmp; + insn_ptr = read_sleb128 (insn_ptr, &stmp); + fs->regs.cfa_offset = (_Unwind_Sword)stmp; + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_offset *= fs->data_align; + break; + + case DW_CFA_def_cfa_offset_sf: + insn_ptr = read_sleb128 (insn_ptr, &stmp); + fs->regs.cfa_offset = (_Unwind_Sword)stmp; + fs->regs.cfa_offset *= fs->data_align; + /* cfa_how deliberately not set. */ + break; + + case DW_CFA_val_offset: + insn_ptr = read_uleb128 (insn_ptr, ®); + insn_ptr = read_uleb128 (insn_ptr, &utmp); + offset = (_Unwind_Sword) utmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_VAL_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; + break; + + case DW_CFA_val_offset_sf: + insn_ptr = read_uleb128 (insn_ptr, ®); + insn_ptr = read_sleb128 (insn_ptr, &stmp); + offset = stmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_VAL_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset; + break; + + case DW_CFA_val_expression: + insn_ptr = read_uleb128 (insn_ptr, ®); + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_VAL_EXP; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr; + insn_ptr = read_uleb128 (insn_ptr, &utmp); + insn_ptr += utmp; + 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, &utmp); + context->args_size = (_Unwind_Word)utmp; + 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, ®); + insn_ptr = read_uleb128 (insn_ptr, &utmp); + offset = (_Unwind_Word) utmp * fs->data_align; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how + = REG_SAVED_OFFSET; + fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset; + break; + + default: + gcc_unreachable (); + } + } +} + +/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for + its caller and decode it into FS. This function also sets the + args_size and lsda members of CONTEXT, as they are really information + about the caller's frame. */ + +static _Unwind_Reason_Code +uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + const struct dwarf_fde *fde; + const struct dwarf_cie *cie; + const unsigned char *aug, *insn, *end; + + memset (fs, 0, sizeof (*fs)); + context->args_size = 0; + context->lsda = 0; + + if (context->ra == 0) + return _URC_END_OF_STACK; + + fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1, + &context->bases); + if (fde == NULL) + { +#ifdef MD_FALLBACK_FRAME_STATE_FOR + /* Couldn't find frame unwind info for this function. Try a + target-specific fallback mechanism. This will necessarily + not provide a personality routine or LSDA. */ + return MD_FALLBACK_FRAME_STATE_FOR (context, fs); +#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 = (const unsigned char *) next_fde ((const struct dwarf_fde *) cie); + execute_cfa_program (insn, end, context, fs); + + /* Locate augmentation for the fde. */ + aug = (const unsigned char *) fde + sizeof (*fde); + aug += 2 * size_of_encoded_value (fs->fde_encoding); + insn = NULL; + if (fs->saw_z) + { + _uleb128_t i; + aug = read_uleb128 (aug, &i); + insn = aug + i; + } + if (fs->lsda_encoding != DW_EH_PE_omit) + { + _Unwind_Ptr lsda; + + aug = read_encoded_value (context, fs->lsda_encoding, aug, &lsda); + context->lsda = (void *) lsda; + } + + /* Then the insns in the FDE up to our target PC. */ + if (insn == NULL) + insn = aug; + end = (const unsigned char *) next_fde (fde); + execute_cfa_program (insn, end, context, fs); + + return _URC_NO_REASON; +} + +typedef struct frame_state +{ + void *cfa; + void *eh_ptr; + long cfa_offset; + long args_size; + long reg_or_offset[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; + unsigned short cfa_reg; + unsigned short retaddr_column; + char saved[PRE_GCC3_DWARF_FRAME_REGISTERS+1]; +} frame_state; + +struct frame_state * __frame_state_for (void *, struct frame_state *); + +/* Called from pre-G++ 3.0 __throw to find the registers to restore for + a given PC_TARGET. The caller should allocate a local variable of + `struct frame_state' and pass its address to STATE_IN. */ + +struct frame_state * +__frame_state_for (void *pc_target, struct frame_state *state_in) +{ + struct _Unwind_Context context; + _Unwind_FrameState fs; + int reg; + + memset (&context, 0, sizeof (struct _Unwind_Context)); + context.flags = EXTENDED_CONTEXT_BIT; + context.ra = pc_target + 1; + + if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON) + return 0; + + /* We have no way to pass a location expression for the CFA to our + caller. It wouldn't understand it anyway. */ + if (fs.regs.cfa_how == CFA_EXP) + return 0; + + for (reg = 0; reg < PRE_GCC3_DWARF_FRAME_REGISTERS + 1; reg++) + { + state_in->saved[reg] = fs.regs.reg[reg].how; + switch (state_in->saved[reg]) + { + case REG_SAVED_REG: + state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.reg; + break; + case REG_SAVED_OFFSET: + state_in->reg_or_offset[reg] = fs.regs.reg[reg].loc.offset; + break; + default: + state_in->reg_or_offset[reg] = 0; + break; + } + } + + state_in->cfa_offset = fs.regs.cfa_offset; + state_in->cfa_reg = fs.regs.cfa_reg; + state_in->retaddr_column = fs.retaddr_column; + state_in->args_size = context.args_size; + state_in->eh_ptr = fs.eh_ptr; + + return state_in; +} + +typedef union { _Unwind_Ptr ptr; _Unwind_Word word; } _Unwind_SpTmp; + +static inline void +_Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa, + _Unwind_SpTmp *tmp_sp) +{ + int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()]; + + if (size == sizeof(_Unwind_Ptr)) + tmp_sp->ptr = (_Unwind_Ptr) cfa; + else + { + gcc_assert (size == sizeof(_Unwind_Word)); + tmp_sp->word = (_Unwind_Ptr) cfa; + } + _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp); +} + +static void +uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + struct _Unwind_Context orig_context = *context; + void *cfa; + long i; + +#ifdef EH_RETURN_STACKADJ_RTX + /* 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. + + In very special situations (such as unwind info for signal return), + there may be location expressions that use the stack pointer as well. + + Do this conditionally for one frame. This allows the unwind info + for one frame to save a copy of the stack pointer from the previous + frame, and be able to use much easier CFA mechanisms to do it. + Always zap the saved stack pointer value for the next frame; carrying + the value over from one frame to another doesn't make sense. */ + + _Unwind_SpTmp tmp_sp; + + if (!_Unwind_GetGRPtr (&orig_context, __builtin_dwarf_sp_column ())) + _Unwind_SetSpColumn (&orig_context, context->cfa, &tmp_sp); + _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), NULL); +#endif + + /* Compute this frame's CFA. */ + switch (fs->regs.cfa_how) + { + case CFA_REG_OFFSET: + cfa = _Unwind_GetPtr (&orig_context, fs->regs.cfa_reg); + cfa += fs->regs.cfa_offset; + break; + + case CFA_EXP: + { + const unsigned char *exp = fs->regs.cfa_exp; + _uleb128_t len; + + exp = read_uleb128 (exp, &len); + cfa = (void *) (_Unwind_Ptr) + execute_stack_op (exp, exp + len, &orig_context, 0); + break; + } + + default: + gcc_unreachable (); + } + 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: + case REG_UNDEFINED: + break; + + case REG_SAVED_OFFSET: + _Unwind_SetGRPtr (context, i, + (void *) (cfa + fs->regs.reg[i].loc.offset)); + break; + + case REG_SAVED_REG: + if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg)) + _Unwind_SetGRValue (context, i, + _Unwind_GetGR (&orig_context, + fs->regs.reg[i].loc.reg)); + else + _Unwind_SetGRPtr (context, i, + _Unwind_GetGRPtr (&orig_context, + fs->regs.reg[i].loc.reg)); + break; + + case REG_SAVED_EXP: + { + const unsigned char *exp = fs->regs.reg[i].loc.exp; + _uleb128_t len; + _Unwind_Ptr val; + + exp = read_uleb128 (exp, &len); + val = execute_stack_op (exp, exp + len, &orig_context, + (_Unwind_Ptr) cfa); + _Unwind_SetGRPtr (context, i, (void *) val); + } + break; + + case REG_SAVED_VAL_OFFSET: + _Unwind_SetGRValue (context, i, + (_Unwind_Internal_Ptr) + (cfa + fs->regs.reg[i].loc.offset)); + break; + + case REG_SAVED_VAL_EXP: + { + const unsigned char *exp = fs->regs.reg[i].loc.exp; + _uleb128_t len; + _Unwind_Ptr val; + + exp = read_uleb128 (exp, &len); + val = execute_stack_op (exp, exp + len, &orig_context, + (_Unwind_Ptr) cfa); + _Unwind_SetGRValue (context, i, val); + } + break; + } + + _Unwind_SetSignalFrame (context, fs->signal_frame); + +#ifdef MD_FROB_UPDATE_CONTEXT + MD_FROB_UPDATE_CONTEXT (context, fs); +#endif +} + +/* CONTEXT describes the unwind state for a frame, and FS describes the FDE + of its caller. Update CONTEXT to refer to the caller as well. Note + that the args_size and lsda members are not updated here, but later in + uw_frame_state_for. */ + +static void +uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context_1 (context, fs); + + /* In general this unwinder doesn't make any distinction between + undefined and same_value rule. Call-saved registers are assumed + to have same_value rule by default and explicit undefined + rule is handled like same_value. The only exception is + DW_CFA_undefined on retaddr_column which is supposed to + mark outermost frame in DWARF 3. */ + if (fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (fs->retaddr_column)].how + == REG_UNDEFINED) + /* uw_frame_state_for uses context->ra == 0 check to find outermost + stack frame. */ + context->ra = 0; + else + /* Compute the return address now, since the return address column + can change from frame to frame. */ + context->ra = __builtin_extract_return_addr + (_Unwind_GetPtr (context, fs->retaddr_column)); +} + +static void +uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + uw_update_context (context, fs); +} + +/* 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 inline void +init_dwarf_reg_size_table (void) +{ + __builtin_init_dwarf_reg_size_table (dwarf_reg_size_table); +} + +static void __attribute__((noinline)) +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; + _Unwind_SpTmp sp_slot; + _Unwind_Reason_Code code; + + memset (context, 0, sizeof (struct _Unwind_Context)); + context->ra = ra; + context->flags = EXTENDED_CONTEXT_BIT; + + code = uw_frame_state_for (context, &fs); + gcc_assert (code == _URC_NO_REASON); + +#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 + + /* Force the frame state to use the known cfa value. */ + _Unwind_SetSpColumn (context, outer_cfa, &sp_slot); + fs.regs.cfa_how = CFA_REG_OFFSET; + fs.regs.cfa_reg = __builtin_dwarf_sp_column (); + fs.regs.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); +} + +static void _Unwind_DebugHook (void *, void *) + __attribute__ ((__noinline__, __used__, __noclone__)); + +/* This function is called during unwinding. It is intended as a hook + for a debugger to intercept exceptions. CFA is the CFA of the + target frame. HANDLER is the PC to which control will be + transferred. */ +static void +_Unwind_DebugHook (void *cfa __attribute__ ((__unused__)), + void *handler __attribute__ ((__unused__))) +{ + /* We only want to use stap probes starting with v3. Earlier + versions added too much startup cost. */ +#if defined (HAVE_SYS_SDT_H) && defined (STAP_PROBE2) && _SDT_NOTE_TYPE >= 3 + STAP_PROBE2 (libgcc, unwind, cfa, handler); +#else + asm (""); +#endif +} + +/* 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); \ + _Unwind_DebugHook ((TARGET)->cfa, handler); \ + __builtin_eh_return (offset, handler); \ + } \ + while (0) + +static long +uw_install_context_1 (struct _Unwind_Context *current, + struct _Unwind_Context *target) +{ + long i; + _Unwind_SpTmp sp_slot; + + /* If the target frame does not have a saved stack pointer, + then set up the target's CFA. */ + if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ())) + _Unwind_SetSpColumn (target, target->cfa, &sp_slot); + + for (i = 0; i < DWARF_FRAME_REGISTERS; ++i) + { + void *c = current->reg[i]; + void *t = target->reg[i]; + + gcc_assert (current->by_value[i] == 0); + if (target->by_value[i] && c) + { + _Unwind_Word w; + _Unwind_Ptr p; + if (dwarf_reg_size_table[i] == sizeof (_Unwind_Word)) + { + w = (_Unwind_Internal_Ptr) t; + memcpy (c, &w, sizeof (_Unwind_Word)); + } + else + { + gcc_assert (dwarf_reg_size_table[i] == sizeof (_Unwind_Ptr)); + p = (_Unwind_Internal_Ptr) t; + memcpy (c, &p, sizeof (_Unwind_Ptr)); + } + } + else if (t && c && t != c) + memcpy (c, t, dwarf_reg_size_table[i]); + } + + /* If the current frame doesn't have a saved stack pointer, then we + need to rely on EH_RETURN_STACKADJ_RTX to get our target stack + pointer value reloaded. */ + if (!_Unwind_GetGRPtr (current, __builtin_dwarf_sp_column ())) + { + void *target_cfa; + + target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ()); + + /* 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; + } + return 0; +} + +static inline _Unwind_Ptr +uw_identify_context (struct _Unwind_Context *context) +{ + /* The CFA is not sufficient to disambiguate the context of a function + interrupted by a signal before establishing its frame and the context + of the signal itself. */ + if (STACK_GROWS_DOWNWARD) + return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context); + else + return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context); +} + + +#include "unwind.inc" + +#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS) +alias (_Unwind_Backtrace); +alias (_Unwind_DeleteException); +alias (_Unwind_FindEnclosingFunction); +alias (_Unwind_ForcedUnwind); +alias (_Unwind_GetDataRelBase); +alias (_Unwind_GetTextRelBase); +alias (_Unwind_GetCFA); +alias (_Unwind_GetGR); +alias (_Unwind_GetIP); +alias (_Unwind_GetLanguageSpecificData); +alias (_Unwind_GetRegionStart); +alias (_Unwind_RaiseException); +alias (_Unwind_Resume); +alias (_Unwind_Resume_or_Rethrow); +alias (_Unwind_SetGR); +alias (_Unwind_SetIP); +#endif + +#endif /* !USING_SJLJ_EXCEPTIONS */ diff --git a/libgcc/unwind-dw2.h b/libgcc/unwind-dw2.h new file mode 100644 index 00000000000..2c558b4962a --- /dev/null +++ b/libgcc/unwind-dw2.h @@ -0,0 +1,87 @@ +/* DWARF2 frame unwind data structure. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2009 + Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* 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 + +/* 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 { + _Unwind_Word reg; + _Unwind_Sword offset; + const unsigned char *exp; + } loc; + enum { + REG_UNSAVED, + REG_SAVED_OFFSET, + REG_SAVED_REG, + REG_SAVED_EXP, + REG_SAVED_VAL_OFFSET, + REG_SAVED_VAL_EXP, + REG_UNDEFINED + } how; + } reg[DWARF_FRAME_REGISTERS+1]; + + /* Used to implement DW_CFA_remember_state. */ + struct frame_state_reg_info *prev; + + /* 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; + } regs; + + /* The PC described by the current frame state. */ + void *pc; + + /* The information we care about from the CIE/FDE. */ + _Unwind_Personality_Fn personality; + _Unwind_Sword data_align; + _Unwind_Word code_align; + _Unwind_Word retaddr_column; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char saw_z; + unsigned char signal_frame; + void *eh_ptr; +} _Unwind_FrameState; + diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h new file mode 100644 index 00000000000..4ff9017b88b --- /dev/null +++ b/libgcc/unwind-generic.h @@ -0,0 +1,276 @@ +/* Exception handling and frame unwind runtime interface routines. + Copyright (C) 2001, 2003, 2004, 2006, 2008, 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This is derived from the C++ ABI for IA-64. Where we diverge + for cross-architecture compatibility are noted with "@@@". */ + +#ifndef _UNWIND_H +#define _UNWIND_H + +#ifndef HIDE_EXPORTS +#pragma GCC visibility push(default) +#endif + +#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__(__unwind_word__))); +typedef signed _Unwind_Sword __attribute__((__mode__(__unwind_word__))); +#if defined(__ia64__) && defined(__hpux__) +typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__))); +#else +typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); +#endif +typedef unsigned _Unwind_Internal_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 +#define _UA_END_OF_STACK 16 + +/* The target can override this macro to define any back-end-specific + attributes required for the lowest-level stack frame. */ +#ifndef LIBGCC2_UNWIND_ATTRIBUTE +#define LIBGCC2_UNWIND_ATTRIBUTE +#endif + +/* 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 LIBGCC2_UNWIND_ATTRIBUTE +_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 LIBGCC2_UNWIND_ATTRIBUTE +_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 LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume (struct _Unwind_Exception *); + +/* @@@ Resume propagation of a FORCE_UNWIND exception, or to rethrow + a normal exception that was handled. */ +extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *); + +/* @@@ Use unwind data to perform a stack backtrace. The trace callback + is called for every stack frame in the call chain, but no cleanup + actions are performed. */ +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) + (struct _Unwind_Context *, void *); + +extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Backtrace (_Unwind_Trace_Fn, void *); + +/* 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 may be 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 _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *); +extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr); + +/* @@@ Retrieve the CFA of the given context. */ +extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); + +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 LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_RaiseException (struct _Unwind_Exception *); +extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_ForcedUnwind (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); +extern void LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_Resume (struct _Unwind_Exception *); +extern _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_SjLj_Resume_or_Rethrow (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 + +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 __attribute__ ((__unused__))) +{ + abort (); + return 0; +} + +/* @@@ Retrieve the Backing Store Pointer of the given context. */ +extern _Unwind_Word _Unwind_GetBSP (struct _Unwind_Context *); +#else +extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *); +extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *); +#endif + +/* @@@ Given an address, return the entry point of the function that + contains it. */ +extern void * _Unwind_FindEnclosingFunction (void *pc); + +#ifndef __SIZEOF_LONG__ + #error "__SIZEOF_LONG__ macro not defined" +#endif + +#ifndef __SIZEOF_POINTER__ + #error "__SIZEOF_POINTER__ macro not defined" +#endif + + +/* leb128 type numbers have a potentially unlimited size. + The target of the following definitions of _sleb128_t and _uleb128_t + is to have efficient data types large enough to hold the leb128 type + numbers used in the unwind code. + Mostly these types will simply be defined to long and unsigned long + except when a unsigned long data type on the target machine is not + capable of storing a pointer. */ + +#if __SIZEOF_LONG__ >= __SIZEOF_POINTER__ + typedef long _sleb128_t; + typedef unsigned long _uleb128_t; +#elif __SIZEOF_LONG_LONG__ >= __SIZEOF_POINTER__ + typedef long long _sleb128_t; + typedef unsigned long long _uleb128_t; +#else +# error "What type shall we use for _sleb128_t?" +#endif + +#ifdef __cplusplus +} +#endif + +#ifndef HIDE_EXPORTS +#pragma GCC visibility pop +#endif + +#endif /* unwind.h */ diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h new file mode 100644 index 00000000000..121f8776721 --- /dev/null +++ b/libgcc/unwind-pe.h @@ -0,0 +1,289 @@ +/* Exception handling and frame unwind runtime interface routines. + Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* @@@ 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. */ + +#ifndef GCC_UNWIND_PE_H +#define GCC_UNWIND_PE_H + +/* 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 + + +#ifndef NO_SIZE_OF_ENCODED_VALUE + +/* 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) __attribute__ ((unused)); + +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 (); +} + +#endif + +#ifndef NO_BASE_OF_ENCODED_VALUE + +/* 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 (); +} + +#endif + +/* Read an unsigned leb128 value from P, store the value in VAL, return + P incremented past the value. We assume that a word is large enough to + hold any value so encoded; if it is smaller than a pointer on some target, + pointers should not be leb128 encoded on that target. */ + +static const unsigned char * +read_uleb128 (const unsigned char *p, _uleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + + result = 0; + do + { + byte = *p++; + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + *val = result; + return p; +} + +/* Similar, but read a signed leb128 value. */ + +static const unsigned char * +read_sleb128 (const unsigned char *p, _sleb128_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + _uleb128_t result; + + result = 0; + do + { + byte = *p++; + result |= ((_uleb128_t)byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + /* Sign-extend a negative value. */ + if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) + result |= -(((_uleb128_t)1L) << shift); + + *val = (_sleb128_t) result; + return p; +} + +/* 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__)); + + const union unaligned *u = (const union unaligned *) p; + _Unwind_Internal_Ptr result; + + if (encoding == DW_EH_PE_aligned) + { + _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; + a = (a + sizeof (void *) - 1) & - sizeof(void *); + result = *(_Unwind_Internal_Ptr *) a; + p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *)); + } + else + { + switch (encoding & 0x0f) + { + case DW_EH_PE_absptr: + result = (_Unwind_Internal_Ptr) u->ptr; + p += sizeof (void *); + break; + + case DW_EH_PE_uleb128: + { + _uleb128_t tmp; + p = read_uleb128 (p, &tmp); + result = (_Unwind_Internal_Ptr) tmp; + } + break; + + case DW_EH_PE_sleb128: + { + _sleb128_t tmp; + p = read_sleb128 (p, &tmp); + result = (_Unwind_Internal_Ptr) tmp; + } + 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_Internal_Ptr) u : base); + if (encoding & DW_EH_PE_indirect) + result = *(_Unwind_Internal_Ptr *) result; + } + } + + *val = result; + return p; +} + +#ifndef NO_BASE_OF_ENCODED_VALUE + +/* 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); +} + +#endif + +#endif /* unwind-pe.h */ diff --git a/libgcc/unwind-sjlj.c b/libgcc/unwind-sjlj.c new file mode 100644 index 00000000000..c71e79858ee --- /dev/null +++ b/libgcc/unwind-sjlj.c @@ -0,0 +1,326 @@ +/* SJLJ exception handling and frame unwind runtime interface routines. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, + 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" +#include "unwind.h" +#include "gthr.h" + +#ifdef __USING_SJLJ_EXCEPTIONS__ + +#ifdef DONT_USE_BUILTIN_SETJMP +#ifndef inhibit_libc +#include +#else +typedef void *jmp_buf[JMP_BUF_SIZE]; +extern void longjmp(jmp_buf, int) __attribute__((noreturn)); +#endif +#else +#define longjmp __builtin_longjmp +#endif + +/* The setjmp side is dealt with in the except.c file. */ +#undef setjmp +#define setjmp setjmp_should_not_be_used_in_this_file + + +/* This structure is allocated on the stack of the target function. + This must match the definition created in except.c:init_eh. */ +struct SjLj_Function_Context +{ + /* This is the chain through all registered contexts. It is + filled in by _Unwind_SjLj_Register. */ + struct SjLj_Function_Context *prev; + + /* This is assigned in by the target function before every call + to the index of the call site in the lsda. It is assigned by + the personality routine to the landing pad index. */ + int call_site; + + /* This is how data is returned from the personality routine to + the target function's handler. */ + _Unwind_Word data[4]; + + /* These are filled in once by the target function before any + exceptions are expected to be handled. */ + _Unwind_Personality_Fn personality; + void *lsda; + +#ifdef DONT_USE_BUILTIN_SETJMP + /* We don't know what sort of alignment requirements the system + jmp_buf has. We over estimated in except.c, and now we have + to match that here just in case the system *didn't* have more + restrictive requirements. */ + jmp_buf jbuf __attribute__((aligned)); +#else + void *jbuf[]; +#endif +}; + +struct _Unwind_Context +{ + struct SjLj_Function_Context *fc; +}; + +typedef struct +{ + _Unwind_Personality_Fn personality; +} _Unwind_FrameState; + + +/* Manage the chain of registered function contexts. */ + +/* Single threaded fallback chain. */ +static struct SjLj_Function_Context *fc_static; + +#if __GTHREADS +static __gthread_key_t fc_key; +static int use_fc_key = -1; + +static void +fc_key_init (void) +{ + use_fc_key = __gthread_key_create (&fc_key, 0) == 0; +} + +static void +fc_key_init_once (void) +{ + static __gthread_once_t once = __GTHREAD_ONCE_INIT; + if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0) + use_fc_key = 0; +} +#endif + +void +_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) +{ +#if __GTHREADS + if (use_fc_key < 0) + fc_key_init_once (); + + if (use_fc_key) + { + fc->prev = __gthread_getspecific (fc_key); + __gthread_setspecific (fc_key, fc); + } + else +#endif + { + fc->prev = fc_static; + fc_static = fc; + } +} + +static inline struct SjLj_Function_Context * +_Unwind_SjLj_GetContext (void) +{ +#if __GTHREADS + if (use_fc_key < 0) + fc_key_init_once (); + + if (use_fc_key) + return __gthread_getspecific (fc_key); +#endif + return fc_static; +} + +static inline void +_Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc) +{ +#if __GTHREADS + if (use_fc_key < 0) + fc_key_init_once (); + + if (use_fc_key) + __gthread_setspecific (fc_key, fc); + else +#endif + fc_static = fc; +} + +void +_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) +{ + _Unwind_SjLj_SetContext (fc->prev); +} + + +/* Get/set the return data value at INDEX in CONTEXT. */ + +_Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + return context->fc->data[index]; +} + +/* Get the value of the CFA as saved in CONTEXT. */ + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context __attribute__((unused))) +{ + /* ??? Ideally __builtin_setjmp places the CFA in the jmpbuf. */ + +#ifndef DONT_USE_BUILTIN_SETJMP + /* This is a crude imitation of the CFA: the saved stack pointer. + This is roughly the CFA of the frame before CONTEXT. When using the + DWARF-2 unwinder _Unwind_GetCFA returns the CFA of the frame described + by CONTEXT instead; but for DWARF-2 the cleanups associated with + CONTEXT have already been run, and for SJLJ they have not yet been. */ + if (context->fc != NULL) + return (_Unwind_Word) context->fc->jbuf[2]; +#endif + + /* Otherwise we're out of luck for now. */ + return (_Unwind_Word) 0; +} + +void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + context->fc->data[index] = val; +} + +/* Get the call-site index as saved in CONTEXT. */ + +_Unwind_Ptr +_Unwind_GetIP (struct _Unwind_Context *context) +{ + return context->fc->call_site + 1; +} + +_Unwind_Ptr +_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn) +{ + *ip_before_insn = 0; + if (context->fc != NULL) + return context->fc->call_site + 1; + else + return 0; +} + +/* Set the return landing pad index in CONTEXT. */ + +void +_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val) +{ + context->fc->call_site = val - 1; +} + +void * +_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context) +{ + return context->fc->lsda; +} + +_Unwind_Ptr +_Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) ) +{ + return 0; +} + +void * +_Unwind_FindEnclosingFunction (void *pc __attribute__((unused))) +{ + return NULL; +} + +#ifndef __ia64__ +_Unwind_Ptr +_Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) ) +{ + return 0; +} + +_Unwind_Ptr +_Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) ) +{ + return 0; +} +#endif + +static inline _Unwind_Reason_Code +uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + if (context->fc == NULL) + { + fs->personality = NULL; + return _URC_END_OF_STACK; + } + else + { + fs->personality = context->fc->personality; + return _URC_NO_REASON; + } +} + +static inline void +uw_update_context (struct _Unwind_Context *context, + _Unwind_FrameState *fs __attribute__((unused)) ) +{ + context->fc = context->fc->prev; +} + +static void +uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) +{ + _Unwind_SjLj_Unregister (context->fc); + uw_update_context (context, fs); +} + +static inline void +uw_init_context (struct _Unwind_Context *context) +{ + context->fc = _Unwind_SjLj_GetContext (); +} + +static void __attribute__((noreturn)) +uw_install_context (struct _Unwind_Context *current __attribute__((unused)), + struct _Unwind_Context *target) +{ + _Unwind_SjLj_SetContext (target->fc); + longjmp (target->fc->jbuf, 1); +} + +static inline _Unwind_Ptr +uw_identify_context (struct _Unwind_Context *context) +{ + return (_Unwind_Ptr) context->fc; +} + + +/* Play games with unwind symbols so that we can have call frame + and sjlj symbols in the same shared library. Not that you can + use them simultaneously... */ +#define _Unwind_RaiseException _Unwind_SjLj_RaiseException +#define _Unwind_ForcedUnwind _Unwind_SjLj_ForcedUnwind +#define _Unwind_Resume _Unwind_SjLj_Resume +#define _Unwind_Resume_or_Rethrow _Unwind_SjLj_Resume_or_Rethrow + +#include "unwind.inc" + +#endif /* USING_SJLJ_EXCEPTIONS */ diff --git a/libgcc/unwind.inc b/libgcc/unwind.inc new file mode 100644 index 00000000000..5e2ec29c79a --- /dev/null +++ b/libgcc/unwind.inc @@ -0,0 +1,307 @@ +/* Exception handling and frame unwind runtime interface routines. -*- C -*- + Copyright (C) 2001, 2003, 2008, 2009 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC 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 3, or (at your option) + any later version. + + GCC 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This is derived from the C++ ABI for IA-64. Where we diverge + for cross-architecture compatibility are noted with "@@@". + This file is included from unwind-dw2.c, unwind-sjlj.c or + unwind-ia64.c. */ + +/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. + + Unwind the stack calling the personality routine to find both the + exception handler and intermediary cleanup code. We'll only locate + the first such frame here. Cleanup code will call back into + _Unwind_Resume and we'll continue Phase 2 there. */ + +static _Unwind_Reason_Code +_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, + struct _Unwind_Context *context) +{ + _Unwind_Reason_Code code; + + while (1) + { + _Unwind_FrameState fs; + int match_handler; + + code = uw_frame_state_for (context, &fs); + + /* Identify when we've reached the designated handler context. */ + match_handler = (uw_identify_context (context) == exc->private_2 + ? _UA_HANDLER_FRAME : 0); + + if (code != _URC_NO_REASON) + /* Some error encountered. Usually the unwinder doesn't + diagnose these and merely crashes. */ + return _URC_FATAL_PHASE2_ERROR; + + /* Unwind successful. Run the personality routine, if any. */ + if (fs.personality) + { + code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, + exc->exception_class, exc, context); + if (code == _URC_INSTALL_CONTEXT) + break; + if (code != _URC_CONTINUE_UNWIND) + return _URC_FATAL_PHASE2_ERROR; + } + + /* Don't let us unwind past the handler context. */ + gcc_assert (!match_handler); + + uw_update_context (context, &fs); + } + + return code; +} + +/* Raise an exception, passing along the given exception object. */ + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_RaiseException(struct _Unwind_Exception *exc) +{ + struct _Unwind_Context this_context, cur_context; + _Unwind_Reason_Code code; + + /* Set up this_context to describe the current stack frame. */ + uw_init_context (&this_context); + cur_context = this_context; + + /* Phase 1: Search. Unwind the stack, calling the personality routine + with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ + while (1) + { + _Unwind_FrameState fs; + + /* Set up fs to describe the FDE for the caller of cur_context. The + first time through the loop, that means __cxa_throw. */ + code = uw_frame_state_for (&cur_context, &fs); + + if (code == _URC_END_OF_STACK) + /* Hit end of stack with no handler found. */ + return _URC_END_OF_STACK; + + if (code != _URC_NO_REASON) + /* Some error encountered. Usually the unwinder doesn't + diagnose these and merely crashes. */ + return _URC_FATAL_PHASE1_ERROR; + + /* Unwind successful. Run the personality routine, if any. */ + if (fs.personality) + { + code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, + exc, &cur_context); + if (code == _URC_HANDLER_FOUND) + break; + else if (code != _URC_CONTINUE_UNWIND) + return _URC_FATAL_PHASE1_ERROR; + } + + /* Update cur_context to describe the same frame as fs. */ + uw_update_context (&cur_context, &fs); + } + + /* Indicate to _Unwind_Resume and associated subroutines that this + is not a forced unwind. Further, note where we found a handler. */ + exc->private_1 = 0; + exc->private_2 = uw_identify_context (&cur_context); + + cur_context = this_context; + code = _Unwind_RaiseException_Phase2 (exc, &cur_context); + if (code != _URC_INSTALL_CONTEXT) + return code; + + uw_install_context (&this_context, &cur_context); +} + + +/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ + +static _Unwind_Reason_Code +_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, + struct _Unwind_Context *context) +{ + _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; + void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; + _Unwind_Reason_Code code, stop_code; + + while (1) + { + _Unwind_FrameState fs; + int action; + + /* Set up fs to describe the FDE for the caller of cur_context. */ + code = uw_frame_state_for (context, &fs); + if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) + return _URC_FATAL_PHASE2_ERROR; + + /* Unwind successful. */ + action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; + if (code == _URC_END_OF_STACK) + action |= _UA_END_OF_STACK; + stop_code = (*stop) (1, action, exc->exception_class, exc, + context, stop_argument); + if (stop_code != _URC_NO_REASON) + return _URC_FATAL_PHASE2_ERROR; + + /* Stop didn't want to do anything. Invoke the personality + handler, if applicable, to run cleanups. */ + if (code == _URC_END_OF_STACK) + break; + + if (fs.personality) + { + code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, + exc->exception_class, exc, context); + if (code == _URC_INSTALL_CONTEXT) + break; + if (code != _URC_CONTINUE_UNWIND) + return _URC_FATAL_PHASE2_ERROR; + } + + /* Update cur_context to describe the same frame as fs, and discard + the previous context if necessary. */ + uw_advance_context (context, &fs); + } + + return code; +} + + +/* Raise an exception for forced unwinding. */ + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, + _Unwind_Stop_Fn stop, void * stop_argument) +{ + struct _Unwind_Context this_context, cur_context; + _Unwind_Reason_Code code; + + uw_init_context (&this_context); + cur_context = this_context; + + exc->private_1 = (_Unwind_Ptr) stop; + exc->private_2 = (_Unwind_Ptr) stop_argument; + + code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); + if (code != _URC_INSTALL_CONTEXT) + return code; + + uw_install_context (&this_context, &cur_context); +} + + +/* Resume propagation of an existing exception. This is used after + e.g. executing cleanup code, and not to implement rethrowing. */ + +void LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume (struct _Unwind_Exception *exc) +{ + struct _Unwind_Context this_context, cur_context; + _Unwind_Reason_Code code; + + uw_init_context (&this_context); + cur_context = this_context; + + /* Choose between continuing to process _Unwind_RaiseException + or _Unwind_ForcedUnwind. */ + if (exc->private_1 == 0) + code = _Unwind_RaiseException_Phase2 (exc, &cur_context); + else + code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); + + gcc_assert (code == _URC_INSTALL_CONTEXT); + + uw_install_context (&this_context, &cur_context); +} + + +/* Resume propagation of an FORCE_UNWIND exception, or to rethrow + a normal exception that was handled. */ + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) +{ + struct _Unwind_Context this_context, cur_context; + _Unwind_Reason_Code code; + + /* Choose between continuing to process _Unwind_RaiseException + or _Unwind_ForcedUnwind. */ + if (exc->private_1 == 0) + return _Unwind_RaiseException (exc); + + uw_init_context (&this_context); + cur_context = this_context; + + code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); + + gcc_assert (code == _URC_INSTALL_CONTEXT); + + uw_install_context (&this_context, &cur_context); +} + + +/* A convenience function that calls the exception_cleanup field. */ + +void +_Unwind_DeleteException (struct _Unwind_Exception *exc) +{ + if (exc->exception_cleanup) + (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); +} + + +/* Perform stack backtrace through unwind data. */ + +_Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE +_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) +{ + struct _Unwind_Context context; + _Unwind_Reason_Code code; + + uw_init_context (&context); + + while (1) + { + _Unwind_FrameState fs; + + /* Set up fs to describe the FDE for the caller of context. */ + code = uw_frame_state_for (&context, &fs); + if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) + return _URC_FATAL_PHASE1_ERROR; + + /* Call trace function. */ + if ((*trace) (&context, trace_argument) != _URC_NO_REASON) + return _URC_FATAL_PHASE1_ERROR; + + /* We're done at end of stack. */ + if (code == _URC_END_OF_STACK) + break; + + /* Update context to describe the same frame as fs. */ + uw_update_context (&context, &fs); + } + + return code; +} diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 26a6e78d64f..740e8d257f4 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -38,7 +38,7 @@ ACLOCAL_AMFLAGS = -I ./config -I ../config AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \ $(STRINGOPS_FLAG) \ - -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include + -I $(srcdir)/../libgcc -I $(MULTIBUILDTOP)../../gcc/include if USING_SPLIT_STACK AM_LDFLAGS = -XCClinker $(SPLIT_STACK) diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 5060d289261..42a160f3cf5 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -495,7 +495,7 @@ AM_CPPFLAGS = -I $(srcdir)/runtime $(LIBFFIINCS) $(PTHREAD_CFLAGS) ACLOCAL_AMFLAGS = -I ./config -I ../config AM_CFLAGS = -fexceptions -fplan9-extensions $(SPLIT_STACK) $(WARN_CFLAGS) \ $(STRINGOPS_FLAG) \ - -I $(srcdir)/../gcc -I $(MULTIBUILDTOP)../../gcc/include + -I $(srcdir)/../libgcc -I $(MULTIBUILDTOP)../../gcc/include @USING_SPLIT_STACK_TRUE@AM_LDFLAGS = -XCClinker $(SPLIT_STACK) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 98b72f501fe..f6bb404978e 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,12 @@ +2011-08-05 Rainer Orth + + * configure.ac (GCC_UNWIND_INCLUDE): Rename to + LIBGCC_UNWIND_INCLUDE. + Point to $(multi_basedir)/./libjava/../libgcc. + * configure: Regenerate. + * Makefile.am (GCC_UNWIND_INCLUDE): Reflect this. + * Makefile.in: Regenerate. + 2011-07-12 Andrew Haley * interpret.cc (check_handler): Fix bit rot. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 152170862c0..1309defb623 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -342,7 +342,7 @@ LIBLINK = $(LIBTOOL) --tag=CXX $(LIBTOOLFLAGS) --mode=link $(CXX) -L$(here) \ CXXLINK = $(LIBTOOL) --tag=CXX $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LTLDFLAGS) -o $@ -GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@ +LIBGCC_UNWIND_INCLUDE = @LIBGCC_UNWIND_INCLUDE@ WARNINGS = -Wextra -Wall ## Some systems don't allow `$' in identifiers by default, so we force @@ -410,7 +410,7 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -Iclasspath/include \ -I$(top_srcdir)/classpath/native/fdlibm \ $(GCINCS) $(THREADINCS) $(INCLTDL) \ - $(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS) + $(LIBGCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS) BOOTCLASSPATH = $(srcdir)/classpath/lib diff --git a/libjava/Makefile.in b/libjava/Makefile.in index 6c966a1efd5..e741f26d06d 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -552,7 +552,6 @@ EXCEPTIONSPEC = @EXCEPTIONSPEC@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GCC_FOR_ECJX = @GCC_FOR_ECJX@ -GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@ GCDEPS = @GCDEPS@ GCINCS = @GCINCS@ GCJ = @GCJ@ @@ -600,6 +599,7 @@ LIBART_LIBS = @LIBART_LIBS@ LIBDIR = @LIBDIR@ LIBFFI = @LIBFFI@ LIBFFIINCS = @LIBFFIINCS@ +LIBGCC_UNWIND_INCLUDE = @LIBGCC_UNWIND_INCLUDE@ LIBGCJDEBUG = @LIBGCJDEBUG@ LIBGCJTESTSPEC = @LIBGCJTESTSPEC@ LIBGCJ_BC_SPEC = @LIBGCJ_BC_SPEC@ @@ -1040,7 +1040,7 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -Iclasspath/include \ -I$(top_srcdir)/classpath/native/fdlibm \ $(GCINCS) $(THREADINCS) $(INCLTDL) \ - $(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS) + $(LIBGCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS) BOOTCLASSPATH = $(srcdir)/classpath/lib libgij_la_SOURCES = gij.cc diff --git a/libjava/configure b/libjava/configure index 4c3ab55746b..c2779c07c91 100755 --- a/libjava/configure +++ b/libjava/configure @@ -648,7 +648,7 @@ GCJVERSION toolexeclibdir toolexecmainlibdir toolexecdir -GCC_UNWIND_INCLUDE +LIBGCC_UNWIND_INCLUDE INSTALL_BINARIES_FALSE INSTALL_BINARIES_TRUE NEEDS_DATA_START_FALSE @@ -6781,7 +6781,7 @@ case "${which_gcj}" in cross) if test "x${with_newlib}" = "xyes"; then # FIXME (comment): Why is this needed? - GCC_UNWIND_INCLUDE= + LIBGCC_UNWIND_INCLUDE= fi GCJH='$(target_noncanonical)-gcjh' ;; @@ -20907,8 +20907,8 @@ else fi -# We're in the tree with gcc, and need to include some of its headers. -GCC_UNWIND_INCLUDE='-I$(multi_basedir)/./libjava/../gcc' +# We're in the tree with libgcc, and need to include some of its headers. +LIBGCC_UNWIND_INCLUDE='-I$(multi_basedir)/./libjava/../libgcc' if test "x${with_newlib}" = "xyes"; then # We are being configured with a cross compiler. AC_REPLACE_FUNCS diff --git a/libjava/configure.ac b/libjava/configure.ac index 5f673ea7cfd..92546f72b99 100644 --- a/libjava/configure.ac +++ b/libjava/configure.ac @@ -469,7 +469,7 @@ case "${which_gcj}" in cross) if test "x${with_newlib}" = "xyes"; then # FIXME (comment): Why is this needed? - GCC_UNWIND_INCLUDE= + LIBGCC_UNWIND_INCLUDE= fi GCJH='$(target_noncanonical)-gcjh' ;; @@ -1204,8 +1204,8 @@ AC_SUBST(HASH_SYNC_SPEC) AM_CONDITIONAL(USING_GCC, test "$GCC" = yes) -# We're in the tree with gcc, and need to include some of its headers. -GCC_UNWIND_INCLUDE='-I$(multi_basedir)/./libjava/../gcc' +# We're in the tree with libgcc, and need to include some of its headers. +LIBGCC_UNWIND_INCLUDE='-I$(multi_basedir)/./libjava/../libgcc' if test "x${with_newlib}" = "xyes"; then # We are being configured with a cross compiler. AC_REPLACE_FUNCS @@ -1569,7 +1569,7 @@ AM_CONDITIONAL(NATIVE, test "$NATIVE" = yes) AM_CONDITIONAL(ENABLE_SHARED, test "$enable_shared" = yes) AM_CONDITIONAL(NEEDS_DATA_START, test "$NEEDS_DATA_START" = yes && test "$NATIVE" = yes) AM_CONDITIONAL(INSTALL_BINARIES, test -z "${with_multisubdir}") -AC_SUBST(GCC_UNWIND_INCLUDE) +AC_SUBST(LIBGCC_UNWIND_INCLUDE) # Process the option "--enable-version-specific-runtime-libs" # Calculate toolexeclibdir diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index 45f04859578..61d4ac335d7 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,3 +1,8 @@ +2011-08-05 Rainer Orth + + * Makefile.in (INCLUDES): Search + $(srcdir)/$(MULTISRCTOP)../libgcc. + 2011-06-08 Nicola Pero * objc/objc.h (__GNU_LIBOBJC__): Bumped to 20110608. diff --git a/libobjc/Makefile.in b/libobjc/Makefile.in index 02443327058..0935ccd98d6 100644 --- a/libobjc/Makefile.in +++ b/libobjc/Makefile.in @@ -101,6 +101,7 @@ OBJC_BOEHM_GC_LIBS=../boehm-gc/libgcjgc_convenience.la $(thread_libs_and_flags) INCLUDES = -I$(srcdir)/$(MULTISRCTOP)../gcc \ -I$(srcdir)/$(MULTISRCTOP)../gcc/config \ -I$(MULTIBUILDTOP)../../$(host_subdir)/gcc \ + -I$(srcdir)/$(MULTISRCTOP)../libgcc \ -I$(srcdir)/$(MULTISRCTOP)../include \ $(OBJC_BOEHM_GC_INCLUDES) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5168fa3e38d..a02326c6dbe 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2011-08-05 Rainer Orth + + * acinclude.m4 (GLIBCXX_EXPORT_INCLUDES): Point TOPLEVEL_INCLUDES + to $(toplevel_srcdir)/libgcc. + * configure: Regenerate. + 2011-08-04 Benjamin Kosnik * doc/xml/manual/build_hacking.xml: Use relative fileref for PNG diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 6f6810de235..8bbc40e95f2 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -685,9 +685,9 @@ AC_DEFUN([GLIBCXX_EXPORT_INCLUDES], [ fi # Stuff in the actual top level. Currently only used by libsupc++ to - # get unwind* headers from the gcc dir. - #TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/gcc -I$(toplevel_srcdir)/include' - TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/gcc' + # get unwind* headers from the libgcc dir. + #TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc -I$(toplevel_srcdir)/include' + TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc' # Now, export this to all the little Makefiles.... AC_SUBST(GLIBCXX_INCLUDES) diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 0bbc485d300..c7be667dc80 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -65769,9 +65769,9 @@ $as_echo "$gxx_include_dir" >&6; } fi # Stuff in the actual top level. Currently only used by libsupc++ to - # get unwind* headers from the gcc dir. - #TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/gcc -I$(toplevel_srcdir)/include' - TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/gcc' + # get unwind* headers from the libgcc dir. + #TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc -I$(toplevel_srcdir)/include' + TOPLEVEL_INCLUDES='-I$(toplevel_srcdir)/libgcc' # Now, export this to all the little Makefiles....