diff options
Diffstat (limited to 'gcc-4.9/libgcc/config/ia64')
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 (®s[kind - 1], sr->curr.reg + limit[kind - 1], + sr->region_start + t); + } + } + + /* Next, lay out the memory stack spill area. */ + if (sr->any_spills) + { + off = sr->spill_offset; + alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2, + sr->curr.reg + UNW_REG_F31); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_B1, + sr->curr.reg + UNW_REG_B5); + alloc_spill_area (&off, 8, sr->curr.reg + UNW_REG_R4, + sr->curr.reg + UNW_REG_R7); + } +} + +/* + * Region header descriptors. + */ + +static void +desc_prologue (int body, unw_word rlen, unsigned char mask, + unsigned char grsave, struct unw_state_record *sr) +{ + int i; + + if (!(sr->in_body || sr->first_region)) + finish_prologue (sr); + sr->first_region = 0; + + /* Check if we're done. */ + if (sr->when_target < sr->region_start + sr->region_len) + { + sr->done = 1; + return; + } + + for (i = 0; i < sr->epilogue_count; ++i) + pop (sr); + + sr->epilogue_count = 0; + sr->epilogue_start = UNW_WHEN_NEVER; + + if (!body) + push (sr); + + sr->region_start += sr->region_len; + sr->region_len = rlen; + sr->in_body = body; + + if (!body) + { + for (i = 0; i < 4; ++i) + { + if (mask & 0x8) + set_reg (sr->curr.reg + save_order[i], UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, grsave++); + mask <<= 1; + } + sr->gr_save_loc = grsave; + sr->any_spills = 0; + sr->imask = 0; + sr->spill_offset = 0x10; /* default to psp+16 */ + } +} + +/* + * Prologue descriptors. + */ + +static inline void +desc_abi (unsigned char abi, + unsigned char context, + struct unw_state_record *sr) +{ + sr->unwabi = (abi << 8) | context; +} + +static inline void +desc_br_gr (unsigned char brmask, unsigned char gr, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + brmask >>= 1; + } +} + +static inline void +desc_br_mem (unsigned char brmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 5; ++i) + { + if (brmask & 1) + { + set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + brmask >>= 1; + } +} + +static inline void +desc_frgr_mem (unsigned char grmask, unw_word frmask, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } + for (i = 0; i < 20; ++i) + { + if ((frmask & 1) != 0) + { + enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4; + set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_fr_mem (unsigned char frmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((frmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + frmask >>= 1; + } +} + +static inline void +desc_gr_gr (unsigned char grmask, unsigned char gr, + struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, gr++); + grmask >>= 1; + } +} + +static inline void +desc_gr_mem (unsigned char grmask, struct unw_state_record *sr) +{ + int i; + + for (i = 0; i < 4; ++i) + { + if ((grmask & 1) != 0) + { + set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, + sr->region_start + sr->region_len - 1, 0); + sr->any_spills = 1; + } + grmask >>= 1; + } +} + +static inline void +desc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, + sr->region_start + MIN ((int)t, sr->region_len - 1), 16*size); +} + +static inline void +desc_mem_stack_v (unw_word t, struct unw_state_record *sr) +{ + sr->curr.reg[UNW_REG_PSP].when + = sr->region_start + MIN ((int)t, sr->region_len - 1); +} + +static inline void +desc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_GR, + sr->region_start + sr->region_len - 1, dst); +} + +static inline void +desc_reg_psprel (unsigned char reg, unw_word pspoff, + struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_PSPREL, + sr->region_start + sr->region_len - 1, + 0x10 - 4*pspoff); +} + +static inline void +desc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr) +{ + set_reg (sr->curr.reg + reg, UNW_WHERE_SPREL, + sr->region_start + sr->region_len - 1, + 4*spoff); +} + +static inline void +desc_rp_br (unsigned char dst, struct unw_state_record *sr) +{ + sr->return_link_reg = dst; +} + +static inline void +desc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr) +{ + struct unw_reg_info *reg = sr->curr.reg + regnum; + + if (reg->where == UNW_WHERE_NONE) + reg->where = UNW_WHERE_GR_SAVE; + reg->when = sr->region_start + MIN ((int)t, sr->region_len - 1); +} + +static inline void +desc_spill_base (unw_word pspoff, struct unw_state_record *sr) +{ + sr->spill_offset = 0x10 - 4*pspoff; +} + +static inline unsigned char * +desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr) +{ + sr->imask = imaskp; + return imaskp + (2*sr->region_len + 7)/8; +} + +/* + * Body descriptors. + */ +static inline void +desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) +{ + sr->epilogue_start = sr->region_start + sr->region_len - 1 - t; + sr->epilogue_count = ecount + 1; +} + +static inline void +desc_copy_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_labeled_state *ls; + + for (ls = sr->labeled_states; ls; ls = ls->next) + { + if (ls->label == label) + { + free_state_stack (&sr->curr); + memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr)); + sr->curr.next = dup_state_stack (ls->saved_state.next); + return; + } + } + abort (); +} + +static inline void +desc_label_state (unw_word label, struct unw_state_record *sr) +{ + struct unw_labeled_state *ls = alloc_label_state (); + + ls->label = label; + memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state)); + ls->saved_state.next = dup_state_stack (sr->curr.next); + + /* Insert into list of labeled states. */ + ls->next = sr->labeled_states; + sr->labeled_states = ls; +} + +/* + * General descriptors. + */ + +static inline int +desc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr) +{ + if (sr->when_target <= sr->region_start + MIN ((int)t, sr->region_len - 1)) + return 0; + if (qp > 0) + { + if ((sr->pr_val & (1UL << qp)) == 0) + return 0; + sr->pr_mask |= (1UL << qp); + } + return 1; +} + +static inline void +desc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, + struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = UNW_WHERE_NONE; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = 0; +} + +static inline void +desc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, + unsigned char x, unsigned char ytreg, + struct unw_state_record *sr) +{ + enum unw_where where = UNW_WHERE_GR; + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + if (x) + where = UNW_WHERE_BR; + else if (ytreg & 0x80) + where = UNW_WHERE_FR; + + r = sr->curr.reg + decode_abreg (abreg, 0); + r->where = where; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = ytreg & 0x7f; +} + +static inline void +desc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word pspoff, struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = UNW_WHERE_PSPREL; + r->when = sr->region_start + MIN((int)t, sr->region_len - 1); + r->val = 0x10 - 4*pspoff; +} + +static inline void +desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, + unw_word spoff, struct unw_state_record *sr) +{ + struct unw_reg_info *r; + + if (! desc_is_active (qp, t, sr)) + return; + + r = sr->curr.reg + decode_abreg (abreg, 1); + r->where = UNW_WHERE_SPREL; + r->when = sr->region_start + MIN ((int)t, sr->region_len - 1); + r->val = 4*spoff; +} + + +#define UNW_DEC_BAD_CODE(code) abort (); + +/* Region headers. */ +#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg) +#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg) + +/* Prologue descriptors. */ +#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg) +#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg) +#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg) +#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg) +#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg) +#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg) +#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg) +#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg) +#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg) +#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg) +#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg) +#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg) +#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg) +#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg) +#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg) +#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg) +#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg) +#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg) +#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg)) + +/* Body descriptors. */ +#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg) +#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg) +#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg) + +/* General unwind descriptors. */ +#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg) +#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg) +#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg) +#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg) +#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg) +#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg) + + +/* + * Generic IA-64 unwind info decoder. + * + * This file is used both by the Linux kernel and objdump. Please keep + * the copies of this file in sync. + * + * You need to customize the decoder by defining the following + * macros/constants before including this file: + * + * Types: + * unw_word Unsigned integer type with at least 64 bits + * + * Register names: + * UNW_REG_BSP + * UNW_REG_BSPSTORE + * UNW_REG_FPSR + * UNW_REG_LC + * UNW_REG_PFS + * UNW_REG_PR + * UNW_REG_RNAT + * UNW_REG_PSP + * UNW_REG_RP + * UNW_REG_UNAT + * + * Decoder action macros: + * UNW_DEC_BAD_CODE(code) + * UNW_DEC_ABI(fmt,abi,context,arg) + * UNW_DEC_BR_GR(fmt,brmask,gr,arg) + * UNW_DEC_BR_MEM(fmt,brmask,arg) + * UNW_DEC_COPY_STATE(fmt,label,arg) + * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) + * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) + * UNW_DEC_FR_MEM(fmt,frmask,arg) + * UNW_DEC_GR_GR(fmt,grmask,gr,arg) + * UNW_DEC_GR_MEM(fmt,grmask,arg) + * UNW_DEC_LABEL_STATE(fmt,label,arg) + * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) + * UNW_DEC_MEM_STACK_V(fmt,t,arg) + * UNW_DEC_PRIUNAT_GR(fmt,r,arg) + * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) + * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) + * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) + * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) + * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) + * UNW_DEC_REG_REG(fmt,src,dst,arg) + * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) + * UNW_DEC_REG_WHEN(fmt,reg,t,arg) + * UNW_DEC_RESTORE(fmt,t,abreg,arg) + * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) + * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) + * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) + * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) + * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) + */ + +static unw_word +unw_decode_uleb128 (unsigned char **dpp) +{ + unsigned shift = 0; + unw_word byte, result = 0; + unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *dpp = bp; + return result; +} + +static unsigned char * +unw_decode_x1 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, abreg; + unw_word t, off; + + byte1 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x2 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + ytreg = byte2; + x = (byte1 >> 7) & 1; + if ((byte1 & 0x80) == 0 && ytreg == 0) + UNW_DEC_RESTORE(X2, t, abreg, arg); + else + UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_x3 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, abreg, qp; + unw_word t, off; + + byte1 = *dp++; byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg); + return dp; +} + +static unsigned char * +unw_decode_x4 (unsigned char *dp, + unsigned char code __attribute__((unused)), + void *arg) +{ + unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + t = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + x = (byte2 >> 7) & 1; + ytreg = byte3; + + if ((byte2 & 0x80) == 0 && byte3 == 0) + UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg); + else + UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg); + return dp; +} + +static unsigned char * +unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg) +{ + int body = (code & 0x20) != 0; + unw_word rlen; + + rlen = (code & 0x1f); + UNW_DEC_PROLOGUE(R1, body, rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char byte1, mask, grsave; + unw_word rlen; + + byte1 = *dp++; + + mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + grsave = (byte1 & 0x7f); + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg); + return dp; +} + +static unsigned char * +unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word rlen; + + rlen = unw_decode_uleb128 (&dp); + UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg); + return dp; +} + +static unsigned char * +unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char brmask = (code & 0x1f); + + UNW_DEC_BR_MEM(P1, brmask, arg); + return dp; +} + +static unsigned char * +unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg) +{ + if ((code & 0x10) == 0) + { + unsigned char byte1 = *dp++; + + UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1), + (byte1 & 0x7f), arg); + } + else if ((code & 0x08) == 0) + { + unsigned char byte1 = *dp++, r, dst; + + r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + dst = (byte1 & 0x7f); + switch (r) + { + case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break; + case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break; + case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break; + case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break; + case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break; + case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break; + case 6: UNW_DEC_RP_BR(P3, dst, arg); break; + case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break; + case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break; + case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break; + case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break; + case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else if ((code & 0x7) == 0) + UNW_DEC_SPILL_MASK(P4, dp, arg); + else if ((code & 0x7) == 1) + { + unw_word grmask, frmask, byte1, byte2, byte3; + + byte1 = *dp++; byte2 = *dp++; byte3 = *dp++; + grmask = ((byte1 >> 4) & 0xf); + frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; + UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg); + } + else + UNW_DEC_BAD_CODE(code); + return dp; +} + +static unsigned char * +unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg) +{ + int gregs = (code & 0x10) != 0; + unsigned char mask = (code & 0x0f); + + if (gregs) + UNW_DEC_GR_MEM(P6, mask, arg); + else + UNW_DEC_FR_MEM(P6, mask, arg); + return dp; +} + +static unsigned char * +unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg) +{ + unsigned char r, byte1, byte2; + unw_word t, size; + + if ((code & 0x10) == 0) + { + r = (code & 0xf); + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 0: + size = unw_decode_uleb128 (&dp); + UNW_DEC_MEM_STACK_F(P7, t, size, arg); + break; + + case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break; + case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break; + case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break; + case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break; + case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break; + case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break; + case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break; + case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break; + case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break; + case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break; + case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break; + case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + else + { + switch (code & 0xf) + { + case 0x0: /* p8 */ + { + r = *dp++; + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break; + case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break; + case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break; + case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break; + case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break; + case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break; + case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break; + case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break; + case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break; + case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break; + case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break; + case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break; + case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break; + case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break; + case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break; + case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break; + case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break; + case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break; + default: UNW_DEC_BAD_CODE(r); break; + } + } + break; + + case 0x1: + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg); + break; + + case 0xf: /* p10 */ + byte1 = *dp++; byte2 = *dp++; + UNW_DEC_ABI(P10, byte1, byte2, arg); + break; + + case 0x9: + return unw_decode_x1 (dp, code, arg); + + case 0xa: + return unw_decode_x2 (dp, code, arg); + + case 0xb: + return unw_decode_x3 (dp, code, arg); + + case 0xc: + return unw_decode_x4 (dp, code, arg); + + default: + UNW_DEC_BAD_CODE(code); + break; + } + } + return dp; +} + +static unsigned char * +unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word label = (code & 0x1f); + + if ((code & 0x20) != 0) + UNW_DEC_COPY_STATE(B1, label, arg); + else + UNW_DEC_LABEL_STATE(B1, label, arg); + return dp; +} + +static unsigned char * +unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t; + + t = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg); + return dp; +} + +static unsigned char * +unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg) +{ + unw_word t, ecount, label; + + if ((code & 0x10) == 0) + { + t = unw_decode_uleb128 (&dp); + ecount = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE(B3, t, ecount, arg); + } + else if ((code & 0x07) == 0) + { + label = unw_decode_uleb128 (&dp); + if ((code & 0x08) != 0) + UNW_DEC_COPY_STATE(B4, label, arg); + else + UNW_DEC_LABEL_STATE(B4, label, arg); + } + else + switch (code & 0x7) + { + case 1: return unw_decode_x1 (dp, code, arg); + case 2: return unw_decode_x2 (dp, code, arg); + case 3: return unw_decode_x3 (dp, code, arg); + case 4: return unw_decode_x4 (dp, code, arg); + default: UNW_DEC_BAD_CODE(code); break; + } + return dp; +} + +typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *); + +static const unw_decoder unw_decode_table[2][8] = +{ + /* prologue table: */ + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_p1, /* 4 */ + unw_decode_p2_p5, + unw_decode_p6, + unw_decode_p7_p10 + }, + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_b1, /* 4 */ + unw_decode_b1, + unw_decode_b2, + unw_decode_b3_x4 + } +}; + +/* + * Decode one descriptor and return address of next descriptor. + */ +static inline unsigned char * +unw_decode (unsigned char *dp, int inside_body, void *arg) +{ + unw_decoder decoder; + unsigned char code; + + code = *dp++; + decoder = unw_decode_table[inside_body][code >> 5]; + dp = (*decoder) (dp, code, arg); + return dp; +} + + +/* RSE helper functions. */ + +static inline 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; +} + |