summaryrefslogtreecommitdiff
path: root/gcc/config/ia64/frame-ia64.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/ia64/frame-ia64.c')
-rw-r--r--gcc/config/ia64/frame-ia64.c1272
1 files changed, 0 insertions, 1272 deletions
diff --git a/gcc/config/ia64/frame-ia64.c b/gcc/config/ia64/frame-ia64.c
deleted file mode 100644
index 4834a8b3cdf..00000000000
--- 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);
-}