+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * 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 <hongjiu.lu@intel.com>
* config/i386/i386.c (processor_alias_table): Add core-avx-i.
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).
-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
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)
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
# 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.
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; \
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])
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * gcc-interface/Makefile.in (raise-gcc.o): Search
+ $(srcdir)/../libgcc.
+
2011-08-05 Bob Duff <duff@adacore.com>
* sinfo.ads, sinfo.adb (Subpool_Handle_Name): New attribute for
necessary.
* put_scos.adb: Code simplification based on above change.
+>>>>>>> .r177446
2011-08-05 Robert Dewar <dewar@adacore.com>
* sem_ch3.adb, gnatcmd.adb, switch-c.adb, exp_attr.adb, make.adb,
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
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"
;;
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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__ */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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 ();
-}
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
_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
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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);
-}
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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 */
-# 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.
#
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)
+++ /dev/null
-/* Copyright (C) 2000, 2001, 2003, 2009 Free Software Foundation, Inc.
- Contributed by Richard Henderson <rth@cygnus.com>.
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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 <stddef.h>
-#include <stdlib.h>
-#include <link.h>
-#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;
-}
+++ /dev/null
-/* Copyright (C) 2004, 2009 Free Software Foundation, Inc.
- Contributed by Douglas B Rupp <rupp@gnat.com>
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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 <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "unwind-ia64.h"
-
-#define __int64 long
-#include <vms/ossddef.h>
-#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;
-}
-# 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
+++ /dev/null
-# Build libunwind for IA-64 GLIBC based system.
-LIBUNWIND = $(srcdir)/config/ia64/fde-glibc.c \
- $(srcdir)/config/ia64/unwind-ia64.c
-LIBUNWINDDEP = unwind.inc
# Copyright (C) 2001, 2002, 2003, 2004, 2005,
-# 2006 Free Software Foundation, Inc.
+# 2006, 2011 Free Software Foundation, Inc.
#
# This file is part of GCC.
#
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.
# 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) \
$(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
+++ /dev/null
-/* 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 <amacleod@cygnus.com>
- Andrew Haley <aph@cygnus.com>
- David Mosberger-Tang <davidm@hpl.hp.com>
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-#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 <register number> - 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
-};
-
-\f
-#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);
- }
-}
-\f
-/* 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;
-}
-
-\f
-#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)
-
-\f
-/*
- * 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;
-}
-
-\f
-/* 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;
-}
-
-\f
-/* 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;
- }
-}
-\f
-/* 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"
-\f
-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
+++ /dev/null
-/* Copyright (C) 1999, 2000, 2001, 2007, 2009 Free Software Foundation, Inc.
- Contributed by Andrew MacLeod <amacleod@cygnus.com>
- Andrew Haley <aph@cygnus.com>
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-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")));
/* 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. */
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
/* 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
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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 <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <signal.h>
-
-#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 <ucontext.h> and <mach/thread_status.h>,
- 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
# 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.
#
# 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
# 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.
#
$(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)
$(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
$(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
# 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
-# 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.
#
# 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
+++ /dev/null
-# 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
-# <http://www.gnu.org/licenses/>.
-
-# 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)
# 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
# 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
-# 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.
#
_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) \
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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;
-};
-
-\f
-/* 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; }
-\f
-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;
-}
-\f
-/* 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"
-\f
-/* 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;
-}
-\f
-/* 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;
-}
-\f
-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);
-}
-\f
-/* 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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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;
-
with_libiconv_prefix
enable_initfini_array
enable_sjlj_exceptions
-with_system_libunwind
enable_secureplt
enable_leading_mingw64_underscores
enable_cld
--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]
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
# --------------------------------------------------------
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
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
[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
# --------------------------------------------------------
+++ /dev/null
-/* TLS emulation.
- Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc.
- Contributed by Jakub Jelinek <jakub@redhat.com>.
-
-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
-<http://www.gnu.org/licenses/>. */
-
-#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;
-}
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * 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 <joseph@codesourcery.com>
* de.po: Update.
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
/* 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
+++ /dev/null
-/* Supporting functions for C exception handling.
- Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc.
- Contributed by Aldy Hernandez <aldy@quesejoda.com>.
- 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
-<http://www.gnu.org/licenses/>. */
-
-#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;
-}
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#define symver(name, version) \
- __asm__ (".symver " #name"," #name "@" #version)
-
-#define alias(name) \
- __typeof(name) __libunwind##name __attribute__ ((alias (#name)))
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* Locate the FDE entry for a given address, using Darwin's keymgr support. */
-
-#include "tconfig.h"
-#include "tsystem.h"
-#include <string.h>
-#include <stdlib.h>
-#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. */
-};
-\f
-/* 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;
-}
-
+++ /dev/null
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2010
- Free Software Foundation, Inc.
- Contributed by Jakub Jelinek <jakub@redhat.com>.
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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 <elf.h> /* 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 <link.h>
-
-#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
+++ /dev/null
-/* 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 <jason@cygnus.com>.
-
-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
-<http://www.gnu.org/licenses/>. */
-
-#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));
-}
-
-\f
-/* 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));
-}
-
-\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);
- }
-}
-
-\f
-/* 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;
-}
+++ /dev/null
-/* 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 <jason@cygnus.com>.
-
-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
-<http://www.gnu.org/licenses/>. */
-
-#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 *);
-
-\f
-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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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 <sys/sdt.h>
-#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];
-
-\f
-/* 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; }
-\f
-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;
-}
-\f
-/* 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"
-\f
-/* 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 ();
- }
- }
-}
-\f
-/* 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;
-}
-\f
-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;
-}
-\f
-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);
-}
-\f
-/* 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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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;
-
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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 <stdlib.h>
-
-static inline _Unwind_Ptr
-_Unwind_GetDataRelBase (struct _Unwind_Context *_C)
-{
- /* The GP is stored in R1. */
- return _Unwind_GetGR (_C, 1);
-}
-
-static inline _Unwind_Ptr
-_Unwind_GetTextRelBase (struct _Unwind_Context *_C __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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* @@@ 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
-\f
-
-#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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-#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 <setjmp.h>
-#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;
-
-\f
-/* 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);
-}
-
-\f
-/* 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
-\f
-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 */
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* 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;
-}
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * 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 <hongjiu.lu@intel.com>
* config/i386/linux-unwind.h (RT_SIGRETURN_SYSCALL): New.
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)
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 \
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
# 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/-.*$//'`
# 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*)
*-*-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
;;
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*)
;;
;;
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*)
pdp11-*-*)
;;
picochip-*-*)
+ tmake_file=picochip/t-picochip
;;
powerpc-*-darwin*)
case ${host} in
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"
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)
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*)
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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__ */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 ();
+}
--- /dev/null
+LIB2ADDEH = $(srcdir)/config/arm/unwind-arm.c \
+ $(srcdir)/config/arm/libunwind.S \
+ $(srcdir)/config/arm/pr-support.c $(srcdir)/unwind-c.c
--- /dev/null
+# Include the gcc personality routine
+LIB2ADDEH = $(srcdir)/unwind-c.c $(srcdir)/config/arm/pr-support.c
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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);
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 */
--- /dev/null
+/* Copyright (C) 2000, 2001, 2003, 2009 Free Software Foundation, Inc.
+ Contributed by Richard Henderson <rth@cygnus.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stddef.h>
+#include <stdlib.h>
+#include <link.h>
+#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;
+}
--- /dev/null
+/* Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc.
+ Contributed by Douglas B Rupp <rupp@gnat.com>
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "md-unwind-support.h"
+#include "unwind-ia64.h"
+
+#define __int64 long
+#include <vms/ossddef.h>
+#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;
+}
--- /dev/null
+LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \
+ $(srcdir)/unwind-c.c
--- /dev/null
+# Use system libunwind library on IA-64 GLIBC based system.
+LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \
+ $(srcdir)/unwind-compat.c
--- /dev/null
+# Build libunwind for IA-64 GLIBC based system.
+LIBUNWIND = $(srcdir)/config/ia64/fde-glibc.c \
+ $(srcdir)/config/ia64/unwind-ia64.c
--- /dev/null
+LIB2ADDEH = $(srcdir)/unwind-c.c
--- /dev/null
+LIB2ADDEH += $(srcdir)/config/ia64/fde-vms.c
--- /dev/null
+/* 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 <amacleod@cygnus.com>
+ Andrew Haley <aph@cygnus.com>
+ David Mosberger-Tang <davidm@hpl.hp.com>
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <register number> - 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
+};
+
+\f
+#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);
+ }
+}
+\f
+/* 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;
+}
+
+\f
+#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)
+
+\f
+/*
+ * 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;
+}
+
+\f
+/* 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;
+}
+
+\f
+/* 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;
+ }
+}
+\f
+/* 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
+
+\f
+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
--- /dev/null
+/* Copyright (C) 1999, 2000, 2001, 2007, 2009 Free Software Foundation, Inc.
+ Contributed by Andrew MacLeod <amacleod@cygnus.com>
+ Andrew Haley <aph@cygnus.com>
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+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")));
/* 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.
#include <stdio.h>
#include <string.h>
+#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. */
--- /dev/null
+# Turn off the building of exception handling libraries.
+LIB2ADDEH =
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#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 <ucontext.h> and <mach/thread_status.h>,
+ 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
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
# 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
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
--- /dev/null
+# Use unwind-dw2-fde-dip.
+LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-dip.c \
+ $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
--- /dev/null
+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
--- /dev/null
+# 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
+# <http://www.gnu.org/licenses/>.
+
+# 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)
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
-# 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 $<
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Locate the FDE entry for a given address, using Darwin's keymgr support. */
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include <string.h>
+#include <stdlib.h>
+#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. */
+};
+\f
+/* 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;
+}
+
--- /dev/null
+LIB2ADDEH = $(srcdir)/config/xtensa/unwind-dw2-xtensa.c \
+ $(srcdir)/unwind-dw2-fde.c $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+};
+
+\f
+/* 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; }
+\f
+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;
+}
+\f
+/* 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"
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+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);
+}
+\f
+/* 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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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;
+
enable_maintainer_mode
with_build_libsubdir
enable_decimal_float
+with_system_libunwind
enable_tls
'
ac_precious_vars='build_alias
--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
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 :
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"
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" ;;
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])
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])
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.
--- /dev/null
+/* TLS emulation.
+ Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#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;
+}
--- /dev/null
+/* Supporting functions for C exception handling.
+ Copyright (C) 2002, 2003, 2009 Free Software Foundation, Inc.
+ Contributed by Aldy Hernandez <aldy@quesejoda.com>.
+ 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
+<http://www.gnu.org/licenses/>. */
+
+#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;
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define symver(name, version) \
+ __asm__ (".symver " #name"," #name "@" #version)
+
+#define alias(name) \
+ __typeof(name) __libunwind##name __attribute__ ((alias (#name)))
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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
--- /dev/null
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2010
+ Free Software Foundation, Inc.
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <elf.h> /* 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 <link.h>
+
+#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
--- /dev/null
+/* 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 <jason@cygnus.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#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));
+}
+
+\f
+/* 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));
+}
+
+\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);
+ }
+}
+
+\f
+/* 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;
+}
--- /dev/null
+/* 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 <jason@cygnus.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#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 *);
+
+\f
+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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <sys/sdt.h>
+#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];
+
+\f
+/* 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; }
+\f
+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;
+}
+\f
+/* 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"
+\f
+/* 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 ();
+ }
+ }
+}
+\f
+/* 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;
+}
+\f
+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;
+}
+\f
+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);
+}
+\f
+/* 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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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;
+
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stdlib.h>
+
+static inline _Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *_C)
+{
+ /* The GP is stored in R1. */
+ return _Unwind_GetGR (_C, 1);
+}
+
+static inline _Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *_C __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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* @@@ 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
+\f
+
+#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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <setjmp.h>
+#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;
+
+\f
+/* 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);
+}
+
+\f
+/* 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
+\f
+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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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;
+}
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)
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)
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * 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 <aph@redhat.com>
* interpret.cc (check_handler): Fix bit rot.
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
-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
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GCC_FOR_ECJX = @GCC_FOR_ECJX@
-GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
GCDEPS = @GCDEPS@
GCINCS = @GCINCS@
GCJ = @GCJ@
LIBDIR = @LIBDIR@
LIBFFI = @LIBFFI@
LIBFFIINCS = @LIBFFIINCS@
+LIBGCC_UNWIND_INCLUDE = @LIBGCC_UNWIND_INCLUDE@
LIBGCJDEBUG = @LIBGCJDEBUG@
LIBGCJTESTSPEC = @LIBGCJTESTSPEC@
LIBGCJ_BC_SPEC = @LIBGCJ_BC_SPEC@
-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
toolexeclibdir
toolexecmainlibdir
toolexecdir
-GCC_UNWIND_INCLUDE
+LIBGCC_UNWIND_INCLUDE
INSTALL_BINARIES_FALSE
INSTALL_BINARIES_TRUE
NEEDS_DATA_START_FALSE
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'
;;
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
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'
;;
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
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
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * Makefile.in (INCLUDES): Search
+ $(srcdir)/$(MULTISRCTOP)../libgcc.
+
2011-06-08 Nicola Pero <nicola.pero@meta-innovation.com>
* objc/objc.h (__GNU_LIBOBJC__): Bumped to 20110608.
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)
+2011-08-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * acinclude.m4 (GLIBCXX_EXPORT_INCLUDES): Point TOPLEVEL_INCLUDES
+ to $(toplevel_srcdir)/libgcc.
+ * configure: Regenerate.
+
2011-08-04 Benjamin Kosnik <bkoz@redhat.com>
* doc/xml/manual/build_hacking.xml: Use relative fileref for PNG
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)
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....