aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2001-05-11 23:03:20 -0700
committerRichard Henderson <rth@gcc.gnu.org>2001-05-11 23:03:20 -0700
commit2a1ee410cefc93b247bbcc9b8a153ba5af72be73 (patch)
tree41492fd525139d18c6f3c8bd8894fcdf4cbcd139
parentf12f25a7f625fc69ab610b8997e1f6f5c1ccf982 (diff)
downloadgcc-2a1ee410cefc93b247bbcc9b8a153ba5af72be73.zip
gcc-2a1ee410cefc93b247bbcc9b8a153ba5af72be73.tar.gz
gcc-2a1ee410cefc93b247bbcc9b8a153ba5af72be73.tar.bz2
defaults.h (ASM_PREFERRED_EH_DATA_FORMAT): New.
* defaults.h (ASM_PREFERRED_EH_DATA_FORMAT): New. * dwarf2asm.c (dw2_force_const_mem, dw2_output_indirect_constant_1, dw2_output_indirect_constants, dw2_asm_output_encoded_addr_rtx): New. * dwarf2asm.h (dw2_asm_output_encoded_addr_rtx): Prototype. (dw2_output_indirect_constants): Prototype. * dwarf2out.c (dwarf2out_begin_prologue): Generate current_function_func_begin_label if we'll need it for EH. Exit early for IA64_UNWIND_INFO. * except.c: Get DW_EH_PE_* defines from dwarf2.h. (eh_data_format_name): Update for indirect references. (output_function_exception_table): Care for IA64_UNWIND_INFO. Handle ASM_PREFERRED_EH_DATA_FORMAT. * except.h (MUST_USE_SJLJ_EXCEPTIONS): IA64_UNWIND_INFO needn't define HAVE_eh_return etc. * final.c (final_start_function): Always call dwarf2out_begin_prologue. (final_end_function): Don't call output_function_exception_table. * toplev.c (compile_file): Call dw2_output_indirect_constants. (rest_of_compilation): Invoke output_function_exception_table for ia64 before assemble_end_function. * tm.texi (ASM_PREFERRED_EH_DATA_FORMAT): Document. (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Document. * unwind-dw2.c (_Unwind_GetTextRelBase, _Unwind_GetDataRelBase): New. * unwind.h: Declare them. * libgcc-std.ver: Export them. * unwind-pe.h: New file. * config/alpha/elf.h (ASM_PREFERRED_EH_DATA_FORMAT): New. * config/ia64/fde-glibc.c: Use "struct unw_table_entry" instead of "fde". (find_fde_for_dso): Extract DT_PLTGOT. (_Unwind_FindTableEntry): Rename from __ia64_find_fde; return the segment and gp as well. * config/ia64/frame-ia64.c: Remove file. * config/ia64/frame-ia64.h: Remove file. * config/ia64/unwind-ia64.c: New file. * config/ia64/unwind-ia64.h: New file. * config/ia64/ia64.h (ASM_OUTPUT_EH_CHAR): Remove. (ASM_OUTPUT_EH_SHORT, ASM_OUTPUT_EH_INT): Remove. (ASM_OUTPUT_EH_DOUBLE_INT): Remove. (ASM_PREFERRED_EH_DATA_FORMAT): New. (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): New. (IA64_UNWIND_INFO): Re-enable. (HANDLER_SECTION): Remove. (EH_RETURN_DATA_REGNO): New. * config/ia64/ia64.md (exception_receiver): Remove. * config/ia64/t-glibc (LIB2ADDEH): Re-enable. * config/ia64/t-ia64 (LIB2ADDEH): Re-enable. From-SVN: r41981
-rw-r--r--gcc/ChangeLog52
-rw-r--r--gcc/config/alpha/elf.h13
-rw-r--r--gcc/config/ia64/fde-glibc.c83
-rw-r--r--gcc/config/ia64/frame-ia64.c1272
-rw-r--r--gcc/config/ia64/ia64.h85
-rw-r--r--gcc/config/ia64/ia64.md7
-rw-r--r--gcc/config/ia64/t-glibc2
-rw-r--r--gcc/config/ia64/t-ia642
-rw-r--r--gcc/config/ia64/unwind-ia64.c2015
-rw-r--r--gcc/config/ia64/unwind-ia64.h (renamed from gcc/config/ia64/frame-ia64.h)23
-rw-r--r--gcc/defaults.h7
-rw-r--r--gcc/dwarf2asm.c176
-rw-r--r--gcc/dwarf2asm.h4
-rw-r--r--gcc/dwarf2out.c23
-rw-r--r--gcc/except.c126
-rw-r--r--gcc/except.h12
-rw-r--r--gcc/final.c13
-rw-r--r--gcc/libgcc-std.ver2
-rw-r--r--gcc/tm.texi27
-rw-r--r--gcc/toplev.c12
-rw-r--r--gcc/unwind-dw2.c13
-rw-r--r--gcc/unwind-pe.h208
-rw-r--r--gcc/unwind.h25
23 files changed, 2771 insertions, 1431 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 63309d3..cd72d90 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,57 @@
2001-05-11 Richard Henderson <rth@redhat.com>
+ * defaults.h (ASM_PREFERRED_EH_DATA_FORMAT): New.
+ * dwarf2asm.c (dw2_force_const_mem, dw2_output_indirect_constant_1,
+ dw2_output_indirect_constants, dw2_asm_output_encoded_addr_rtx): New.
+ * dwarf2asm.h (dw2_asm_output_encoded_addr_rtx): Prototype.
+ (dw2_output_indirect_constants): Prototype.
+ * dwarf2out.c (dwarf2out_begin_prologue): Generate
+ current_function_func_begin_label if we'll need it for EH. Exit
+ early for IA64_UNWIND_INFO.
+ * except.c: Get DW_EH_PE_* defines from dwarf2.h.
+ (eh_data_format_name): Update for indirect references.
+ (output_function_exception_table): Care for IA64_UNWIND_INFO.
+ Handle ASM_PREFERRED_EH_DATA_FORMAT.
+ * except.h (MUST_USE_SJLJ_EXCEPTIONS): IA64_UNWIND_INFO needn't
+ define HAVE_eh_return etc.
+ * final.c (final_start_function): Always call dwarf2out_begin_prologue.
+ (final_end_function): Don't call output_function_exception_table.
+ * toplev.c (compile_file): Call dw2_output_indirect_constants.
+ (rest_of_compilation): Invoke output_function_exception_table
+ for ia64 before assemble_end_function.
+ * tm.texi (ASM_PREFERRED_EH_DATA_FORMAT): Document.
+ (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Document.
+
+ * unwind-dw2.c (_Unwind_GetTextRelBase, _Unwind_GetDataRelBase): New.
+ * unwind.h: Declare them.
+ * libgcc-std.ver: Export them.
+ * unwind-pe.h: New file.
+
+ * config/alpha/elf.h (ASM_PREFERRED_EH_DATA_FORMAT): New.
+
+ * config/ia64/fde-glibc.c: Use "struct unw_table_entry"
+ instead of "fde".
+ (find_fde_for_dso): Extract DT_PLTGOT.
+ (_Unwind_FindTableEntry): Rename from __ia64_find_fde; return
+ the segment and gp as well.
+ * config/ia64/frame-ia64.c: Remove file.
+ * config/ia64/frame-ia64.h: Remove file.
+ * config/ia64/unwind-ia64.c: New file.
+ * config/ia64/unwind-ia64.h: New file.
+ * config/ia64/ia64.h (ASM_OUTPUT_EH_CHAR): Remove.
+ (ASM_OUTPUT_EH_SHORT, ASM_OUTPUT_EH_INT): Remove.
+ (ASM_OUTPUT_EH_DOUBLE_INT): Remove.
+ (ASM_PREFERRED_EH_DATA_FORMAT): New.
+ (ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): New.
+ (IA64_UNWIND_INFO): Re-enable.
+ (HANDLER_SECTION): Remove.
+ (EH_RETURN_DATA_REGNO): New.
+ * config/ia64/ia64.md (exception_receiver): Remove.
+ * config/ia64/t-glibc (LIB2ADDEH): Re-enable.
+ * config/ia64/t-ia64 (LIB2ADDEH): Re-enable.
+
+2001-05-11 Richard Henderson <rth@redhat.com>
+
* config/ia64/ia64.c (group_barrier_needed_p): Don't allow
calls and jumps to be bundled together.
(ia64_reorg): Emit a break after a noreturn call that ends
diff --git a/gcc/config/alpha/elf.h b/gcc/config/alpha/elf.h
index 700f2c5..fd0874e 100644
--- a/gcc/config/alpha/elf.h
+++ b/gcc/config/alpha/elf.h
@@ -685,3 +685,16 @@ void FN () \
#undef UNALIGNED_SHORT_ASM_OP
#undef UNALIGNED_INT_ASM_OP
#undef UNALIGNED_DOUBLE_INT_ASM_OP
+
+/* ??? This should be possible for ECOFF as well, since the relocations
+ exist. But the assembler doesn't seem to create them. */
+/* Select a format to encode pointers in exception handling data. CODE
+ is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
+ true if the symbol may be affected by dynamic relocations.
+
+ Since application size is already constrained to <2GB by the form of
+ the ldgp relocation, we can use a 32-bit pc-relative relocation to
+ static data. Dynamic data is accessed indirectly to allow for read
+ only EH sections. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4)
diff --git a/gcc/config/ia64/fde-glibc.c b/gcc/config/ia64/fde-glibc.c
index 8000be2..7dd6984 100644
--- a/gcc/config/ia64/fde-glibc.c
+++ b/gcc/config/ia64/fde-glibc.c
@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <link.h>
#include <bits/libc-lock.h>
-#include "frame-ia64.h"
+#include "unwind-ia64.h"
/* Initialized by crtbegin from the main application. */
@@ -41,20 +41,17 @@ extern Elf64_Ehdr *__ia64_app_header;
appear in <link.h> in a new glibc version. */
__libc_lock_define (extern, _dl_load_lock)
-/* ??? _dl_load_lock is not exported from glibc 2.1, but it is
- from glibc 2.2. Remove this when folks have migrated. */
-#pragma weak _dl_load_lock
-
/* This always exists, even in a static application. */
extern struct link_map *_dl_loaded;
-static fde *
-find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr)
+static struct unw_table_entry *
+find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr,
+ unsigned long *pseg_base, unsigned long *pgp)
{
- Elf64_Phdr *phdr, *p_unwind;
+ Elf64_Phdr *phdr, *p_unwind, *p_dynamic;
long n, match;
Elf64_Addr load_base, seg_base;
- fde *f_base;
+ struct unw_table_entry *f_base, *f;
size_t lo, hi;
/* Verify that we are looking at an ELF header. */
@@ -71,6 +68,7 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr)
phdr = (Elf64_Phdr *)((char *)ehdr + ehdr->e_phoff);
load_base = (ehdr->e_type == ET_DYN ? (Elf64_Addr)ehdr : 0);
p_unwind = NULL;
+ p_dynamic = NULL;
/* See if PC falls into one of the loaded segments. Find the unwind
segment at the same time. */
@@ -84,69 +82,96 @@ find_fde_for_dso (Elf64_Addr pc, Elf64_Ehdr *ehdr)
}
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 NULL;
/* Search for the FDE within the unwind segment. */
- f_base = (fde *) (p_unwind->p_vaddr + load_base);
+ f_base = (struct unw_table_entry *) (p_unwind->p_vaddr + load_base);
seg_base = (Elf64_Addr) ehdr;
lo = 0;
- hi = p_unwind->p_memsz / sizeof (fde);
+ hi = p_unwind->p_memsz / sizeof (struct unw_table_entry);
while (lo < hi)
{
size_t mid = (lo + hi) / 2;
- fde *f = f_base + mid;
+ f = f_base + mid;
if (pc < f->start_offset + seg_base)
hi = mid;
else if (pc >= f->end_offset + seg_base)
lo = mid + 1;
else
- return f;
+ goto found;
}
-
return NULL;
+
+ found:
+ *pseg_base = seg_base;
+ *pgp = 0;
+
+ if (p_dynamic)
+ {
+ /* For dynamicly 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)
+ {
+ /* ??? Glibc seems to have relocated this already. */
+ *pgp = 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");
+ *pgp = gp;
+ }
+
+ return f;
}
-/* Return a pointer to the FDE for the function containing PC. */
-fde *
-__ia64_find_fde (void *pc, void **pc_base)
+/* Return a pointer to the unwind table entry for the function
+ containing PC. */
+
+struct unw_table_entry *
+_Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
+ unsigned long *gp)
{
- fde *ret;
+ struct unw_table_entry *ret;
struct link_map *map;
/* Check the main application first, hoping that most of the user's
code is there instead of in some library. */
- ret = find_fde_for_dso ((Elf64_Addr)pc, __ia64_app_header);
+ ret = find_fde_for_dso ((Elf64_Addr)pc, __ia64_app_header,
+ segment_base, gp);
if (ret)
- {
- *pc_base = __ia64_app_header;
- return ret;
- }
+ return ret;
/* Glibc is probably unique in that we can (with certain restrictions)
dynamicly load libraries into staticly linked applications. Thus
we _always_ check _dl_loaded. */
- if (&_dl_load_lock)
- __libc_lock_lock (_dl_load_lock);
+ __libc_lock_lock (_dl_load_lock);
for (map = _dl_loaded; map ; map = map->l_next)
{
/* Skip the main application's entry. */
if (map->l_name[0] == 0)
continue;
- ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr);
+ ret = find_fde_for_dso ((Elf64_Addr)pc, (Elf64_Ehdr *)map->l_addr,
+ segment_base, gp);
if (ret)
break;
}
- if (&_dl_load_lock)
- __libc_lock_unlock (_dl_load_lock);
+ __libc_lock_unlock (_dl_load_lock);
- *pc_base = (void *)(map ? map->l_addr : 0);
return ret;
}
diff --git a/gcc/config/ia64/frame-ia64.c b/gcc/config/ia64/frame-ia64.c
deleted file mode 100644
index 4834a8b..0000000
--- a/gcc/config/ia64/frame-ia64.c
+++ /dev/null
@@ -1,1272 +0,0 @@
-/* Subroutines needed for unwinding IA-64 standard format stack frame
- info for exception handling. */
-/* Compile this one with gcc. */
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- Contributed by Andrew MacLeod <amacleod@cygnus.com>
- Andrew Haley <aph@cygnus.com>
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-/* As a special exception, if you link this library with other files,
- some of which are compiled with GCC, to produce an executable,
- this library does not by itself cause the resulting executable
- to be covered by the GNU General Public License.
- This exception does not however invalidate any other reasons why
- the executable file might be covered by the GNU General Public License. */
-
-/* It is incorrect to include config.h here, because this file is being
- compiled for the target, and hence definitions concerning only the host
- do not apply. */
-
-#include "tconfig.h"
-
-/* We disable this when inhibit_libc, so that gcc can still be built without
- needing header files first. */
-/* ??? This is not a good solution, since prototypes may be required in
- some cases for correct code. See also libgcc2.c/crtstuff.c. */
-#ifndef inhibit_libc
-#include <stdlib.h>
-#include <unistd.h>
-#else
-#include <stddef.h>
-#endif
-
-#include "frame-ia64.h"
-#include "eh-common.h"
-
-/* Some types used by the DWARF 2 spec. */
-
-typedef int sword __attribute__ ((mode (SI)));
-typedef unsigned int uword __attribute__ ((mode (SI)));
-typedef unsigned int uaddr __attribute__ ((mode (pointer)));
-typedef int saddr __attribute__ ((mode (pointer)));
-typedef unsigned char ubyte;
-
-#include "frame.h"
-
-/* Decode the unsigned LEB128 constant at BUF and return it. The value at
- MEM is updated to reflect the next position in the buffer. */
-
-static unsigned long
-read_uleb128 (unsigned char **mem)
-{
- unsigned shift = 0;
- unsigned long result = 0;
- unsigned char *buf = *mem;
-
- while (1)
- {
- unsigned long byte = *buf++;
- result |= (byte & 0x7f) << shift;
- if ((byte & 0x80) == 0)
- break;
- shift += 7;
- }
- *mem = buf;
- return result;
-}
-
-
-static unsigned char *
-read_R_record (unwind_record *data, unsigned char val, unsigned char *ptr)
-{
- if ((val & 0x40) == 0)
- {
- /* R1 format. */
- if (val & 0x20)
- data->type = body;
- else
- data->type = prologue;
- data->record.r.rlen = (val & 0x1f);
- return ptr;
- }
-
- if ((val & 0xF8) == UNW_R2)
- {
- /* R2 format. */
- unsigned char mask = (val & 0x07) << 1;
- if (*ptr & 0x80)
- mask = mask | 1;
- data->type = prologue_gr;
- data->record.r.mask = mask;
- data->record.r.grsave = (*ptr++ & 0x7f);
- data->record.r.rlen = read_uleb128 (&ptr);
- return ptr;
- }
-
- if ((val & 0xFC) == UNW_R3)
- {
- /* R3 format. */
- val = (val & 0x03);
- if (val == 0)
- data->type = prologue;
- else
- if (val == 1)
- data->type = body;
- else
- abort ();
- data->record.r.rlen = read_uleb128 (&ptr);
- return ptr;
- }
- abort ();
-}
-
-static void
-process_a_b_reg_code(unwind_record *data, unsigned char val)
-{
- int code = (val & 0x60) >> 5;
- int reg = (val & 0x1f);
- switch (code)
- {
- case 0:
- data->record.x.reg = GR_REG (reg);
- break;
- case 1:
- data->record.x.reg = FR_REG (reg);
- break;
- case 2:
- data->record.x.reg = BR_REG (reg);
- break;
- case 3:
- /* TODO. We need to encode the specialty regs here. The table is
- on page B-9 of the runtime manual (under the X1 description.) */
- break;
- }
-}
-
-static unsigned char *
-read_X_record (unwind_record *data, unsigned char val, unsigned char *ptr)
-{
- unsigned long tmp;
- int byte1, byte2;
- switch (val)
- {
- case UNW_X1:
- byte1 = *ptr++;
- data->record.x.t = read_uleb128 (&ptr);
- tmp = read_uleb128 (&ptr);
- if ((byte1 & 0x80) == 0)
- {
- data->type = spill_psprel;
- data->record.x.pspoff = tmp;
- }
- else
- {
- data->type = spill_sprel;
- data->record.x.spoff = tmp;
- }
- process_a_b_reg_code (data, byte1);
- return ptr;
- case UNW_X4:
- byte1 = *ptr++;
- data->record.x.qp = PR_REG (byte1 & 0x3f);
- data->type = spill_reg_p;
- case UNW_X2:
- {
- int xy;
- int treg;
- /* Only set type if we didn't fall through the UNW_X4 case. */
- if (val == UNW_X2)
- data->type = spill_reg;
- byte1 = *ptr++;
- byte2 = *ptr++;
- process_a_b_reg_code (data, byte1);
- xy = (((byte1 >> 7) << 1 ) | (byte2 >> 7));
- treg = (byte2 & 0x7f);
- switch (xy)
- {
- case 0:
- data->record.x.treg = GR_REG (treg);
- break;
- case 1:
- data->record.x.treg = FR_REG (treg);
- break;
- case 2:
- data->record.x.treg = BR_REG (treg);
- break;
- case 3:
- abort ();
- }
- data->record.x.t = read_uleb128 (&ptr);
- }
- return ptr;
- case UNW_X3:
- byte1 = *ptr++;
- byte2 = *ptr++;
- data->record.x.qp = PR_REG (byte1 & 0x3f);
- process_a_b_reg_code (data, byte2);
- data->record.x.t = read_uleb128 (&ptr);
- tmp = read_uleb128 (&ptr);
- if ((byte1 & 0x80) == 0)
- {
- data->type = spill_psprel_p;
- data->record.x.pspoff = tmp;
- }
- else
- {
- data->type = spill_sprel_p;
- data->record.x.spoff = tmp;
- }
- return ptr;
- default:
- abort ();
- }
- return NULL;
-}
-
-static unsigned char *
-read_B_record (unwind_record *data, unsigned char val, unsigned char *ptr)
-{
- if ((val & 0xc0) == 0x80)
- {
- /* B1 format. */
- if ((val & 0x20) == 0)
- data->type = label_state;
- else
- data->type = copy_state;
- data->record.b.label = (val & 0x1f);
- return ptr;
- }
-
- if ((val & 0xe0) == 0xc0)
- {
- /* B2 format. */
- data->type = epilogue;
- data->record.b.ecount = (val & 0x1f);
- data->record.b.t = read_uleb128 (&ptr);
- return ptr;
- }
-
- if (val == UNW_B3)
- {
- /* B3 format. */
- data->type = epilogue;
- data->record.b.t = read_uleb128 (&ptr);
- data->record.b.ecount = read_uleb128 (&ptr);
- return ptr;
- }
-
- if (val == UNW_B4)
- {
- /* B4 format, with r == 0. */
- data->type = label_state;
- data->record.b.label = read_uleb128 (&ptr);
- return ptr;
- }
-
- if (val == (UNW_B4 | 0x08))
- {
- /* B4 format, with r == 1. */
- data->type = copy_state;
- data->record.b.label = read_uleb128 (&ptr);
- return ptr;
- }
- abort ();
-}
-
-/* This array is used to set the TYPE field for format P3. */
-static unw_record_type const P3_record_types[] = {
- psp_gr, rp_gr, pfs_gr, preds_gr, unat_gr, lc_gr, rp_br, rnat_gr,
- bsp_gr, bspstore_gr, fpsr_gr, priunat_gr
-};
-
-/* This array is used to set the TYPE field for format P7. */
-static unw_record_type const P7_record_types[] = {
- mem_stack_f, mem_stack_v, spill_base, psp_sprel, rp_when, rp_psprel,
- pfs_when, pfs_psprel, preds_when, preds_psprel, lc_when, lc_psprel,
- unat_when, unat_psprel, fpsr_when, fpsr_psprel
-};
-
-/* These values and the array are used to determine which additional ULEB128
- fields are required for the P7 format. */
-#define P7_T_SIZE 0
-#define P7_T 1
-#define P7_PSPOFF 2
-#define P7_SPOFF 3
-static unsigned char const P7_additional_fields [] = {
- P7_T_SIZE, P7_T, P7_PSPOFF, P7_SPOFF, P7_T, P7_PSPOFF,
- P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF, P7_T, P7_PSPOFF
-};
-
-/* This array is used to set the TYPE field for format P8.
- Note that entry 0 is not used in this array, so it is filled with
- rp_spel for completely arbitrary reasons. */
-static unw_record_type const P8_record_types[] = {
- rp_sprel, rp_sprel, pfs_sprel, preds_sprel, lc_sprel, unat_sprel, fpsr_sprel,
- bsp_when, bsp_psprel, bsp_sprel, bspstore_when, bspstore_psprel,
- bspstore_sprel, rnat_when, rnat_psprel, rnat_sprel, priunat_when_gr,
- priunat_psprel, priunat_sprel, priunat_when_mem
-};
-
-/* These values and the array are used to determine which additional ULEB128
- fields are required for the P8 format. */
-#define P8_T 0
-#define P8_PSPOFF 1
-#define P8_SPOFF 2
-static unsigned char const P8_additional_fields [] = {
- P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF, P8_SPOFF,
- P8_T, P8_PSPOFF, P8_SPOFF, P8_T, P8_PSPOFF, P8_SPOFF,
- P8_T, P8_PSPOFF, P8_SPOFF, P8_T, P8_PSPOFF, P8_SPOFF, P8_T
-};
-
-
-static unsigned char *
-read_P_record (unwind_record *data, unsigned char val, unsigned char *ptr,
- unwind_record *header)
-{
- if ((val & 0xe0) == 0x80)
- {
- /* P1 format. */
- data->type = br_mem;
- data->record.p.brmask = (val & 0x1f);
- return ptr;
- }
-
- if ((val & 0xf0) == 0xa0)
- {
- /* P2 format. */
- int byte1;
- data->type = br_gr;
- byte1 = *ptr++;
- data->record.p.brmask = ((val & 0x0f) << 1) + (byte1 >> 7);
- data->record.p.gr = GR_REG (byte1 & 0x7f);
- return ptr;
- }
-
- if ((val & 0xf8) == 0xB0)
- {
- /* P3 format. */
- int byte1 = *ptr++;
- int r = ((val & 0x07) << 1) + (byte1 >> 7);
- data->type = P3_record_types[r];
- if (r == 6)
- data->record.p.br = BR_REG (byte1 & 0x7f);
- else
- data->record.p.gr = GR_REG (byte1 & 0x7f);
- if (r > 11)
- abort ();
- return ptr;
- }
-
- if (val == UNW_P4)
- {
- /* P4 format. */
- int size = (header->record.r.rlen * 2 + 7) / 8;
-
- data->type = spill_mask;
- data->record.p.imask = ptr;
- return ptr+size;
- }
-
- if (val == UNW_P5)
- {
- /* P5 format. */
- int byte1 = *ptr++;
- int byte2 = *ptr++;
- int byte3 = *ptr++;
- data->type = frgr_mem;
- data->record.p.grmask = (byte1 >> 4);
- data->record.p.frmask = ((byte1 & 0x0f) << 16) | (byte2 << 8) | byte3;
- return ptr;
- }
-
- if ((val & 0xe0) == UNW_P6)
- {
- /* P6 format. */
- if ((val & 0x10) == 0)
- data->type = fr_mem;
- else
- data->type = gr_mem;
- data->record.p.rmask = (val & 0x0f);
- return ptr;
- }
-
- if ((val & 0xf0) == UNW_P7)
- {
- /* P7 format. */
- int r = (val & 0x0f);
- data->type = P7_record_types[r];
- switch (P7_additional_fields[r])
- {
- case P7_T_SIZE:
- data->record.p.t = read_uleb128 (&ptr);
- data->record.p.size = read_uleb128 (&ptr) << 4;
- break;
- case P7_T:
- data->record.p.t = read_uleb128 (&ptr);
- break;
- case P7_PSPOFF:
- data->record.p.pspoff = read_uleb128 (&ptr);
- break;
- case P7_SPOFF:
- data->record.p.spoff = read_uleb128 (&ptr);
- break;
- }
- return ptr;
- }
-
- if (val == UNW_P8)
- {
- /* P8 format. */
- int r = *ptr++;
- data->type = P8_record_types[r];
- switch (P8_additional_fields[r])
- {
- case P8_T:
- data->record.p.t = read_uleb128 (&ptr);
- break;
- case P8_PSPOFF:
- data->record.p.pspoff = read_uleb128 (&ptr);
- break;
- case P8_SPOFF:
- data->record.p.spoff = read_uleb128 (&ptr);
- break;
- }
- return ptr;
- }
-
- if (val == UNW_P9)
- {
- /* P9 format. */
- int byte1 = *ptr++;
- int byte2 = *ptr++;
- data->type = gr_gr;
- data->record.p.grmask = (byte1 & 0x0f);
- data->record.p.gr = GR_REG (byte2 & 0x7f);
- return ptr;
- }
-
- if (val == UNW_P10)
- {
-#if 0
- /* P10 format. */
- int abi = ptr[0];
- int context = ptr[1];
- /* TODO. something about abi entries. */
-#endif
- return ptr + 2;
- }
-
- return ptr;
-}
-
-/* This routine will determine what type of record the memory pointer
- is refering to, and fill in the appropriate fields for that record type.
- HEADER is a pointer to the last region header unwind record.
- DATA is a pointer to an unwind record which will be filled in.
- PTR is a pointer to the current location in the unwind table where we
- will read the next record from.
- The return value is the start of the next record. */
-
-static unsigned char *
-get_unwind_record (unwind_record *header, unwind_record *data,
- unsigned char *ptr)
-{
- unsigned char val = *ptr++;
-
- if ((val & 0x80) == 0)
- return read_R_record (data, val, ptr);
-
- if (val == UNW_X1 || val == UNW_X2 || val == UNW_X3 || val == UNW_X4)
- return read_X_record (data, val, ptr);
-
- if (header->type != body)
- return read_P_record (data, val, ptr, header);
- else
- return read_B_record (data, val, ptr);
-}
-
-/* Frame processing routines. */
-
-/* Initialize a single register structure. */
-static inline void
-init_ia64_reg_loc (ia64_reg_loc *reg, short size)
-{
- reg->when = -1;
- reg->loc_type = IA64_UNW_LOC_TYPE_NONE;
- reg->l.mem = (void *)0;
- reg->reg_size = size;
-}
-
-/* Iniitialize an entire frame to the default of nothing. */
-static void
-init_ia64_unwind_frame (ia64_frame_state *frame)
-{
- int x;
-
- for (x = 0; x < 4; x++)
- init_ia64_reg_loc (&frame->gr[x], 8);
- for (x = 0; x < 20; x++)
- init_ia64_reg_loc (&frame->fr[x], 16);
- for (x = 0; x < 5; x++)
- init_ia64_reg_loc (&frame->br[x], 8);
-
- init_ia64_reg_loc (&frame->rp, 8);
- init_ia64_reg_loc (&frame->fpsr, 8);
- init_ia64_reg_loc (&frame->bsp, 8);
- init_ia64_reg_loc (&frame->bspstore, 8);
- init_ia64_reg_loc (&frame->rnat, 8);
- init_ia64_reg_loc (&frame->pfs, 8);
- init_ia64_reg_loc (&frame->unat, 8);
- init_ia64_reg_loc (&frame->lc, 8);
- init_ia64_reg_loc (&frame->pr, 8);
- init_ia64_reg_loc (&frame->priunat, 8);
- init_ia64_reg_loc (&frame->sp, 8);
- init_ia64_reg_loc (&frame->psp, 8);
- init_ia64_reg_loc (&frame->spill_base, 8);
-}
-
-/* This fuction will process a single descriptor.
- addr is a pointer to the descriptor record to read,
- frame is the current frame state structure, which will be
- modified to reflect this descriptor.
- len is the length of a prologue region, or -1 if it wasn't one.
- the return value is a pointer to the start of the next descriptor. */
-
-static void *
-execute_one_ia64_descriptor (void *addr, ia64_frame_state *frame, long *len)
-{
- /* The last region_header. Needed to distinguish between prologue and body
- descriptors. Also needed for length of P4 format. */
- static unwind_record region_header;
-
- unwind_record r;
- ia64_reg_loc *loc_ptr = NULL;
- int grmask = 0, frmask = 0;
-
- *len = -1;
- addr = get_unwind_record (&region_header, &r, addr);
-
- /* Process it in 2 phases, the first phase will either do the work,
- or set up a pointer to the records we care about
- (ie a special purpose ar perhaps, and the second will actually
- fill in the record. */
- switch (r.type)
- {
- case prologue:
- case body:
- *len = r.record.r.rlen;
- region_header = r;
- break;
- case prologue_gr:
- {
- int val, reg;
-
- *len = r.record.r.rlen;
- val = r.record.r.mask;
- reg = r.record.r.grsave;
- if (val & 0x08)
- {
- frame->rp.when = 0;
- frame->rp.loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->rp.l.regno = reg++;
- }
- if (val & 0x04)
- {
- frame->pfs.when = 0;
- frame->pfs.loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->pfs.l.regno = reg++;
- }
- if (val & 0x02)
- {
- frame->psp.when = 0;
- frame->psp.loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->psp.l.regno = reg++;
- }
- if (val & 0x01)
- {
- frame->pr.when = 0;
- frame->pr.loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->pr.l.regno = reg++;
- }
- region_header = r;
- break;
- }
- case mem_stack_f:
- frame->sp.l.offset = r.record.p.size;
- frame->sp.loc_type = IA64_UNW_LOC_TYPE_OFFSET;
- frame->sp.when = r.record.p.t;
- break;
- case mem_stack_v:
- frame->psp.when = r.record.p.t;
- break;
- case psp_gr:
- case psp_sprel:
- loc_ptr = &frame->psp;
- break;
- case rp_br:
- case rp_gr:
- case rp_when:
- case rp_psprel:
- case rp_sprel:
- loc_ptr = &frame->rp;
- break;
- case pfs_gr:
- case pfs_when:
- case pfs_psprel:
- case pfs_sprel:
- loc_ptr = &frame->pfs;
- break;
- case preds_gr:
- case preds_when:
- case preds_psprel:
- case preds_sprel:
- loc_ptr = &frame->pr;
- break;
- case unat_gr:
- case unat_when:
- case unat_psprel:
- case unat_sprel:
- loc_ptr = &frame->unat;
- break;
- case lc_gr:
- case lc_when:
- case lc_psprel:
- case lc_sprel:
- loc_ptr = &frame->lc;
- break;
- case fpsr_gr:
- case fpsr_when:
- case fpsr_psprel:
- case fpsr_sprel:
- loc_ptr = &frame->fpsr;
- break;
- case priunat_gr:
- case priunat_sprel:
- case priunat_when_gr:
- case priunat_when_mem:
- case priunat_psprel:
- loc_ptr = &frame->priunat;
- break;
- case bsp_gr:
- case bsp_sprel:
- case bsp_when:
- case bsp_psprel:
- loc_ptr = &frame->bsp;
- break;
- case bspstore_gr:
- case bspstore_sprel:
- case bspstore_when:
- case bspstore_psprel:
- loc_ptr = &frame->bspstore;
- break;
- case rnat_gr:
- case rnat_sprel:
- case rnat_when:
- case rnat_psprel:
- loc_ptr = &frame->rnat;
- break;
- case spill_base:
- loc_ptr = &frame->spill_base;
- break;
- case fr_mem:
- frmask = r.record.p.rmask;
- break;
- case gr_mem:
- grmask = r.record.p.rmask;
- break;
- case frgr_mem:
- frmask = r.record.p.frmask;
- grmask = r.record.p.grmask;
- break;
- case br_mem:
- {
- int x, mask = 0x01;
- int saved = r.record.p.brmask;
- for (x = 0; x < 5; x++)
- {
- if (saved & mask)
- frame->br[x].loc_type = IA64_UNW_LOC_TYPE_SPILLBASE;
- mask = mask << 1;
- }
- break;
- }
- case br_gr:
- {
- int x, mask = 0x01;
- int reg = r.record.p.gr;
- int saved = r.record.p.brmask;
- for (x = 0; x < 5; x++)
- {
- if (saved & mask)
- {
- frame->br[x].loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->br[x].l.regno = reg++;
- }
- mask = mask << 1;
- }
- break;
- }
- case gr_gr:
- {
- int x, mask = 0x01;
- int reg = r.record.p.gr;
- int saved = r.record.p.grmask;
- for (x = 0; x < 4; x++)
- {
- if (saved & mask)
- {
- frame->br[x].loc_type = IA64_UNW_LOC_TYPE_GR;
- frame->br[x].l.regno = reg++;
- }
- mask = mask << 1;
- }
- break;
- }
- case spill_mask:
- /* TODO. */
- break;
- case epilogue:
- /* TODO. */
- break;
- case label_state:
- /* TODO. */
- break;
- case copy_state:
- /* TODO. */
- break;
- case spill_psprel:
- case spill_sprel:
- case spill_reg:
- case spill_psprel_p:
- case spill_sprel_p:
- case spill_reg_p:
- /* TODO. */
- break;
- default:
- abort ();
- break;
- }
-
- if (frmask)
- {
- int x, mask = 0x01;
- for (x = 0; x < 20; x++)
- {
- if (frmask & mask)
- frame->fr[x].loc_type = IA64_UNW_LOC_TYPE_SPILLBASE;
- mask = mask << 1;
- }
- }
-
- if (grmask)
- {
- int x, mask = 0x01;
- for (x = 0; x < 4; x++)
- {
- if (grmask & mask)
- frame->gr[x].loc_type = IA64_UNW_LOC_TYPE_SPILLBASE;
- mask = mask << 1;
- }
- }
-
- /* If there is more to do: */
- if (loc_ptr != NULL)
- switch (r.type)
- {
- case psp_gr:
- case rp_gr:
- case pfs_gr:
- case preds_gr:
- case unat_gr:
- case lc_gr:
- case fpsr_gr:
- case priunat_gr:
- case bsp_gr:
- case bspstore_gr:
- case rnat_gr:
- loc_ptr->loc_type = IA64_UNW_LOC_TYPE_GR;
- loc_ptr->l.regno = r.record.p.gr;
- break;
- case rp_br:
- loc_ptr->loc_type = IA64_UNW_LOC_TYPE_BR;
- loc_ptr->l.regno = r.record.p.br;
- break;
- case rp_when:
- case pfs_when:
- case preds_when:
- case unat_when:
- case lc_when:
- case fpsr_when:
- case priunat_when_gr:
- case priunat_when_mem:
- case bsp_when:
- case bspstore_when:
- case rnat_when:
- loc_ptr->when = r.record.p.t;
- break;
- case rp_psprel:
- case pfs_psprel:
- case preds_psprel:
- case unat_psprel:
- case lc_psprel:
- case fpsr_psprel:
- case priunat_psprel:
- case bsp_psprel:
- case bspstore_psprel:
- case rnat_psprel:
- case spill_base:
- loc_ptr->loc_type = IA64_UNW_LOC_TYPE_PSPOFF;
- loc_ptr->l.offset = r.record.p.pspoff;
- break;
- case psp_sprel:
- case rp_sprel:
- case pfs_sprel:
- case preds_sprel:
- case unat_sprel:
- case lc_sprel:
- case fpsr_sprel:
- case priunat_sprel:
- case bsp_sprel:
- case bspstore_sprel:
- case rnat_sprel:
- loc_ptr->loc_type = IA64_UNW_LOC_TYPE_SPOFF;
- loc_ptr->l.offset = r.record.p.spoff;
- break;
- default:
- abort ();
- break;
- }
- return addr;
-}
-
-
-#define IS_NaT_COLLECTION_ADDR(addr) ((((long)(addr) >> 3) & 0x3f) == 0x3f)
-
-/* Returns the address of the slot that's NSLOTS slots away from
- the address ADDR. NSLOTS may be positive or negative. */
-static void *
-rse_address_add(unsigned char *addr, int nslots)
-{
- unsigned char *new_addr;
- int mandatory_nat_slots = nslots / 63;
- int direction = nslots < 0 ? -1 : 1;
-
- new_addr = addr + 8 * (nslots + mandatory_nat_slots);
-
- if (((long)new_addr >> 9)
- != ((long)(addr + 8 * 64 * mandatory_nat_slots) >> 9))
- new_addr += 8 * direction;
-
- if (IS_NaT_COLLECTION_ADDR(new_addr))
- new_addr += 8 * direction;
-
- return new_addr;
-}
-
-
-/* Normalize a record to originate in either a register or memory
- location. */
-static void
-normalize_reg_loc (ia64_frame_state *frame, ia64_reg_loc *reg)
-{
- unsigned char *tmp;
- switch (reg->loc_type)
- {
- case IA64_UNW_LOC_TYPE_MEM:
- /* Already done. */
- break;
- case IA64_UNW_LOC_TYPE_GR:
- /* If the register its saved in is a LOCAL register, we know
- its actually in memory, so we'll pick it up from there. */
- if (reg->l.regno >= 32 && frame->my_bsp != 0)
- {
- /* Get from backing store. */
- tmp = rse_address_add(frame->my_bsp, reg->l.regno - 32);
- reg->l.mem = tmp;
- reg->loc_type = IA64_UNW_LOC_TYPE_MEM;
- }
- break;
- case IA64_UNW_LOC_TYPE_FR:
- /* If the register its saved in is a LOCAL register, we know
- its actually in memory, so we'll pick it up from there. */
- if (reg->l.regno >= 32)
- {
- /* TODO. get from backing store. */
- }
- break;
- case IA64_UNW_LOC_TYPE_BR:
- break;
- case IA64_UNW_LOC_TYPE_SPOFF:
- /* Offset from the stack pointer, calculate the memory address
- now. */
- tmp = (unsigned char *)frame->my_sp + reg->l.offset * 4;
- reg->l.mem = tmp;
- reg->loc_type = IA64_UNW_LOC_TYPE_MEM;
- break;
- case IA64_UNW_LOC_TYPE_PSPOFF:
- /* Actualy go get the value of the PSP add the offset, and thats
- the mem location we can find this value at. */
- tmp = (unsigned char *)frame->my_psp + 16 - reg->l.offset * 4;
- reg->l.mem = tmp;
- reg->loc_type = IA64_UNW_LOC_TYPE_MEM;
- break;
- case IA64_UNW_LOC_TYPE_SPILLBASE:
- /* located at the current spill base memory location, and we
- have to bump it as well. */
- reg->l.mem = frame->spill_base.l.mem;
- reg->loc_type = IA64_UNW_LOC_TYPE_MEM;
- frame->spill_base.l.mem += 8;
- break;
- }
-
-}
-
-/* This function looks at a reg_loc and determines if its going
- to be an executed record or not between time start and end.
- It is executed if it is exectued at START time. It is NOT
- executed if it happens at END time. */
-static void
-maybe_normalize_reg_loc (ia64_frame_state *frame, ia64_reg_loc *reg,
- long start, long end)
-{
- if (reg->loc_type != IA64_UNW_LOC_TYPE_NONE
- && reg->when >= start && reg->when < end)
- normalize_reg_loc (frame, reg);
-}
-
-
-/* Only works for 8 byte or less registers. */
-void *
-__get_real_reg_value (ia64_reg_loc *reg)
-{
- if (reg->loc_type == IA64_UNW_LOC_TYPE_MEM)
- return *((void **)(reg->l.mem));
-
- /* All registers should be in memory if we've saved them. Local
- registers will be in backing store. */
- abort ();
-}
-
-void
-__set_real_reg_value (ia64_reg_loc *reg, void *val)
-{
- if (reg->loc_type == IA64_UNW_LOC_TYPE_MEM)
- {
- void **ptr = reg->l.mem;
- *ptr = val;
- return;
- }
- abort ();
-}
-
-static void
-copy_reg_value (ia64_reg_loc *src, ia64_reg_loc *dest)
-{
- void **p = dest->l.mem;
- if (src->loc_type == IA64_UNW_LOC_TYPE_NONE)
- return;
-
- if (src->reg_size != dest->reg_size)
- abort ();
- if (src->reg_size <= 8)
- *p = __get_real_reg_value (src);
- else
- {
- void **d;
- if (src->reg_size > 16)
- abort ();
- if (dest->loc_type != IA64_UNW_LOC_TYPE_MEM)
- abort ();
- d = (void **)(dest->l.mem);
- *p++ = *d++;
- *p = *d;
- }
- return;
-}
-
-/* Copy the values of any relevant saved registers in one frame
- to another for unwinding. */
-void
-__copy_saved_reg_state (ia64_frame_state *dest, ia64_frame_state *src)
-{
- int x;
- for (x = 0; x < 4 ; x++)
- copy_reg_value (&src->gr[x], &dest->gr[x]);
- for (x = 0; x < 20 ; x++)
- copy_reg_value (&src->fr[x], &dest->fr[x]);
- for (x = 0; x < 5 ; x++)
- copy_reg_value (&src->br[x], &dest->br[x]);
-
- copy_reg_value (&src->fpsr, &dest->fpsr);
- copy_reg_value (&src->rnat, &dest->rnat);
- copy_reg_value (&src->unat, &dest->unat);
- copy_reg_value (&src->lc, &dest->lc);
- copy_reg_value (&src->pr, &dest->pr);
- copy_reg_value (&src->priunat, &dest->priunat);
- copy_reg_value (&src->pfs, &dest->pfs);
-}
-
-
-static void
-process_state_between (ia64_frame_state *frame, long start, long end)
-{
- int x;
- /* PSP, RP, SP, and PFS are handled seperately from here. */
-
- /* GR's, FR's and BR's are saved at an arbitrary point, so we
- should handle them at the very beginning. */
- /* ??? Err, no they aren't. There's the spill_mask record that
- tells us when each is processed. */
- if (start == 0)
- {
- for (x = 0; x < 4 ; x++)
- normalize_reg_loc (frame, &frame->gr[x]);
- for (x = 0; x < 20 ; x++)
- normalize_reg_loc (frame, &frame->fr[x]);
- for (x = 0; x < 5 ; x++)
- normalize_reg_loc (frame, &frame->br[x]);
- }
-
- maybe_normalize_reg_loc (frame, &frame->fpsr, start, end);
- maybe_normalize_reg_loc (frame, &frame->bsp, start, end);
- maybe_normalize_reg_loc (frame, &frame->bspstore, start, end);
- maybe_normalize_reg_loc (frame, &frame->rnat, start, end);
- maybe_normalize_reg_loc (frame, &frame->unat, start, end);
- maybe_normalize_reg_loc (frame, &frame->lc, start, end);
- maybe_normalize_reg_loc (frame, &frame->pr, start, end);
- maybe_normalize_reg_loc (frame, &frame->priunat, start, end);
-}
-
-/* This function will take a frame state, and translate all the location
- records into actual memory address, or register numbers, based on
- what the ia64_reg_loc fields require to actually go get the values.
- (ie, this translates SPOFF and PSPOFF, etc into MEM types.
- frame is the frame to be changed.
- unwind_time is the insn slot number we are unwinding to. Anything
- that has a WHEN record beyond this time is cleared since it
- isn't relevant. */
-static void
-frame_translate (ia64_frame_state *frame, long unwind_time)
-{
- /* ??? Is this supposed to mark the end of the stack? */
- if (frame->rp.loc_type == IA64_UNW_LOC_TYPE_NONE)
- return;
-
- /* At function entry, SP == PSP. */
- frame->my_psp = frame->my_sp;
- if (frame->psp.loc_type != IA64_UNW_LOC_TYPE_NONE)
- {
- /* We've saved a frame pointer somewhere. This will be the
- canonical PSP for the function. */
- normalize_reg_loc (frame, &frame->psp);
- if (frame->psp.when < unwind_time)
- frame->my_psp = __get_real_reg_value (&frame->psp);
- }
- else if (frame->sp.loc_type == IA64_UNW_LOC_TYPE_OFFSET)
- {
- /* We've a fixed sized stack frame. The PSP is at a known offset. */
-
- if (frame->sp.when < unwind_time)
- frame->my_psp = frame->my_sp + frame->sp.l.offset;
- }
- /* Otherwise the stack frame size was zero and no adjustment needed. */
-
- /* Find PFS, RP and the spill base. All of which might have
- addresses based off the PSP computed above. */
- normalize_reg_loc (frame, &frame->pfs);
- normalize_reg_loc (frame, &frame->rp);
-
- if (frame->spill_base.loc_type != IA64_UNW_LOC_TYPE_NONE)
- normalize_reg_loc (frame, &frame->spill_base);
- else
- {
- /* Otherwise we're supposed to infer it from the size of the
- saved GR/BR/FR registers, putting the top at psp+16. */
- long size = 0, i;
- for (i = 0; i < 4; ++i)
- if (frame->gr[i].when >= 0)
- size += 8;
- for (i = 0; i < 5; ++i)
- if (frame->br[i].when >= 0)
- size += 8;
- for (i = 0; i < 20; ++i)
- if (frame->fr[i].when >= 0)
- size += 16;
- frame->spill_base.l.mem = frame->my_psp + 16 - size;
- }
-
- /* If the SP is adjusted, process records up to where it
- is adjusted, then adjust it, then process the rest. */
- if (frame->sp.when >= 0)
- {
- process_state_between (frame, 0, frame->sp.when);
- if (frame->sp.loc_type != IA64_UNW_LOC_TYPE_OFFSET)
- abort ();
- frame->my_sp = frame->my_psp - frame->sp.l.offset;
- process_state_between (frame, frame->sp.when, unwind_time);
- }
- else
- process_state_between (frame, 0, unwind_time);
-}
-
-/* This function will set a frame_state with all the required fields
- from a functions unwind descriptors.
- pc is the location we need info up until (ie, the unwind point)
- frame is the frame_state structure to be set up.
- Returns a pointer to the unwind info pointer for the frame. */
-unwind_info_ptr *
-__build_ia64_frame_state (unsigned char *pc, ia64_frame_state *frame,
- void *bsp, void *sp, void **pc_base_ptr)
-{
- long len;
- int region_offset = 0;
- int last_region_size = 0;
- void *addr, *end;
- unwind_table_entry *entry;
- unsigned char *start_pc;
- void *pc_base;
- int pc_offset;
- struct unwind_info_ptr *unw_info_ptr;
-
- entry = __ia64_find_fde (pc, &pc_base);
- if (!entry)
- return 0;
-
- start_pc = pc_base + entry->start_offset;
- unw_info_ptr = ((struct unwind_info_ptr *)(pc_base + entry->unwind_offset));
- addr = unw_info_ptr->unwind_descriptors;
- end = addr + IA64_UNW_HDR_LENGTH (unw_info_ptr->header) * 8;
- pc_offset = (pc - start_pc) / 16 * 3;
-
- init_ia64_unwind_frame (frame);
- frame->my_bsp = bsp;
- frame->my_sp = sp;
-
- /* Stop when we get to the end of the descriptor list, or if we
- encounter a region whose initial offset is already past the
- PC we are unwinding too. */
-
- while (addr < end && pc_offset > region_offset)
- {
- /* First one must be a record header. */
- addr = execute_one_ia64_descriptor (addr, frame, &len);
- if (len > 0)
- {
- region_offset += last_region_size;
- last_region_size = len;
- }
- }
-
- /* Now we go get the actual values. */
- frame_translate (frame, pc_offset);
- if (pc_base_ptr)
- *pc_base_ptr = pc_base;
- return unw_info_ptr;
-}
-
-/* Given an unwind info pointer, return the personality routine. */
-void *
-__get_personality (unwind_info_ptr *ptr)
-{
- void **p;
-
- /* There is a personality routine only if one of the EHANDLER or UHANDLER
- bits is set. */
- if (! (IA64_UNW_HDR_FLAGS (ptr->header)
- & (IA64_UNW_EHANDLER|IA64_UNW_UHANDLER)))
- return 0;
-
- p = (void **) (ptr->unwind_descriptors
- + IA64_UNW_HDR_LENGTH (ptr->header) * 8);
- return *p;
-}
-
-/* Given an unwind info pointer, return the exception table. */
-void *
-__get_except_table (unwind_info_ptr *ptr)
-{
- void *table;
-
- /* If there is no personality, there is no handler data.
- There is a personality routine only if one of the EHANDLER or UHANDLER
- bits is set. */
- if (! (IA64_UNW_HDR_FLAGS (ptr->header)
- & (IA64_UNW_EHANDLER|IA64_UNW_UHANDLER)))
- return 0;
-
- table = (void *) (ptr->unwind_descriptors
- + IA64_UNW_HDR_LENGTH (ptr->header) * 8 + 8);
- return table;
-}
-
-/* Given a PFS value, and the current BSp, calculate the BSp of the caller. */
-void *
-__calc_caller_bsp (long pfs, unsigned char *bsp)
-{
- int size_of_locals;
-
- /* The PFS looks like : xxxx SOL:7 SOF:7. The SOF is bits 0-7 and SOL
- is bits 8-15. We only care about SOL. */
-
- size_of_locals = (pfs >> 7) & 0x7f;
- return rse_address_add (bsp, -size_of_locals);
-}
-
-static int
-ia64_backtrace_helper (void **array, ia64_frame_state *throw_frame,
- ia64_frame_state *frame, void *bsp, void *sp, int size)
-{
- void *throw_pc = __builtin_return_address (0);
- void *pc = NULL;
- int frame_count = 0;
- unwind_info_ptr *info;
-
- __builtin_ia64_flushrs (); /* Make the local register stacks available. */
-
- /* Start at our stack frame, get our state. */
- info = __build_ia64_frame_state (throw_pc, throw_frame, bsp, sp, NULL);
-
- *frame = *throw_frame;
-
- while (info && frame_count < size)
- {
- pc = array[frame_count++] = __get_real_reg_value (&frame->rp);
- --pc;
- bsp = __calc_caller_bsp
- ((long)__get_real_reg_value (&frame->pfs), frame->my_bsp);
- info = __build_ia64_frame_state (pc, frame, bsp, frame->my_psp, NULL);
- if (frame->rp.loc_type == IA64_UNW_LOC_TYPE_NONE) /* We've finished. */
- break;
- }
-
- return frame_count;
-}
-
-/* This is equivalent to glibc's backtrace(). */
-
-extern int __ia64_backtrace (void **array, int size);
-
-int
-__ia64_backtrace (void **array, int size)
-{
- register void *stack_pointer __asm__("r12");
- ia64_frame_state my_frame;
- ia64_frame_state originator; /* For the context handler is in. */
- void *bsp;
-
- /* Do any necessary initialization to access arbitrary stack frames.
- This forces gcc to save memory in our stack frame for saved
- registers. */
- __builtin_unwind_init ();
-
- bsp = __builtin_ia64_bsp ();
-
- return ia64_backtrace_helper (array, &my_frame, &originator, bsp,
- stack_pointer, size);
-}
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index 396764b..62cc4fb 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -2149,19 +2149,6 @@ do { \
} while (0)
-/* Output EH data to the unwind segment. */
-#define ASM_OUTPUT_EH_CHAR(FILE, VALUE) \
- ASM_OUTPUT_XDATA_CHAR(FILE, ".IA_64.unwind_info", VALUE)
-
-#define ASM_OUTPUT_EH_SHORT(FILE, VALUE) \
- ASM_OUTPUT_XDATA_SHORT(FILE, ".IA_64.unwind_info", VALUE)
-
-#define ASM_OUTPUT_EH_INT(FILE, VALUE) \
- ASM_OUTPUT_XDATA_INT(FILE, ".IA_64.unwind_info", VALUE)
-
-#define ASM_OUTPUT_EH_DOUBLE_INT(FILE, VALUE) \
- ASM_OUTPUT_XDATA_DOUBLE_INT(FILE, ".IA_64.unwind_info", VALUE)
-
/* A C statement to output to the stdio stream STREAM an assembler instruction
to assemble a single byte containing the number VALUE. */
@@ -2473,26 +2460,6 @@ do { \
/* Assembler Commands for Exception Regions. */
-/* ??? This entire section of ia64.h needs to be implemented and then cleaned
- up. */
-
-/* A C expression to output text to mark the start of an exception region.
-
- This macro need not be defined on most platforms. */
-/* #define ASM_OUTPUT_EH_REGION_BEG() */
-
-/* A C expression to output text to mark the end of an exception region.
-
- This macro need not be defined on most platforms. */
-/* #define ASM_OUTPUT_EH_REGION_END() */
-
-/* A C expression to switch to the section in which the main exception table is
- to be placed. The default is a section named `.gcc_except_table' on machines
- that support named sections via `ASM_OUTPUT_SECTION_NAME', otherwise if `-fpic'
- or `-fPIC' is in effect, the `data_section', otherwise the
- `readonly_data_section'. */
-/* #define EXCEPTION_SECTION() */
-
/* If defined, a C string constant for the assembler operation to switch to the
section for exception handling frame unwind information. If not defined,
GNU CC will provide a default definition if the target supports named
@@ -2503,26 +2470,34 @@ do { \
information and the default definition does not work. */
#define EH_FRAME_SECTION_ASM_OP "\t.section\t.IA_64.unwind,\"aw\""
-/* A C expression that is nonzero if the normal exception table output should
- be omitted.
-
- This macro need not be defined on most platforms. */
-/* #define OMIT_EH_TABLE() */
-
-/* Alternate runtime support for looking up an exception at runtime and finding
- the associated handler, if the default method won't work.
-
- This macro need not be defined on most platforms. */
-/* #define EH_TABLE_LOOKUP() */
-
-/* A C expression that decides whether or not the current function needs to
- have a function unwinder generated for it. See the file `except.c' for
- details on when to define this, and how. */
-/* #define DOESNT_NEED_UNWINDER */
+/* Select a format to encode pointers in exception handling data. CODE
+ is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
+ true if the symbol may be affected by dynamic relocations. */
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) \
+ (((CODE) == 1 ? DW_EH_PE_textrel : DW_EH_PE_datarel) \
+ | ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_udata8)
+
+/* Handle special EH pointer encodings. Absolute, pc-relative, and
+ indirect are handled automatically. */
+#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \
+ do { \
+ const char *reltag = NULL; \
+ if (((ENCODING) & 0xF0) == DW_EH_PE_textrel) \
+ reltag = "@segrel("; \
+ else if (((ENCODING) & 0xF0) == DW_EH_PE_datarel) \
+ reltag = "@gprel("; \
+ if (reltag) \
+ { \
+ fputs (((SIZE) == 4 ? UNALIGNED_INT_ASM_OP \
+ : (SIZE) == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP \
+ : (abort (), "")), FILE); \
+ fputs (reltag, FILE); \
+ assemble_name (FILE, XSTR (ADDR, 0)); \
+ fputc (')', FILE); \
+ goto DONE; \
+ } \
+ } while (0)
-/* An rtx used to mask the return address found via RETURN_ADDR_RTX, so that it
- does not contain any extraneous set bits in it. */
-/* #define MASK_RETURN_ADDR */
/* Assembler Commands for Alignment. */
@@ -2846,13 +2821,11 @@ do { \
extern int ia64_final_schedule;
-/* ??? Hack until frame-ia64.c is updated.
#define IA64_UNWIND_INFO 1
-*/
-
-#define HANDLER_SECTION fprintf (asm_out_file, "\t.personality\t__ia64_personality_v1\n\t.handlerdata\n");
#define IA64_UNWIND_EMIT(f,i) process_for_unwind_directive (f,i)
+#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 15 : INVALID_REGNUM)
+
/* This function contains machine specific function data. */
struct machine_function
{
diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md
index 36823d6..9850777 100644
--- a/gcc/config/ia64/ia64.md
+++ b/gcc/config/ia64/ia64.md
@@ -4979,13 +4979,6 @@
DONE;
}")
-;; Restore the GP after the exception/longjmp. The preceeding call will
-;; have tucked it away.
-(define_expand "exception_receiver"
- [(set (reg:DI 1) (match_dup 0))]
- ""
- "operands[0] = ia64_gp_save_reg (0);")
-
;; The rest of the setjmp processing happens with the nonlocal_goto expander.
;; ??? This is not tested.
(define_expand "builtin_setjmp_setup"
diff --git a/gcc/config/ia64/t-glibc b/gcc/config/ia64/t-glibc
index 5336209..a105662 100644
--- a/gcc/config/ia64/t-glibc
+++ b/gcc/config/ia64/t-glibc
@@ -1 +1 @@
-# LIB2ADDEH += $(srcdir)/config/ia64/fde-glibc.c
+LIB2ADDEH += $(srcdir)/config/ia64/fde-glibc.c
diff --git a/gcc/config/ia64/t-ia64 b/gcc/config/ia64/t-ia64
index b8f053c..274f9a4 100644
--- a/gcc/config/ia64/t-ia64
+++ b/gcc/config/ia64/t-ia64
@@ -41,4 +41,4 @@ crtendS.o: $(srcdir)/config/ia64/crtend.asm $(GCC_PASSES)
$(GCC_FOR_TARGET) -DSHARED -c -o crtendS.o -x assembler-with-cpp $(srcdir)/config/ia64/crtend.asm
EXTRA_HEADERS = $(srcdir)/config/ia64/ia64intrin.h
-# LIB2ADDEH = $(srcdir)/config/ia64/frame-ia64.c
+LIB2ADDEH = $(srcdir)/config/ia64/unwind-ia64.c $(srcdir)/unwind-sjlj.c
diff --git a/gcc/config/ia64/unwind-ia64.c b/gcc/config/ia64/unwind-ia64.c
new file mode 100644
index 0000000..15d6683
--- /dev/null
+++ b/gcc/config/ia64/unwind-ia64.c
@@ -0,0 +1,2015 @@
+/* Subroutines needed for unwinding IA-64 standard format stack frame
+ info for exception handling.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001 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 GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+
+#include "tconfig.h"
+#include "tsystem.h"
+#include "unwind.h"
+#include "unwind-ia64.h"
+
+#if !USING_SJLJ_EXCEPTIONS
+
+#define inline
+
+#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)
+
+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_B1,
+ UNW_REG_B5 = UNW_REG_B1 + 4,
+
+ UNW_NUM_REGS
+};
+
+enum unw_where
+{
+ UNW_WHERE_NONE, /* register isn't saved at all */
+ UNW_WHERE_GR, /* register is saved in a general register */
+ UNW_WHERE_FR, /* register is saved in a floating-point register */
+ UNW_WHERE_BR, /* register is saved in a branch register */
+ UNW_WHERE_SPREL, /* register is saved on memstack (sp-relative) */
+ UNW_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */
+
+ /* At the end of each prologue these locations get resolved to
+ UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively. */
+ UNW_WHERE_SPILL_HOME, /* register is saved in its spill home */
+ UNW_WHERE_GR_SAVE /* register is saved in next general register */
+};
+
+#define UNW_WHEN_NEVER 0x7fffffff
+
+struct unw_reg_info
+{
+ unsigned long val; /* save location: register number or offset */
+ enum unw_where where; /* where the register gets saved */
+ int when; /* when the register gets saved */
+};
+
+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 char *imask; /* imask of of spill_mask record or NULL */
+ unsigned long pr_val; /* predicate values */
+ unsigned long pr_mask; /* predicate mask */
+ long spill_offset; /* psp-relative offset for spill base */
+ int region_start;
+ int region_len;
+ int epilogue_start;
+ int epilogue_count;
+ int when_target;
+
+ unsigned char gr_save_loc; /* next general register to use for saving */
+ unsigned char return_link_reg; /* branch register for return link */
+
+ struct unw_reg_state {
+ struct unw_reg_state *next;
+ unsigned long label; /* label of this state record */
+ struct unw_reg_info reg[UNW_NUM_REGS];
+ } curr, *stack, *reg_state_list;
+
+ _Unwind_Personality_Fn personality;
+
+} _Unwind_FrameState;
+
+enum unw_nat_type
+{
+ UNW_NAT_NONE, /* NaT not represented */
+ UNW_NAT_VAL, /* NaT represented by NaT value (fp reg) */
+ UNW_NAT_MEMSTK, /* NaT value is in unat word at offset OFF */
+ UNW_NAT_REGSTK /* NaT is in rnat */
+};
+
+struct unw_stack
+{
+ unsigned long limit;
+ unsigned long top;
+};
+
+struct _Unwind_Context
+{
+ /* Initial frame info. */
+ unsigned long rnat; /* rse nat collection */
+ unsigned long regstk_top; /* bsp for first frame */
+
+ /* Current frame info. */
+ unsigned long bsp; /* backing store pointer value */
+ unsigned long sp; /* stack pointer value */
+ unsigned long psp; /* previous sp value */
+ unsigned long rp; /* return pointer */
+ unsigned long pr; /* predicate collection */
+
+ unsigned long region_start; /* start of unwind region */
+ unsigned long gp; /* global pointer value */
+ void *lsda; /* language specific data area */
+
+ /* Preserved state. */
+ unsigned long *bsp_loc; /* previous bsp save location */
+ unsigned long *bspstore_loc;
+ unsigned long *pfs_loc;
+ unsigned long *pri_unat_loc;
+ unsigned long *unat_loc;
+ unsigned long *lc_loc;
+ unsigned long *fpsr_loc;
+
+ unsigned long eh_data[4];
+
+ struct unw_ireg
+ {
+ unsigned long *loc;
+ struct unw_ireg_nat
+ {
+ enum unw_nat_type type : 3;
+ signed long off : 61; /* NaT word is at loc+nat.off */
+ } nat;
+ } ireg[32 - 2];
+
+ unsigned long *br_loc[6 - 1];
+ void *fr_loc[32 - 2];
+};
+
+typedef unsigned long unw_word;
+
+/* Implicit register save order. See section 11.4.2.3 Rules for Using
+ Unwind Descriptors, rule 3. */
+
+static unsigned char const save_order[] =
+{
+ UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
+ UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
+};
+
+
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+
+/* Unwind decoder routines */
+
+static void
+push (struct unw_state_record *sr)
+{
+ struct unw_reg_state *rs;
+
+ rs = malloc (sizeof (struct unw_reg_state));
+ memcpy (rs, &sr->curr, sizeof (*rs));
+ rs->next = sr->stack;
+ sr->stack = rs;
+}
+
+static void
+pop (struct unw_state_record *sr)
+{
+ struct unw_reg_state *rs;
+
+ rs = sr->stack;
+ sr->stack = rs->next;
+ free (rs);
+}
+
+static enum unw_register_index __attribute__((const))
+decode_abreg (unsigned char abreg, int memory)
+{
+ switch (abreg)
+ {
+ case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
+ case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
+ case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
+ case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
+ case 0x60: return UNW_REG_PR;
+ case 0x61: return UNW_REG_PSP;
+ case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR;
+ case 0x63: return UNW_REG_RP;
+ case 0x64: return UNW_REG_BSP;
+ case 0x65: return UNW_REG_BSPSTORE;
+ case 0x66: return UNW_REG_RNAT;
+ case 0x67: return UNW_REG_UNAT;
+ case 0x68: return UNW_REG_FPSR;
+ case 0x69: return UNW_REG_PFS;
+ case 0x6a: return UNW_REG_LC;
+ default:
+ abort ();
+ }
+}
+
+static void
+set_reg (struct unw_reg_info *reg, enum unw_where where,
+ int when, unsigned long val)
+{
+ reg->val = val;
+ reg->where = where;
+ if (reg->when == UNW_WHEN_NEVER)
+ reg->when = when;
+}
+
+static void
+alloc_spill_area (unsigned long *offp, unsigned long regsize,
+ struct unw_reg_info *lo, struct unw_reg_info *hi)
+{
+ struct unw_reg_info *reg;
+
+ for (reg = hi; reg >= lo; --reg)
+ {
+ if (reg->where == UNW_WHERE_SPILL_HOME)
+ {
+ reg->where = UNW_WHERE_PSPREL;
+ reg->val = 0x10 - *offp;
+ *offp += regsize;
+ }
+ }
+}
+
+static inline void
+spill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim,
+ unw_word t)
+{
+ struct unw_reg_info *reg;
+
+ for (reg = *regp; reg <= lim; ++reg)
+ {
+ if (reg->where == UNW_WHERE_SPILL_HOME)
+ {
+ reg->when = t;
+ *regp = reg + 1;
+ return;
+ }
+ }
+ /* Excess spill. */
+ abort ();
+}
+
+static void
+finish_prologue (struct unw_state_record *sr)
+{
+ struct unw_reg_info *reg;
+ unsigned long off;
+ int i;
+
+ /* First, resolve implicit register save locations
+ (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3). */
+
+ for (i = 0; i < (int) sizeof(save_order); ++i)
+ {
+ reg = sr->curr.reg + save_order[i];
+ if (reg->where == UNW_WHERE_GR_SAVE)
+ {
+ reg->where = UNW_WHERE_GR;
+ reg->val = sr->gr_save_loc++;
+ }
+ }
+
+ /* Next, compute when the fp, general, and branch registers get saved.
+ This must come before alloc_spill_area() because we need to know
+ which registers are spilled to their home locations. */
+ if (sr->imask)
+ {
+ static unsigned char const limit[3] = {
+ UNW_REG_F31, UNW_REG_R7, UNW_REG_B5
+ };
+
+ unsigned char kind, mask = 0, *cp = sr->imask;
+ int t;
+ struct unw_reg_info *(regs[3]);
+
+ regs[0] = sr->curr.reg + UNW_REG_F2;
+ regs[1] = sr->curr.reg + UNW_REG_R4;
+ regs[2] = sr->curr.reg + UNW_REG_B1;
+
+ for (t = 0; t < sr->region_len; ++t)
+ {
+ if ((t & 3) == 0)
+ mask = *cp++;
+ kind = (mask >> 2*(3-(t & 3))) & 3;
+ if (kind > 0)
+ spill_next_when(&regs[kind - 1], sr->curr.reg + limit[kind - 1],
+ sr->region_start + t);
+ }
+ }
+
+ /* Next, lay out the memory stack spill area. */
+ if (sr->any_spills)
+ {
+ off = sr->spill_offset;
+ alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2,
+ sr->curr.reg + UNW_REG_F31);
+ alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1,
+ sr->curr.reg + UNW_REG_B5);
+ alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4,
+ sr->curr.reg + UNW_REG_R7);
+ }
+}
+
+/*
+ * Region header descriptors.
+ */
+
+static void
+desc_prologue (int body, unw_word rlen, unsigned char mask,
+ unsigned char grsave, struct unw_state_record *sr)
+{
+ int i;
+
+ if (!(sr->in_body || sr->first_region))
+ finish_prologue(sr);
+ sr->first_region = 0;
+
+ /* Check if we're done. */
+ if (body && 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 __attribute__((unused)),
+ unsigned char context __attribute__((unused)),
+ struct unw_state_record *sr __attribute__((unused)))
+{
+ /* Anything to do? */
+}
+
+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)
+ {
+ 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_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_reg_state *rs;
+
+ for (rs = sr->reg_state_list; rs; rs = rs->next)
+ {
+ if (rs->label == label)
+ {
+ memcpy (&sr->curr, rs, sizeof(sr->curr));
+ return;
+ }
+ }
+ abort ();
+}
+
+static inline void
+desc_label_state (unw_word label, struct unw_state_record *sr)
+{
+ struct unw_reg_state *rs;
+
+ rs = malloc (sizeof (struct unw_reg_state));
+ memcpy (rs, &sr->curr, sizeof (*rs));
+ rs->label = label;
+ rs->next = sr->reg_state_list;
+ sr->reg_state_list = rs;
+}
+
+/*
+ * 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 unw_decoder unw_decode_table[2][8] =
+{
+ /* prologue table: */
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_p1, /* 4 */
+ unw_decode_p2_p5,
+ unw_decode_p6,
+ unw_decode_p7_p10
+ },
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_b1, /* 4 */
+ unw_decode_b1,
+ unw_decode_b2,
+ unw_decode_b3_x4
+ }
+};
+
+/*
+ * Decode one descriptor and return address of next descriptor.
+ */
+static inline unsigned char *
+unw_decode (unsigned char *dp, int inside_body, void *arg)
+{
+ unw_decoder decoder;
+ unsigned char code;
+
+ code = *dp++;
+ decoder = unw_decode_table[inside_body][code >> 5];
+ dp = (*decoder) (dp, code, arg);
+ return dp;
+}
+
+
+/* RSE helper functions. */
+
+static inline unsigned long
+ia64_rse_slot_num (unsigned long *addr)
+{
+ return (((unsigned long) addr) >> 3) & 0x3f;
+}
+
+/* Return TRUE if ADDR is the address of an RNAT slot. */
+static inline unsigned long
+ia64_rse_is_rnat_slot (unsigned long *addr)
+{
+ return ia64_rse_slot_num (addr) == 0x3f;
+}
+
+/* Returns the address of the RNAT slot that covers the slot at
+ address SLOT_ADDR. */
+static inline unsigned long *
+ia64_rse_rnat_addr (unsigned long *slot_addr)
+{
+ return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
+}
+
+/* Calcuate the number of registers in the dirty partition starting at
+ BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY
+ divided by eight because the 64th slot is used to store ar.rnat. */
+static inline unsigned long
+ia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp)
+{
+ unsigned long slots = (bsp - bspstore);
+
+ return slots - (ia64_rse_slot_num (bspstore) + slots)/0x40;
+}
+
+/* The inverse of the above: given bspstore and the number of
+ registers, calculate ar.bsp. */
+static inline unsigned long *
+ia64_rse_skip_regs (unsigned long *addr, long num_regs)
+{
+ long delta = ia64_rse_slot_num (addr) + num_regs;
+
+ if (num_regs < 0)
+ delta -= 0x3e;
+ return addr + num_regs + delta/0x3f;
+}
+
+
+/* Unwind accessors. */
+
+static void
+unw_access_gr (struct _Unwind_Context *info, int regnum,
+ unsigned long *val, char *nat, int write)
+{
+ unsigned long *addr, *nat_addr = 0, nat_mask = 0, dummy_nat;
+ struct unw_ireg *ireg;
+
+ if ((unsigned) regnum - 1 >= 127)
+ abort ();
+
+ if (regnum < 1)
+ {
+ nat_addr = addr = &dummy_nat;
+ dummy_nat = 0;
+ }
+ else if (regnum < 32)
+ {
+ /* Access a non-stacked register. */
+ ireg = &info->ireg[regnum - 1];
+ addr = ireg->loc;
+ if (addr)
+ {
+ nat_addr = addr + ireg->nat.off;
+ switch (ireg->nat.type)
+ {
+ case UNW_NAT_VAL:
+ /* Simulate getf.sig/setf.sig. */
+ if (write)
+ {
+ if (*nat)
+ {
+ /* Write NaTVal and be done with it. */
+ addr[0] = 0;
+ addr[1] = 0x1fffe;
+ return;
+ }
+ addr[1] = 0x1003e;
+ }
+ else if (addr[0] == 0 && addr[1] == 0x1ffe)
+ {
+ /* Return NaT and be done with it. */
+ *val = 0;
+ *nat = 1;
+ return;
+ }
+ /* FALLTHRU */
+
+ case UNW_NAT_NONE:
+ dummy_nat = 0;
+ nat_addr = &dummy_nat;
+ break;
+
+ case UNW_NAT_MEMSTK:
+ nat_mask = 1UL << ((long) addr & 0x1f8)/8;
+ break;
+
+ case UNW_NAT_REGSTK:
+ nat_addr = ia64_rse_rnat_addr (addr);
+ if ((unsigned long) nat_addr >= info->regstk_top)
+ nat_addr = &info->rnat;
+ nat_mask = 1UL << ia64_rse_slot_num (addr);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Access a stacked register. */
+ addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32);
+ nat_addr = ia64_rse_rnat_addr (addr);
+ if ((unsigned long) nat_addr >= info->regstk_top)
+ nat_addr = &info->rnat;
+ 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;
+}
+
+/* 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;
+}
+
+
+static _Unwind_Reason_Code
+uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ struct unw_table_entry *ent;
+ unsigned long *unw, header, length;
+ unsigned char *insn, *insn_end;
+ unsigned long segment_base;
+
+ memset (fs, 0, sizeof (*fs));
+ context->lsda = 0;
+
+ ent = _Unwind_FindTableEntry ((void *) context->rp,
+ &segment_base, &context->gp);
+ if (ent == NULL)
+ {
+ /* Couldn't find unwind info for this function. Try an
+ os-specific fallback mechanism. This will necessarily
+ not profide a personality routine or LSDA. */
+#ifdef MD_FALLBACK_FRAME_STATE_FOR
+ MD_FALLBACK_FRAME_STATE_FOR (context, fs, success);
+ return _URC_END_OF_STACK;
+ success:
+ return _URC_NO_REASON;
+#else
+ return _URC_END_OF_STACK;
+#endif
+ }
+
+ context->region_start = ent->start_offset + segment_base;
+ fs->when_target = (context->rp - context->region_start) / 16 * 3;
+
+ unw = (unsigned long *) (ent->info_offset + segment_base);
+ header = *unw;
+ length = UNW_LENGTH (header);
+
+ /* ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK. */
+
+ if (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);
+
+ /* 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;
+ }
+
+ /* If RP did'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;
+ }
+
+ return _URC_NO_REASON;
+}
+
+static void
+uw_update_reg_address (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs,
+ enum unw_register_index regno)
+{
+ struct unw_reg_info *r = fs->curr.reg + regno;
+ void *addr;
+ unsigned long rval;
+
+ if (r->where == UNW_WHERE_NONE || r->when >= fs->when_target)
+ return;
+
+ rval = r->val;
+ switch (r->where)
+ {
+ case UNW_WHERE_GR:
+ if (rval >= 32)
+ addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32);
+ else if (rval >= 2)
+ addr = context->ireg[rval - 2].loc;
+ else
+ abort ();
+ break;
+
+ case UNW_WHERE_FR:
+ if (rval >= 2 && rval < 32)
+ addr = context->fr_loc[rval - 2];
+ else
+ abort ();
+ break;
+
+ case UNW_WHERE_BR:
+ if (rval >= 1 && rval <= 5)
+ addr = context->br_loc[rval - 1];
+ else
+ abort ();
+ break;
+
+ case UNW_WHERE_SPREL:
+ addr = (void *)(context->sp + rval);
+ break;
+
+ case UNW_WHERE_PSPREL:
+ addr = (void *)(context->psp + rval);
+ break;
+
+ default:
+ abort ();
+ }
+
+ switch (regno)
+ {
+ case UNW_REG_R2 ... UNW_REG_R31:
+ context->ireg[regno - UNW_REG_R2].loc = addr;
+ switch (r->where)
+ {
+ case UNW_WHERE_GR:
+ if (rval >= 32)
+ {
+ context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK;
+ context->ireg[regno - UNW_REG_R2].nat.off
+ = context->pri_unat_loc - (unsigned long *) addr;
+ }
+ else if (rval >= 2)
+ {
+ context->ireg[regno - UNW_REG_R2].nat
+ = context->ireg[rval - 2].nat;
+ }
+ else
+ abort ();
+ break;
+
+ case UNW_WHERE_FR:
+ context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_VAL;
+ context->ireg[regno - UNW_REG_R2].nat.off = 0;
+ break;
+
+ case UNW_WHERE_BR:
+ context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE;
+ context->ireg[regno - UNW_REG_R2].nat.off = 0;
+ break;
+
+ case UNW_WHERE_PSPREL:
+ case UNW_WHERE_SPREL:
+ context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK;
+ context->ireg[regno - UNW_REG_R2].nat.off
+ = context->pri_unat_loc - (unsigned long *) addr;
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ case UNW_REG_F2 ... UNW_REG_F31:
+ context->fr_loc[regno - UNW_REG_F2] = addr;
+ break;
+
+ case UNW_REG_B1 ... UNW_REG_B5:
+ context->br_loc[regno - UNW_REG_B1] = addr;
+ break;
+
+ case UNW_REG_BSP:
+ context->bsp_loc = addr;
+ break;
+ case UNW_REG_BSPSTORE:
+ context->bspstore_loc = addr;
+ break;
+ case UNW_REG_PFS:
+ context->pfs_loc = addr;
+ break;
+ case UNW_REG_RP:
+ context->rp = *(unsigned long *)addr;
+ break;
+ case UNW_REG_UNAT:
+ context->unat_loc = addr;
+ break;
+ case UNW_REG_PR:
+ context->pr = *(unsigned long *) addr;
+ break;
+ case UNW_REG_LC:
+ context->lc_loc = addr;
+ break;
+ case UNW_REG_FPSR:
+ context->fpsr_loc = addr;
+ break;
+
+ case UNW_REG_PSP:
+ context->psp = *(unsigned long *)addr;
+ break;
+
+ case UNW_REG_RNAT:
+ case UNW_NUM_REGS:
+ abort ();
+ }
+}
+
+static void
+uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
+{
+ long i;
+
+ 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. */
+ if (fs->when_target > fs->curr.reg[UNW_REG_PFS].when)
+ {
+ unsigned long pfs = *context->pfs_loc;
+ unsigned long sol = (pfs >> 7) & 0x7f;
+ context->bsp = (unsigned long)
+ ia64_rse_skip_regs ((unsigned long *) context->bsp, -sol);
+ }
+}
+
+/* Fill in CONTEXT for top-of-stack. The only valid registers at this
+ level will be the return address and the CFA. */
+
+#define uw_init_context(CONTEXT) \
+ uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), __builtin_ia64_bsp ())
+
+static void
+uw_init_context_1 (struct _Unwind_Context *context, void *psp, void *bsp)
+{
+ void *rp = __builtin_extract_return_addr (__builtin_return_address (0));
+ void *sp = __builtin_dwarf_cfa ();
+ _Unwind_FrameState fs;
+
+ /* Flush the register stack to memory so that we can access it. */
+ __builtin_ia64_flushrs ();
+
+ memset (context, 0, sizeof (struct _Unwind_Context));
+ context->bsp = (unsigned long) bsp;
+ context->sp = (unsigned long) sp;
+ context->psp = (unsigned long) psp;
+ context->rp = (unsigned long) rp;
+
+ asm ("mov %0 = pr" : "=r" (context->pr));
+ /* ??? Get rnat. Don't we have to turn off the rse for that? */
+
+ if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
+ abort ();
+
+ /* Force the frame state to use the known cfa value. */
+ fs.curr.reg[UNW_REG_PSP].when = -1;
+ fs.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
+ fs.curr.reg[UNW_REG_PSP].val = sp - psp;
+
+ uw_update_context (context, &fs);
+}
+
+/* Install (ie longjmp to) the contents of TARGET. */
+
+static void __attribute__((noreturn))
+uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
+ struct _Unwind_Context *target)
+{
+ unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0;
+ long i;
+
+ /* Copy integer register data from the target context to a
+ temporary buffer. Do this so that we can frob AR.UNAT
+ to get the NaT bits for these registers set properly. */
+ for (i = 4; i <= 7; ++i)
+ {
+ char nat;
+ void *t = target->ireg[i - 2].loc;
+ if (t)
+ {
+ unw_access_gr (target, i, &ireg_buf[i - 4], &nat, 0);
+ ireg_nat |= (long)nat << (((size_t)&ireg_buf[i - 4] >> 3) & 0x3f);
+ /* Set p6 - p9. */
+ ireg_pr |= 4L << i;
+ }
+ }
+
+ /* The value in uc_bsp that we've computed is that for the
+ target function. The value that we install below will be
+ adjusted by the BR.RET instruction based on the contents
+ of AR.PFS. So we must unadjust that here. */
+ target->bsp
+ = ia64_rse_skip_regs (target->bsp, (*target->pfs_loc >> 7) & 0x7f);
+
+ /* 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 + 8, %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, %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 + 24)\n\t"
+ ";; \n\t"
+ "ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 32)\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 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.i ar.fpsr = r30 \n\t"
+ ";; \n\t"
+ "and r25 = 0x1c, r25 \n\t"
+ "mov b0 = r26 \n\t"
+ ";; \n\t"
+ "mov.m ar.rsc = r25 \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"
+ "or r25 = 0x3, r25 \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"
+#endif
diff --git a/gcc/config/ia64/frame-ia64.h b/gcc/config/ia64/unwind-ia64.h
index d638ca3..a6b850d 100644
--- a/gcc/config/ia64/frame-ia64.h
+++ b/gcc/config/ia64/unwind-ia64.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Andrew MacLeod <amacleod@cygnus.com>
Andrew Haley <aph@cygnus.com>
@@ -19,18 +19,13 @@
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* This structure represents a single unwind table entry. We lie and say
- its the dwarf_fde structure to use the common object in frame.h */
-
-typedef struct dwarf_fde
+struct unw_table_entry
{
- long start_offset;
- long end_offset;
- long unwind_offset;
-} unwind_table_entry;
-
-/* Defining dwarf_fde allows us to use the common object registration. */
-typedef unwind_table_entry dwarf_fde;
-typedef unwind_table_entry fde;
+ unsigned long start_offset;
+ unsigned long end_offset;
+ unsigned long info_offset;
+};
-extern fde *__ia64_find_fde (void *, void **);
+extern struct unw_table_entry *
+_Unwind_FindTableEntry (void *pc, unsigned long *segment_base,
+ unsigned long *gp);
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 4ed35f2..9ec2af1 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -318,5 +318,12 @@ do { \
#endif
#endif
+/* Select a format to encode pointers in exception handling data. We
+ prefer those that result in fewer dynamic relocations. Assume no
+ special support here and encode direct references. */
+#ifndef ASM_PREFERRED_EH_DATA_FORMAT
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_absptr
+#endif
+
#endif /* GCC_DEFAULTS_H */
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 9866735..104879e 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -22,9 +22,13 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "flags.h"
+#include "tree.h"
#include "rtl.h"
#include "output.h"
#include "dwarf2asm.h"
+#include "dwarf2.h"
+#include "splay-tree.h"
+#include "ggc.h"
#include "tm_p.h"
@@ -647,3 +651,175 @@ dw2_asm_output_delta_sleb128 VPARAMS ((const char *lab1 ATTRIBUTE_UNUSED,
va_end (ap);
}
+
+static rtx dw2_force_const_mem PARAMS ((rtx));
+static int dw2_output_indirect_constant_1 PARAMS ((splay_tree_node, void *));
+
+static splay_tree indirect_pool;
+
+static rtx
+dw2_force_const_mem (x)
+ rtx x;
+{
+ splay_tree_node node;
+ const char *const_sym;
+
+ if (! indirect_pool)
+ indirect_pool = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+ node = splay_tree_lookup (indirect_pool, (splay_tree_key) XSTR (x, 0));
+ if (node)
+ const_sym = (const char *) node->value;
+ else
+ {
+ extern int const_labelno;
+ char label[32];
+ tree id;
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno);
+ ++const_labelno;
+ const_sym = ggc_strdup (label);
+
+ id = maybe_get_identifier (XSTR (x, 0));
+ if (id)
+ TREE_SYMBOL_REFERENCED (id) = 1;
+
+ splay_tree_insert (indirect_pool, (splay_tree_key) XSTR (x, 0),
+ (splay_tree_value) const_sym);
+ }
+
+ return gen_rtx_SYMBOL_REF (Pmode, const_sym);
+}
+
+static int
+dw2_output_indirect_constant_1 (node, data)
+ splay_tree_node node;
+ void* data ATTRIBUTE_UNUSED;
+{
+ const char *label, *sym;
+ rtx sym_ref;
+
+ label = (const char *) node->value;
+ sym = (const char *) node->key;
+ sym_ref = gen_rtx_SYMBOL_REF (Pmode, sym);
+
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ assemble_integer (sym_ref, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ return 0;
+}
+
+void
+dw2_output_indirect_constants ()
+{
+ if (! indirect_pool)
+ return;
+
+ /* Assume that the whole reason we're emitting these symbol references
+ indirectly is that they contain dynamic relocations, and are thus
+ read-write. If there was no possibility of a dynamic relocation, we
+ might as well have used a direct relocation. */
+ data_section ();
+
+ /* Everything we're emitting is a pointer. Align appropriately. */
+ assemble_align (POINTER_SIZE);
+
+ splay_tree_foreach (indirect_pool, dw2_output_indirect_constant_1, NULL);
+}
+
+void
+dw2_asm_output_encoded_addr_rtx (encoding, addr)
+ int encoding;
+ rtx addr;
+{
+ int size;
+
+ switch (encoding & 0x07)
+ {
+ case DW_EH_PE_absptr:
+ size = POINTER_SIZE / BITS_PER_UNIT;
+ break;
+ case DW_EH_PE_udata2:
+ size = 2;
+ break;
+ case DW_EH_PE_udata4:
+ size = 4;
+ break;
+ case DW_EH_PE_udata8:
+ size = 8;
+ break;
+ default:
+ abort ();
+ }
+
+ /* NULL is _always_ represented as a plain zero. */
+ if (addr == const0_rtx)
+ {
+ assemble_integer (addr, size, 1);
+ return;
+ }
+
+ restart:
+
+ /* Allow the target first crack at emitting this. Some of the
+ special relocations require special directives instead of
+ just ".4byte" or whatever. */
+#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
+ ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(asm_out_file, encoding, size, addr, done);
+#endif
+
+ /* Indirection is used to get dynamic relocations out of a read-only
+ section. */
+ if (encoding & DW_EH_PE_indirect)
+ {
+ /* It is very tempting to use force_const_mem so that we share data
+ with the normal constant pool. However, we've already emitted
+ the constant pool for this function. Moreover, we'd like to share
+ these constants across the entire unit of translation, or better,
+ across the entire application (or DSO). */
+ addr = dw2_force_const_mem (addr);
+ encoding &= ~DW_EH_PE_indirect;
+ goto restart;
+ }
+
+ switch (encoding & 0xF0)
+ {
+ case DW_EH_PE_absptr:
+#ifdef UNALIGNED_INT_ASM_OP
+ fputs (unaligned_integer_asm_op (size), asm_out_file);
+ output_addr_const (asm_out_file, addr);
+#else
+ assemble_integer (addr, size, 1);
+#endif
+ break;
+
+ case DW_EH_PE_pcrel:
+ if (GET_CODE (addr) != SYMBOL_REF)
+ abort ();
+#ifdef ASM_OUTPUT_DWARF_PCREL
+ ASM_OUTPUT_DWARF_PCREL (asm_out_file, size, XSTR (addr, 0));
+#else
+#ifdef UNALIGNED_INT_ASM_OP
+ fputs (unaligned_integer_asm_op (size), asm_out_file);
+ assemble_name (asm_out_file, XSTR (addr, 0));
+ fputc ('-', asm_out_file);
+ fputc ('.', asm_out_file);
+#else
+ abort ();
+#endif
+#endif
+ break;
+
+ default:
+ /* Other encodings should have been handled by
+ ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX. */
+ abort ();
+ }
+
+#ifdef ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
+ done:
+#endif
+ fputc ('\n', asm_out_file);
+}
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
index 51b6755..4b663c9 100644
--- a/gcc/dwarf2asm.h
+++ b/gcc/dwarf2asm.h
@@ -48,6 +48,8 @@ extern void dw2_asm_output_addr_rtx PARAMS ((int, rtx,
const char *, ...))
/* ATTRIBUTE_PRINTF_3 */;
+extern void dw2_asm_output_encoded_addr_rtx PARAMS ((int, rtx));
+
extern void dw2_asm_output_nstring PARAMS ((const char *, size_t,
const char *, ...))
/* ATTRIBUTE_PRINTF_3 */;
@@ -70,3 +72,5 @@ extern void dw2_asm_output_delta_sleb128 PARAMS ((const char *, const char *,
extern int size_of_uleb128 PARAMS ((unsigned HOST_WIDE_INT));
extern int size_of_sleb128 PARAMS ((HOST_WIDE_INT));
+
+extern void dw2_output_indirect_constants PARAMS ((void));
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5952936..db83932 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1904,14 +1904,35 @@ dwarf2out_begin_prologue ()
char label[MAX_ARTIFICIAL_LABEL_BYTES];
register dw_fde_ref fde;
+ current_function_func_begin_label = 0;
+
+#ifdef IA64_UNWIND_INFO
+ /* ??? current_function_func_begin_label is also used by except.c
+ for call-site information. We must emit this label if it might
+ be used. */
+ if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
+ && ! dwarf2out_do_frame ())
+ return;
+#else
+ if (! dwarf2out_do_frame ())
+ return;
+#endif
+
++current_funcdef_number;
function_section (current_function_decl);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_funcdef_number);
- ASM_OUTPUT_LABEL (asm_out_file, label);
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
+ current_funcdef_number);
current_function_func_begin_label = get_identifier (label);
+#ifdef IA64_UNWIND_INFO
+ /* We can elide the fde allocation if we're not emitting debug info. */
+ if (! dwarf2out_do_frame ())
+ return;
+#endif
+
/* Expand the fde table if necessary. */
if (fde_table_in_use == fde_table_allocated)
{
diff --git a/gcc/except.c b/gcc/except.c
index ca68f65..66ea787 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -62,6 +62,7 @@ Boston, MA 02111-1307, USA. */
#include "output.h"
#include "dwarf2asm.h"
#include "dwarf2out.h"
+#include "dwarf2.h"
#include "toplev.h"
#include "hashtab.h"
#include "intl.h"
@@ -3366,24 +3367,6 @@ push_sleb128 (data_area, value)
}
-#define DW_EH_PE_absptr 0x00
-#define DW_EH_PE_omit 0xff
-
-#define DW_EH_PE_uleb128 0x01
-#define DW_EH_PE_udata2 0x02
-#define DW_EH_PE_udata4 0x03
-#define DW_EH_PE_udata8 0x04
-#define DW_EH_PE_sleb128 0x09
-#define DW_EH_PE_sdata2 0x0A
-#define DW_EH_PE_sdata4 0x0B
-#define DW_EH_PE_sdata8 0x0C
-#define DW_EH_PE_signed 0x08
-
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-
static const char *
eh_data_format_name (format)
int format;
@@ -3438,6 +3421,74 @@ eh_data_format_name (format)
case DW_EH_PE_sdata4 | DW_EH_PE_funcrel: return "funcrel sdata4";
case DW_EH_PE_sdata8 | DW_EH_PE_funcrel: return "funcrel sdata8";
+ case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_pcrel:
+ return "indirect pcrel uleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_pcrel:
+ return "indirect pcrel udata2";
+ case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_pcrel:
+ return "indirect pcrel udata4";
+ case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_pcrel:
+ return "indirect pcrel udata8";
+ case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_pcrel:
+ return "indirect pcrel sleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_pcrel:
+ return "indirect pcrel sdata2";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_pcrel:
+ return "indirect pcrel sdata4";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_pcrel:
+ return "indirect pcrel sdata8";
+
+ case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_textrel:
+ return "indirect textrel uleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_textrel:
+ return "indirect textrel udata2";
+ case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_textrel:
+ return "indirect textrel udata4";
+ case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_textrel:
+ return "indirect textrel udata8";
+ case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_textrel:
+ return "indirect textrel sleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_textrel:
+ return "indirect textrel sdata2";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_textrel:
+ return "indirect textrel sdata4";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_textrel:
+ return "indirect textrel sdata8";
+
+ case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_datarel:
+ return "indirect datarel uleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_datarel:
+ return "indirect datarel udata2";
+ case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_datarel:
+ return "indirect datarel udata4";
+ case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_datarel:
+ return "indirect datarel udata8";
+ case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_datarel:
+ return "indirect datarel sleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_datarel:
+ return "indirect datarel sdata2";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_datarel:
+ return "indirect datarel sdata4";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_datarel:
+ return "indirect datarel sdata8";
+
+ case DW_EH_PE_indirect | DW_EH_PE_uleb128 | DW_EH_PE_funcrel:
+ return "indirect funcrel uleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_udata2 | DW_EH_PE_funcrel:
+ return "indirect funcrel udata2";
+ case DW_EH_PE_indirect | DW_EH_PE_udata4 | DW_EH_PE_funcrel:
+ return "indirect funcrel udata4";
+ case DW_EH_PE_indirect | DW_EH_PE_udata8 | DW_EH_PE_funcrel:
+ return "indirect funcrel udata8";
+ case DW_EH_PE_indirect | DW_EH_PE_sleb128 | DW_EH_PE_funcrel:
+ return "indirect funcrel sleb128";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata2 | DW_EH_PE_funcrel:
+ return "indirect funcrel sdata2";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata4 | DW_EH_PE_funcrel:
+ return "indirect funcrel sdata4";
+ case DW_EH_PE_indirect | DW_EH_PE_sdata8 | DW_EH_PE_funcrel:
+ return "indirect funcrel sdata8";
+
default:
abort ();
}
@@ -3551,7 +3602,7 @@ sjlj_output_call_site_table ()
void
output_function_exception_table ()
{
- int format, i, n;
+ int tt_format, cs_format, lp_format, i, n;
#ifdef HAVE_AS_LEB128
char ttype_label[32];
char cs_after_size_label[32];
@@ -3570,7 +3621,15 @@ output_function_exception_table ()
? sjlj_funcdef_number
: current_funcdef_number);
+#ifdef IA64_UNWIND_INFO
+ fputs ("\t.personality\t", asm_out_file);
+ output_addr_const (asm_out_file, eh_personality_libfunc);
+ fputs ("\n\t.handlerdata\n", asm_out_file);
+ /* Note that varasm still thinks we're in the function's code section.
+ The ".endp" directive that will immediately follow will take us back. */
+#else
exception_section ();
+#endif
have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
|| VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
@@ -3588,26 +3647,24 @@ output_function_exception_table ()
be most useful in moving the landing pads completely out of
line to another section, but it could also be used to minimize
the size of uleb128 landing pad offsets. */
- format = DW_EH_PE_omit;
- dw2_asm_output_data (1, format, "@LPStart format (%s)",
- eh_data_format_name (format));
+ lp_format = DW_EH_PE_omit;
+ dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
+ eh_data_format_name (lp_format));
/* @LPStart pointer would go here. */
/* Indicate the format of the @TType entries. */
if (! have_tt_data)
- format = DW_EH_PE_omit;
+ tt_format = DW_EH_PE_omit;
else
{
- /* ??? Define a ASM_PREFERRED_DATA_FORMAT to say what
- sort of dynamic-relocation-free reference to emit. */
- format = 0;
+ tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
#ifdef HAVE_AS_LEB128
ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
#endif
}
- dw2_asm_output_data (1, format, "@TType format (%s)",
- eh_data_format_name (format));
+ dw2_asm_output_data (1, tt_format, "@TType format (%s)",
+ eh_data_format_name (tt_format));
#ifndef HAVE_AS_LEB128
if (USING_SJLJ_EXCEPTIONS)
@@ -3659,12 +3716,12 @@ output_function_exception_table ()
/* Indicate the format of the call-site offsets. */
#ifdef HAVE_AS_LEB128
- format = DW_EH_PE_uleb128;
+ cs_format = DW_EH_PE_uleb128;
#else
- format = DW_EH_PE_udata4;
+ cs_format = DW_EH_PE_udata4;
#endif
- dw2_asm_output_data (1, format, "call-site format (%s)",
- eh_data_format_name (format));
+ dw2_asm_output_data (1, cs_format, "call-site format (%s)",
+ eh_data_format_name (cs_format));
#ifdef HAVE_AS_LEB128
ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
@@ -3706,8 +3763,9 @@ output_function_exception_table ()
else
type = lookup_type_for_runtime (type);
- /* ??? Handle ASM_PREFERRED_DATA_FORMAT. */
- output_constant (type, GET_MODE_SIZE (ptr_mode));
+ dw2_asm_output_encoded_addr_rtx (tt_format,
+ expand_expr (type, NULL_RTX, VOIDmode,
+ EXPAND_INITIALIZER));
}
#ifdef HAVE_AS_LEB128
diff --git a/gcc/except.h b/gcc/except.h
index b2c3943..e0c8c2e 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -173,12 +173,12 @@ extern tree (*lang_eh_runtime_type) PARAMS ((tree));
mean that we can use call frame exceptions. Detect that the target
has appropriate support. */
-#if !defined (EH_RETURN_DATA_REGNO) \
- || !defined(EH_RETURN_STACKADJ_RTX) \
- || ! (defined(EH_RETURN_HANDLER_RTX) \
- || defined(HAVE_eh_return)) \
- || ! (defined(DWARF2_UNWIND_INFO) \
- || defined(IA64_UNWIND_INFO))
+#if ! (defined (EH_RETURN_DATA_REGNO) \
+ && (defined (IA64_UNWIND_INFO) \
+ || (defined (DWARF2_UNWIND_INFO) \
+ && defined (EH_RETURN_STACKADJ_RTX) \
+ && (defined (EH_RETURN_HANDLER_RTX) \
+ || defined (HAVE_eh_return)))))
#define MUST_USE_SJLJ_EXCEPTIONS 1
#else
#define MUST_USE_SJLJ_EXCEPTIONS 0
diff --git a/gcc/final.c b/gcc/final.c
index 57d34f5..64a4241 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -1583,12 +1583,9 @@ final_start_function (first, file, optimize)
last_linenum = high_block_linenum = high_function_linenum
= NOTE_LINE_NUMBER (first);
-#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
- /* Output DWARF definition of the function. */
- if (dwarf2out_do_frame ())
- dwarf2out_begin_prologue ();
- else
- current_function_func_begin_label = 0;
+#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) \
+ || defined (DWARF2_DEBUGGING_INFO)
+ dwarf2out_begin_prologue ();
#endif
/* For SDB and XCOFF, the function beginning must be marked between
@@ -1811,10 +1808,6 @@ final_end_function (first, file, optimize)
bb_func_label_num = -1; /* not in function, nuke label # */
-#ifdef IA64_UNWIND_INFO
- output_function_exception_table ();
-#endif
-
/* If FUNCTION_EPILOGUE is not defined, then the function body
itself contains return instructions wherever needed. */
}
diff --git a/gcc/libgcc-std.ver b/gcc/libgcc-std.ver
index 43e6fcf..3b7597a 100644
--- a/gcc/libgcc-std.ver
+++ b/gcc/libgcc-std.ver
@@ -116,6 +116,8 @@ GCC_3.0 {
_Unwind_GetIP
_Unwind_GetLanguageSpecificData
_Unwind_GetRegionStart
+ _Unwind_GetTextRelBase
+ _Unwind_GetDataRelBase
_Unwind_RaiseException
_Unwind_Resume
_Unwind_SetGR
diff --git a/gcc/tm.texi b/gcc/tm.texi
index bbc8cf2..1a1ad21 100644
--- a/gcc/tm.texi
+++ b/gcc/tm.texi
@@ -2553,6 +2553,33 @@ the @code{eh_return} instruction pattern should be used instead.
If you want to support call frame exception handling, you must
define either this macro or the @code{eh_return} instruction pattern.
+@findex ASM_PREFERRED_EH_DATA_FORMAT
+@item ASM_PREFERRED_EH_DATA_FORMAT(@var{CODE}, @var{GLOBAL})
+This macro chooses the encoding of pointers embedded in the exception
+handling sections. If at all possible, this should be defined such
+that the exception handling section will not require dynamic relocations,
+and so may be read-only.
+
+@var{CODE} is 0 for data, 1 for code labels, 2 for function pointers.
+@var{GLOBAL} is true if the symbol may be affected by dynamic relocations.
+The macro should return a combination of the @code{DW_EH_PE_*} defines
+as found in @file{dwarf2.h}.
+
+If this macro is not defined, pointers will not be encoded but
+represented directly.
+
+@findex ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX
+@item ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(@var{FILE}, @var{ENCODING}, @var{SIZE}, @var{ADDR}, @var{DONE})
+This macro allows the target to emit whatever special magic is required
+to represent the encoding chosen by @code{ASM_PREFERRED_EH_DATA_FORMAT}.
+Generic code takes care of pc-relative and indirect encodings; this must
+be defined if the target uses text-relative or data-relative encodings.
+
+This is a C statement that branches to @var{DONE} if the format was
+handled. @var{ENCODING} is the format chosen, @var{SIZE} is the number
+of bytes that the format occupies, @var{ADDR} is the @code{SYMBOL_REF}
+to be emitted.
+
@findex SMALL_STACK
@item SMALL_STACK
Define this macro if the stack size for the target is very small. This
diff --git a/gcc/toplev.c b/gcc/toplev.c
index bec26c1..b80e26b 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -2404,6 +2404,8 @@ compile_file (name)
/* Output some stuff at end of file if nec. */
+ dw2_output_indirect_constants ();
+
end_final (dump_base_name);
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
@@ -3721,9 +3723,19 @@ rest_of_compilation (decl)
final_start_function (insns, asm_out_file, optimize);
final (insns, asm_out_file, optimize, 0);
final_end_function (insns, asm_out_file, optimize);
+
+#ifdef IA64_UNWIND_INFO
+ /* ??? The IA-64 ".handlerdata" directive must be issued before
+ the ".endp" directive that closes the procedure descriptor. */
+ output_function_exception_table ();
+#endif
+
assemble_end_function (decl, fnname);
+#ifndef IA64_UNWIND_INFO
+ /* Otherwise, it feels unclean to switch sections in the middle. */
output_function_exception_table ();
+#endif
if (! quiet_flag)
fflush (asm_out_file);
diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c
index e2f20c9..6eb163d 100644
--- a/gcc/unwind-dw2.c
+++ b/gcc/unwind-dw2.c
@@ -314,6 +314,19 @@ _Unwind_GetRegionStart (struct _Unwind_Context *context)
return (_Unwind_Ptr) context->bases.func;
}
+#ifndef __ia64__
+_Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bases.dbase;
+}
+
+_Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *context)
+{
+ return (_Unwind_Ptr) context->bases.tbase;
+}
+#endif
/* Extract any interesting information from the CIE for the translation
unit F belongs to. Return a pointer to the byte after the augmentation,
diff --git a/gcc/unwind-pe.h b/gcc/unwind-pe.h
new file mode 100644
index 0000000..9eda448
--- /dev/null
+++ b/gcc/unwind-pe.h
@@ -0,0 +1,208 @@
+/* Exception handling and frame unwind runtime interface routines.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* @@@ Really this should be out of line, but this also causes link
+ compatibility problems with the base ABI. This is slightly better
+ than duplicating code, however. */
+
+/* Pointer encodings, from dwarf2.h. */
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_omit 0xff
+
+#define DW_EH_PE_uleb128 0x01
+#define DW_EH_PE_udata2 0x02
+#define DW_EH_PE_udata4 0x03
+#define DW_EH_PE_udata8 0x04
+#define DW_EH_PE_sleb128 0x09
+#define DW_EH_PE_sdata2 0x0A
+#define DW_EH_PE_sdata4 0x0B
+#define DW_EH_PE_sdata8 0x0C
+#define DW_EH_PE_signed 0x08
+
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+
+#define DW_EH_PE_indirect 0x80
+
+static unsigned int
+size_of_encoded_value (unsigned char encoding)
+{
+ if (encoding == DW_EH_PE_omit)
+ return 0;
+
+ switch (encoding & 0x07)
+ {
+ case DW_EH_PE_absptr:
+ return sizeof (void *);
+ case DW_EH_PE_udata2:
+ return 2;
+ case DW_EH_PE_udata4:
+ return 4;
+ case DW_EH_PE_udata8:
+ return 8;
+ }
+ abort ();
+}
+
+static _Unwind_Ptr
+base_of_encoded_value (unsigned char encoding, _Unwind_Context *context)
+{
+ if (encoding == DW_EH_PE_omit)
+ return 0;
+
+ switch (encoding & 0x70)
+ {
+ case DW_EH_PE_absptr:
+ case DW_EH_PE_pcrel:
+ return 0;
+
+ case DW_EH_PE_textrel:
+ return _Unwind_GetTextRelBase (context);
+ case DW_EH_PE_datarel:
+ return _Unwind_GetDataRelBase (context);
+ case DW_EH_PE_funcrel:
+ return _Unwind_GetRegionStart (context);
+ }
+ abort ();
+}
+
+static const unsigned char *
+read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
+ const unsigned char *p, _Unwind_Ptr *val)
+{
+ union unaligned
+ {
+ void *ptr;
+ unsigned u2 __attribute__ ((mode (HI)));
+ unsigned u4 __attribute__ ((mode (SI)));
+ unsigned u8 __attribute__ ((mode (DI)));
+ signed s2 __attribute__ ((mode (HI)));
+ signed s4 __attribute__ ((mode (SI)));
+ signed s8 __attribute__ ((mode (DI)));
+ } __attribute__((__packed__));
+
+ union unaligned *u = (union unaligned *) p;
+ _Unwind_Ptr result;
+
+ switch (encoding & 0x0f)
+ {
+ case DW_EH_PE_absptr:
+ result = (_Unwind_Ptr) u->ptr;
+ p += sizeof (void *);
+ break;
+
+ case DW_EH_PE_uleb128:
+ {
+ unsigned int shift = 0;
+ unsigned char byte;
+
+ result = 0;
+ do
+ {
+ byte = *p++;
+ result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
+ shift += 7;
+ }
+ while (byte & 0x80);
+ }
+ break;
+
+ case DW_EH_PE_sleb128:
+ {
+ unsigned int shift = 0;
+ unsigned char byte;
+
+ result = 0;
+ do
+ {
+ byte = *p++;
+ result |= (_Unwind_Ptr)(byte & 0x7f) << shift;
+ shift += 7;
+ }
+ while (byte & 0x80);
+
+ if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
+ result |= -(1L << shift);
+ }
+ break;
+
+ case DW_EH_PE_udata2:
+ result = u->u2;
+ p += 2;
+ break;
+ case DW_EH_PE_udata4:
+ result = u->u4;
+ p += 4;
+ break;
+ case DW_EH_PE_udata8:
+ result = u->u8;
+ p += 8;
+ break;
+
+ case DW_EH_PE_sdata2:
+ result = u->s2;
+ p += 2;
+ break;
+ case DW_EH_PE_sdata4:
+ result = u->s4;
+ p += 4;
+ break;
+ case DW_EH_PE_sdata8:
+ result = u->s8;
+ p += 8;
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (result != 0)
+ {
+ result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Ptr)u : base);
+ if (encoding & DW_EH_PE_indirect)
+ result = *(_Unwind_Ptr *)result;
+ }
+
+ *val = result;
+ return p;
+}
+
+static inline const unsigned char *
+read_encoded_value (_Unwind_Context *context, unsigned char encoding,
+ const unsigned char *p, _Unwind_Ptr *val)
+{
+ return read_encoded_value_with_base (encoding,
+ base_of_encoded_value (encoding, context),
+ p, val);
+}
+
+static inline const unsigned char *
+read_uleb128 (const unsigned char *p, _Unwind_Ptr *val)
+{
+ return read_encoded_value_with_base (DW_EH_PE_uleb128, 0, p, val);
+}
+
+static inline const unsigned char *
+read_sleb128 (const unsigned char *p, _Unwind_Ptr *val)
+{
+ return read_encoded_value_with_base (DW_EH_PE_sleb128, 0, p, val);
+}
diff --git a/gcc/unwind.h b/gcc/unwind.h
index 8df0930..ce43365 100644
--- a/gcc/unwind.h
+++ b/gcc/unwind.h
@@ -161,6 +161,31 @@ extern _Unwind_Reason_Code _Unwind_SjLj_ForcedUnwind
(struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
extern void _Unwind_SjLj_Resume (struct _Unwind_Exception *);
+/* @@@ The following provide access to the base addresses for text
+ and data-relative addressing in the LDSA. In order to stay link
+ compatible with the standard ABI for IA-64, we inline these. */
+
+#ifdef __ia64__
+#include <stdlib.h>
+
+static inline _Unwind_Ptr
+_Unwind_GetDataRelBase (struct _Unwind_Context *_C)
+{
+ /* The GP is stored in R1. */
+ return _Unwind_GetGR (_C, 1);
+}
+
+static inline _Unwind_Ptr
+_Unwind_GetTextRelBase (struct _Unwind_Context *_C)
+{
+ abort ();
+ return 0;
+}
+#else
+extern _Unwind_Ptr _Unwind_GetDataRelBase (struct _Unwind_Context *);
+extern _Unwind_Ptr _Unwind_GetTextRelBase (struct _Unwind_Context *);
+#endif
+
#ifdef __cplusplus
}
#endif