aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/libgcc/config/ia64
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/libgcc/config/ia64')
-rw-r--r--gcc-4.9/libgcc/config/ia64/__divxf3.S11
-rw-r--r--gcc-4.9/libgcc/config/ia64/_fixtfdi.S11
-rw-r--r--gcc-4.9/libgcc/config/ia64/_fixunstfdi.S11
-rw-r--r--gcc-4.9/libgcc/config/ia64/_floatditf.S11
-rw-r--r--gcc-4.9/libgcc/config/ia64/crtbegin.S254
-rw-r--r--gcc-4.9/libgcc/config/ia64/crtend.S121
-rw-r--r--gcc-4.9/libgcc/config/ia64/crtfastmath.c34
-rw-r--r--gcc-4.9/libgcc/config/ia64/crti.S53
-rw-r--r--gcc-4.9/libgcc/config/ia64/crtn.S43
-rw-r--r--gcc-4.9/libgcc/config/ia64/fde-glibc.c161
-rw-r--r--gcc-4.9/libgcc/config/ia64/fde-vms.c159
-rw-r--r--gcc-4.9/libgcc/config/ia64/lib1funcs.S795
-rw-r--r--gcc-4.9/libgcc/config/ia64/libgcc-glibc.ver97
-rw-r--r--gcc-4.9/libgcc/config/ia64/libgcc-ia64.ver30
-rw-r--r--gcc-4.9/libgcc/config/ia64/linux-unwind.h199
-rw-r--r--gcc-4.9/libgcc/config/ia64/quadlib.c78
-rw-r--r--gcc-4.9/libgcc/config/ia64/sfp-exceptions.c54
-rw-r--r--gcc-4.9/libgcc/config/ia64/sfp-machine.h95
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-eh-ia642
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-hpux9
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-ia6418
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-ia64-elf20
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-linux5
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-linux-libunwind3
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-slibgcc-hpux6
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-softfp4
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-softfp-compat7
-rw-r--r--gcc-4.9/libgcc/config/ia64/t-vms9
-rw-r--r--gcc-4.9/libgcc/config/ia64/tf-signs.c60
-rw-r--r--gcc-4.9/libgcc/config/ia64/unwind-ia64.c2468
-rw-r--r--gcc-4.9/libgcc/config/ia64/unwind-ia64.h57
-rw-r--r--gcc-4.9/libgcc/config/ia64/vms-crtinit.S24
-rw-r--r--gcc-4.9/libgcc/config/ia64/vms-unwind.h308
33 files changed, 5217 insertions, 0 deletions
diff --git a/gcc-4.9/libgcc/config/ia64/__divxf3.S b/gcc-4.9/libgcc/config/ia64/__divxf3.S
new file mode 100644
index 000000000..9cba8f594
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/__divxf3.S
@@ -0,0 +1,11 @@
+#ifdef SHARED
+#define __divtf3 __divtf3_compat
+#endif
+
+#define L__divxf3
+#include "config/ia64/lib1funcs.S"
+
+#ifdef SHARED
+#undef __divtf3
+.symver __divtf3_compat, __divtf3@GCC_3.0
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/_fixtfdi.S b/gcc-4.9/libgcc/config/ia64/_fixtfdi.S
new file mode 100644
index 000000000..863b70f7e
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/_fixtfdi.S
@@ -0,0 +1,11 @@
+#ifdef SHARED
+#define __fixtfti __fixtfti_compat
+#endif
+
+#define L_fixtfdi
+#include "config/ia64/lib1funcs.S"
+
+#ifdef SHARED
+#undef __fixtfti
+.symver __fixtfti_compat, __fixtfti@GCC_3.0
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/_fixunstfdi.S b/gcc-4.9/libgcc/config/ia64/_fixunstfdi.S
new file mode 100644
index 000000000..aac6a284e
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/_fixunstfdi.S
@@ -0,0 +1,11 @@
+#ifdef SHARED
+#define __fixunstfti __fixunstfti_compat
+#endif
+
+#define L_fixunstfdi
+#include "config/ia64/lib1funcs.S"
+
+#ifdef SHARED
+#undef __fixunstfti
+.symver __fixunstfti_compat, __fixunstfti@GCC_3.0
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/_floatditf.S b/gcc-4.9/libgcc/config/ia64/_floatditf.S
new file mode 100644
index 000000000..e37404d26
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/_floatditf.S
@@ -0,0 +1,11 @@
+#ifdef SHARED
+#define __floattitf __floattitf_compat
+#endif
+
+#define L_floatditf
+#include "config/ia64/lib1funcs.S"
+
+#ifdef SHARED
+#undef __floattitf
+.symver __floattitf_compat, __floattitf@GCC_3.0
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/crtbegin.S b/gcc-4.9/libgcc/config/ia64/crtbegin.S
new file mode 100644
index 000000000..001b69bb4
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/crtbegin.S
@@ -0,0 +1,254 @@
+/* Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Contributed by Jes Sorensen, <Jes.Sorensen@cern.ch>
+
+ 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 "auto-host.h"
+
+.section .ctors,"aw","progbits"
+ .align 8
+__CTOR_LIST__:
+ data8 -1
+
+.section .dtors,"aw","progbits"
+ .align 8
+__DTOR_LIST__:
+ data8 -1
+
+.section .jcr,"aw","progbits"
+ .align 8
+__JCR_LIST__:
+
+.section .sdata
+ .type dtor_ptr,@object
+ .size dtor_ptr,8
+dtor_ptr:
+ data8 @gprel(__DTOR_LIST__ + 8)
+
+ /* A handle for __cxa_finalize to manage c++ local destructors. */
+ .global __dso_handle
+ .type __dso_handle,@object
+ .size __dso_handle,8
+#ifdef SHARED
+ .section .data
+__dso_handle:
+ data8 __dso_handle
+#else
+ .section .bss
+ .align 8
+__dso_handle:
+ .skip 8
+#endif
+ .hidden __dso_handle
+
+
+#ifdef HAVE_INITFINI_ARRAY_SUPPORT
+
+.section .fini_array, "a"
+ data8 @fptr(__do_global_dtors_aux)
+
+.section .init_array, "a"
+ data8 @fptr(__do_jv_register_classes)
+ data8 @fptr(__do_global_ctors_aux)
+
+#else /* !HAVE_INITFINI_ARRAY_SUPPORT */
+/*
+ * Fragment of the ELF _fini routine that invokes our dtor cleanup.
+ *
+ * We make the call by indirection, because in large programs the
+ * .fini and .init sections are not in range of the destination, and
+ * we cannot allow the linker to insert a stub at the end of this
+ * fragment of the _fini function. Further, Itanium does not implement
+ * the long branch instructions, and we do not wish every program to
+ * trap to the kernel for emulation.
+ *
+ * Note that we require __do_global_dtors_aux to preserve the GP,
+ * so that the next fragment in .fini gets the right value.
+ */
+.section .fini,"ax","progbits"
+ { .mlx
+ movl r2 = @pcrel(__do_global_dtors_aux - 16)
+ }
+ { .mii
+ mov r3 = ip
+ ;;
+ add r2 = r2, r3
+ ;;
+ }
+ { .mib
+ nop 0
+ mov b6 = r2
+ br.call.sptk.many b0 = b6
+ }
+
+/* Likewise for _init. */
+
+.section .init,"ax","progbits"
+ { .mlx
+ movl r2 = @pcrel(__do_jv_register_classes - 16)
+ }
+ { .mii
+ mov r3 = ip
+ ;;
+ add r2 = r2, r3
+ ;;
+ }
+ { .mib
+ nop 0
+ mov b6 = r2
+ br.call.sptk.many b0 = b6
+ }
+#endif /* !HAVE_INITFINI_ARRAY_SUPPORT */
+
+.section .text
+ .align 32
+ .proc __do_global_dtors_aux
+__do_global_dtors_aux:
+ .prologue
+#ifndef SHARED
+ .save ar.pfs, r35
+ alloc loc3 = ar.pfs, 0, 4, 1, 0
+ addl loc0 = @gprel(dtor_ptr), gp
+ .save rp, loc1
+ mov loc1 = rp
+ .body
+
+ mov loc2 = gp
+ nop 0
+ br.sptk.many .entry
+#else
+ /*
+ if (__cxa_finalize)
+ __cxa_finalize(__dso_handle)
+ */
+ .save ar.pfs, r35
+ alloc loc3 = ar.pfs, 0, 4, 1, 0
+ addl loc0 = @gprel(dtor_ptr), gp
+ addl r16 = @ltoff(@fptr(__cxa_finalize)), gp
+ ;;
+
+ ld8 r16 = [r16]
+ ;;
+ addl out0 = @ltoff(__dso_handle), gp
+ cmp.ne p7, p0 = r0, r16
+ ;;
+
+ ld8 out0 = [out0]
+(p7) ld8 r18 = [r16], 8
+ .save rp, loc1
+ mov loc1 = rp
+ .body
+ ;;
+
+ mov loc2 = gp
+(p7) ld8 gp = [r16]
+(p7) mov b6 = r18
+
+ nop 0
+ nop 0
+(p7) br.call.sptk.many rp = b6
+ ;;
+
+ nop 0
+ nop 0
+ br.sptk.many .entry
+#endif
+ /*
+ do {
+ dtor_ptr++;
+ (*(dtor_ptr-1)) ();
+ } while (dtor_ptr);
+ */
+.loop:
+ st8 [loc0] = r15 // update dtor_ptr (in memory)
+ ld8 r17 = [r16], 8 // r17 <- dtor's entry-point
+ nop 0
+ ;;
+
+ ld8 gp = [r16] // gp <- dtor's gp
+ mov b6 = r17
+ br.call.sptk.many rp = b6
+
+.entry: ld8 r15 = [loc0] // r15 <- dtor_ptr (gp-relative)
+ ;;
+ add r16 = r15, loc2 // r16 <- dtor_ptr (absolute)
+ adds r15 = 8, r15
+ ;;
+
+ ld8 r16 = [r16] // r16 <- pointer to dtor's fdesc
+ mov rp = loc1
+ mov ar.pfs = loc3
+ ;;
+
+ cmp.ne p6, p0 = r0, r16
+(p6) br.cond.sptk.few .loop
+ br.ret.sptk.many rp
+ .endp __do_global_dtors_aux
+
+ .align 32
+ .proc __do_jv_register_classes
+__do_jv_register_classes:
+ .prologue
+ .save ar.pfs, r33
+ alloc loc1 = ar.pfs, 0, 3, 1, 0
+ movl out0 = @gprel(__JCR_LIST__)
+ ;;
+
+ addl r14 = @ltoff(@fptr(_Jv_RegisterClasses)), gp
+ add out0 = out0, gp
+ .save rp, loc0
+ mov loc0 = rp
+ .body
+ ;;
+
+ ld8 r14 = [r14]
+ ld8 r15 = [out0]
+ cmp.ne p6, p0 = r0, r0
+ ;;
+
+ cmp.eq.or p6, p0 = r0, r14
+ cmp.eq.or p6, p0 = r0, r15
+(p6) br.ret.sptk.many rp
+
+ ld8 r15 = [r14], 8
+ ;;
+ nop 0
+ mov b6 = r15
+
+ mov loc2 = gp
+ ld8 gp = [r14]
+ br.call.sptk.many rp = b6
+ ;;
+
+ mov gp = loc2
+ mov rp = loc0
+ mov ar.pfs = loc1
+
+ nop 0
+ nop 0
+ br.ret.sptk.many rp
+ .endp __do_jv_register_classes
+
+#ifdef SHARED
+.weak __cxa_finalize
+#endif
+.weak _Jv_RegisterClasses
diff --git a/gcc-4.9/libgcc/config/ia64/crtend.S b/gcc-4.9/libgcc/config/ia64/crtend.S
new file mode 100644
index 000000000..72bdca089
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/crtend.S
@@ -0,0 +1,121 @@
+/* Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Contributed by Jes Sorensen, <Jes.Sorensen@cern.ch>
+
+ 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 "auto-host.h"
+
+.section .ctors,"aw","progbits"
+ .align 8
+__CTOR_END__:
+ data8 0
+
+.section .dtors,"aw","progbits"
+ .align 8
+__DTOR_END__:
+ data8 0
+
+.section .jcr,"aw","progbits"
+ .align 8
+__JCR_END__:
+ data8 0
+
+#ifdef HAVE_INITFINI_ARRAY_SUPPORT
+ .global __do_global_ctors_aux
+ .hidden __do_global_ctors_aux
+#else /* !HAVE_INITFINI_ARRAY_SUPPORT */
+/*
+ * Fragment of the ELF _init routine that invokes our dtor cleanup.
+ *
+ * We make the call by indirection, because in large programs the
+ * .fini and .init sections are not in range of the destination, and
+ * we cannot allow the linker to insert a stub at the end of this
+ * fragment of the _fini function. Further, Itanium does not implement
+ * the long branch instructions, and we do not wish every program to
+ * trap to the kernel for emulation.
+ *
+ * Note that we require __do_global_ctors_aux to preserve the GP,
+ * so that the next fragment in .fini gets the right value.
+ */
+.section .init,"ax","progbits"
+ { .mlx
+ movl r2 = @pcrel(__do_global_ctors_aux - 16)
+ }
+ { .mii
+ mov r3 = ip
+ ;;
+ add r2 = r2, r3
+ ;;
+ }
+ { .mib
+ mov b6 = r2
+ br.call.sptk.many b0 = b6
+ ;;
+ }
+#endif /* !HAVE_INITFINI_ARRAY_SUPPORT */
+
+.text
+ .align 32
+ .proc __do_global_ctors_aux
+__do_global_ctors_aux:
+ .prologue
+ /*
+ for (loc0 = __CTOR_END__-1; *p != -1; --p)
+ (*p) ();
+ */
+ .save ar.pfs, r34
+ alloc loc2 = ar.pfs, 0, 5, 0, 0
+ movl loc0 = @gprel(__CTOR_END__ - 8)
+ ;;
+
+ add loc0 = loc0, gp
+ ;;
+ ld8 loc3 = [loc0], -8
+ .save rp, loc1
+ mov loc1 = rp
+ .body
+ ;;
+
+ cmp.eq p6, p0 = -1, loc3
+ mov loc4 = gp
+(p6) br.cond.spnt.few .exit
+
+.loop: ld8 r15 = [loc3], 8
+ ;;
+ ld8 gp = [loc3]
+ mov b6 = r15
+
+ ld8 loc3 = [loc0], -8
+ nop 0
+ br.call.sptk.many rp = b6
+ ;;
+
+ cmp.ne p6, p0 = -1, loc3
+ nop 0
+(p6) br.cond.sptk.few .loop
+
+.exit: mov gp = loc3
+ mov rp = loc1
+ mov ar.pfs = loc2
+
+ br.ret.sptk.many rp
+ .endp __do_global_ctors_aux
diff --git a/gcc-4.9/libgcc/config/ia64/crtfastmath.c b/gcc-4.9/libgcc/config/ia64/crtfastmath.c
new file mode 100644
index 000000000..34b679236
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/crtfastmath.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2001-2014 Free Software Foundation, Inc.
+ Contributed by David Mosberger <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/>. */
+
+/* We could call fesetenv() here but that would create a confusing
+ dependency on libm (since that is where fesetenv() gets defined.
+ To avoid this, just do everything locally. */
+#define FE_NONIEEE_ENV 0x0009a04d0270037f
+
+static void __attribute__((constructor))
+__ia64_set_fast_math (void)
+{
+ __asm__ __volatile__ ("mov.m ar.fpsr=%0" : : "r"(FE_NONIEEE_ENV));
+}
diff --git a/gcc-4.9/libgcc/config/ia64/crti.S b/gcc-4.9/libgcc/config/ia64/crti.S
new file mode 100644
index 000000000..6326053de
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/crti.S
@@ -0,0 +1,53 @@
+# Copyright (C) 2000-2014 Free Software Foundation, Inc.
+# Written By Timothy Wall
+#
+# 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/>.
+
+# This file just make a stack frame for the contents of the .fini and
+# .init sections. Users may put any desired instructions in those
+# sections.
+
+ .section ".init"
+ .align 16
+ .global _init
+_init:
+ .prologue 14, 33
+ .save ar.pfs, r34
+ alloc r34 = ar.pfs, 0, 4, 0, 0
+ .vframe r35
+ mov r35 = r12
+ .save rp, r33
+ mov r33 = b0
+ .body
+
+ .section ".fini"
+ .align 16
+ .global _fini
+_fini:
+ .prologue 14, 33
+ .save ar.pfs, r34
+ alloc r34 = ar.pfs, 0, 4, 0, 0
+ .vframe r35
+ mov r35 = r12
+ .save rp, r33
+ mov r33 = b0
+ .body
+
+# end of crti.S
diff --git a/gcc-4.9/libgcc/config/ia64/crtn.S b/gcc-4.9/libgcc/config/ia64/crtn.S
new file mode 100644
index 000000000..7a9558fd0
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/crtn.S
@@ -0,0 +1,43 @@
+# Copyright (C) 2000-2014 Free Software Foundation, Inc.
+# Written By Timothy Wall
+#
+# 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/>.
+
+# This file just makes sure that the .fini and .init sections do in
+# fact return. Users may put any desired instructions in those sections.
+# This file is the last thing linked into any executable.
+
+ .section ".init"
+ ;;
+ mov ar.pfs = r34
+ mov b0 = r33
+ .restore sp
+ mov r12 = r35
+ br.ret.sptk.many b0
+
+ .section ".fini"
+ ;;
+ mov ar.pfs = r34
+ mov b0 = r33
+ .restore sp
+ mov r12 = r35
+ br.ret.sptk.many b0
+
+# end of crtn.S
diff --git a/gcc-4.9/libgcc/config/ia64/fde-glibc.c b/gcc-4.9/libgcc/config/ia64/fde-glibc.c
new file mode 100644
index 000000000..8643b86ba
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/fde-glibc.c
@@ -0,0 +1,161 @@
+/* Copyright (C) 2000-2014 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, unw_word *segment_base, unw_word *gp,
+ struct unw_table_entry *ent ATTRIBUTE_UNUSED)
+{
+ struct unw_ia64_callback_data data;
+
+ data.pc = (Elf64_Addr) pc;
+ data.segment_base = segment_base;
+ data.gp = gp;
+ data.ret = NULL;
+
+ if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
+ return NULL;
+
+ return data.ret;
+}
diff --git a/gcc-4.9/libgcc/config/ia64/fde-vms.c b/gcc-4.9/libgcc/config/ia64/fde-vms.c
new file mode 100644
index 000000000..5dffe7f67
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/fde-vms.c
@@ -0,0 +1,159 @@
+/* Copyright (C) 2004-2014 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 "libgcc_tm.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "unwind-ia64.h"
+
+#include <ossddef.h>
+#ifndef SS$_NORMAL
+#define SS$_NORMAL 1
+#endif
+
+#define UNW_IVMS_MODE(HEADER) (((HEADER) >> 44) & 0x3L)
+
+typedef struct
+{
+ unw_word start_offset;
+ unw_word end_offset;
+ unw_word info_offset;
+ unw_word 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, unw_word *segment_base,
+ unw_word *gp, struct unw_table_entry *ent)
+{
+ vms_unw_table_entry vueblock;
+
+ if (SYS$GET_UNWIND_ENTRY_INFO (pc, &vueblock, 0) != SS$_NORMAL)
+ return 0;
+
+ /* If there is no unwind information, use fallback. */
+ if (vueblock.info_offset == 0)
+ return 0;
+
+ /* If we need to force fallback processing, just pretend there is
+ no entry. */
+ if (force_fallback_processing_for (pc, &vueblock))
+ return 0;
+
+ *segment_base = 0; /* ??? Fixme. ??? */
+ *gp = vueblock.gp_value;
+ ent->start_offset = vueblock.start_offset;
+ ent->end_offset = vueblock.end_offset;
+ ent->info_offset = vueblock.info_offset;
+
+ return ent;
+}
diff --git a/gcc-4.9/libgcc/config/ia64/lib1funcs.S b/gcc-4.9/libgcc/config/ia64/lib1funcs.S
new file mode 100644
index 000000000..d47a00f8f
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/lib1funcs.S
@@ -0,0 +1,795 @@
+/* Copyright (C) 2000-2014 Free Software Foundation, Inc.
+ Contributed by James E. Wilson <wilson@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/>. */
+
+#ifdef L__divxf3
+// Compute a 80-bit IEEE double-extended quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// farg0 holds the dividend. farg1 holds the divisor.
+//
+// __divtf3 is an alternate symbol name for backward compatibility.
+
+ .text
+ .align 16
+ .global __divxf3
+ .proc __divxf3
+__divxf3:
+#ifdef SHARED
+ .global __divtf3
+__divtf3:
+#endif
+ cmp.eq p7, p0 = r0, r0
+ frcpa.s0 f10, p6 = farg0, farg1
+ ;;
+(p6) cmp.ne p7, p0 = r0, r0
+ .pred.rel.mutex p6, p7
+(p6) fnma.s1 f11 = farg1, f10, f1
+(p6) fma.s1 f12 = farg0, f10, f0
+ ;;
+(p6) fma.s1 f13 = f11, f11, f0
+(p6) fma.s1 f14 = f11, f11, f11
+ ;;
+(p6) fma.s1 f11 = f13, f13, f11
+(p6) fma.s1 f13 = f14, f10, f10
+ ;;
+(p6) fma.s1 f10 = f13, f11, f10
+(p6) fnma.s1 f11 = farg1, f12, farg0
+ ;;
+(p6) fma.s1 f11 = f11, f10, f12
+(p6) fnma.s1 f12 = farg1, f10, f1
+ ;;
+(p6) fma.s1 f10 = f12, f10, f10
+(p6) fnma.s1 f12 = farg1, f11, farg0
+ ;;
+(p6) fma.s0 fret0 = f12, f10, f11
+(p7) mov fret0 = f10
+ br.ret.sptk rp
+ .endp __divxf3
+#endif
+
+#ifdef L__divdf3
+// Compute a 64-bit IEEE double quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// farg0 holds the dividend. farg1 holds the divisor.
+
+ .text
+ .align 16
+ .global __divdf3
+ .proc __divdf3
+__divdf3:
+ cmp.eq p7, p0 = r0, r0
+ frcpa.s0 f10, p6 = farg0, farg1
+ ;;
+(p6) cmp.ne p7, p0 = r0, r0
+ .pred.rel.mutex p6, p7
+(p6) fmpy.s1 f11 = farg0, f10
+(p6) fnma.s1 f12 = farg1, f10, f1
+ ;;
+(p6) fma.s1 f11 = f12, f11, f11
+(p6) fmpy.s1 f13 = f12, f12
+ ;;
+(p6) fma.s1 f10 = f12, f10, f10
+(p6) fma.s1 f11 = f13, f11, f11
+ ;;
+(p6) fmpy.s1 f12 = f13, f13
+(p6) fma.s1 f10 = f13, f10, f10
+ ;;
+(p6) fma.d.s1 f11 = f12, f11, f11
+(p6) fma.s1 f10 = f12, f10, f10
+ ;;
+(p6) fnma.d.s1 f8 = farg1, f11, farg0
+ ;;
+(p6) fma.d fret0 = f8, f10, f11
+(p7) mov fret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __divdf3
+#endif
+
+#ifdef L__divsf3
+// Compute a 32-bit IEEE float quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// farg0 holds the dividend. farg1 holds the divisor.
+
+ .text
+ .align 16
+ .global __divsf3
+ .proc __divsf3
+__divsf3:
+ cmp.eq p7, p0 = r0, r0
+ frcpa.s0 f10, p6 = farg0, farg1
+ ;;
+(p6) cmp.ne p7, p0 = r0, r0
+ .pred.rel.mutex p6, p7
+(p6) fmpy.s1 f8 = farg0, f10
+(p6) fnma.s1 f9 = farg1, f10, f1
+ ;;
+(p6) fma.s1 f8 = f9, f8, f8
+(p6) fmpy.s1 f9 = f9, f9
+ ;;
+(p6) fma.s1 f8 = f9, f8, f8
+(p6) fmpy.s1 f9 = f9, f9
+ ;;
+(p6) fma.d.s1 f10 = f9, f8, f8
+ ;;
+(p6) fnorm.s.s0 fret0 = f10
+(p7) mov fret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __divsf3
+#endif
+
+#ifdef L__divdi3
+// Compute a 64-bit integer quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __divdi3
+ .proc __divdi3
+__divdi3:
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ // Convert the inputs to FP, so that they won't be treated as unsigned.
+ fcvt.xf f8 = f8
+ fcvt.xf f9 = f9
+(p7) break 1
+ ;;
+ // Compute the reciprocal approximation.
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+ // 3 Newton-Raphson iterations.
+(p6) fnma.s1 f11 = f9, f10, f1
+(p6) fmpy.s1 f12 = f8, f10
+ ;;
+(p6) fmpy.s1 f13 = f11, f11
+(p6) fma.s1 f12 = f11, f12, f12
+ ;;
+(p6) fma.s1 f10 = f11, f10, f10
+(p6) fma.s1 f11 = f13, f12, f12
+ ;;
+(p6) fma.s1 f10 = f13, f10, f10
+(p6) fnma.s1 f12 = f9, f11, f8
+ ;;
+(p6) fma.s1 f10 = f12, f10, f11
+ ;;
+ // Round quotient to an integer.
+ fcvt.fx.trunc.s1 f10 = f10
+ ;;
+ // Transfer result to GP registers.
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __divdi3
+#endif
+
+#ifdef L__moddi3
+// Compute a 64-bit integer modulus.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend (a). in1 holds the divisor (b).
+
+ .text
+ .align 16
+ .global __moddi3
+ .proc __moddi3
+__moddi3:
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ setf.sig f14 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ // Convert the inputs to FP, so that they won't be treated as unsigned.
+ fcvt.xf f8 = f14
+ fcvt.xf f9 = f9
+(p7) break 1
+ ;;
+ // Compute the reciprocal approximation.
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+ // 3 Newton-Raphson iterations.
+(p6) fmpy.s1 f12 = f8, f10
+(p6) fnma.s1 f11 = f9, f10, f1
+ ;;
+(p6) fma.s1 f12 = f11, f12, f12
+(p6) fmpy.s1 f13 = f11, f11
+ ;;
+(p6) fma.s1 f10 = f11, f10, f10
+(p6) fma.s1 f11 = f13, f12, f12
+ ;;
+ sub in1 = r0, in1
+(p6) fma.s1 f10 = f13, f10, f10
+(p6) fnma.s1 f12 = f9, f11, f8
+ ;;
+ setf.sig f9 = in1
+(p6) fma.s1 f10 = f12, f10, f11
+ ;;
+ fcvt.fx.trunc.s1 f10 = f10
+ ;;
+ // r = q * (-b) + a
+ xma.l f10 = f10, f9, f14
+ ;;
+ // Transfer result to GP registers.
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __moddi3
+#endif
+
+#ifdef L__udivdi3
+// Compute a 64-bit unsigned integer quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __udivdi3
+ .proc __udivdi3
+__udivdi3:
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ // Convert the inputs to FP, to avoid FP software-assist faults.
+ fcvt.xuf.s1 f8 = f8
+ fcvt.xuf.s1 f9 = f9
+(p7) break 1
+ ;;
+ // Compute the reciprocal approximation.
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+ // 3 Newton-Raphson iterations.
+(p6) fnma.s1 f11 = f9, f10, f1
+(p6) fmpy.s1 f12 = f8, f10
+ ;;
+(p6) fmpy.s1 f13 = f11, f11
+(p6) fma.s1 f12 = f11, f12, f12
+ ;;
+(p6) fma.s1 f10 = f11, f10, f10
+(p6) fma.s1 f11 = f13, f12, f12
+ ;;
+(p6) fma.s1 f10 = f13, f10, f10
+(p6) fnma.s1 f12 = f9, f11, f8
+ ;;
+(p6) fma.s1 f10 = f12, f10, f11
+ ;;
+ // Round quotient to an unsigned integer.
+ fcvt.fxu.trunc.s1 f10 = f10
+ ;;
+ // Transfer result to GP registers.
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __udivdi3
+#endif
+
+#ifdef L__umoddi3
+// Compute a 64-bit unsigned integer modulus.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend (a). in1 holds the divisor (b).
+
+ .text
+ .align 16
+ .global __umoddi3
+ .proc __umoddi3
+__umoddi3:
+ .regstk 2,0,0,0
+ // Transfer inputs to FP registers.
+ setf.sig f14 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ // Convert the inputs to FP, to avoid FP software assist faults.
+ fcvt.xuf.s1 f8 = f14
+ fcvt.xuf.s1 f9 = f9
+(p7) break 1;
+ ;;
+ // Compute the reciprocal approximation.
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+ // 3 Newton-Raphson iterations.
+(p6) fmpy.s1 f12 = f8, f10
+(p6) fnma.s1 f11 = f9, f10, f1
+ ;;
+(p6) fma.s1 f12 = f11, f12, f12
+(p6) fmpy.s1 f13 = f11, f11
+ ;;
+(p6) fma.s1 f10 = f11, f10, f10
+(p6) fma.s1 f11 = f13, f12, f12
+ ;;
+ sub in1 = r0, in1
+(p6) fma.s1 f10 = f13, f10, f10
+(p6) fnma.s1 f12 = f9, f11, f8
+ ;;
+ setf.sig f9 = in1
+(p6) fma.s1 f10 = f12, f10, f11
+ ;;
+ // Round quotient to an unsigned integer.
+ fcvt.fxu.trunc.s1 f10 = f10
+ ;;
+ // r = q * (-b) + a
+ xma.l f10 = f10, f9, f14
+ ;;
+ // Transfer result to GP registers.
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __umoddi3
+#endif
+
+#ifdef L__divsi3
+// Compute a 32-bit integer quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __divsi3
+ .proc __divsi3
+__divsi3:
+ .regstk 2,0,0,0
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ sxt4 in0 = in0
+ sxt4 in1 = in1
+ ;;
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+(p7) break 1
+ ;;
+ mov r2 = 0x0ffdd
+ fcvt.xf f8 = f8
+ fcvt.xf f9 = f9
+ ;;
+ setf.exp f11 = r2
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+(p6) fmpy.s1 f8 = f8, f10
+(p6) fnma.s1 f9 = f9, f10, f1
+ ;;
+(p6) fma.s1 f8 = f9, f8, f8
+(p6) fma.s1 f9 = f9, f9, f11
+ ;;
+(p6) fma.s1 f10 = f9, f8, f8
+ ;;
+ fcvt.fx.trunc.s1 f10 = f10
+ ;;
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __divsi3
+#endif
+
+#ifdef L__modsi3
+// Compute a 32-bit integer modulus.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __modsi3
+ .proc __modsi3
+__modsi3:
+ .regstk 2,0,0,0
+ mov r2 = 0x0ffdd
+ sxt4 in0 = in0
+ sxt4 in1 = in1
+ ;;
+ setf.sig f13 = r32
+ setf.sig f9 = r33
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ sub in1 = r0, in1
+ fcvt.xf f8 = f13
+ fcvt.xf f9 = f9
+ ;;
+ setf.exp f11 = r2
+ frcpa.s1 f10, p6 = f8, f9
+(p7) break 1
+ ;;
+(p6) fmpy.s1 f12 = f8, f10
+(p6) fnma.s1 f10 = f9, f10, f1
+ ;;
+ setf.sig f9 = in1
+(p6) fma.s1 f12 = f10, f12, f12
+(p6) fma.s1 f10 = f10, f10, f11
+ ;;
+(p6) fma.s1 f10 = f10, f12, f12
+ ;;
+ fcvt.fx.trunc.s1 f10 = f10
+ ;;
+ xma.l f10 = f10, f9, f13
+ ;;
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __modsi3
+#endif
+
+#ifdef L__udivsi3
+// Compute a 32-bit unsigned integer quotient.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __udivsi3
+ .proc __udivsi3
+__udivsi3:
+ .regstk 2,0,0,0
+ mov r2 = 0x0ffdd
+ zxt4 in0 = in0
+ zxt4 in1 = in1
+ ;;
+ setf.sig f8 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ fcvt.xf f8 = f8
+ fcvt.xf f9 = f9
+(p7) break 1
+ ;;
+ setf.exp f11 = r2
+ frcpa.s1 f10, p6 = f8, f9
+ ;;
+(p6) fmpy.s1 f8 = f8, f10
+(p6) fnma.s1 f9 = f9, f10, f1
+ ;;
+(p6) fma.s1 f8 = f9, f8, f8
+(p6) fma.s1 f9 = f9, f9, f11
+ ;;
+(p6) fma.s1 f10 = f9, f8, f8
+ ;;
+ fcvt.fxu.trunc.s1 f10 = f10
+ ;;
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __udivsi3
+#endif
+
+#ifdef L__umodsi3
+// Compute a 32-bit unsigned integer modulus.
+//
+// From the Intel IA-64 Optimization Guide, choose the minimum latency
+// alternative.
+//
+// in0 holds the dividend. in1 holds the divisor.
+
+ .text
+ .align 16
+ .global __umodsi3
+ .proc __umodsi3
+__umodsi3:
+ .regstk 2,0,0,0
+ mov r2 = 0x0ffdd
+ zxt4 in0 = in0
+ zxt4 in1 = in1
+ ;;
+ setf.sig f13 = in0
+ setf.sig f9 = in1
+ // Check divide by zero.
+ cmp.ne.unc p0,p7=0,in1
+ ;;
+ sub in1 = r0, in1
+ fcvt.xf f8 = f13
+ fcvt.xf f9 = f9
+ ;;
+ setf.exp f11 = r2
+ frcpa.s1 f10, p6 = f8, f9
+(p7) break 1;
+ ;;
+(p6) fmpy.s1 f12 = f8, f10
+(p6) fnma.s1 f10 = f9, f10, f1
+ ;;
+ setf.sig f9 = in1
+(p6) fma.s1 f12 = f10, f12, f12
+(p6) fma.s1 f10 = f10, f10, f11
+ ;;
+(p6) fma.s1 f10 = f10, f12, f12
+ ;;
+ fcvt.fxu.trunc.s1 f10 = f10
+ ;;
+ xma.l f10 = f10, f9, f13
+ ;;
+ getf.sig ret0 = f10
+ br.ret.sptk rp
+ ;;
+ .endp __umodsi3
+#endif
+
+#ifdef L__save_stack_nonlocal
+// Notes on save/restore stack nonlocal: We read ar.bsp but write
+// ar.bspstore. This is because ar.bsp can be read at all times
+// (independent of the RSE mode) but since it's read-only we need to
+// restore the value via ar.bspstore. This is OK because
+// ar.bsp==ar.bspstore after executing "flushrs".
+
+// void __ia64_save_stack_nonlocal(void *save_area, void *stack_pointer)
+
+ .text
+ .align 16
+ .global __ia64_save_stack_nonlocal
+ .proc __ia64_save_stack_nonlocal
+__ia64_save_stack_nonlocal:
+ { .mmf
+ alloc r18 = ar.pfs, 2, 0, 0, 0
+ mov r19 = ar.rsc
+ ;;
+ }
+ { .mmi
+ flushrs
+ st8 [in0] = in1, 24
+ and r19 = 0x1c, r19
+ ;;
+ }
+ { .mmi
+ st8 [in0] = r18, -16
+ mov ar.rsc = r19
+ or r19 = 0x3, r19
+ ;;
+ }
+ { .mmi
+ mov r16 = ar.bsp
+ mov r17 = ar.rnat
+ adds r2 = 8, in0
+ ;;
+ }
+ { .mmi
+ st8 [in0] = r16
+ st8 [r2] = r17
+ }
+ { .mib
+ mov ar.rsc = r19
+ br.ret.sptk.few rp
+ ;;
+ }
+ .endp __ia64_save_stack_nonlocal
+#endif
+
+#ifdef L__nonlocal_goto
+// void __ia64_nonlocal_goto(void *target_label, void *save_area,
+// void *static_chain);
+
+ .text
+ .align 16
+ .global __ia64_nonlocal_goto
+ .proc __ia64_nonlocal_goto
+__ia64_nonlocal_goto:
+ { .mmi
+ alloc r20 = ar.pfs, 3, 0, 0, 0
+ ld8 r12 = [in1], 8
+ mov.ret.sptk rp = in0, .L0
+ ;;
+ }
+ { .mmf
+ ld8 r16 = [in1], 8
+ mov r19 = ar.rsc
+ ;;
+ }
+ { .mmi
+ flushrs
+ ld8 r17 = [in1], 8
+ and r19 = 0x1c, r19
+ ;;
+ }
+ { .mmi
+ ld8 r18 = [in1]
+ mov ar.rsc = r19
+ or r19 = 0x3, r19
+ ;;
+ }
+ { .mmi
+ mov ar.bspstore = r16
+ ;;
+ mov ar.rnat = r17
+ ;;
+ }
+ { .mmi
+ loadrs
+ invala
+ mov r15 = in2
+ ;;
+ }
+.L0: { .mib
+ mov ar.rsc = r19
+ mov ar.pfs = r18
+ br.ret.sptk.few rp
+ ;;
+ }
+ .endp __ia64_nonlocal_goto
+#endif
+
+#ifdef L__restore_stack_nonlocal
+// This is mostly the same as nonlocal_goto above.
+// ??? This has not been tested yet.
+
+// void __ia64_restore_stack_nonlocal(void *save_area)
+
+ .text
+ .align 16
+ .global __ia64_restore_stack_nonlocal
+ .proc __ia64_restore_stack_nonlocal
+__ia64_restore_stack_nonlocal:
+ { .mmf
+ alloc r20 = ar.pfs, 4, 0, 0, 0
+ ld8 r12 = [in0], 8
+ ;;
+ }
+ { .mmb
+ ld8 r16=[in0], 8
+ mov r19 = ar.rsc
+ ;;
+ }
+ { .mmi
+ flushrs
+ ld8 r17 = [in0], 8
+ and r19 = 0x1c, r19
+ ;;
+ }
+ { .mmf
+ ld8 r18 = [in0]
+ mov ar.rsc = r19
+ ;;
+ }
+ { .mmi
+ mov ar.bspstore = r16
+ ;;
+ mov ar.rnat = r17
+ or r19 = 0x3, r19
+ ;;
+ }
+ { .mmf
+ loadrs
+ invala
+ ;;
+ }
+.L0: { .mib
+ mov ar.rsc = r19
+ mov ar.pfs = r18
+ br.ret.sptk.few rp
+ ;;
+ }
+ .endp __ia64_restore_stack_nonlocal
+#endif
+
+#ifdef L__trampoline
+// Implement the nested function trampoline. This is out of line
+// so that we don't have to bother with flushing the icache, as
+// well as making the on-stack trampoline smaller.
+//
+// The trampoline has the following form:
+//
+// +-------------------+ >
+// TRAMP: | __ia64_trampoline | |
+// +-------------------+ > fake function descriptor
+// | TRAMP+16 | |
+// +-------------------+ >
+// | target descriptor |
+// +-------------------+
+// | static link |
+// +-------------------+
+
+ .text
+ .align 16
+ .global __ia64_trampoline
+ .proc __ia64_trampoline
+__ia64_trampoline:
+ { .mmi
+ ld8 r2 = [r1], 8
+ ;;
+ ld8 r15 = [r1]
+ }
+ { .mmi
+ ld8 r3 = [r2], 8
+ ;;
+ ld8 r1 = [r2]
+ mov b6 = r3
+ }
+ { .bbb
+ br.sptk.many b6
+ ;;
+ }
+ .endp __ia64_trampoline
+#endif
+
+#ifdef SHARED
+// Thunks for backward compatibility.
+#ifdef L_fixtfdi
+ .text
+ .align 16
+ .global __fixtfti
+ .proc __fixtfti
+__fixtfti:
+ { .bbb
+ br.sptk.many __fixxfti
+ ;;
+ }
+ .endp __fixtfti
+#endif
+#ifdef L_fixunstfdi
+ .align 16
+ .global __fixunstfti
+ .proc __fixunstfti
+__fixunstfti:
+ { .bbb
+ br.sptk.many __fixunsxfti
+ ;;
+ }
+ .endp __fixunstfti
+#endif
+#ifdef L_floatditf
+ .align 16
+ .global __floattitf
+ .proc __floattitf
+__floattitf:
+ { .bbb
+ br.sptk.many __floattixf
+ ;;
+ }
+ .endp __floattitf
+#endif
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/libgcc-glibc.ver b/gcc-4.9/libgcc/config/ia64/libgcc-glibc.ver
new file mode 100644
index 000000000..793745250
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/libgcc-glibc.ver
@@ -0,0 +1,97 @@
+# Copyright (C) 2009-2014 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/>.
+
+# 128 bit long double support was introduced with GCC 4.4.0. These lines
+# make the symbols to get @@GCC_4.4.0 attached.
+
+%exclude {
+ __addtf3
+ __divtc3
+ __divtf3
+ __eqtf2
+ __extenddftf2
+ __extendsftf2
+ __extendxftf2
+ __fixtfdi
+ __fixtfsi
+ __fixtfti
+ __fixunstfdi
+ __fixunstfsi
+ __fixunstfti
+ __floatditf
+ __floatsitf
+ __floattitf
+ __floatunditf
+ __floatunsitf
+ __floatuntitf
+ __getf2
+ __gttf2
+ __letf2
+ __lttf2
+ __multc3
+ __multf3
+ __negtf2
+ __netf2
+ __powitf2
+ __subtf3
+ __trunctfdf2
+ __trunctfsf2
+ __trunctfxf2
+ __unordtf2
+}
+
+# Those TF functions are the aliases of the XF functions before gcc 3.4.
+GCC_3.0 {
+ __divtf3
+ __fixtfti
+ __fixunstfti
+ __floattitf
+}
+
+GCC_4.4.0 {
+ __addtf3
+ __copysigntf3
+ __divtc3
+ __divtf3
+ __eqtf2
+ __extenddftf2
+ __extendsftf2
+ __fabstf2
+ __fixtfdi
+ __fixtfsi
+ __fixunstfdi
+ __fixunstfsi
+ __floatditf
+ __floatsitf
+ __floatunditf
+ __floatunsitf
+ __getf2
+ __gttf2
+ __letf2
+ __lttf2
+ __multc3
+ __multf3
+ __negtf2
+ __netf2
+ __powitf2
+ __subtf3
+ __trunctfdf2
+ __trunctfsf2
+ __trunctfxf2
+ __unordtf2
+}
diff --git a/gcc-4.9/libgcc/config/ia64/libgcc-ia64.ver b/gcc-4.9/libgcc/config/ia64/libgcc-ia64.ver
new file mode 100644
index 000000000..17c2e2e04
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/libgcc-ia64.ver
@@ -0,0 +1,30 @@
+# Copyright (C) 2000-2014 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/>.
+
+GCC_3.0 {
+ # IA-64 symbols
+ __ia64_nonlocal_goto
+ __ia64_personality_v1
+ __ia64_restore_stack_nonlocal
+ __ia64_save_stack_nonlocal
+ __ia64_trampoline
+ __ia64_backtrace
+}
+GCC_3.3.2 {
+ _Unwind_GetBSP
+}
diff --git a/gcc-4.9/libgcc/config/ia64/linux-unwind.h b/gcc-4.9/libgcc/config/ia64/linux-unwind.h
new file mode 100644
index 000000000..b260b9c2e
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/linux-unwind.h
@@ -0,0 +1,199 @@
+/* DWARF2 EH unwinding support for IA64 Linux.
+ Copyright (C) 2004-2014 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/>. */
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-ia64.c for the structs. */
+
+/* This works only for glibc-2.3 and later, because sigcontext is different
+ in glibc-2.2.4. */
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)
+#include <signal.h>
+#include <sys/ucontext.h>
+
+#define IA64_GATE_AREA_START 0xa000000000000100LL
+#define IA64_GATE_AREA_END 0xa000000000030000LL
+
+#define MD_FALLBACK_FRAME_STATE_FOR ia64_fallback_frame_state
+
+static _Unwind_Reason_Code
+ia64_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ if (context->rp >= IA64_GATE_AREA_START
+ && context->rp < IA64_GATE_AREA_END)
+ {
+ struct sigframe {
+ char scratch[16];
+ unsigned long sig_number;
+ siginfo_t *info;
+ struct sigcontext *sc;
+ } *frame_ = (struct sigframe *)context->psp;
+ struct sigcontext *sc = frame_->sc;
+
+ /* Restore scratch registers in case the unwinder needs to
+ refer to a value stored in one of them. */
+ {
+ int i;
+
+ for (i = 2; i < 4; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ for (i = 8; i < 12; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ for (i = 14; i < 32; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ }
+
+ context->fpsr_loc = &(sc->sc_ar_fpsr);
+ context->signal_pfs_loc = &(sc->sc_ar_pfs);
+ context->lc_loc = &(sc->sc_ar_lc);
+ context->unat_loc = &(sc->sc_ar_unat);
+ context->br_loc[0] = &(sc->sc_br[0]);
+ context->br_loc[6] = &(sc->sc_br[6]);
+ context->br_loc[7] = &(sc->sc_br[7]);
+ context->pr = sc->sc_pr;
+ context->psp = sc->sc_gr[12];
+ context->gp = sc->sc_gr[1];
+ /* Signal frame doesn't have an associated reg. stack frame
+ other than what we adjust for below. */
+ fs -> no_reg_stack_frame = 1;
+
+ if (sc->sc_rbs_base)
+ {
+ /* Need to switch from alternate register backing store. */
+ long ndirty, loadrs = sc->sc_loadrs >> 16;
+ unsigned long alt_bspstore = context->bsp - loadrs;
+ unsigned long bspstore;
+ unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
+
+ ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
+ (unsigned long *) context->bsp);
+ bspstore = (unsigned long)
+ ia64_rse_skip_regs (ar_bsp, -ndirty);
+ ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
+ sc->sc_ar_rnat);
+ }
+
+ /* Don't touch the branch registers o.t. b0, b6 and b7.
+ The kernel doesn't pass the preserved branch registers
+ in the sigcontext but leaves them intact, so there's no
+ need to do anything with them here. */
+ {
+ unsigned long sof = sc->sc_cfm & 0x7f;
+ context->bsp = (unsigned long)
+ ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
+ }
+
+ /* Account for use of br.ret to resume execution of user code. */
+ fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_SPREL;
+ fs->curr.reg[UNW_REG_RP].val
+ = (unsigned long)&(sc->sc_ip) - context->psp;
+ fs->curr.reg[UNW_REG_RP].when = -1;
+
+ fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_SPREL;
+ fs->curr.reg[UNW_REG_PFS].val
+ = (unsigned long)&(sc->sc_cfm) - context->psp;
+ fs ->curr.reg[UNW_REG_PFS].when = -1;
+
+ return _URC_NO_REASON;
+ }
+ return _URC_END_OF_STACK;
+}
+
+#define MD_HANDLE_UNWABI ia64_handle_unwabi
+
+#define ABI_MARKER_OLD_LINUX_SIGTRAMP ((0 << 8) | 's')
+#define ABI_MARKER_OLD_LINUX_INTERRUPT ((0 << 8) | 'i')
+#define ABI_MARKER_LINUX_SIGTRAMP ((3 << 8) | 's')
+#define ABI_MARKER_LINUX_INTERRUPT ((3 << 8) | 'i')
+
+static void
+ia64_handle_unwabi (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ if (fs->unwabi == ABI_MARKER_LINUX_SIGTRAMP
+ || fs->unwabi == ABI_MARKER_OLD_LINUX_SIGTRAMP)
+ {
+ struct sigframe {
+ char scratch[16];
+ unsigned long sig_number;
+ siginfo_t *info;
+ struct sigcontext *sc;
+ } *frame = (struct sigframe *)context->psp;
+ struct sigcontext *sc = frame->sc;
+
+ /* Restore scratch registers in case the unwinder needs to
+ refer to a value stored in one of them. */
+ {
+ int i;
+
+ for (i = 2; i < 4; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ for (i = 8; i < 12; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ for (i = 14; i < 32; i++)
+ context->ireg[i - 2].loc = &sc->sc_gr[i];
+ }
+
+ context->signal_pfs_loc = &(sc->sc_ar_pfs);
+ context->lc_loc = &(sc->sc_ar_lc);
+ context->unat_loc = &(sc->sc_ar_unat);
+ context->br_loc[0] = &(sc->sc_br[0]);
+ context->br_loc[6] = &(sc->sc_br[6]);
+ context->br_loc[7] = &(sc->sc_br[7]);
+ context->pr = sc->sc_pr;
+ context->gp = sc->sc_gr[1];
+ /* Signal frame doesn't have an associated reg. stack frame
+ other than what we adjust for below. */
+ fs -> no_reg_stack_frame = 1;
+
+ if (sc->sc_rbs_base)
+ {
+ /* Need to switch from alternate register backing store. */
+ long ndirty, loadrs = sc->sc_loadrs >> 16;
+ unsigned long alt_bspstore = context->bsp - loadrs;
+ unsigned long bspstore;
+ unsigned long *ar_bsp = (unsigned long *)(sc->sc_ar_bsp);
+
+ ndirty = ia64_rse_num_regs ((unsigned long *) alt_bspstore,
+ (unsigned long *) context->bsp);
+ bspstore = (unsigned long) ia64_rse_skip_regs (ar_bsp, -ndirty);
+ ia64_copy_rbs (context, bspstore, alt_bspstore, loadrs,
+ sc->sc_ar_rnat);
+ }
+
+ /* Don't touch the branch registers o.t. b0, b6 and b7.
+ The kernel doesn't pass the preserved branch registers
+ in the sigcontext but leaves them intact, so there's no
+ need to do anything with them here. */
+ {
+ unsigned long sof = sc->sc_cfm & 0x7f;
+ context->bsp = (unsigned long)
+ ia64_rse_skip_regs ((unsigned long *)(sc->sc_ar_bsp), -sof);
+ }
+
+ /* The use of br.ret to resume execution of user code is already
+ accounted for in the unwind ABI. */
+ }
+}
+#endif /* glibc-2.3 or better */
diff --git a/gcc-4.9/libgcc/config/ia64/quadlib.c b/gcc-4.9/libgcc/config/ia64/quadlib.c
new file mode 100644
index 000000000..e11d4ac31
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/quadlib.c
@@ -0,0 +1,78 @@
+/* Subroutines for long double support.
+ Copyright (C) 2000-2014 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/>. */
+
+extern int _U_Qfcmp (long double a, long double b, int);
+
+int _U_Qfeq (long double, long double);
+int _U_Qfne (long double, long double);
+int _U_Qfgt (long double, long double);
+int _U_Qfge (long double, long double);
+int _U_Qflt (long double, long double);
+int _U_Qfle (long double, long double);
+int _U_Qfcomp (long double, long double);
+
+int
+_U_Qfeq (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 4) != 0);
+}
+
+int
+_U_Qfne (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 4) == 0);
+}
+
+int
+_U_Qfgt (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 17) != 0);
+}
+
+int
+_U_Qfge (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 21) != 0);
+}
+
+int
+_U_Qflt (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 9) != 0);
+}
+
+int
+_U_Qfle (long double a, long double b)
+{
+ return (_U_Qfcmp (a, b, 13) != 0);
+}
+
+int
+_U_Qfcomp (long double a, long double b)
+{
+ if (_U_Qfcmp (a, b, 4) == 0)
+ return 0;
+
+ return (_U_Qfcmp (a, b, 22) != 0 ? 1 : -1);
+}
diff --git a/gcc-4.9/libgcc/config/ia64/sfp-exceptions.c b/gcc-4.9/libgcc/config/ia64/sfp-exceptions.c
new file mode 100644
index 000000000..13d9986c5
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/sfp-exceptions.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ *
+ * 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 "sfp-machine.h"
+
+void
+__sfp_handle_exceptions (int _fex)
+{
+ double d;
+
+ if (_fex & FP_EX_INVALID)
+ {
+ asm volatile ("frcpa.s0 %0, p1 = f0, f0" : "=f" (d) : : "p1");
+ }
+ if (_fex & FP_EX_DIVZERO)
+ {
+ asm volatile ("frcpa.s0 %0, p1 = f1, f0" : "=f" (d) : : "p1");
+ }
+ if (_fex & FP_EX_OVERFLOW)
+ {
+ d = __DBL_MAX__;
+ asm volatile ("fadd.d.s0 %0 = %0, %0" : "+f" (d));
+ }
+ if (_fex & FP_EX_UNDERFLOW)
+ {
+ d = __DBL_MIN__;
+ asm volatile ("fnma.d.s0 %0 = %0, %0, f0" : "+f" (d));
+ }
+ if (_fex & FP_EX_INEXACT)
+ {
+ d = __DBL_MAX__;
+ asm volatile ("fsub.d.s0 %0 = %0, f1" : "+f" (d));
+ }
+}
diff --git a/gcc-4.9/libgcc/config/ia64/sfp-machine.h b/gcc-4.9/libgcc/config/ia64/sfp-machine.h
new file mode 100644
index 000000000..0769fc67c
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/sfp-machine.h
@@ -0,0 +1,95 @@
+#define _FP_W_TYPE_SIZE 64
+#define _FP_W_TYPE unsigned long
+#define _FP_WS_TYPE signed long
+#define _FP_I_TYPE long
+
+typedef int TItype __attribute__ ((mode (TI)));
+typedef unsigned int UTItype __attribute__ ((mode (TI)));
+
+#define TI_BITS (__CHAR_BIT__ * (int)sizeof(TItype))
+
+/* The type of the result of a floating point comparison. This must
+ match `__libgcc_cmp_return__' in GCC for the target. */
+typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
+#define CMPtype __gcc_CMPtype
+
+#define _FP_MUL_MEAT_Q(R,X,Y) \
+ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S _FP_QNANBIT_S
+#define _FP_NANFRAC_D _FP_QNANBIT_D
+#define _FP_NANFRAC_E _FP_QNANBIT_E, 0
+#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0
+
+#define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
+
+#define _FP_NANSIGN_S 1
+#define _FP_NANSIGN_D 1
+#define _FP_NANSIGN_E 1
+#define _FP_NANSIGN_Q 1
+
+/* Here is something Intel misdesigned: the specs don't define
+ the case where we have two NaNs with same mantissas, but
+ different sign. Different operations pick up different NaNs. */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
+ do { \
+ if (_FP_FRAC_GT_##wc(X, Y) \
+ || (_FP_FRAC_EQ_##wc(X,Y) && (OP == '+' || OP == '*'))) \
+ { \
+ R##_s = X##_s; \
+ _FP_FRAC_COPY_##wc(R,X); \
+ } \
+ else \
+ { \
+ R##_s = Y##_s; \
+ _FP_FRAC_COPY_##wc(R,Y); \
+ } \
+ R##_c = FP_CLS_NAN; \
+ } while (0)
+
+#define FP_EX_INVALID 0x01
+#define FP_EX_DENORM 0x02
+#define FP_EX_DIVZERO 0x04
+#define FP_EX_OVERFLOW 0x08
+#define FP_EX_UNDERFLOW 0x10
+#define FP_EX_INEXACT 0x20
+
+#define _FP_TININESS_AFTER_ROUNDING 1
+
+void __sfp_handle_exceptions (int);
+
+#define FP_HANDLE_EXCEPTIONS \
+ do { \
+ if (__builtin_expect (_fex, 0)) \
+ __sfp_handle_exceptions (_fex); \
+ } while (0);
+
+#define FP_RND_NEAREST 0
+#define FP_RND_ZERO 0xc00L
+#define FP_RND_PINF 0x800L
+#define FP_RND_MINF 0x400L
+
+#define FP_RND_MASK 0xc00L
+
+#define _FP_DECL_EX \
+ unsigned long int _fcw __attribute__ ((unused)) = FP_RND_NEAREST
+
+#define FP_INIT_ROUNDMODE \
+ do { \
+ __asm__ __volatile__ ("mov.m %0 = ar.fpsr" : "=r" (_fcw)); \
+ } while (0)
+
+#define FP_ROUNDMODE (_fcw & FP_RND_MASK)
+
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+/* Define ALIASNAME as a strong alias for NAME. */
+#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+#define _strong_alias(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((alias (#name)));
diff --git a/gcc-4.9/libgcc/config/ia64/t-eh-ia64 b/gcc-4.9/libgcc/config/ia64/t-eh-ia64
new file mode 100644
index 000000000..6aa4bb930
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-eh-ia64
@@ -0,0 +1,2 @@
+LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c \
+ $(srcdir)/unwind-c.c
diff --git a/gcc-4.9/libgcc/config/ia64/t-hpux b/gcc-4.9/libgcc/config/ia64/t-hpux
new file mode 100644
index 000000000..ddc1135d7
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-hpux
@@ -0,0 +1,9 @@
+# On HP-UX we do not want _fixtfdi, _fixunstfdi, or _floatditf from
+# LIB1ASMSRC. These functions map the 128 bit conversion function names
+# to 80 bit conversions and were done for Linux backwards compatibility.
+LIB1ASMFUNCS := $(filter-out _fixtfdi _fixunstfdi _floatditf,$(LIB1ASMFUNCS))
+
+# Support routines for HP-UX 128 bit floats.
+LIB2ADD = $(srcdir)/config/ia64/quadlib.c $(srcdir)/floatunsitf.c
+
+LIB2ADDEH = $(srcdir)/unwind-c.c
diff --git a/gcc-4.9/libgcc/config/ia64/t-ia64 b/gcc-4.9/libgcc/config/ia64/t-ia64
new file mode 100644
index 000000000..1776ddd79
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-ia64
@@ -0,0 +1,18 @@
+LIB1ASMSRC = ia64/lib1funcs.S
+
+# We use different names for the DImode div/mod files so that they won't
+# conflict with libgcc2.c files. We used to use __ia64 as a prefix, now
+# we use __ as the prefix. Note that L_divdi3 in libgcc2.c actually defines
+# a TImode divide function, so there is no actual overlap here between
+# libgcc2.c and lib1funcs.S.
+LIB1ASMFUNCS = __divxf3 __divdf3 __divsf3 \
+ __divdi3 __moddi3 __udivdi3 __umoddi3 \
+ __divsi3 __modsi3 __udivsi3 __umodsi3 __save_stack_nonlocal \
+ __nonlocal_goto __restore_stack_nonlocal __trampoline
+
+# ??? Hack to get -P option used when compiling lib1funcs.S, because Intel
+# assembler does not accept # line number as a comment.
+# ??? This breaks C++ pragma interface/implementation, which is used in the
+# C++ part of libgcc2, hence it had to be disabled. Must find some other way
+# to support the Intel assembler.
+#LIBGCC2_DEBUG_CFLAGS = -g1 -P
diff --git a/gcc-4.9/libgcc/config/ia64/t-ia64-elf b/gcc-4.9/libgcc/config/ia64/t-ia64-elf
new file mode 100644
index 000000000..08784dfaf
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-ia64-elf
@@ -0,0 +1,20 @@
+LIB1ASMFUNCS += _fixtfdi _fixunstfdi _floatditf
+
+CUSTOM_CRTSTUFF = yes
+
+# Assemble startup files.
+# FIXME: -I$(gcc_objdir) is necessary to find auto-host.h. Really?
+crtbegin.o: $(srcdir)/config/ia64/crtbegin.S
+ $(CC) $(compile_deps) -I. -I$(gcc_objdir) -c -x assembler-with-cpp \
+ -o $@ $<
+crtend.o: $(srcdir)/config/ia64/crtend.S
+ $(CC) $(compile_deps) -I. -I$(gcc_objdir) -c -x assembler-with-cpp \
+ -o $@ $<
+crtbeginS.o: $(srcdir)/config/ia64/crtbegin.S
+ $(CC) $(compile_deps) -I. -I$(gcc_objdir) -c -x assembler-with-cpp \
+ -o $@ -DSHARED $<
+crtendS.o: $(srcdir)/config/ia64/crtend.S
+ $(CC) $(compile_deps) -I. -I$(gcc_objdir) -c -x assembler-with-cpp \
+ -o $@ -DSHARED $<
+
+SHLIB_MAPFILES += $(srcdir)/config/ia64/libgcc-ia64.ver
diff --git a/gcc-4.9/libgcc/config/ia64/t-linux b/gcc-4.9/libgcc/config/ia64/t-linux
new file mode 100644
index 000000000..e6d72b94a
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-linux
@@ -0,0 +1,5 @@
+# Use system libunwind library on IA-64 GLIBC based system.
+LIB2ADDEH = $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c \
+ $(srcdir)/unwind-compat.c
+
+SHLIB_MAPFILES += $(srcdir)/config/ia64/libgcc-glibc.ver
diff --git a/gcc-4.9/libgcc/config/ia64/t-linux-libunwind b/gcc-4.9/libgcc/config/ia64/t-linux-libunwind
new file mode 100644
index 000000000..8b1736a2d
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-linux-libunwind
@@ -0,0 +1,3 @@
+# Build libunwind for IA-64 GLIBC based system.
+LIBUNWIND = $(srcdir)/config/ia64/fde-glibc.c \
+ $(srcdir)/config/ia64/unwind-ia64.c
diff --git a/gcc-4.9/libgcc/config/ia64/t-slibgcc-hpux b/gcc-4.9/libgcc/config/ia64/t-slibgcc-hpux
new file mode 100644
index 000000000..27c7a661b
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-slibgcc-hpux
@@ -0,0 +1,6 @@
+# Build a shared libgcc library with the HP-UX linker on IA64.
+
+SHLIB_SOVERSION = 0
+# Must include -lunwind in the link, so that libgcc_s.so has the necessary
+# DT_NEEDED entry for libunwind.
+SHLIB_LC += -lunwind
diff --git a/gcc-4.9/libgcc/config/ia64/t-softfp b/gcc-4.9/libgcc/config/ia64/t-softfp
new file mode 100644
index 000000000..0ac35e72d
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-softfp
@@ -0,0 +1,4 @@
+# Provide fallbacks for __builtin_copysignq and __builtin_fabsq.
+LIB2ADD += $(srcdir)/config/ia64/tf-signs.c
+
+LIB2ADD += $(srcdir)/config/ia64/sfp-exceptions.c
diff --git a/gcc-4.9/libgcc/config/ia64/t-softfp-compat b/gcc-4.9/libgcc/config/ia64/t-softfp-compat
new file mode 100644
index 000000000..00f45d51c
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-softfp-compat
@@ -0,0 +1,7 @@
+# Filter out the following TImode functions and provide backward binary
+# compatibility.
+# Replace __dvxf3 _fixtfdi _fixunstfdi _floatditf
+libgcc1-tf-functions = __divxf3 _fixtfdi _fixunstfdi _floatditf
+LIB1ASMFUNCS := $(filter-out $(libgcc1-tf-functions), $(LIB1ASMFUNCS))
+libgcc1-tf-compats = $(addsuffix .S, $(libgcc1-tf-functions))
+LIB2ADD += $(addprefix $(srcdir)/config/ia64/, $(libgcc1-tf-compats))
diff --git a/gcc-4.9/libgcc/config/ia64/t-vms b/gcc-4.9/libgcc/config/ia64/t-vms
new file mode 100644
index 000000000..e95c58d8b
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/t-vms
@@ -0,0 +1,9 @@
+CRTSTUFF_T_CFLAGS = -O0
+CRTSTUFF_T_CFLAGS_S = -O0
+
+crtinitS.o: $(srcdir)/config/ia64/vms-crtinit.S
+ $(gcc_compile) -c -x assembler-with-cpp $<
+
+LIB2ADDEH += $(srcdir)/config/ia64/fde-vms.c
+
+HOST_LIBGCC2_CFLAGS=-mpointer-size=64
diff --git a/gcc-4.9/libgcc/config/ia64/tf-signs.c b/gcc-4.9/libgcc/config/ia64/tf-signs.c
new file mode 100644
index 000000000..ef1a2ec65
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/tf-signs.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2008-2014 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/>. */
+
+union _FP_UNION_Q
+{
+ __float128 flt;
+ struct
+ {
+ unsigned long frac1 : 64;
+ unsigned long frac0 : 48;
+ unsigned exp : 15;
+ unsigned sign : 1;
+ } bits __attribute__((packed));
+};
+
+__float128 __copysigntf3 (__float128, __float128);
+__float128 __fabstf2 (__float128);
+
+__float128
+__copysigntf3 (__float128 a, __float128 b)
+{
+ union _FP_UNION_Q A, B;
+
+ A.flt = a;
+ B.flt = b;
+ A.bits.sign = B.bits.sign;
+
+ return A.flt;
+}
+
+__float128
+__fabstf2 (__float128 a)
+{
+ union _FP_UNION_Q A;
+
+ A.flt = a;
+ A.bits.sign = 0;
+
+ return A.flt;
+}
diff --git a/gcc-4.9/libgcc/config/ia64/unwind-ia64.c b/gcc-4.9/libgcc/config/ia64/unwind-ia64.c
new file mode 100644
index 000000000..6c5207c11
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/unwind-ia64.c
@@ -0,0 +1,2468 @@
+/* Subroutines needed for unwinding IA-64 standard format stack frame
+ info for exception handling.
+ Copyright (C) 1997-2014 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 "libgcc_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
+{
+ unw_word 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) */
+ unw_word 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 */
+ unw_word pr_val; /* predicate values */
+ unw_word pr_mask; /* predicate mask */
+ unw_sword 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
+{
+ unw_word limit;
+ unw_word top;
+};
+
+struct _Unwind_Context
+{
+ /* Initial frame info. */
+ unw_word rnat; /* rse nat collection */
+ unw_word regstk_top; /* lowest address of rbs stored register
+ which uses context->rnat collection */
+
+ /* Current frame info. */
+ unw_word bsp; /* backing store pointer value
+ corresponding to psp. */
+ unw_word sp; /* stack pointer value */
+ unw_word psp; /* previous sp value */
+ unw_word rp; /* return pointer */
+ unw_word pr; /* predicate collection */
+
+ unw_word region_start;/* start of unwind region */
+ unw_word gp; /* global pointer value */
+ void *lsda; /* language specific data area */
+
+ /* Preserved state. */
+ unw_word *bsp_loc; /* previous bsp save location
+ Appears to be write-only? */
+ unw_word *bspstore_loc;
+ unw_word *pfs_loc; /* Save location for pfs in current
+ (corr. to sp) frame. Target
+ contains cfm for caller. */
+ unw_word *signal_pfs_loc;/* Save location for pfs in current
+ signal frame. Target contains
+ pfs for caller. */
+ unw_word *pri_unat_loc;
+ unw_word *unat_loc;
+ unw_word *lc_loc;
+ unw_word *fpsr_loc;
+
+ unw_word eh_data[4];
+
+ struct unw_ireg
+ {
+ unw_word *loc;
+ struct unw_ireg_nat
+ {
+ enum unw_nat_type type : 3;
+ unw_sword off : 61; /* NaT word is at loc+nat.off */
+ } nat;
+ } ireg[32 - 2]; /* Indexed by <register number> - 2 */
+
+ unw_word *br_loc[8];
+ void *fr_loc[32 - 2];
+
+ /* ??? We initially point pri_unat_loc here. The entire NAT bit
+ logic needs work. */
+ unw_word initial_unat;
+};
+
+/* Implicit register save order. See section 11.4.2.3 Rules for Using
+ Unwind Descriptors, rule 3. */
+
+static unsigned char const save_order[] =
+{
+ UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
+ UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
+};
+
+
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+
+/* MASK is a bitmap describing the allocation state of emergency buffers,
+ with bit set indicating free. Return >= 0 if allocation is successful;
+ < 0 if failure. */
+
+static inline int
+atomic_alloc (unsigned int *mask)
+{
+ unsigned int old = *mask, ret, new;
+
+ while (1)
+ {
+ if (old == 0)
+ return -1;
+ ret = old & -old;
+ new = old & ~ret;
+ new = __sync_val_compare_and_swap (mask, old, new);
+ if (old == new)
+ break;
+ old = new;
+ }
+
+ return __builtin_ffs (ret) - 1;
+}
+
+/* Similarly, free an emergency buffer. */
+
+static inline void
+atomic_free (unsigned int *mask, int bit)
+{
+ __sync_xor_and_fetch (mask, 1 << bit);
+}
+
+
+#define SIZE(X) (sizeof(X) / sizeof(*(X)))
+#define MASK_FOR(X) ((2U << (SIZE (X) - 1)) - 1)
+#define PTR_IN(X, P) ((P) >= (X) && (P) < (X) + SIZE (X))
+
+static struct unw_reg_state emergency_reg_state[32];
+static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
+
+static struct unw_labeled_state emergency_labeled_state[8];
+static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
+
+#ifdef ENABLE_MALLOC_CHECKING
+static int reg_state_alloced;
+static int labeled_state_alloced;
+#endif
+
+/* Allocation and deallocation of structures. */
+
+static struct unw_reg_state *
+alloc_reg_state (void)
+{
+ struct unw_reg_state *rs;
+
+#ifdef ENABLE_MALLOC_CHECKING
+ reg_state_alloced++;
+#endif
+
+ rs = malloc (sizeof (struct unw_reg_state));
+ if (!rs)
+ {
+ int n = atomic_alloc (&emergency_reg_state_free);
+ if (n >= 0)
+ rs = &emergency_reg_state[n];
+ }
+
+ return rs;
+}
+
+static void
+free_reg_state (struct unw_reg_state *rs)
+{
+#ifdef ENABLE_MALLOC_CHECKING
+ reg_state_alloced--;
+#endif
+
+ if (PTR_IN (emergency_reg_state, rs))
+ atomic_free (&emergency_reg_state_free, rs - emergency_reg_state);
+ else
+ free (rs);
+}
+
+static struct unw_labeled_state *
+alloc_label_state (void)
+{
+ struct unw_labeled_state *ls;
+
+#ifdef ENABLE_MALLOC_CHECKING
+ labeled_state_alloced++;
+#endif
+
+ ls = malloc(sizeof(struct unw_labeled_state));
+ if (!ls)
+ {
+ int n = atomic_alloc (&emergency_labeled_state_free);
+ if (n >= 0)
+ ls = &emergency_labeled_state[n];
+ }
+
+ return ls;
+}
+
+static void
+free_label_state (struct unw_labeled_state *ls)
+{
+#ifdef ENABLE_MALLOC_CHECKING
+ labeled_state_alloced--;
+#endif
+
+ if (PTR_IN (emergency_labeled_state, ls))
+ atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls);
+ else
+ free (ls);
+}
+
+/* Routines to manipulate the state stack. */
+
+static void
+push (struct unw_state_record *sr)
+{
+ struct unw_reg_state *rs = alloc_reg_state ();
+ memcpy (rs, &sr->curr, sizeof (*rs));
+ sr->curr.next = rs;
+}
+
+static void
+pop (struct unw_state_record *sr)
+{
+ struct unw_reg_state *rs = sr->curr.next;
+
+ if (!rs)
+ abort ();
+ memcpy (&sr->curr, rs, sizeof(*rs));
+ free_reg_state (rs);
+}
+
+/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */
+
+static struct unw_reg_state *
+dup_state_stack (struct unw_reg_state *rs)
+{
+ struct unw_reg_state *copy, *prev = NULL, *first = NULL;
+
+ while (rs)
+ {
+ copy = alloc_reg_state ();
+ memcpy (copy, rs, sizeof(*copy));
+ if (first)
+ prev->next = copy;
+ else
+ first = copy;
+ rs = rs->next;
+ prev = copy;
+ }
+
+ return first;
+}
+
+/* Free all stacked register states (but not RS itself). */
+static void
+free_state_stack (struct unw_reg_state *rs)
+{
+ struct unw_reg_state *p, *next;
+
+ for (p = rs->next; p != NULL; p = next)
+ {
+ next = p->next;
+ free_reg_state (p);
+ }
+ rs->next = NULL;
+}
+
+/* Free all labeled states. */
+
+static void
+free_label_states (struct unw_labeled_state *ls)
+{
+ struct unw_labeled_state *next;
+
+ for (; ls ; ls = next)
+ {
+ next = ls->next;
+
+ free_state_stack (&ls->saved_state);
+ free_label_state (ls);
+ }
+}
+
+/* Unwind decoder routines */
+
+static enum unw_register_index __attribute__((const))
+decode_abreg (unsigned char abreg, int memory)
+{
+ switch (abreg)
+ {
+#if TARGET_ABI_OPEN_VMS
+ /* OpenVMS Calling Standard specifies R3 - R31. */
+ case 0x03 ... 0x1f: return UNW_REG_R2 + (abreg - 0x02);
+#else
+ /* Standard Intel ABI specifies GR 4 - 7. */
+ case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
+#endif
+ case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
+ case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
+ case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
+ case 0x60: return UNW_REG_PR;
+ case 0x61: return UNW_REG_PSP;
+ case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR;
+ case 0x63: return UNW_REG_RP;
+ case 0x64: return UNW_REG_BSP;
+ case 0x65: return UNW_REG_BSPSTORE;
+ case 0x66: return UNW_REG_RNAT;
+ case 0x67: return UNW_REG_UNAT;
+ case 0x68: return UNW_REG_FPSR;
+ case 0x69: return UNW_REG_PFS;
+ case 0x6a: return UNW_REG_LC;
+ default:
+ abort ();
+ }
+}
+
+static void
+set_reg (struct unw_reg_info *reg, enum unw_where where,
+ int when, unw_word val)
+{
+ reg->val = val;
+ reg->where = where;
+ if (reg->when == UNW_WHEN_NEVER)
+ reg->when = when;
+}
+
+static void
+alloc_spill_area (unw_word *offp, unw_word 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;
+ unw_word 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 (&regs[kind - 1], sr->curr.reg + limit[kind - 1],
+ sr->region_start + t);
+ }
+ }
+
+ /* Next, lay out the memory stack spill area. */
+ if (sr->any_spills)
+ {
+ off = sr->spill_offset;
+ alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2,
+ sr->curr.reg + UNW_REG_F31);
+ alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_B1,
+ sr->curr.reg + UNW_REG_B5);
+ alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_R4,
+ sr->curr.reg + UNW_REG_R7);
+ }
+}
+
+/*
+ * Region header descriptors.
+ */
+
+static void
+desc_prologue (int body, unw_word rlen, unsigned char mask,
+ unsigned char grsave, struct unw_state_record *sr)
+{
+ int i;
+
+ if (!(sr->in_body || sr->first_region))
+ finish_prologue (sr);
+ sr->first_region = 0;
+
+ /* Check if we're done. */
+ if (sr->when_target < sr->region_start + sr->region_len)
+ {
+ sr->done = 1;
+ return;
+ }
+
+ for (i = 0; i < sr->epilogue_count; ++i)
+ pop (sr);
+
+ sr->epilogue_count = 0;
+ sr->epilogue_start = UNW_WHEN_NEVER;
+
+ if (!body)
+ push (sr);
+
+ sr->region_start += sr->region_len;
+ sr->region_len = rlen;
+ sr->in_body = body;
+
+ if (!body)
+ {
+ for (i = 0; i < 4; ++i)
+ {
+ if (mask & 0x8)
+ set_reg (sr->curr.reg + save_order[i], UNW_WHERE_GR,
+ sr->region_start + sr->region_len - 1, grsave++);
+ mask <<= 1;
+ }
+ sr->gr_save_loc = grsave;
+ sr->any_spills = 0;
+ sr->imask = 0;
+ sr->spill_offset = 0x10; /* default to psp+16 */
+ }
+}
+
+/*
+ * Prologue descriptors.
+ */
+
+static inline void
+desc_abi (unsigned char abi,
+ unsigned char context,
+ struct unw_state_record *sr)
+{
+ sr->unwabi = (abi << 8) | context;
+}
+
+static inline void
+desc_br_gr (unsigned char brmask, unsigned char gr,
+ struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 5; ++i)
+ {
+ if (brmask & 1)
+ set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR,
+ sr->region_start + sr->region_len - 1, gr++);
+ brmask >>= 1;
+ }
+}
+
+static inline void
+desc_br_mem (unsigned char brmask, struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 5; ++i)
+ {
+ if (brmask & 1)
+ {
+ set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME,
+ sr->region_start + sr->region_len - 1, 0);
+ sr->any_spills = 1;
+ }
+ brmask >>= 1;
+ }
+}
+
+static inline void
+desc_frgr_mem (unsigned char grmask, unw_word frmask,
+ struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if ((grmask & 1) != 0)
+ {
+ set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME,
+ sr->region_start + sr->region_len - 1, 0);
+ sr->any_spills = 1;
+ }
+ grmask >>= 1;
+ }
+ for (i = 0; i < 20; ++i)
+ {
+ if ((frmask & 1) != 0)
+ {
+ enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4;
+ set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME,
+ sr->region_start + sr->region_len - 1, 0);
+ sr->any_spills = 1;
+ }
+ frmask >>= 1;
+ }
+}
+
+static inline void
+desc_fr_mem (unsigned char frmask, struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if ((frmask & 1) != 0)
+ {
+ set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME,
+ sr->region_start + sr->region_len - 1, 0);
+ sr->any_spills = 1;
+ }
+ frmask >>= 1;
+ }
+}
+
+static inline void
+desc_gr_gr (unsigned char grmask, unsigned char gr,
+ struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if ((grmask & 1) != 0)
+ set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR,
+ sr->region_start + sr->region_len - 1, gr++);
+ grmask >>= 1;
+ }
+}
+
+static inline void
+desc_gr_mem (unsigned char grmask, struct unw_state_record *sr)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if ((grmask & 1) != 0)
+ {
+ set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME,
+ sr->region_start + sr->region_len - 1, 0);
+ sr->any_spills = 1;
+ }
+ grmask >>= 1;
+ }
+}
+
+static inline void
+desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr)
+{
+ set_reg (sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE,
+ sr->region_start + MIN ((int)t, sr->region_len - 1), 16*size);
+}
+
+static inline void
+desc_mem_stack_v (unw_word t, struct unw_state_record *sr)
+{
+ sr->curr.reg[UNW_REG_PSP].when
+ = sr->region_start + MIN ((int)t, sr->region_len - 1);
+}
+
+static inline void
+desc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr)
+{
+ set_reg (sr->curr.reg + reg, UNW_WHERE_GR,
+ sr->region_start + sr->region_len - 1, dst);
+}
+
+static inline void
+desc_reg_psprel (unsigned char reg, unw_word pspoff,
+ struct unw_state_record *sr)
+{
+ set_reg (sr->curr.reg + reg, UNW_WHERE_PSPREL,
+ sr->region_start + sr->region_len - 1,
+ 0x10 - 4*pspoff);
+}
+
+static inline void
+desc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr)
+{
+ set_reg (sr->curr.reg + reg, UNW_WHERE_SPREL,
+ sr->region_start + sr->region_len - 1,
+ 4*spoff);
+}
+
+static inline void
+desc_rp_br (unsigned char dst, struct unw_state_record *sr)
+{
+ sr->return_link_reg = dst;
+}
+
+static inline void
+desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr)
+{
+ struct unw_reg_info *reg = sr->curr.reg + regnum;
+
+ if (reg->where == UNW_WHERE_NONE)
+ reg->where = UNW_WHERE_GR_SAVE;
+ reg->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
+}
+
+static inline void
+desc_spill_base (unw_word pspoff, struct unw_state_record *sr)
+{
+ sr->spill_offset = 0x10 - 4*pspoff;
+}
+
+static inline unsigned char *
+desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr)
+{
+ sr->imask = imaskp;
+ return imaskp + (2*sr->region_len + 7)/8;
+}
+
+/*
+ * Body descriptors.
+ */
+static inline void
+desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr)
+{
+ sr->epilogue_start = sr->region_start + sr->region_len - 1 - t;
+ sr->epilogue_count = ecount + 1;
+}
+
+static inline void
+desc_copy_state (unw_word label, struct unw_state_record *sr)
+{
+ struct unw_labeled_state *ls;
+
+ for (ls = sr->labeled_states; ls; ls = ls->next)
+ {
+ if (ls->label == label)
+ {
+ free_state_stack (&sr->curr);
+ memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
+ sr->curr.next = dup_state_stack (ls->saved_state.next);
+ return;
+ }
+ }
+ abort ();
+}
+
+static inline void
+desc_label_state (unw_word label, struct unw_state_record *sr)
+{
+ struct unw_labeled_state *ls = alloc_label_state ();
+
+ ls->label = label;
+ memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
+ ls->saved_state.next = dup_state_stack (sr->curr.next);
+
+ /* Insert into list of labeled states. */
+ ls->next = sr->labeled_states;
+ sr->labeled_states = ls;
+}
+
+/*
+ * General descriptors.
+ */
+
+static inline int
+desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr)
+{
+ if (sr->when_target <= sr->region_start + MIN ((int)t, sr->region_len - 1))
+ return 0;
+ if (qp > 0)
+ {
+ if ((sr->pr_val & (1UL << qp)) == 0)
+ return 0;
+ sr->pr_mask |= (1UL << qp);
+ }
+ return 1;
+}
+
+static inline void
+desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg,
+ struct unw_state_record *sr)
+{
+ struct unw_reg_info *r;
+
+ if (! desc_is_active (qp, t, sr))
+ return;
+
+ r = sr->curr.reg + decode_abreg (abreg, 0);
+ r->where = UNW_WHERE_NONE;
+ r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
+ r->val = 0;
+}
+
+static inline void
+desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg,
+ unsigned char x, unsigned char ytreg,
+ struct unw_state_record *sr)
+{
+ enum unw_where where = UNW_WHERE_GR;
+ struct unw_reg_info *r;
+
+ if (! desc_is_active (qp, t, sr))
+ return;
+
+ if (x)
+ where = UNW_WHERE_BR;
+ else if (ytreg & 0x80)
+ where = UNW_WHERE_FR;
+
+ r = sr->curr.reg + decode_abreg (abreg, 0);
+ r->where = where;
+ r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
+ r->val = ytreg & 0x7f;
+}
+
+static inline void
+desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg,
+ unw_word pspoff, struct unw_state_record *sr)
+{
+ struct unw_reg_info *r;
+
+ if (! desc_is_active (qp, t, sr))
+ return;
+
+ r = sr->curr.reg + decode_abreg (abreg, 1);
+ r->where = UNW_WHERE_PSPREL;
+ r->when = sr->region_start + MIN((int)t, sr->region_len - 1);
+ r->val = 0x10 - 4*pspoff;
+}
+
+static inline void
+desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg,
+ unw_word spoff, struct unw_state_record *sr)
+{
+ struct unw_reg_info *r;
+
+ if (! desc_is_active (qp, t, sr))
+ return;
+
+ r = sr->curr.reg + decode_abreg (abreg, 1);
+ r->where = UNW_WHERE_SPREL;
+ r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
+ r->val = 4*spoff;
+}
+
+
+#define UNW_DEC_BAD_CODE(code) abort ();
+
+/* Region headers. */
+#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg)
+#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg)
+
+/* Prologue descriptors. */
+#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg)
+#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg)
+#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg)
+#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg)
+#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg)
+#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg)
+#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg)
+#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg)
+#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg)
+#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg)
+#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg)
+#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg)
+#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg)
+#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg)
+#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg)
+#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg)
+#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg)
+#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg)
+#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg)
+#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg)
+#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg))
+
+/* Body descriptors. */
+#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg)
+#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg)
+#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg)
+
+/* General unwind descriptors. */
+#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg)
+#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg)
+#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg)
+#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg)
+#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg)
+#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg)
+#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg)
+#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
+
+
+/*
+ * Generic IA-64 unwind info decoder.
+ *
+ * This file is used both by the Linux kernel and objdump. Please keep
+ * the copies of this file in sync.
+ *
+ * You need to customize the decoder by defining the following
+ * macros/constants before including this file:
+ *
+ * Types:
+ * unw_word Unsigned integer type with at least 64 bits
+ *
+ * Register names:
+ * UNW_REG_BSP
+ * UNW_REG_BSPSTORE
+ * UNW_REG_FPSR
+ * UNW_REG_LC
+ * UNW_REG_PFS
+ * UNW_REG_PR
+ * UNW_REG_RNAT
+ * UNW_REG_PSP
+ * UNW_REG_RP
+ * UNW_REG_UNAT
+ *
+ * Decoder action macros:
+ * UNW_DEC_BAD_CODE(code)
+ * UNW_DEC_ABI(fmt,abi,context,arg)
+ * UNW_DEC_BR_GR(fmt,brmask,gr,arg)
+ * UNW_DEC_BR_MEM(fmt,brmask,arg)
+ * UNW_DEC_COPY_STATE(fmt,label,arg)
+ * UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
+ * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
+ * UNW_DEC_FR_MEM(fmt,frmask,arg)
+ * UNW_DEC_GR_GR(fmt,grmask,gr,arg)
+ * UNW_DEC_GR_MEM(fmt,grmask,arg)
+ * UNW_DEC_LABEL_STATE(fmt,label,arg)
+ * UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
+ * UNW_DEC_MEM_STACK_V(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_GR(fmt,r,arg)
+ * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
+ * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
+ * UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
+ * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
+ * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
+ * UNW_DEC_REG_REG(fmt,src,dst,arg)
+ * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
+ * UNW_DEC_REG_WHEN(fmt,reg,t,arg)
+ * UNW_DEC_RESTORE(fmt,t,abreg,arg)
+ * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
+ * UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
+ * UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
+ * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
+ * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ */
+
+static unw_word
+unw_decode_uleb128 (unsigned char **dpp)
+{
+ unsigned shift = 0;
+ unw_word byte, result = 0;
+ unsigned char *bp = *dpp;
+
+ while (1)
+ {
+ byte = *bp++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ *dpp = bp;
+ return result;
+}
+
+static unsigned char *
+unw_decode_x1 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, abreg;
+ unw_word t, off;
+
+ byte1 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x2 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++; byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ ytreg = byte2;
+ x = (byte1 >> 7) & 1;
+ if ((byte1 & 0x80) == 0 && ytreg == 0)
+ UNW_DEC_RESTORE(X2, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x3 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, abreg, qp;
+ unw_word t, off;
+
+ byte1 = *dp++; byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x4 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+ x = (byte2 >> 7) & 1;
+ ytreg = byte3;
+
+ if ((byte2 & 0x80) == 0 && byte3 == 0)
+ UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ int body = (code & 0x20) != 0;
+ unw_word rlen;
+
+ rlen = (code & 0x1f);
+ UNW_DEC_PROLOGUE(R1, body, rlen, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char byte1, mask, grsave;
+ unw_word rlen;
+
+ byte1 = *dp++;
+
+ mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ grsave = (byte1 & 0x7f);
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word rlen;
+
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char brmask = (code & 0x1f);
+
+ UNW_DEC_BR_MEM(P1, brmask, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
+{
+ if ((code & 0x10) == 0)
+ {
+ unsigned char byte1 = *dp++;
+
+ UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
+ (byte1 & 0x7f), arg);
+ }
+ else if ((code & 0x08) == 0)
+ {
+ unsigned char byte1 = *dp++, r, dst;
+
+ r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ dst = (byte1 & 0x7f);
+ switch (r)
+ {
+ case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break;
+ case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break;
+ case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break;
+ case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break;
+ case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break;
+ case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break;
+ case 6: UNW_DEC_RP_BR(P3, dst, arg); break;
+ case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break;
+ case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break;
+ case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break;
+ case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break;
+ case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ else if ((code & 0x7) == 0)
+ UNW_DEC_SPILL_MASK(P4, dp, arg);
+ else if ((code & 0x7) == 1)
+ {
+ unw_word grmask, frmask, byte1, byte2, byte3;
+
+ byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
+ grmask = ((byte1 >> 4) & 0xf);
+ frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
+ UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg);
+ }
+ else
+ UNW_DEC_BAD_CODE(code);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
+{
+ int gregs = (code & 0x10) != 0;
+ unsigned char mask = (code & 0x0f);
+
+ if (gregs)
+ UNW_DEC_GR_MEM(P6, mask, arg);
+ else
+ UNW_DEC_FR_MEM(P6, mask, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char r, byte1, byte2;
+ unw_word t, size;
+
+ if ((code & 0x10) == 0)
+ {
+ r = (code & 0xf);
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 0:
+ size = unw_decode_uleb128 (&dp);
+ UNW_DEC_MEM_STACK_F(P7, t, size, arg);
+ break;
+
+ case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break;
+ case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break;
+ case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break;
+ case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break;
+ case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break;
+ case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break;
+ case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break;
+ case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break;
+ case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break;
+ case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break;
+ case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break;
+ case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break;
+ case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break;
+ case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break;
+ case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ else
+ {
+ switch (code & 0xf)
+ {
+ case 0x0: /* p8 */
+ {
+ r = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break;
+ case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break;
+ case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break;
+ case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break;
+ case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break;
+ case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break;
+ case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break;
+ case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break;
+ case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break;
+ case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break;
+ case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break;
+ case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break;
+ case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break;
+ case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break;
+ case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break;
+ case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ break;
+
+ case 0x1:
+ byte1 = *dp++; byte2 = *dp++;
+ UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
+ break;
+
+ case 0xf: /* p10 */
+ byte1 = *dp++; byte2 = *dp++;
+ UNW_DEC_ABI(P10, byte1, byte2, arg);
+ break;
+
+ case 0x9:
+ return unw_decode_x1 (dp, code, arg);
+
+ case 0xa:
+ return unw_decode_x2 (dp, code, arg);
+
+ case 0xb:
+ return unw_decode_x3 (dp, code, arg);
+
+ case 0xc:
+ return unw_decode_x4 (dp, code, arg);
+
+ default:
+ UNW_DEC_BAD_CODE(code);
+ break;
+ }
+ }
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word label = (code & 0x1f);
+
+ if ((code & 0x20) != 0)
+ UNW_DEC_COPY_STATE(B1, label, arg);
+ else
+ UNW_DEC_LABEL_STATE(B1, label, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word t;
+
+ t = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word t, ecount, label;
+
+ if ((code & 0x10) == 0)
+ {
+ t = unw_decode_uleb128 (&dp);
+ ecount = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE(B3, t, ecount, arg);
+ }
+ else if ((code & 0x07) == 0)
+ {
+ label = unw_decode_uleb128 (&dp);
+ if ((code & 0x08) != 0)
+ UNW_DEC_COPY_STATE(B4, label, arg);
+ else
+ UNW_DEC_LABEL_STATE(B4, label, arg);
+ }
+ else
+ switch (code & 0x7)
+ {
+ case 1: return unw_decode_x1 (dp, code, arg);
+ case 2: return unw_decode_x2 (dp, code, arg);
+ case 3: return unw_decode_x3 (dp, code, arg);
+ case 4: return unw_decode_x4 (dp, code, arg);
+ default: UNW_DEC_BAD_CODE(code); break;
+ }
+ return dp;
+}
+
+typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
+
+static const unw_decoder unw_decode_table[2][8] =
+{
+ /* prologue table: */
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_p1, /* 4 */
+ unw_decode_p2_p5,
+ unw_decode_p6,
+ unw_decode_p7_p10
+ },
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_b1, /* 4 */
+ unw_decode_b1,
+ unw_decode_b2,
+ unw_decode_b3_x4
+ }
+};
+
+/*
+ * Decode one descriptor and return address of next descriptor.
+ */
+static inline unsigned char *
+unw_decode (unsigned char *dp, int inside_body, void *arg)
+{
+ unw_decoder decoder;
+ unsigned char code;
+
+ code = *dp++;
+ decoder = unw_decode_table[inside_body][code >> 5];
+ dp = (*decoder) (dp, code, arg);
+ return dp;
+}
+
+
+/* RSE helper functions. */
+
+static inline unw_word
+ia64_rse_slot_num (unw_word *addr)
+{
+ return (((unw_word) addr) >> 3) & 0x3f;
+}
+
+/* Return TRUE if ADDR is the address of an RNAT slot. */
+static inline unw_word
+ia64_rse_is_rnat_slot (unw_word *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 unw_word *
+ia64_rse_rnat_addr (unw_word *slot_addr)
+{
+ return (unw_word *) ((unw_word) 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 unw_word
+ia64_rse_num_regs (unw_word *bspstore, unw_word *bsp)
+{
+ unw_word 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 unw_word *
+ia64_rse_skip_regs (unw_word *addr, int num_regs)
+{
+ int delta = ia64_rse_slot_num (addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + num_regs + delta/0x3f;
+}
+
+
+/* Copy register backing store from SRC to DST, LEN words
+ (which include both saved registers and nat collections).
+ DST_RNAT is a partial nat collection for DST. SRC and DST
+ don't have to be equal modulo 64 slots, so it cannot be
+ done with a simple memcpy as the nat collections will be
+ at different relative offsets and need to be combined together. */
+static void
+ia64_copy_rbs (struct _Unwind_Context *info, unw_word dst,
+ unw_word src, unw_word len, unw_word dst_rnat)
+{
+ unw_word count;
+ unw_word src_rnat;
+ unw_word shift1, shift2;
+
+ len <<= 3;
+ dst_rnat &= (1ULL << ((dst >> 3) & 0x3f)) - 1;
+ src_rnat = src >= info->regstk_top
+ ? info->rnat : *(unw_word *) (src | 0x1f8);
+ src_rnat &= ~((1ULL << ((src >> 3) & 0x3f)) - 1);
+ /* Just to make sure. */
+ src_rnat &= ~(1ULL << 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 : *(unw_word *) (src | 0x1f8);
+ /* Just to make sure. */
+ src_rnat &= ~(1ULL << 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) & ~(1ULL << 63);
+ if (len <= 0)
+ break;
+ *(unw_word *) 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)
+ {
+ *(unw_word *) 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 & ~0x1ffULL;
+ info->rnat = dst_rnat;
+}
+
+/* Unwind accessors. */
+
+static void
+unw_access_gr (struct _Unwind_Context *info, int regnum,
+ unw_word *val, char *nat, int write)
+{
+ unw_word *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 << ((unw_word) addr & 0x1f8)/8;
+ break;
+
+ case UNW_NAT_REGSTK:
+ if ((unw_word) addr >= info->regstk_top)
+ nat_addr = &info->rnat;
+ else
+ nat_addr = ia64_rse_rnat_addr (addr);
+ nat_mask = 1ULL << ia64_rse_slot_num (addr);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Access a stacked register. */
+ addr = ia64_rse_skip_regs ((unw_word *) info->bsp, regnum - 32);
+ if ((unw_word) addr >= info->regstk_top)
+ nat_addr = &info->rnat;
+ else
+ nat_addr = ia64_rse_rnat_addr (addr);
+ nat_mask = 1UL << ia64_rse_slot_num (addr);
+ }
+
+ if (write)
+ {
+ *addr = *val;
+ if (*nat)
+ *nat_addr |= nat_mask;
+ else
+ *nat_addr &= ~nat_mask;
+ }
+ else
+ {
+ *val = *addr;
+ *nat = (*nat_addr & nat_mask) != 0;
+ }
+}
+
+/* Get the value of register REG as saved in CONTEXT. */
+
+_Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *context, int index)
+{
+ _Unwind_Word ret;
+ char nat;
+
+ if (index == 1)
+ return context->gp;
+ else if (index >= 15 && index <= 18)
+ return context->eh_data[index - 15];
+ else
+ unw_access_gr (context, index, &ret, &nat, 0);
+
+ return ret;
+}
+
+/* Overwrite the saved value for register REG in CONTEXT with VAL. */
+
+void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+ char nat = 0;
+
+ if (index == 1)
+ context->gp = val;
+ else if (index >= 15 && index <= 18)
+ context->eh_data[index - 15] = val;
+ else
+ unw_access_gr (context, index, &val, &nat, 1);
+}
+
+/* Retrieve the return address for CONTEXT. */
+
+inline _Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+ return context->rp;
+}
+
+inline _Unwind_Ptr
+_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
+{
+ *ip_before_insn = 0;
+ return context->rp;
+}
+
+/* Overwrite the return address for CONTEXT with VAL. */
+
+inline void
+_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
+{
+ context->rp = val;
+}
+
+void *
+_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
+{
+ return context->lsda;
+}
+
+_Unwind_Ptr
+_Unwind_GetRegionStart (struct _Unwind_Context *context)
+{
+ return context->region_start;
+}
+
+void *
+_Unwind_FindEnclosingFunction (void *pc)
+{
+ struct unw_table_entry *entp, ent;
+ unw_word segment_base, gp;
+
+ entp = _Unwind_FindTableEntry (pc, &segment_base, &gp, &ent);
+ if (entp == NULL)
+ return NULL;
+ else
+ return (void *)(segment_base + entp->start_offset);
+}
+
+/* Get the value of the CFA as saved in CONTEXT. In GCC/Dwarf2 parlance,
+ the CFA is the value of the stack pointer on entry; In IA-64 unwind
+ parlance, this is the PSP. */
+
+_Unwind_Word
+_Unwind_GetCFA (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->psp;
+}
+
+/* Get the value of the Backing Store Pointer as saved in CONTEXT. */
+
+_Unwind_Word
+_Unwind_GetBSP (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bsp;
+}
+
+#include "md-unwind-support.h"
+
+/* By default, assume personality routine interface compatibility with
+ our expectations. */
+#ifndef MD_UNW_COMPATIBLE_PERSONALITY_P
+#define MD_UNW_COMPATIBLE_PERSONALITY_P(HEADER) 1
+#endif
+
+
+static _Unwind_Reason_Code
+uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ struct unw_table_entry *entp, ent;
+ unw_word *unw, header, length;
+ unsigned char *insn, *insn_end;
+ unw_word 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 = (unw_word *) (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;
+ unw_word 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 ((unw_word *) context->bsp, rval - 32);
+ else if (rval >= 2)
+ addr = context->ireg[rval - 2].loc;
+ else if (rval == 0)
+ {
+ static const unw_word 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 - (unw_word *) 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 - (unw_word *) 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 = *(unw_word *)addr;
+ break;
+ case UNW_REG_UNAT:
+ context->unat_loc = addr;
+ break;
+ case UNW_REG_PR:
+ context->pr = *(unw_word *) 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 = *(unw_word *)addr;
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+static void
+uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ int 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))
+ {
+ unw_word pfs = *context->pfs_loc;
+ unw_word sol = (pfs >> 7) & 0x7f;
+ context->bsp = (unw_word)
+ ia64_rse_skip_regs ((unw_word *) 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;
+ unw_word 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 = (unw_word) 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 = (unw_word) psp;
+ context->rp = (unw_word) 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)
+{
+ unw_word ireg_buf[4], ireg_nat = 0, ireg_pr = 0;
+ unw_word saved_lc;
+ int i;
+
+ /* ??? LC is a fixed register so the call to __builtin_unwind_init in
+ uw_init_context doesn't cause it to be saved. In case it isn't in
+ the user frames either, we need to manually do so here, lest it be
+ clobbered by the loop just below. */
+ if (target->lc_loc == NULL)
+ {
+ register unw_word lc asm ("ar.lc");
+ saved_lc = lc;
+ target->lc_loc = &saved_lc;
+ }
+
+ /* 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 |= (unw_word)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 = (unw_word)
+ ia64_rse_skip_regs ((unw_word *)target->bsp,
+ (*target->pfs_loc >> 7) & 0x7f);
+
+ if (target->bsp < target->regstk_top)
+ target->rnat = *ia64_rse_rnat_addr ((unw_word *) target->bsp);
+
+ /* Provide assembly with the offsets into the _Unwind_Context. */
+ asm volatile ("uc_rnat = %0"
+ : : "i"(offsetof (struct _Unwind_Context, rnat)));
+ asm volatile ("uc_bsp = %0"
+ : : "i"(offsetof (struct _Unwind_Context, bsp)));
+ asm volatile ("uc_psp = %0"
+ : : "i"(offsetof (struct _Unwind_Context, psp)));
+ asm volatile ("uc_rp = %0"
+ : : "i"(offsetof (struct _Unwind_Context, rp)));
+ asm volatile ("uc_pr = %0"
+ : : "i"(offsetof (struct _Unwind_Context, pr)));
+ asm volatile ("uc_gp = %0"
+ : : "i"(offsetof (struct _Unwind_Context, gp)));
+ asm volatile ("uc_pfs_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, pfs_loc)));
+ asm volatile ("uc_unat_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, unat_loc)));
+ asm volatile ("uc_lc_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, lc_loc)));
+ asm volatile ("uc_fpsr_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, fpsr_loc)));
+ asm volatile ("uc_eh_data = %0"
+ : : "i"(offsetof (struct _Unwind_Context, eh_data)));
+ asm volatile ("uc_br_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, br_loc)));
+ asm volatile ("uc_fr_loc = %0"
+ : : "i"(offsetof (struct _Unwind_Context, fr_loc)));
+
+ asm volatile (
+ /* Load up call-saved non-window integer registers from ireg_buf. */
+ "add r20 = 8, %1 \n\t"
+ "mov ar.unat = %2 \n\t"
+ "mov pr = %3, 0x3c0 \n\t"
+ ";; \n\t"
+ "(p6) ld8.fill r4 = [%1] \n\t"
+ "(p7) ld8.fill r5 = [r20] \n\t"
+ "add r21 = uc_br_loc + 16, %0 \n\t"
+ "adds %1 = 16, %1 \n\t"
+ "adds r20 = 16, r20 \n\t"
+ ";; \n\t"
+ "(p8) ld8.fill r6 = [%1] \n\t"
+ "(p9) ld8.fill r7 = [r20] \n\t"
+ "add r20 = uc_br_loc + 8, %0 \n\t"
+ ";; \n\t"
+ /* Load up call-saved branch registers. */
+ "ld8 r22 = [r20], 16 \n\t"
+ "ld8 r23 = [r21], 16 \n\t"
+ ";; \n\t"
+ "ld8 r24 = [r20], 16 \n\t"
+ "ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 32)\n\t"
+ ";; \n\t"
+ "ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 40)\n\t"
+ "ld8 r27 = [r21], 24 \n\t"
+ "cmp.ne p6, p0 = r0, r22 \n\t"
+ ";; \n\t"
+ "ld8 r28 = [r20], 8 \n\t"
+ "(p6) ld8 r22 = [r22] \n\t"
+ "cmp.ne p7, p0 = r0, r23 \n\t"
+ ";; \n\t"
+ "(p7) ld8 r23 = [r23] \n\t"
+ "cmp.ne p8, p0 = r0, r24 \n\t"
+ ";; \n\t"
+ "(p8) ld8 r24 = [r24] \n\t"
+ "(p6) mov b1 = r22 \n\t"
+ "cmp.ne p9, p0 = r0, r25 \n\t"
+ ";; \n\t"
+ "(p9) ld8 r25 = [r25] \n\t"
+ "(p7) mov b2 = r23 \n\t"
+ "cmp.ne p6, p0 = r0, r26 \n\t"
+ ";; \n\t"
+ "(p6) ld8 r26 = [r26] \n\t"
+ "(p8) mov b3 = r24 \n\t"
+ "cmp.ne p7, p0 = r0, r27 \n\t"
+ ";; \n\t"
+ /* Load up call-saved fp registers. */
+ "(p7) ldf.fill f2 = [r27] \n\t"
+ "(p9) mov b4 = r25 \n\t"
+ "cmp.ne p8, p0 = r0, r28 \n\t"
+ ";; \n\t"
+ "(p8) ldf.fill f3 = [r28] \n\t"
+ "(p6) mov b5 = r26 \n\t"
+ ";; \n\t"
+ "ld8 r29 = [r20], 16*8 - 4*8 \n\t"
+ "ld8 r30 = [r21], 17*8 - 5*8 \n\t"
+ ";; \n\t"
+ "ld8 r22 = [r20], 16 \n\t"
+ "ld8 r23 = [r21], 16 \n\t"
+ ";; \n\t"
+ "ld8 r24 = [r20], 16 \n\t"
+ "ld8 r25 = [r21] \n\t"
+ "cmp.ne p6, p0 = r0, r29 \n\t"
+ ";; \n\t"
+ "ld8 r26 = [r20], 8 \n\t"
+ "(p6) ldf.fill f4 = [r29] \n\t"
+ "cmp.ne p7, p0 = r0, r30 \n\t"
+ ";; \n\t"
+ "ld8 r27 = [r20], 8 \n\t"
+ "(p7) ldf.fill f5 = [r30] \n\t"
+ "cmp.ne p6, p0 = r0, r22 \n\t"
+ ";; \n\t"
+ "ld8 r28 = [r20], 8 \n\t"
+ "(p6) ldf.fill f16 = [r22] \n\t"
+ "cmp.ne p7, p0 = r0, r23 \n\t"
+ ";; \n\t"
+ "ld8 r29 = [r20], 8 \n\t"
+ "(p7) ldf.fill f17 = [r23] \n\t"
+ "cmp.ne p6, p0 = r0, r24 \n\t"
+ ";; \n\t"
+ "ld8 r22 = [r20], 8 \n\t"
+ "(p6) ldf.fill f18 = [r24] \n\t"
+ "cmp.ne p7, p0 = r0, r25 \n\t"
+ ";; \n\t"
+ "ld8 r23 = [r20], 8 \n\t"
+ "(p7) ldf.fill f19 = [r25] \n\t"
+ "cmp.ne p6, p0 = r0, r26 \n\t"
+ ";; \n\t"
+ "ld8 r24 = [r20], 8 \n\t"
+ "(p6) ldf.fill f20 = [r26] \n\t"
+ "cmp.ne p7, p0 = r0, r27 \n\t"
+ ";; \n\t"
+ "ld8 r25 = [r20], 8 \n\t"
+ "(p7) ldf.fill f21 = [r27] \n\t"
+ "cmp.ne p6, p0 = r0, r28 \n\t"
+ ";; \n\t"
+ "ld8 r26 = [r20], 8 \n\t"
+ "(p6) ldf.fill f22 = [r28] \n\t"
+ "cmp.ne p7, p0 = r0, r29 \n\t"
+ ";; \n\t"
+ "ld8 r27 = [r20], 8 \n\t"
+ ";; \n\t"
+ "ld8 r28 = [r20], 8 \n\t"
+ "(p7) ldf.fill f23 = [r29] \n\t"
+ "cmp.ne p6, p0 = r0, r22 \n\t"
+ ";; \n\t"
+ "ld8 r29 = [r20], 8 \n\t"
+ "(p6) ldf.fill f24 = [r22] \n\t"
+ "cmp.ne p7, p0 = r0, r23 \n\t"
+ ";; \n\t"
+ "(p7) ldf.fill f25 = [r23] \n\t"
+ "cmp.ne p6, p0 = r0, r24 \n\t"
+ "cmp.ne p7, p0 = r0, r25 \n\t"
+ ";; \n\t"
+ "(p6) ldf.fill f26 = [r24] \n\t"
+ "(p7) ldf.fill f27 = [r25] \n\t"
+ "cmp.ne p6, p0 = r0, r26 \n\t"
+ ";; \n\t"
+ "(p6) ldf.fill f28 = [r26] \n\t"
+ "cmp.ne p7, p0 = r0, r27 \n\t"
+ "cmp.ne p6, p0 = r0, r28 \n\t"
+ ";; \n\t"
+ "(p7) ldf.fill f29 = [r27] \n\t"
+ "(p6) ldf.fill f30 = [r28] \n\t"
+ "cmp.ne p7, p0 = r0, r29 \n\t"
+ ";; \n\t"
+ "(p7) ldf.fill f31 = [r29] \n\t"
+ "add r20 = uc_rnat, %0 \n\t"
+ "add r21 = uc_bsp, %0 \n\t"
+ ";; \n\t"
+ /* Load the balance of the thread state from the context. */
+ "ld8 r22 = [r20], uc_psp - uc_rnat \n\t"
+ "ld8 r23 = [r21], uc_gp - uc_bsp \n\t"
+ ";; \n\t"
+ "ld8 r24 = [r20], uc_pfs_loc - uc_psp \n\t"
+ "ld8 r1 = [r21], uc_rp - uc_gp \n\t"
+ ";; \n\t"
+ "ld8 r25 = [r20], uc_unat_loc - uc_pfs_loc\n\t"
+ "ld8 r26 = [r21], uc_pr - uc_rp \n\t"
+ ";; \n\t"
+ "ld8 r27 = [r20], uc_lc_loc - uc_unat_loc\n\t"
+ "ld8 r28 = [r21], uc_fpsr_loc - uc_pr \n\t"
+ ";; \n\t"
+ "ld8 r29 = [r20], uc_eh_data - uc_lc_loc\n\t"
+ "ld8 r30 = [r21], uc_eh_data + 8 - uc_fpsr_loc\n\t"
+ ";; \n\t"
+ /* Load data for the exception handler. */
+ "ld8 r15 = [r20], 16 \n\t"
+ "ld8 r16 = [r21], 16 \n\t"
+ ";; \n\t"
+ "ld8 r17 = [r20] \n\t"
+ "ld8 r18 = [r21] \n\t"
+ ";; \n\t"
+ /* Install the balance of the thread state loaded above. */
+ "cmp.ne p6, p0 = r0, r25 \n\t"
+ "cmp.ne p7, p0 = r0, r27 \n\t"
+ ";; \n\t"
+ "(p6) ld8 r25 = [r25] \n\t"
+ "(p7) ld8 r27 = [r27] \n\t"
+ ";; \n\t"
+ "(p7) mov.m ar.unat = r27 \n\t"
+ "(p6) mov.i ar.pfs = r25 \n\t"
+ "cmp.ne p9, p0 = r0, r29 \n\t"
+ ";; \n\t"
+ "(p9) ld8 r29 = [r29] \n\t"
+ "cmp.ne p6, p0 = r0, r30 \n\t"
+ ";; \n\t"
+ "(p6) ld8 r30 = [r30] \n\t"
+ /* Don't clobber p6-p9, which are in use at present. */
+ "mov pr = r28, ~0x3c0 \n\t"
+ "(p9) mov.i ar.lc = r29 \n\t"
+ ";; \n\t"
+ "mov.m r25 = ar.rsc \n\t"
+ "(p6) mov.m ar.fpsr = r30 \n\t"
+ ";; \n\t"
+ "and r29 = 0x1c, r25 \n\t"
+ "mov b0 = r26 \n\t"
+ ";; \n\t"
+ "mov.m ar.rsc = r29 \n\t"
+ ";; \n\t"
+ /* This must be done before setting AR.BSPSTORE, otherwise
+ AR.BSP will be initialized with a random displacement
+ below the value we want, based on the current number of
+ dirty stacked registers. */
+ "loadrs \n\t"
+ "invala \n\t"
+ ";; \n\t"
+ "mov.m ar.bspstore = r23 \n\t"
+ ";; \n\t"
+ "mov.m ar.rnat = r22 \n\t"
+ ";; \n\t"
+ "mov.m ar.rsc = r25 \n\t"
+ "mov sp = r24 \n\t"
+ "br.ret.sptk.few b0"
+ : : "r"(target), "r"(ireg_buf), "r"(ireg_nat), "r"(ireg_pr)
+ : "r15", "r16", "r17", "r18", "r20", "r21", "r22",
+ "r23", "r24", "r25", "r26", "r27", "r28", "r29",
+ "r30", "r31");
+ /* NOTREACHED */
+ while (1);
+}
+
+static inline _Unwind_Ptr
+uw_identify_context (struct _Unwind_Context *context)
+{
+ return _Unwind_GetIP (context);
+}
+
+#include "unwind.inc"
+
+#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
+alias (_Unwind_Backtrace);
+alias (_Unwind_DeleteException);
+alias (_Unwind_FindEnclosingFunction);
+alias (_Unwind_ForcedUnwind);
+alias (_Unwind_GetBSP);
+alias (_Unwind_GetCFA);
+alias (_Unwind_GetGR);
+alias (_Unwind_GetIP);
+alias (_Unwind_GetLanguageSpecificData);
+alias (_Unwind_GetRegionStart);
+alias (_Unwind_RaiseException);
+alias (_Unwind_Resume);
+alias (_Unwind_Resume_or_Rethrow);
+alias (_Unwind_SetGR);
+alias (_Unwind_SetIP);
+#endif
+
+#endif
diff --git a/gcc-4.9/libgcc/config/ia64/unwind-ia64.h b/gcc-4.9/libgcc/config/ia64/unwind-ia64.h
new file mode 100644
index 000000000..309a949b7
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/unwind-ia64.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 1999-2014 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.
+
+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 __VMS__
+/* On VMS, long is a 32 bit type. */
+typedef unsigned long long unw_word;
+typedef long long unw_sword;
+#else
+typedef unsigned long unw_word;
+typedef long unw_sword;
+#endif
+
+struct unw_table_entry
+{
+ unw_word start_offset;
+ unw_word end_offset;
+ unw_word 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, unw_word *segment_base,
+ unw_word *gp, struct unw_table_entry *ent)
+ __attribute__ ((__visibility__ ("hidden")));
diff --git a/gcc-4.9/libgcc/config/ia64/vms-crtinit.S b/gcc-4.9/libgcc/config/ia64/vms-crtinit.S
new file mode 100644
index 000000000..6df876210
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/vms-crtinit.S
@@ -0,0 +1,24 @@
+/* Copyright (C) 2009-2014 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/>. */
+
+ .global LIB$INITIALIZE#
diff --git a/gcc-4.9/libgcc/config/ia64/vms-unwind.h b/gcc-4.9/libgcc/config/ia64/vms-unwind.h
new file mode 100644
index 000000000..b0fe7e517
--- /dev/null
+++ b/gcc-4.9/libgcc/config/ia64/vms-unwind.h
@@ -0,0 +1,308 @@
+/* DWARF2 EH unwinding support for IA64 VMS.
+ Copyright (C) 2005-2014 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 __NEW_STARLET
+#include <libicb.h>
+#include <chfdef.h>
+#include <lib_c/chfctxdef.h>
+#include <lib_c/intstkdef.h>
+
+#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. */
+
+#define MD_FALLBACK_FRAME_STATE_FOR ia64_vms_fallback_frame_state
+
+extern INVO_CONTEXT_BLK * LIB$I64_CREATE_INVO_CONTEXT (void);
+
+extern int LIB$I64_IS_EXC_DISPATCH_FRAME (void *);
+extern int LIB$I64_IS_AST_DISPATCH_FRAME (void *);
+
+extern int LIB$I64_INIT_INVO_CONTEXT (INVO_CONTEXT_BLK *, int, int);
+extern int LIB$I64_GET_CURR_INVO_CONTEXT (INVO_CONTEXT_BLK *);
+extern int LIB$I64_GET_PREV_INVO_CONTEXT (INVO_CONTEXT_BLK *);
+
+typedef unsigned int uint;
+typedef unsigned __int64 uw_reg;
+typedef uw_reg * uw_loc;
+
+typedef char fp_reg[16];
+
+#define DENOTES_VMS_DISPATCHER_FRAME(icb) \
+(LIB$I64_IS_EXC_DISPATCH_FRAME (&(icb)->libicb$ih_pc))
+
+#define DENOTES_BOTTOM_OF_STACK(icb) ((icb)->libicb$v_bottom_of_stack)
+
+#define FAIL_IF(COND) \
+ do { if (COND) { context->rp = 0; return _URC_END_OF_STACK; } } while (0)
+/* Clearing context->rp is required to prevent the ia64 gcc unwinder from
+ attempting to keep on walking the call chain. */
+
+static int
+ia64_vms_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ int i, status;
+
+ INVO_CONTEXT_BLK local_icb;
+ INVO_CONTEXT_BLK *icb = &local_icb;
+
+ CHFCTX * chfctx;
+ CHF$MECH_ARRAY * chfmech;
+ CHF64$SIGNAL_ARRAY *chfsig64;
+ INTSTK * intstk;
+
+ static int eh_debug = -1;
+ int try_bs_copy = 0;
+ /* Non zero to attempt copy of alternate backing store contents for
+ dirty partition in interrupted context. ??? Alpha code, only activated
+ on specific request via specific bit in EH_DEBUG. */
+
+ if (eh_debug == -1)
+ {
+ char * EH_DEBUG = getenv ("EH_DEBUG");
+ const uint try_bs_copy_mask = (1 << 16);
+
+ eh_debug = EH_DEBUG ? atoi (EH_DEBUG) : 0;
+
+ /* Fetch and clear the try_bs_copy bit. */
+ try_bs_copy = (uint)eh_debug & try_bs_copy_mask;
+ eh_debug &= ~try_bs_copy_mask;
+ }
+
+ /* We're called to attempt unwinding through a frame for which no unwind
+ info is available, typical of an operating system exception dispatcher
+ frame. The code below knows how to handle this case, and only this one,
+ returning a failure code if it finds it is not in this situation.
+
+ Note that we're called from deep down in the exception propagation call
+ chain, possibly below an exception dispatcher but for a frame above it
+ like some os entry point. */
+
+ if (eh_debug)
+ printf ("FALLBACK - ctxt->rp=0x%lx, sp=0x%lx, psp=0x%lx, bsp=0x%lx\n",
+ context->rp, context->sp, context->psp, context->bsp);
+
+ /* Step 0 :
+ -------------------------------------------------------------------------
+ VMS-unwind up until we reach a VMS dispatcher frame corresponding to the
+ context we are trying to unwind through. Fail if get past this context or
+ if we reach the bottom of stack along the way.
+ -------------------------------------------------------------------------
+ */
+
+ status = LIB$I64_INIT_INVO_CONTEXT (icb, LIBICB$K_INVO_CONTEXT_VERSION, 0);
+ FAIL_IF (status == 0);
+
+ status = LIB$I64_GET_CURR_INVO_CONTEXT (icb);
+
+ /* Beware: we might be unwinding through nested condition handlers, so the
+ dispatcher frame we seek might not be the first one on the way up. Loop
+ thus. */
+ do {
+
+ /* Seek the next dispatcher frame up the "current" point. Stop if we
+ either get past the target context or hit the bottom-of-stack along
+ the way. */
+ status = LIB$I64_GET_PREV_INVO_CONTEXT (icb);
+ FAIL_IF (status == 0);
+ FAIL_IF ((uw_reg)icb->libicb$ih_sp > (uw_reg)context->psp
+ || DENOTES_BOTTOM_OF_STACK (icb));
+
+ if (eh_debug)
+ printf ("frame%s sp @ 0x%llx, pc @ 0x%llx bsp=0x%llx\n",
+ DENOTES_VMS_DISPATCHER_FRAME (icb) ? " (dispatcher)" : "",
+ icb->libicb$ih_sp, icb->libicb$ih_pc, icb->libicb$ih_bsp);
+
+ /* Continue until the target frame is found. */
+ } while ((uw_reg)icb->libicb$ih_bsp != (uw_reg)context->bsp);
+
+ /* If this is not a dispatcher frame, this is certainly a frame for a leaf
+ subprogram. Use default unwind information. */
+ if (! DENOTES_VMS_DISPATCHER_FRAME (icb))
+ return _URC_END_OF_STACK;
+
+ /* At this point, we know we are really trying to unwind past an exception
+ dispatcher frame, and have it described in ICB. Proceed. */
+
+ /* Step 1 :
+ ------------------------------------------------------------------------
+ We have the VMS dispatcher frame ICB handy and know we are trying to
+ unwind past it. Fetch pointers to useful datastructures from there, then
+ unwind one step further up to the interrupted user context from which
+ some required values will be easily accessible.
+ ------------------------------------------------------------------------
+ */
+
+ chfctx = icb->libicb$ph_chfctx_addr;
+ FAIL_IF (chfctx == 0);
+
+ chfmech = (CHF$MECH_ARRAY *)chfctx->chfctx$q_mcharglst;
+ FAIL_IF (chfmech == 0);
+
+ chfsig64 = (CHF64$SIGNAL_ARRAY *)chfmech->chf$ph_mch_sig64_addr;
+ FAIL_IF (chfsig64 == 0);
+
+ intstk = (INTSTK *)chfmech->chf$q_mch_esf_addr;
+ FAIL_IF (intstk == 0 || intstk->intstk$b_subtype == DYN$C_SSENTRY);
+
+ status = LIB$I64_GET_PREV_INVO_CONTEXT (icb);
+ FAIL_IF (status == 0);
+
+ if (eh_debug)
+ printf ("User frame, "
+ "chfmech @ 0x%p, chfsig64 @ 0x%p, intstk @ 0x%p\n",
+ chfmech, chfsig64, intstk);
+
+ /* Step 2 :
+ ------------------------------------------------------------------------
+ Point the GCC context locations/values required for further unwinding at
+ their corresponding locations/values in the datastructures at hand.
+ ------------------------------------------------------------------------
+ */
+
+ /* Static General Register locations, including scratch registers in case
+ the unwinder needs to refer to a value stored in one of them. */
+ {
+ uw_reg * ctxregs = (uw_reg *)&intstk->intstk$q_regbase;
+
+ for (i = 2; i <= 3; i++)
+ context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
+ for (i = 8; i <= 11; i++)
+ context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
+ for (i = 14; i <= 31; i++)
+ context->ireg[i - 2].loc = (uw_loc)&ctxregs[i];
+ }
+
+ /* Static Floating Point Register locations, as available from the
+ mechargs array, which happens to include all the to be preserved
+ ones + others. */
+ {
+ fp_reg * ctxregs;
+
+ ctxregs = (fp_reg *)&chfmech->chf$fh_mch_savf2;
+ for (i = 2; i <= 5 ; i++)
+ context->fr_loc[i - 2] = (uw_loc)&ctxregs[i - 2];
+
+ ctxregs = (fp_reg *)&chfmech->chf$fh_mch_savf12;
+ for (i = 12; i <= 31 ; i++)
+ context->fr_loc[i - 2] = (uw_loc)&ctxregs[i - 12];
+ }
+
+ /* Relevant application register locations. */
+
+ context->fpsr_loc = (uw_loc)&intstk->intstk$q_fpsr;
+ context->lc_loc = (uw_loc)&intstk->intstk$q_lc;
+ context->unat_loc = (uw_loc)&intstk->intstk$q_unat;
+
+ /* Branch register locations. */
+
+ {
+ uw_reg * ctxregs = (uw_reg *)&intstk->intstk$q_b0;
+
+ for (i = 0; i < 8; i++)
+ context->br_loc[i] = (uw_loc)&ctxregs[i];
+ }
+
+ /* Necessary register values. */
+
+ /* ??? Still unclear if we need to account for possible flushes to an
+ alternate backing store (maybe the unwinding performed above did the
+ trick already) and how this would be handled. Blind alpha tentative
+ below for experimentation purposes in malfunctioning cases. */
+ {
+ uw_reg q_bsp = (uw_reg) intstk->intstk$q_bsp;
+ uw_reg q_bspstore = (uw_reg) intstk->intstk$q_bspstore;
+ uw_reg q_bspbase = (uw_reg) intstk->intstk$q_bspbase;
+ uw_reg ih_bspbase = (uw_reg) icb->libicb$ih_bspbase;
+
+ if (eh_debug)
+ printf ("q_bspstore = 0x%lx, q_bsp = 0x%lx, q_bspbase = 0x%lx\n"
+ "ih_bspbase = 0x%lx\n",
+ q_bspstore, q_bsp, q_bspbase, ih_bspbase);
+
+ /* We witness many situations where q_bspbase is set while ih_bspbase is
+ null, and every attempt made with q_bspbase badly failed while doing
+ nothing resulted in proper behavior. */
+ if (q_bspstore < q_bsp && ih_bspbase && try_bs_copy)
+ {
+ uw_reg dirty_size = q_bsp - q_bspstore;
+ uw_reg q_rnat = (uw_reg) intstk->intstk$q_rnat;
+
+ if (eh_debug)
+ printf ("Attempting an alternate backing store copy ...\n");
+
+ ia64_copy_rbs
+ (context, q_bspstore, ih_bspbase, dirty_size, q_rnat);
+ /* Not clear if these are the proper arguments here. This is what
+ looked the closest to what is performed in the Linux case. */
+ }
+
+ }
+
+ context->bsp = (uw_reg)intstk->intstk$q_bsp;
+ fs->no_reg_stack_frame = 1;
+
+ context->pr = (uw_reg)intstk->intstk$q_preds;
+ context->gp = (uw_reg)intstk->intstk$q_gp;
+
+ /* We're directly setting up the "context" for a VMS exception handler.
+ The "previous SP" for it is the SP upon the handler's entry, that is
+ the SP at the condition/interruption/exception point. */
+ context->psp = (uw_reg)icb->libicb$ih_sp;
+
+ /* Previous Frame State location. What eventually ends up in pfs_loc is
+ installed with ar.pfs = pfs_loc; br.ret; so setup to target intstk->q_ifs
+ to have the interrupted context restored and not that of its caller if
+ we happen to have a handler in the interrupted context itself. */
+ fs->curr.reg[UNW_REG_PFS].where = UNW_WHERE_PSPREL;
+ fs->curr.reg[UNW_REG_PFS].val
+ = (uw_reg)&intstk->intstk$q_ifs - (uw_reg)context->psp;
+ fs->curr.reg[UNW_REG_PFS].when = -1;
+
+ /* If we need to unwind further up, past the interrupted context, we need to
+ hand out the interrupted context's pfs, still. */
+ context->signal_pfs_loc = (uw_loc) &intstk->intstk$q_pfs;
+
+ /* Finally, rules for RP . */
+ {
+ uw_reg * post_sigarray
+ = (uw_reg *)chfsig64 + 1 + chfsig64->chf64$l_sig_args;
+
+ uw_reg * ih_pc_loc = post_sigarray - 2;
+
+ fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_PSPREL;
+ fs->curr.reg[UNW_REG_RP].val
+ = (uw_reg)ih_pc_loc - (uw_reg)context->psp;
+ fs->curr.reg[UNW_REG_RP].when = -1;
+ }
+
+ return _URC_NO_REASON;
+}
+