+++ /dev/null
-/* 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);
-}
-\f
-/* 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 (®ion_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);
-}
--- /dev/null
+/* 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
+\f
+#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
+};
+
+\f
+#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(®s[kind - 1], sr->curr.reg + limit[kind - 1],
+ sr->region_start + t);
+ }
+ }
+
+ /* Next, lay out the memory stack spill area. */
+ if (sr->any_spills)
+ {
+ off = sr->spill_offset;
+ alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2,
+ sr->curr.reg + UNW_REG_F31);
+ alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1,
+ sr->curr.reg + UNW_REG_B5);
+ alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4,
+ sr->curr.reg + UNW_REG_R7);
+ }
+}
+
+/*
+ * Region header descriptors.
+ */
+
+static void
+desc_prologue (int body, unw_word rlen, unsigned char mask,
+ unsigned char grsave, struct unw_state_record *sr)
+{
+ int i;
+
+ if (!(sr->in_body || sr->first_region))
+ finish_prologue(sr);
+ sr->first_region = 0;
+
+ /* Check if we're done. */
+ if (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;
+}
+
+\f
+#define UNW_DEC_BAD_CODE(code) abort ();
+
+/* Region headers. */
+#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg)
+#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg)
+
+/* Prologue descriptors. */
+#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg)
+#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg)
+#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg)
+#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg)
+#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg)
+#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg)
+#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg)
+#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg)
+#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg)
+#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg)
+#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg)
+#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg)
+#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg)
+#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg)
+#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg)
+#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg)
+#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg)
+#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg)
+#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg)
+#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg)
+#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg))
+
+/* Body descriptors. */
+#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg)
+#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg)
+#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg)
+
+/* General unwind descriptors. */
+#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg)
+#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg)
+#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg)
+#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg)
+#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg)
+#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg)
+#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg)
+#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
+
+\f
+/*
+ * Generic IA-64 unwind info decoder.
+ *
+ * This file is used both by the Linux kernel and objdump. Please keep
+ * the copies of this file in sync.
+ *
+ * You need to customize the decoder by defining the following
+ * macros/constants before including this file:
+ *
+ * Types:
+ * unw_word Unsigned integer type with at least 64 bits
+ *
+ * Register names:
+ * UNW_REG_BSP
+ * UNW_REG_BSPSTORE
+ * UNW_REG_FPSR
+ * UNW_REG_LC
+ * UNW_REG_PFS
+ * UNW_REG_PR
+ * UNW_REG_RNAT
+ * UNW_REG_PSP
+ * UNW_REG_RP
+ * UNW_REG_UNAT
+ *
+ * Decoder action macros:
+ * UNW_DEC_BAD_CODE(code)
+ * UNW_DEC_ABI(fmt,abi,context,arg)
+ * UNW_DEC_BR_GR(fmt,brmask,gr,arg)
+ * UNW_DEC_BR_MEM(fmt,brmask,arg)
+ * UNW_DEC_COPY_STATE(fmt,label,arg)
+ * UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
+ * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
+ * UNW_DEC_FR_MEM(fmt,frmask,arg)
+ * UNW_DEC_GR_GR(fmt,grmask,gr,arg)
+ * UNW_DEC_GR_MEM(fmt,grmask,arg)
+ * UNW_DEC_LABEL_STATE(fmt,label,arg)
+ * UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
+ * UNW_DEC_MEM_STACK_V(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_GR(fmt,r,arg)
+ * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
+ * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
+ * UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
+ * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
+ * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
+ * UNW_DEC_REG_REG(fmt,src,dst,arg)
+ * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
+ * UNW_DEC_REG_WHEN(fmt,reg,t,arg)
+ * UNW_DEC_RESTORE(fmt,t,abreg,arg)
+ * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
+ * UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
+ * UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
+ * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
+ * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ */
+
+static unw_word
+unw_decode_uleb128 (unsigned char **dpp)
+{
+ unsigned shift = 0;
+ unw_word byte, result = 0;
+ unsigned char *bp = *dpp;
+
+ while (1)
+ {
+ byte = *bp++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ *dpp = bp;
+ return result;
+}
+
+static unsigned char *
+unw_decode_x1 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, abreg;
+ unw_word t, off;
+
+ byte1 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x2 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++; byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ ytreg = byte2;
+ x = (byte1 >> 7) & 1;
+ if ((byte1 & 0x80) == 0 && ytreg == 0)
+ UNW_DEC_RESTORE(X2, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x3 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, abreg, qp;
+ unw_word t, off;
+
+ byte1 = *dp++; byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_x4 (unsigned char *dp,
+ unsigned char code __attribute__((unused)),
+ void *arg)
+{
+ unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+ x = (byte2 >> 7) & 1;
+ ytreg = byte3;
+
+ if ((byte2 & 0x80) == 0 && byte3 == 0)
+ UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ int body = (code & 0x20) != 0;
+ unw_word rlen;
+
+ rlen = (code & 0x1f);
+ UNW_DEC_PROLOGUE(R1, body, rlen, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char byte1, mask, grsave;
+ unw_word rlen;
+
+ byte1 = *dp++;
+
+ mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ grsave = (byte1 & 0x7f);
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word rlen;
+
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char brmask = (code & 0x1f);
+
+ UNW_DEC_BR_MEM(P1, brmask, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
+{
+ if ((code & 0x10) == 0)
+ {
+ unsigned char byte1 = *dp++;
+
+ UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
+ (byte1 & 0x7f), arg);
+ }
+ else if ((code & 0x08) == 0)
+ {
+ unsigned char byte1 = *dp++, r, dst;
+
+ r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ dst = (byte1 & 0x7f);
+ switch (r)
+ {
+ case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break;
+ case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break;
+ case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break;
+ case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break;
+ case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break;
+ case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break;
+ case 6: UNW_DEC_RP_BR(P3, dst, arg); break;
+ case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break;
+ case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break;
+ case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break;
+ case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break;
+ case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ else if ((code & 0x7) == 0)
+ UNW_DEC_SPILL_MASK(P4, dp, arg);
+ else if ((code & 0x7) == 1)
+ {
+ unw_word grmask, frmask, byte1, byte2, byte3;
+
+ byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
+ grmask = ((byte1 >> 4) & 0xf);
+ frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
+ UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg);
+ }
+ else
+ UNW_DEC_BAD_CODE(code);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
+{
+ int gregs = (code & 0x10) != 0;
+ unsigned char mask = (code & 0x0f);
+
+ if (gregs)
+ UNW_DEC_GR_MEM(P6, mask, arg);
+ else
+ UNW_DEC_FR_MEM(P6, mask, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unsigned char r, byte1, byte2;
+ unw_word t, size;
+
+ if ((code & 0x10) == 0)
+ {
+ r = (code & 0xf);
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 0:
+ size = unw_decode_uleb128 (&dp);
+ UNW_DEC_MEM_STACK_F(P7, t, size, arg);
+ break;
+
+ case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break;
+ case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break;
+ case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break;
+ case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break;
+ case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break;
+ case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break;
+ case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break;
+ case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break;
+ case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break;
+ case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break;
+ case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break;
+ case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break;
+ case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break;
+ case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break;
+ case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ else
+ {
+ switch (code & 0xf)
+ {
+ case 0x0: /* p8 */
+ {
+ r = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break;
+ case 2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break;
+ case 3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break;
+ case 4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break;
+ case 5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break;
+ case 6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break;
+ case 7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break;
+ case 8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break;
+ case 9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break;
+ case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
+ case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break;
+ case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break;
+ case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break;
+ case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break;
+ case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break;
+ case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break;
+ case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break;
+ default: UNW_DEC_BAD_CODE(r); break;
+ }
+ }
+ break;
+
+ case 0x1:
+ byte1 = *dp++; byte2 = *dp++;
+ UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
+ break;
+
+ case 0xf: /* p10 */
+ byte1 = *dp++; byte2 = *dp++;
+ UNW_DEC_ABI(P10, byte1, byte2, arg);
+ break;
+
+ case 0x9:
+ return unw_decode_x1 (dp, code, arg);
+
+ case 0xa:
+ return unw_decode_x2 (dp, code, arg);
+
+ case 0xb:
+ return unw_decode_x3 (dp, code, arg);
+
+ case 0xc:
+ return unw_decode_x4 (dp, code, arg);
+
+ default:
+ UNW_DEC_BAD_CODE(code);
+ break;
+ }
+ }
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word label = (code & 0x1f);
+
+ if ((code & 0x20) != 0)
+ UNW_DEC_COPY_STATE(B1, label, arg);
+ else
+ UNW_DEC_LABEL_STATE(B1, label, arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word t;
+
+ t = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg);
+ return dp;
+}
+
+static unsigned char *
+unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
+{
+ unw_word t, ecount, label;
+
+ if ((code & 0x10) == 0)
+ {
+ t = unw_decode_uleb128 (&dp);
+ ecount = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE(B3, t, ecount, arg);
+ }
+ else if ((code & 0x07) == 0)
+ {
+ label = unw_decode_uleb128 (&dp);
+ if ((code & 0x08) != 0)
+ UNW_DEC_COPY_STATE(B4, label, arg);
+ else
+ UNW_DEC_LABEL_STATE(B4, label, arg);
+ }
+ else
+ switch (code & 0x7)
+ {
+ case 1: return unw_decode_x1 (dp, code, arg);
+ case 2: return unw_decode_x2 (dp, code, arg);
+ case 3: return unw_decode_x3 (dp, code, arg);
+ case 4: return unw_decode_x4 (dp, code, arg);
+ default: UNW_DEC_BAD_CODE(code); break;
+ }
+ return dp;
+}
+
+typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
+
+static unw_decoder unw_decode_table[2][8] =
+{
+ /* prologue table: */
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_p1, /* 4 */
+ unw_decode_p2_p5,
+ unw_decode_p6,
+ unw_decode_p7_p10
+ },
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_b1, /* 4 */
+ unw_decode_b1,
+ unw_decode_b2,
+ unw_decode_b3_x4
+ }
+};
+
+/*
+ * Decode one descriptor and return address of next descriptor.
+ */
+static inline unsigned char *
+unw_decode (unsigned char *dp, int inside_body, void *arg)
+{
+ unw_decoder decoder;
+ unsigned char code;
+
+ code = *dp++;
+ decoder = unw_decode_table[inside_body][code >> 5];
+ dp = (*decoder) (dp, code, arg);
+ return dp;
+}
+
+\f
+/* RSE helper functions. */
+
+static inline unsigned long
+ia64_rse_slot_num (unsigned long *addr)
+{
+ return (((unsigned long) addr) >> 3) & 0x3f;
+}
+
+/* Return TRUE if ADDR is the address of an RNAT slot. */
+static inline unsigned long
+ia64_rse_is_rnat_slot (unsigned long *addr)
+{
+ return ia64_rse_slot_num (addr) == 0x3f;
+}
+
+/* Returns the address of the RNAT slot that covers the slot at
+ address SLOT_ADDR. */
+static inline unsigned long *
+ia64_rse_rnat_addr (unsigned long *slot_addr)
+{
+ return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
+}
+
+/* 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;
+}
+
+\f
+/* 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;
+ }
+}
+\f
+/* Get the value of register REG as saved in CONTEXT. */
+
+_Unwind_Word
+_Unwind_GetGR (struct _Unwind_Context *context, int index)
+{
+ _Unwind_Word ret;
+ char nat;
+
+ if (index == 1)
+ return context->gp;
+ else if (index >= 15 && index <= 18)
+ return context->eh_data[index - 15];
+ else
+ unw_access_gr (context, index, &ret, &nat, 0);
+
+ return ret;
+}
+
+/* Overwrite the saved value for register REG in CONTEXT with VAL. */
+
+void
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+{
+ char nat = 0;
+
+ if (index == 1)
+ context->gp = val;
+ else if (index >= 15 && index <= 18)
+ context->eh_data[index - 15] = val;
+ else
+ unw_access_gr (context, index, &val, &nat, 1);
+}
+
+/* Retrieve the return address for CONTEXT. */
+
+inline _Unwind_Ptr
+_Unwind_GetIP (struct _Unwind_Context *context)
+{
+ return context->rp;
+}
+
+/* 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;
+}
+
+\f
+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