190075Sobrien/* Subroutines needed for unwinding IA-64 standard format stack frame
290075Sobrien   info for exception handling.
3169689Skan   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006
490075Sobrien   Free Software Foundation, Inc.
590075Sobrien   Contributed by Andrew MacLeod  <amacleod@cygnus.com>
690075Sobrien	          Andrew Haley  <aph@cygnus.com>
790075Sobrien		  David Mosberger-Tang <davidm@hpl.hp.com>
890075Sobrien
9132718Skan   This file is part of GCC.
1090075Sobrien
11132718Skan   GCC is free software; you can redistribute it and/or modify
1290075Sobrien   it under the terms of the GNU General Public License as published by
1390075Sobrien   the Free Software Foundation; either version 2, or (at your option)
1490075Sobrien   any later version.
1590075Sobrien
16132718Skan   GCC is distributed in the hope that it will be useful,
1790075Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1890075Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1990075Sobrien   GNU General Public License for more details.
2090075Sobrien
2190075Sobrien   You should have received a copy of the GNU General Public License
22132718Skan   along with GCC; see the file COPYING.  If not, write to
23169689Skan   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
24169689Skan   Boston, MA 02110-1301, USA.  */
2590075Sobrien
2690075Sobrien/* As a special exception, if you link this library with other files,
2790075Sobrien   some of which are compiled with GCC, to produce an executable,
2890075Sobrien   this library does not by itself cause the resulting executable
2990075Sobrien   to be covered by the GNU General Public License.
3090075Sobrien   This exception does not however invalidate any other reasons why
3190075Sobrien   the executable file might be covered by the GNU General Public License.  */
3290075Sobrien
3390075Sobrien
3490075Sobrien#include "tconfig.h"
3590075Sobrien#include "tsystem.h"
36132718Skan#include "coretypes.h"
37132718Skan#include "tm.h"
3890075Sobrien#include "unwind.h"
3990075Sobrien#include "unwind-ia64.h"
40146895Skan#include "unwind-compat.h"
4196263Sobrien#include "ia64intrin.h"
4290075Sobrien
4396263Sobrien/* This isn't thread safe, but nice for occasional tests.  */
4496263Sobrien#undef ENABLE_MALLOC_CHECKING
4596263Sobrien
4690075Sobrien#ifndef __USING_SJLJ_EXCEPTIONS__
47169689Skan
4890075Sobrien#define UNW_VER(x)		((x) >> 48)
4990075Sobrien#define UNW_FLAG_MASK		0x0000ffff00000000
5090075Sobrien#define UNW_FLAG_OSMASK		0x0000f00000000000
5190075Sobrien#define UNW_FLAG_EHANDLER(x)	((x) & 0x0000000100000000L)
5290075Sobrien#define UNW_FLAG_UHANDLER(x)	((x) & 0x0000000200000000L)
5390075Sobrien#define UNW_LENGTH(x)		((x) & 0x00000000ffffffffL)
5490075Sobrien
5590075Sobrienenum unw_application_register
5690075Sobrien{
5790075Sobrien  UNW_AR_BSP,
5890075Sobrien  UNW_AR_BSPSTORE,
5990075Sobrien  UNW_AR_PFS,
6090075Sobrien  UNW_AR_RNAT,
6190075Sobrien  UNW_AR_UNAT,
6290075Sobrien  UNW_AR_LC,
6390075Sobrien  UNW_AR_EC,
6490075Sobrien  UNW_AR_FPSR,
6590075Sobrien  UNW_AR_RSC,
6690075Sobrien  UNW_AR_CCV
6790075Sobrien};
6890075Sobrien
6990075Sobrienenum unw_register_index
7090075Sobrien{
7190075Sobrien  /* Primary UNAT.  */
7290075Sobrien  UNW_REG_PRI_UNAT_GR,
7390075Sobrien  UNW_REG_PRI_UNAT_MEM,
7490075Sobrien
7590075Sobrien  /* Memory Stack.  */
7690075Sobrien  UNW_REG_PSP,			/* previous memory stack pointer */
7790075Sobrien
7890075Sobrien  /* Register Stack.  */
7990075Sobrien  UNW_REG_BSP,			/* register stack pointer */
8090075Sobrien  UNW_REG_BSPSTORE,
8190075Sobrien  UNW_REG_PFS,			/* previous function state */
8290075Sobrien  UNW_REG_RNAT,
8390075Sobrien  /* Return Pointer.  */
8490075Sobrien  UNW_REG_RP,
8590075Sobrien
8690075Sobrien  /* Special preserved registers.  */
8790075Sobrien  UNW_REG_UNAT, UNW_REG_PR, UNW_REG_LC, UNW_REG_FPSR,
8890075Sobrien
8990075Sobrien  /* Non-stacked general registers.  */
9090075Sobrien  UNW_REG_R2,
9190075Sobrien  UNW_REG_R4 = UNW_REG_R2 + 2,
9290075Sobrien  UNW_REG_R7 = UNW_REG_R2 + 5,
9390075Sobrien  UNW_REG_R31 = UNW_REG_R2 + 29,
9490075Sobrien
9590075Sobrien  /* Non-stacked floating point registers.  */
9690075Sobrien  UNW_REG_F2,
9790075Sobrien  UNW_REG_F5 = UNW_REG_F2 + 3,
9890075Sobrien  UNW_REG_F16 = UNW_REG_F2 + 14,
9990075Sobrien  UNW_REG_F31 = UNW_REG_F2 + 29,
10090075Sobrien
10190075Sobrien  /* Branch registers.  */
10290075Sobrien  UNW_REG_B0, UNW_REG_B1,
10390075Sobrien  UNW_REG_B5 = UNW_REG_B1 + 4,
10490075Sobrien
10590075Sobrien  UNW_NUM_REGS
10690075Sobrien};
10790075Sobrien
10890075Sobrienenum unw_where
10990075Sobrien{
11090075Sobrien  UNW_WHERE_NONE,	/* register isn't saved at all */
11190075Sobrien  UNW_WHERE_GR,		/* register is saved in a general register */
11290075Sobrien  UNW_WHERE_FR,		/* register is saved in a floating-point register */
11390075Sobrien  UNW_WHERE_BR,		/* register is saved in a branch register */
11490075Sobrien  UNW_WHERE_SPREL,	/* register is saved on memstack (sp-relative) */
11590075Sobrien  UNW_WHERE_PSPREL,	/* register is saved on memstack (psp-relative) */
11690075Sobrien
11790075Sobrien /* At the end of each prologue these locations get resolved to
11890075Sobrien     UNW_WHERE_PSPREL and UNW_WHERE_GR, respectively.  */
11990075Sobrien  UNW_WHERE_SPILL_HOME,	/* register is saved in its spill home */
12090075Sobrien  UNW_WHERE_GR_SAVE	/* register is saved in next general register */
12190075Sobrien};
12290075Sobrien
12390075Sobrien#define UNW_WHEN_NEVER  0x7fffffff
12490075Sobrien
12590075Sobrienstruct unw_reg_info
12690075Sobrien{
12790075Sobrien  unsigned long val;		/* save location: register number or offset */
12890075Sobrien  enum unw_where where;		/* where the register gets saved */
12990075Sobrien  int when;			/* when the register gets saved */
13090075Sobrien};
13190075Sobrien
13296263Sobrienstruct unw_reg_state {
13396263Sobrien	struct unw_reg_state *next;	/* next (outer) element on state stack */
13496263Sobrien	struct unw_reg_info reg[UNW_NUM_REGS];	/* register save locations */
13596263Sobrien};
13696263Sobrien
13796263Sobrienstruct unw_labeled_state {
13896263Sobrien	struct unw_labeled_state *next;		/* next labeled state (or NULL) */
13996263Sobrien	unsigned long label;			/* label for this state */
14096263Sobrien	struct unw_reg_state saved_state;
14196263Sobrien};
14296263Sobrien
14390075Sobrientypedef struct unw_state_record
14490075Sobrien{
14590075Sobrien  unsigned int first_region : 1;	/* is this the first region? */
14690075Sobrien  unsigned int done : 1;		/* are we done scanning descriptors? */
14790075Sobrien  unsigned int any_spills : 1;		/* got any register spills? */
14890075Sobrien  unsigned int in_body : 1;	/* are we inside a body? */
14996263Sobrien  unsigned int no_reg_stack_frame : 1;	/* Don't adjust bsp for i&l regs */
150117395Skan  unsigned char *imask;		/* imask of spill_mask record or NULL */
15190075Sobrien  unsigned long pr_val;		/* predicate values */
15290075Sobrien  unsigned long pr_mask;	/* predicate mask */
15390075Sobrien  long spill_offset;		/* psp-relative offset for spill base */
15490075Sobrien  int region_start;
15590075Sobrien  int region_len;
15690075Sobrien  int epilogue_start;
15790075Sobrien  int epilogue_count;
15890075Sobrien  int when_target;
15990075Sobrien
16090075Sobrien  unsigned char gr_save_loc;	/* next general register to use for saving */
16190075Sobrien  unsigned char return_link_reg; /* branch register for return link */
162132718Skan  unsigned short unwabi;
16390075Sobrien
16496263Sobrien  struct unw_labeled_state *labeled_states;	/* list of all labeled states */
16596263Sobrien  struct unw_reg_state curr;	/* current state */
16690075Sobrien
16790075Sobrien  _Unwind_Personality_Fn personality;
16890075Sobrien
16990075Sobrien} _Unwind_FrameState;
17090075Sobrien
17190075Sobrienenum unw_nat_type
17290075Sobrien{
17390075Sobrien  UNW_NAT_NONE,			/* NaT not represented */
17490075Sobrien  UNW_NAT_VAL,			/* NaT represented by NaT value (fp reg) */
17590075Sobrien  UNW_NAT_MEMSTK,		/* NaT value is in unat word at offset OFF  */
17690075Sobrien  UNW_NAT_REGSTK		/* NaT is in rnat */
17790075Sobrien};
17890075Sobrien
17990075Sobrienstruct unw_stack
18090075Sobrien{
18190075Sobrien  unsigned long limit;
18290075Sobrien  unsigned long top;
18390075Sobrien};
18490075Sobrien
18590075Sobrienstruct _Unwind_Context
18690075Sobrien{
18790075Sobrien  /* Initial frame info.  */
18890075Sobrien  unsigned long rnat;		/* rse nat collection */
189132718Skan  unsigned long regstk_top;	/* lowest address of rbs stored register
190132718Skan				   which uses context->rnat collection */
19190075Sobrien
19290075Sobrien  /* Current frame info.  */
19390075Sobrien  unsigned long bsp;		/* backing store pointer value
19490075Sobrien				   corresponding to psp.  */
19590075Sobrien  unsigned long sp;		/* stack pointer value */
19690075Sobrien  unsigned long psp;		/* previous sp value */
19790075Sobrien  unsigned long rp;		/* return pointer */
19890075Sobrien  unsigned long pr;		/* predicate collection */
19990075Sobrien
20090075Sobrien  unsigned long region_start;	/* start of unwind region */
20190075Sobrien  unsigned long gp;		/* global pointer value */
20290075Sobrien  void *lsda;			/* language specific data area */
20390075Sobrien
20490075Sobrien  /* Preserved state.  */
20596263Sobrien  unsigned long *bsp_loc;	/* previous bsp save location
20696263Sobrien  				   Appears to be write-only?	*/
20790075Sobrien  unsigned long *bspstore_loc;
20896263Sobrien  unsigned long *pfs_loc;	/* Save location for pfs in current
20996263Sobrien  				   (corr. to sp) frame.  Target
21096263Sobrien  				   contains cfm for caller.	*/
21190075Sobrien  unsigned long *pri_unat_loc;
21290075Sobrien  unsigned long *unat_loc;
21390075Sobrien  unsigned long *lc_loc;
21490075Sobrien  unsigned long *fpsr_loc;
21590075Sobrien
21690075Sobrien  unsigned long eh_data[4];
21790075Sobrien
21890075Sobrien  struct unw_ireg
21990075Sobrien  {
22090075Sobrien    unsigned long *loc;
22190075Sobrien    struct unw_ireg_nat
22290075Sobrien    {
22390075Sobrien      enum unw_nat_type type : 3;
22490075Sobrien      signed long off : 61;		/* NaT word is at loc+nat.off */
22590075Sobrien    } nat;
22690075Sobrien  } ireg[32 - 2];	/* Indexed by <register number> - 2 */
22790075Sobrien
228132718Skan  unsigned long *br_loc[8];
22990075Sobrien  void *fr_loc[32 - 2];
23090075Sobrien
23190075Sobrien  /* ??? We initially point pri_unat_loc here.  The entire NAT bit
23290075Sobrien     logic needs work.  */
23390075Sobrien  unsigned long initial_unat;
23490075Sobrien};
23590075Sobrien
23690075Sobrientypedef unsigned long unw_word;
23790075Sobrien
23890075Sobrien/* Implicit register save order.  See section 11.4.2.3 Rules for Using
23990075Sobrien   Unwind Descriptors, rule 3.  */
24090075Sobrien
24190075Sobrienstatic unsigned char const save_order[] =
24290075Sobrien{
24390075Sobrien  UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,
24490075Sobrien  UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR
24590075Sobrien};
24690075Sobrien
24790075Sobrien
24890075Sobrien#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
24990075Sobrien
25096263Sobrien/* MASK is a bitmap describing the allocation state of emergency buffers,
25196263Sobrien   with bit set indicating free. Return >= 0 if allocation is successful;
25296263Sobrien   < 0 if failure.  */
25390075Sobrien
25496263Sobrienstatic inline int
25596263Sobrienatomic_alloc (unsigned int *mask)
25690075Sobrien{
25796263Sobrien  unsigned int old = *mask, ret, new;
25896263Sobrien
25996263Sobrien  while (1)
26096263Sobrien    {
26196263Sobrien      if (old == 0)
26296263Sobrien	return -1;
26396263Sobrien      ret = old & -old;
26496263Sobrien      new = old & ~ret;
26596263Sobrien      new = __sync_val_compare_and_swap (mask, old, new);
26696263Sobrien      if (old == new)
26796263Sobrien	break;
26896263Sobrien      old = new;
26996263Sobrien    }
27096263Sobrien
27196263Sobrien  return __builtin_ffs (ret) - 1;
27296263Sobrien}
27396263Sobrien
27496263Sobrien/* Similarly, free an emergency buffer.  */
27596263Sobrien
27696263Sobrienstatic inline void
27796263Sobrienatomic_free (unsigned int *mask, int bit)
27896263Sobrien{
27996263Sobrien  __sync_xor_and_fetch (mask, 1 << bit);
28096263Sobrien}
28196263Sobrien
28296263Sobrien
28396263Sobrien#define SIZE(X)		(sizeof(X) / sizeof(*(X)))
28496263Sobrien#define MASK_FOR(X)	((2U << (SIZE (X) - 1)) - 1)
28596263Sobrien#define PTR_IN(X, P)	((P) >= (X) && (P) < (X) + SIZE (X))
28696263Sobrien
28796263Sobrienstatic struct unw_reg_state emergency_reg_state[32];
288169689Skanstatic unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
28996263Sobrien
29096263Sobrienstatic struct unw_labeled_state emergency_labeled_state[8];
291169689Skanstatic unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
29296263Sobrien
29396263Sobrien#ifdef ENABLE_MALLOC_CHECKING
29496263Sobrienstatic int reg_state_alloced;
29596263Sobrienstatic int labeled_state_alloced;
29696263Sobrien#endif
29796263Sobrien
29896263Sobrien/* Allocation and deallocation of structures.  */
29996263Sobrien
30096263Sobrienstatic struct unw_reg_state *
30196263Sobrienalloc_reg_state (void)
30296263Sobrien{
30390075Sobrien  struct unw_reg_state *rs;
30490075Sobrien
30596263Sobrien#ifdef ENABLE_MALLOC_CHECKING
30696263Sobrien  reg_state_alloced++;
30796263Sobrien#endif
30896263Sobrien
30990075Sobrien  rs = malloc (sizeof (struct unw_reg_state));
31096263Sobrien  if (!rs)
31196263Sobrien    {
31296263Sobrien      int n = atomic_alloc (&emergency_reg_state_free);
31396263Sobrien      if (n >= 0)
31496263Sobrien	rs = &emergency_reg_state[n];
31596263Sobrien    }
31696263Sobrien
31796263Sobrien  return rs;
31896263Sobrien}
31996263Sobrien
32096263Sobrienstatic void
32196263Sobrienfree_reg_state (struct unw_reg_state *rs)
32296263Sobrien{
32396263Sobrien#ifdef ENABLE_MALLOC_CHECKING
32496263Sobrien  reg_state_alloced--;
32596263Sobrien#endif
32696263Sobrien
32796263Sobrien  if (PTR_IN (emergency_reg_state, rs))
32896263Sobrien    atomic_free (&emergency_reg_state_free, rs - emergency_reg_state);
32996263Sobrien  else
33096263Sobrien    free (rs);
33196263Sobrien}
33296263Sobrien
33396263Sobrienstatic struct unw_labeled_state *
33496263Sobrienalloc_label_state (void)
33596263Sobrien{
33696263Sobrien  struct unw_labeled_state *ls;
33796263Sobrien
33896263Sobrien#ifdef ENABLE_MALLOC_CHECKING
33996263Sobrien  labeled_state_alloced++;
34096263Sobrien#endif
34196263Sobrien
34296263Sobrien  ls = malloc(sizeof(struct unw_labeled_state));
34396263Sobrien  if (!ls)
34496263Sobrien    {
34596263Sobrien      int n = atomic_alloc (&emergency_labeled_state_free);
34696263Sobrien      if (n >= 0)
34796263Sobrien	ls = &emergency_labeled_state[n];
34896263Sobrien    }
34996263Sobrien
35096263Sobrien  return ls;
35196263Sobrien}
35296263Sobrien
35396263Sobrienstatic void
35496263Sobrienfree_label_state (struct unw_labeled_state *ls)
35596263Sobrien{
35696263Sobrien#ifdef ENABLE_MALLOC_CHECKING
35796263Sobrien  labeled_state_alloced--;
35896263Sobrien#endif
35996263Sobrien
36096263Sobrien  if (PTR_IN (emergency_labeled_state, ls))
36196263Sobrien    atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls);
36296263Sobrien  else
36396263Sobrien    free (ls);
36496263Sobrien}
36596263Sobrien
36696263Sobrien/* Routines to manipulate the state stack.  */
36796263Sobrien
36896263Sobrienstatic void
36996263Sobrienpush (struct unw_state_record *sr)
37096263Sobrien{
37196263Sobrien  struct unw_reg_state *rs = alloc_reg_state ();
37290075Sobrien  memcpy (rs, &sr->curr, sizeof (*rs));
37396263Sobrien  sr->curr.next = rs;
37490075Sobrien}
37590075Sobrien
37690075Sobrienstatic void
37790075Sobrienpop (struct unw_state_record *sr)
37890075Sobrien{
37996263Sobrien  struct unw_reg_state *rs = sr->curr.next;
38090075Sobrien
38196263Sobrien  if (!rs)
38296263Sobrien    abort ();
38396263Sobrien  memcpy (&sr->curr, rs, sizeof(*rs));
38496263Sobrien  free_reg_state (rs);
38590075Sobrien}
38690075Sobrien
38796263Sobrien/* Make a copy of the state stack.  Non-recursive to avoid stack overflows.  */
38896263Sobrien
38996263Sobrienstatic struct unw_reg_state *
39096263Sobriendup_state_stack (struct unw_reg_state *rs)
39196263Sobrien{
39296263Sobrien  struct unw_reg_state *copy, *prev = NULL, *first = NULL;
39396263Sobrien
39496263Sobrien  while (rs)
39596263Sobrien    {
39696263Sobrien      copy = alloc_reg_state ();
39796263Sobrien      memcpy (copy, rs, sizeof(*copy));
39896263Sobrien      if (first)
39996263Sobrien	prev->next = copy;
40096263Sobrien      else
40196263Sobrien	first = copy;
40296263Sobrien      rs = rs->next;
40396263Sobrien      prev = copy;
40496263Sobrien    }
40596263Sobrien
40696263Sobrien  return first;
40796263Sobrien}
40896263Sobrien
40996263Sobrien/* Free all stacked register states (but not RS itself).  */
41096263Sobrienstatic void
41196263Sobrienfree_state_stack (struct unw_reg_state *rs)
41296263Sobrien{
41396263Sobrien  struct unw_reg_state *p, *next;
41496263Sobrien
41596263Sobrien  for (p = rs->next; p != NULL; p = next)
41696263Sobrien    {
41796263Sobrien      next = p->next;
41896263Sobrien      free_reg_state (p);
41996263Sobrien    }
42096263Sobrien  rs->next = NULL;
42196263Sobrien}
42296263Sobrien
42396263Sobrien/* Free all labeled states.  */
42496263Sobrien
42596263Sobrienstatic void
42696263Sobrienfree_label_states (struct unw_labeled_state *ls)
42796263Sobrien{
42896263Sobrien  struct unw_labeled_state *next;
42996263Sobrien
43096263Sobrien  for (; ls ; ls = next)
43196263Sobrien    {
43296263Sobrien      next = ls->next;
43396263Sobrien
43496263Sobrien      free_state_stack (&ls->saved_state);
43596263Sobrien      free_label_state (ls);
43696263Sobrien    }
43796263Sobrien}
43896263Sobrien
43996263Sobrien/* Unwind decoder routines */
44096263Sobrien
44190075Sobrienstatic enum unw_register_index __attribute__((const))
44290075Sobriendecode_abreg (unsigned char abreg, int memory)
44390075Sobrien{
44490075Sobrien  switch (abreg)
44590075Sobrien    {
44690075Sobrien    case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04);
44790075Sobrien    case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22);
44890075Sobrien    case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30);
44990075Sobrien    case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41);
45090075Sobrien    case 0x60: return UNW_REG_PR;
45190075Sobrien    case 0x61: return UNW_REG_PSP;
45290075Sobrien    case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR;
45390075Sobrien    case 0x63: return UNW_REG_RP;
45490075Sobrien    case 0x64: return UNW_REG_BSP;
45590075Sobrien    case 0x65: return UNW_REG_BSPSTORE;
45690075Sobrien    case 0x66: return UNW_REG_RNAT;
45790075Sobrien    case 0x67: return UNW_REG_UNAT;
45890075Sobrien    case 0x68: return UNW_REG_FPSR;
45990075Sobrien    case 0x69: return UNW_REG_PFS;
46090075Sobrien    case 0x6a: return UNW_REG_LC;
46190075Sobrien    default:
46290075Sobrien      abort ();
46390075Sobrien  }
46490075Sobrien}
46590075Sobrien
46690075Sobrienstatic void
46790075Sobrienset_reg (struct unw_reg_info *reg, enum unw_where where,
46890075Sobrien	 int when, unsigned long val)
46990075Sobrien{
47090075Sobrien  reg->val = val;
47190075Sobrien  reg->where = where;
47290075Sobrien  if (reg->when == UNW_WHEN_NEVER)
47390075Sobrien    reg->when = when;
47490075Sobrien}
47590075Sobrien
47690075Sobrienstatic void
47790075Sobrienalloc_spill_area (unsigned long *offp, unsigned long regsize,
47890075Sobrien		  struct unw_reg_info *lo, struct unw_reg_info *hi)
47990075Sobrien{
48090075Sobrien  struct unw_reg_info *reg;
48190075Sobrien
48290075Sobrien  for (reg = hi; reg >= lo; --reg)
48390075Sobrien    {
48490075Sobrien      if (reg->where == UNW_WHERE_SPILL_HOME)
48590075Sobrien	{
48690075Sobrien	  reg->where = UNW_WHERE_PSPREL;
48796263Sobrien	  *offp -= regsize;
48896263Sobrien	  reg->val = *offp;
48990075Sobrien	}
49090075Sobrien    }
49190075Sobrien}
49290075Sobrien
49390075Sobrienstatic inline void
49490075Sobrienspill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim,
49590075Sobrien		 unw_word t)
49690075Sobrien{
49790075Sobrien  struct unw_reg_info *reg;
49890075Sobrien
49990075Sobrien  for (reg = *regp; reg <= lim; ++reg)
50090075Sobrien    {
50190075Sobrien      if (reg->where == UNW_WHERE_SPILL_HOME)
50290075Sobrien	{
50390075Sobrien	  reg->when = t;
50490075Sobrien	  *regp = reg + 1;
50590075Sobrien	  return;
50690075Sobrien	}
50790075Sobrien    }
50890075Sobrien  /* Excess spill.  */
50990075Sobrien  abort ();
51090075Sobrien}
51190075Sobrien
51290075Sobrienstatic void
51390075Sobrienfinish_prologue (struct unw_state_record *sr)
51490075Sobrien{
51590075Sobrien  struct unw_reg_info *reg;
51690075Sobrien  unsigned long off;
51790075Sobrien  int i;
51890075Sobrien
51990075Sobrien  /* First, resolve implicit register save locations
52090075Sobrien     (see Section "11.4.2.3 Rules for Using Unwind Descriptors", rule 3).  */
52190075Sobrien
52296263Sobrien  for (i = 0; i < (int) sizeof (save_order); ++i)
52390075Sobrien    {
52490075Sobrien      reg = sr->curr.reg + save_order[i];
52590075Sobrien      if (reg->where == UNW_WHERE_GR_SAVE)
52690075Sobrien	{
52790075Sobrien	  reg->where = UNW_WHERE_GR;
52890075Sobrien	  reg->val = sr->gr_save_loc++;
52990075Sobrien	}
53090075Sobrien    }
53190075Sobrien
53290075Sobrien  /* Next, compute when the fp, general, and branch registers get saved.
53390075Sobrien     This must come before alloc_spill_area() because we need to know
53490075Sobrien     which registers are spilled to their home locations.  */
53590075Sobrien  if (sr->imask)
53690075Sobrien    {
53790075Sobrien      static unsigned char const limit[3] = {
53890075Sobrien	UNW_REG_F31, UNW_REG_R7, UNW_REG_B5
53990075Sobrien      };
54090075Sobrien
54190075Sobrien      unsigned char kind, mask = 0, *cp = sr->imask;
54290075Sobrien      int t;
54390075Sobrien      struct unw_reg_info *(regs[3]);
54490075Sobrien
54590075Sobrien      regs[0] = sr->curr.reg + UNW_REG_F2;
54690075Sobrien      regs[1] = sr->curr.reg + UNW_REG_R4;
54790075Sobrien      regs[2] = sr->curr.reg + UNW_REG_B1;
54890075Sobrien
54990075Sobrien      for (t = 0; t < sr->region_len; ++t)
55090075Sobrien	{
55190075Sobrien	  if ((t & 3) == 0)
55290075Sobrien	    mask = *cp++;
55390075Sobrien	  kind = (mask >> 2*(3-(t & 3))) & 3;
55490075Sobrien	  if (kind > 0)
55596263Sobrien	    spill_next_when (&regs[kind - 1], sr->curr.reg + limit[kind - 1],
55696263Sobrien			     sr->region_start + t);
55790075Sobrien	}
55890075Sobrien    }
55990075Sobrien
56090075Sobrien  /* Next, lay out the memory stack spill area.  */
56190075Sobrien  if (sr->any_spills)
56290075Sobrien    {
56390075Sobrien      off = sr->spill_offset;
56496263Sobrien      alloc_spill_area (&off, 16, sr->curr.reg + UNW_REG_F2,
56596263Sobrien		        sr->curr.reg + UNW_REG_F31);
56696263Sobrien      alloc_spill_area (&off,  8, sr->curr.reg + UNW_REG_B1,
56796263Sobrien		        sr->curr.reg + UNW_REG_B5);
56896263Sobrien      alloc_spill_area (&off,  8, sr->curr.reg + UNW_REG_R4,
56996263Sobrien		        sr->curr.reg + UNW_REG_R7);
57090075Sobrien    }
57190075Sobrien}
57290075Sobrien
57390075Sobrien/*
57490075Sobrien * Region header descriptors.
57590075Sobrien */
57690075Sobrien
57790075Sobrienstatic void
57890075Sobriendesc_prologue (int body, unw_word rlen, unsigned char mask,
57990075Sobrien	       unsigned char grsave, struct unw_state_record *sr)
58090075Sobrien{
58190075Sobrien  int i;
58290075Sobrien
58390075Sobrien  if (!(sr->in_body || sr->first_region))
58496263Sobrien    finish_prologue (sr);
58590075Sobrien  sr->first_region = 0;
58690075Sobrien
58790075Sobrien  /* Check if we're done.  */
58896263Sobrien  if (sr->when_target < sr->region_start + sr->region_len)
58990075Sobrien    {
59090075Sobrien      sr->done = 1;
59190075Sobrien      return;
59290075Sobrien    }
59390075Sobrien
59490075Sobrien  for (i = 0; i < sr->epilogue_count; ++i)
59596263Sobrien    pop (sr);
59696263Sobrien
59790075Sobrien  sr->epilogue_count = 0;
59890075Sobrien  sr->epilogue_start = UNW_WHEN_NEVER;
59990075Sobrien
60090075Sobrien  if (!body)
60196263Sobrien    push (sr);
60290075Sobrien
60390075Sobrien  sr->region_start += sr->region_len;
60490075Sobrien  sr->region_len = rlen;
60590075Sobrien  sr->in_body = body;
60690075Sobrien
60790075Sobrien  if (!body)
60890075Sobrien    {
60990075Sobrien      for (i = 0; i < 4; ++i)
61090075Sobrien	{
61190075Sobrien	  if (mask & 0x8)
61290075Sobrien	    set_reg (sr->curr.reg + save_order[i], UNW_WHERE_GR,
61390075Sobrien		     sr->region_start + sr->region_len - 1, grsave++);
61490075Sobrien	  mask <<= 1;
61590075Sobrien	}
61690075Sobrien      sr->gr_save_loc = grsave;
61790075Sobrien      sr->any_spills = 0;
61890075Sobrien      sr->imask = 0;
61990075Sobrien      sr->spill_offset = 0x10;	/* default to psp+16 */
62090075Sobrien    }
62190075Sobrien}
62290075Sobrien
62390075Sobrien/*
62490075Sobrien * Prologue descriptors.
62590075Sobrien */
62690075Sobrien
62790075Sobrienstatic inline void
628132718Skandesc_abi (unsigned char abi,
629132718Skan	  unsigned char context,
630132718Skan	  struct unw_state_record *sr)
63190075Sobrien{
632132718Skan  sr->unwabi = (abi << 8) | context;
63390075Sobrien}
63490075Sobrien
63590075Sobrienstatic inline void
63690075Sobriendesc_br_gr (unsigned char brmask, unsigned char gr,
63790075Sobrien	    struct unw_state_record *sr)
63890075Sobrien{
63990075Sobrien  int i;
64090075Sobrien
64190075Sobrien  for (i = 0; i < 5; ++i)
64290075Sobrien    {
64390075Sobrien      if (brmask & 1)
64490075Sobrien	set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR,
64590075Sobrien		 sr->region_start + sr->region_len - 1, gr++);
64690075Sobrien      brmask >>= 1;
64790075Sobrien    }
64890075Sobrien}
64990075Sobrien
65090075Sobrienstatic inline void
65190075Sobriendesc_br_mem (unsigned char brmask, struct unw_state_record *sr)
65290075Sobrien{
65390075Sobrien  int i;
65490075Sobrien
65590075Sobrien  for (i = 0; i < 5; ++i)
65690075Sobrien    {
65790075Sobrien      if (brmask & 1)
65890075Sobrien	{
65990075Sobrien	  set_reg (sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME,
66090075Sobrien		   sr->region_start + sr->region_len - 1, 0);
66190075Sobrien	  sr->any_spills = 1;
66290075Sobrien	}
66390075Sobrien      brmask >>= 1;
66490075Sobrien    }
66590075Sobrien}
66690075Sobrien
66790075Sobrienstatic inline void
66890075Sobriendesc_frgr_mem (unsigned char grmask, unw_word frmask,
66990075Sobrien	       struct unw_state_record *sr)
67090075Sobrien{
67190075Sobrien  int i;
67290075Sobrien
67390075Sobrien  for (i = 0; i < 4; ++i)
67490075Sobrien    {
67590075Sobrien      if ((grmask & 1) != 0)
67690075Sobrien	{
67790075Sobrien	  set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME,
67890075Sobrien		   sr->region_start + sr->region_len - 1, 0);
67990075Sobrien	  sr->any_spills = 1;
68090075Sobrien	}
68190075Sobrien      grmask >>= 1;
68290075Sobrien    }
68390075Sobrien  for (i = 0; i < 20; ++i)
68490075Sobrien    {
68590075Sobrien      if ((frmask & 1) != 0)
68690075Sobrien	{
68796263Sobrien	  enum unw_register_index base = i < 4 ? UNW_REG_F2 : UNW_REG_F16 - 4;
68896263Sobrien	  set_reg (sr->curr.reg + base + i, UNW_WHERE_SPILL_HOME,
68990075Sobrien		   sr->region_start + sr->region_len - 1, 0);
69090075Sobrien	  sr->any_spills = 1;
69190075Sobrien	}
69290075Sobrien      frmask >>= 1;
69390075Sobrien    }
69490075Sobrien}
69590075Sobrien
69690075Sobrienstatic inline void
69790075Sobriendesc_fr_mem (unsigned char frmask, struct unw_state_record *sr)
69890075Sobrien{
69990075Sobrien  int i;
70090075Sobrien
70190075Sobrien  for (i = 0; i < 4; ++i)
70290075Sobrien    {
70390075Sobrien      if ((frmask & 1) != 0)
70490075Sobrien	{
70590075Sobrien	  set_reg (sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME,
70690075Sobrien		   sr->region_start + sr->region_len - 1, 0);
70790075Sobrien	  sr->any_spills = 1;
70890075Sobrien	}
70990075Sobrien      frmask >>= 1;
71090075Sobrien    }
71190075Sobrien}
71290075Sobrien
71390075Sobrienstatic inline void
71490075Sobriendesc_gr_gr (unsigned char grmask, unsigned char gr,
71590075Sobrien	    struct unw_state_record *sr)
71690075Sobrien{
71790075Sobrien  int i;
71890075Sobrien
71990075Sobrien  for (i = 0; i < 4; ++i)
72090075Sobrien    {
72190075Sobrien      if ((grmask & 1) != 0)
72290075Sobrien	set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR,
72390075Sobrien		 sr->region_start + sr->region_len - 1, gr++);
72490075Sobrien      grmask >>= 1;
72590075Sobrien    }
72690075Sobrien}
72790075Sobrien
72890075Sobrienstatic inline void
72990075Sobriendesc_gr_mem (unsigned char grmask, struct unw_state_record *sr)
73090075Sobrien{
73190075Sobrien  int i;
73290075Sobrien
73390075Sobrien  for (i = 0; i < 4; ++i)
73490075Sobrien    {
73590075Sobrien      if ((grmask & 1) != 0)
73690075Sobrien	{
73790075Sobrien	  set_reg (sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME,
73890075Sobrien		   sr->region_start + sr->region_len - 1, 0);
73990075Sobrien	  sr->any_spills = 1;
74090075Sobrien	}
74190075Sobrien      grmask >>= 1;
74290075Sobrien    }
74390075Sobrien}
74490075Sobrien
74590075Sobrienstatic inline void
74690075Sobriendesc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr)
74790075Sobrien{
74890075Sobrien  set_reg (sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE,
74990075Sobrien	   sr->region_start + MIN ((int)t, sr->region_len - 1), 16*size);
75090075Sobrien}
75190075Sobrien
75290075Sobrienstatic inline void
75390075Sobriendesc_mem_stack_v (unw_word t, struct unw_state_record *sr)
75490075Sobrien{
75590075Sobrien  sr->curr.reg[UNW_REG_PSP].when
75690075Sobrien    = sr->region_start + MIN ((int)t, sr->region_len - 1);
75790075Sobrien}
75890075Sobrien
75990075Sobrienstatic inline void
76090075Sobriendesc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr)
76190075Sobrien{
76290075Sobrien  set_reg (sr->curr.reg + reg, UNW_WHERE_GR,
76390075Sobrien	   sr->region_start + sr->region_len - 1, dst);
76490075Sobrien}
76590075Sobrien
76690075Sobrienstatic inline void
76790075Sobriendesc_reg_psprel (unsigned char reg, unw_word pspoff,
76890075Sobrien		 struct unw_state_record *sr)
76990075Sobrien{
77090075Sobrien  set_reg (sr->curr.reg + reg, UNW_WHERE_PSPREL,
77190075Sobrien	   sr->region_start + sr->region_len - 1,
77290075Sobrien	   0x10 - 4*pspoff);
77390075Sobrien}
77490075Sobrien
77590075Sobrienstatic inline void
77690075Sobriendesc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr)
77790075Sobrien{
77890075Sobrien  set_reg (sr->curr.reg + reg, UNW_WHERE_SPREL,
77990075Sobrien	   sr->region_start + sr->region_len - 1,
78090075Sobrien	   4*spoff);
78190075Sobrien}
78290075Sobrien
78390075Sobrienstatic inline void
78490075Sobriendesc_rp_br (unsigned char dst, struct unw_state_record *sr)
78590075Sobrien{
78690075Sobrien  sr->return_link_reg = dst;
78790075Sobrien}
78890075Sobrien
78990075Sobrienstatic inline void
79090075Sobriendesc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr)
79190075Sobrien{
79290075Sobrien  struct unw_reg_info *reg = sr->curr.reg + regnum;
79390075Sobrien
79490075Sobrien  if (reg->where == UNW_WHERE_NONE)
79590075Sobrien    reg->where = UNW_WHERE_GR_SAVE;
79690075Sobrien  reg->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
79790075Sobrien}
79890075Sobrien
79990075Sobrienstatic inline void
80090075Sobriendesc_spill_base (unw_word pspoff, struct unw_state_record *sr)
80190075Sobrien{
80290075Sobrien  sr->spill_offset = 0x10 - 4*pspoff;
80390075Sobrien}
80490075Sobrien
80590075Sobrienstatic inline unsigned char *
80690075Sobriendesc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr)
80790075Sobrien{
80890075Sobrien  sr->imask = imaskp;
80990075Sobrien  return imaskp + (2*sr->region_len + 7)/8;
81090075Sobrien}
81190075Sobrien
81290075Sobrien/*
81390075Sobrien * Body descriptors.
81490075Sobrien */
81590075Sobrienstatic inline void
81690075Sobriendesc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr)
81790075Sobrien{
81890075Sobrien  sr->epilogue_start = sr->region_start + sr->region_len - 1 - t;
81990075Sobrien  sr->epilogue_count = ecount + 1;
82090075Sobrien}
82190075Sobrien
82290075Sobrienstatic inline void
82390075Sobriendesc_copy_state (unw_word label, struct unw_state_record *sr)
82490075Sobrien{
82596263Sobrien  struct unw_labeled_state *ls;
82690075Sobrien
82796263Sobrien  for (ls = sr->labeled_states; ls; ls = ls->next)
82890075Sobrien    {
82996263Sobrien      if (ls->label == label)
83096263Sobrien        {
83196263Sobrien	  free_state_stack (&sr->curr);
83296263Sobrien   	  memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
83396263Sobrien	  sr->curr.next = dup_state_stack (ls->saved_state.next);
83490075Sobrien	  return;
83590075Sobrien	}
83690075Sobrien    }
83790075Sobrien  abort ();
83890075Sobrien}
83990075Sobrien
84090075Sobrienstatic inline void
84190075Sobriendesc_label_state (unw_word label, struct unw_state_record *sr)
84290075Sobrien{
84396263Sobrien  struct unw_labeled_state *ls = alloc_label_state ();
84490075Sobrien
84596263Sobrien  ls->label = label;
84696263Sobrien  memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
84796263Sobrien  ls->saved_state.next = dup_state_stack (sr->curr.next);
84896263Sobrien
84996263Sobrien  /* Insert into list of labeled states.  */
85096263Sobrien  ls->next = sr->labeled_states;
85196263Sobrien  sr->labeled_states = ls;
85290075Sobrien}
85390075Sobrien
85490075Sobrien/*
85590075Sobrien * General descriptors.
85690075Sobrien */
85790075Sobrien
85890075Sobrienstatic inline int
85990075Sobriendesc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr)
86090075Sobrien{
86190075Sobrien  if (sr->when_target <= sr->region_start + MIN ((int)t, sr->region_len - 1))
86290075Sobrien    return 0;
86390075Sobrien  if (qp > 0)
86490075Sobrien    {
86590075Sobrien      if ((sr->pr_val & (1UL << qp)) == 0)
86690075Sobrien	return 0;
86790075Sobrien      sr->pr_mask |= (1UL << qp);
86890075Sobrien    }
86990075Sobrien  return 1;
87090075Sobrien}
87190075Sobrien
87290075Sobrienstatic inline void
87390075Sobriendesc_restore_p (unsigned char qp, unw_word t, unsigned char abreg,
87490075Sobrien		struct unw_state_record *sr)
87590075Sobrien{
87690075Sobrien  struct unw_reg_info *r;
87790075Sobrien
87890075Sobrien  if (! desc_is_active (qp, t, sr))
87990075Sobrien    return;
88090075Sobrien
88190075Sobrien  r = sr->curr.reg + decode_abreg (abreg, 0);
88290075Sobrien  r->where = UNW_WHERE_NONE;
88390075Sobrien  r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
88490075Sobrien  r->val = 0;
88590075Sobrien}
88690075Sobrien
88790075Sobrienstatic inline void
88890075Sobriendesc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg,
88990075Sobrien		  unsigned char x, unsigned char ytreg,
89090075Sobrien		  struct unw_state_record *sr)
89190075Sobrien{
89290075Sobrien  enum unw_where where = UNW_WHERE_GR;
89390075Sobrien  struct unw_reg_info *r;
89490075Sobrien
89590075Sobrien  if (! desc_is_active (qp, t, sr))
89690075Sobrien    return;
89790075Sobrien
89890075Sobrien  if (x)
89990075Sobrien    where = UNW_WHERE_BR;
90090075Sobrien  else if (ytreg & 0x80)
90190075Sobrien    where = UNW_WHERE_FR;
90290075Sobrien
90390075Sobrien  r = sr->curr.reg + decode_abreg (abreg, 0);
90490075Sobrien  r->where = where;
90590075Sobrien  r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
90690075Sobrien  r->val = ytreg & 0x7f;
90790075Sobrien}
90890075Sobrien
90990075Sobrienstatic inline void
91090075Sobriendesc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg,
91190075Sobrien		     unw_word pspoff, struct unw_state_record *sr)
91290075Sobrien{
91390075Sobrien  struct unw_reg_info *r;
91490075Sobrien
91590075Sobrien  if (! desc_is_active (qp, t, sr))
91690075Sobrien    return;
91790075Sobrien
91890075Sobrien  r = sr->curr.reg + decode_abreg (abreg, 1);
91990075Sobrien  r->where = UNW_WHERE_PSPREL;
92090075Sobrien  r->when = sr->region_start + MIN((int)t, sr->region_len - 1);
92190075Sobrien  r->val = 0x10 - 4*pspoff;
92290075Sobrien}
92390075Sobrien
92490075Sobrienstatic inline void
92590075Sobriendesc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg,
92690075Sobrien		    unw_word spoff, struct unw_state_record *sr)
92790075Sobrien{
92890075Sobrien  struct unw_reg_info *r;
92990075Sobrien
93090075Sobrien  if (! desc_is_active (qp, t, sr))
93190075Sobrien    return;
93290075Sobrien
93390075Sobrien  r = sr->curr.reg + decode_abreg (abreg, 1);
93490075Sobrien  r->where = UNW_WHERE_SPREL;
93590075Sobrien  r->when = sr->region_start + MIN ((int)t, sr->region_len - 1);
93690075Sobrien  r->val = 4*spoff;
93790075Sobrien}
93890075Sobrien
93990075Sobrien
94090075Sobrien#define UNW_DEC_BAD_CODE(code)			abort ();
94190075Sobrien
94290075Sobrien/* Region headers.  */
94390075Sobrien#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg)	desc_prologue(0,r,m,gr,arg)
94490075Sobrien#define UNW_DEC_PROLOGUE(fmt,b,r,arg)		desc_prologue(b,r,0,32,arg)
94590075Sobrien
94690075Sobrien/* Prologue descriptors.  */
94790075Sobrien#define UNW_DEC_ABI(fmt,a,c,arg)		desc_abi(a,c,arg)
94890075Sobrien#define UNW_DEC_BR_GR(fmt,b,g,arg)		desc_br_gr(b,g,arg)
94990075Sobrien#define UNW_DEC_BR_MEM(fmt,b,arg)		desc_br_mem(b,arg)
95090075Sobrien#define UNW_DEC_FRGR_MEM(fmt,g,f,arg)		desc_frgr_mem(g,f,arg)
95190075Sobrien#define UNW_DEC_FR_MEM(fmt,f,arg)		desc_fr_mem(f,arg)
95290075Sobrien#define UNW_DEC_GR_GR(fmt,m,g,arg)		desc_gr_gr(m,g,arg)
95390075Sobrien#define UNW_DEC_GR_MEM(fmt,m,arg)		desc_gr_mem(m,arg)
95490075Sobrien#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg)	desc_mem_stack_f(t,s,arg)
95590075Sobrien#define UNW_DEC_MEM_STACK_V(fmt,t,arg)		desc_mem_stack_v(t,arg)
95690075Sobrien#define UNW_DEC_REG_GR(fmt,r,d,arg)		desc_reg_gr(r,d,arg)
95790075Sobrien#define UNW_DEC_REG_PSPREL(fmt,r,o,arg)		desc_reg_psprel(r,o,arg)
95890075Sobrien#define UNW_DEC_REG_SPREL(fmt,r,o,arg)		desc_reg_sprel(r,o,arg)
95990075Sobrien#define UNW_DEC_REG_WHEN(fmt,r,t,arg)		desc_reg_when(r,t,arg)
96090075Sobrien#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)	desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg)
96190075Sobrien#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)	desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg)
96290075Sobrien#define UNW_DEC_PRIUNAT_GR(fmt,r,arg)		desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg)
96390075Sobrien#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg)	desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg)
96490075Sobrien#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg)	desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg)
96590075Sobrien#define UNW_DEC_RP_BR(fmt,d,arg)		desc_rp_br(d,arg)
96690075Sobrien#define UNW_DEC_SPILL_BASE(fmt,o,arg)		desc_spill_base(o,arg)
96790075Sobrien#define UNW_DEC_SPILL_MASK(fmt,m,arg)		(m = desc_spill_mask(m,arg))
96890075Sobrien
96990075Sobrien/* Body descriptors.  */
97090075Sobrien#define UNW_DEC_EPILOGUE(fmt,t,c,arg)		desc_epilogue(t,c,arg)
97190075Sobrien#define UNW_DEC_COPY_STATE(fmt,l,arg)		desc_copy_state(l,arg)
97290075Sobrien#define UNW_DEC_LABEL_STATE(fmt,l,arg)		desc_label_state(l,arg)
97390075Sobrien
97490075Sobrien/* General unwind descriptors.  */
97590075Sobrien#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg)	desc_spill_reg_p(p,t,a,x,y,arg)
97690075Sobrien#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg)	desc_spill_reg_p(0,t,a,x,y,arg)
97790075Sobrien#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg)	desc_spill_psprel_p(p,t,a,o,arg)
97890075Sobrien#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg)	desc_spill_psprel_p(0,t,a,o,arg)
97990075Sobrien#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg)	desc_spill_sprel_p(p,t,a,o,arg)
98090075Sobrien#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg)	desc_spill_sprel_p(0,t,a,o,arg)
98190075Sobrien#define UNW_DEC_RESTORE_P(f,p,t,a,arg)		desc_restore_p(p,t,a,arg)
98290075Sobrien#define UNW_DEC_RESTORE(f,t,a,arg)		desc_restore_p(0,t,a,arg)
98390075Sobrien
98490075Sobrien
98590075Sobrien/*
98690075Sobrien * Generic IA-64 unwind info decoder.
98790075Sobrien *
98890075Sobrien * This file is used both by the Linux kernel and objdump.  Please keep
98990075Sobrien * the copies of this file in sync.
99090075Sobrien *
99190075Sobrien * You need to customize the decoder by defining the following
99290075Sobrien * macros/constants before including this file:
99390075Sobrien *
99490075Sobrien *  Types:
99590075Sobrien *	unw_word	Unsigned integer type with at least 64 bits
99690075Sobrien *
99790075Sobrien *  Register names:
99890075Sobrien *	UNW_REG_BSP
99990075Sobrien *	UNW_REG_BSPSTORE
100090075Sobrien *	UNW_REG_FPSR
100190075Sobrien *	UNW_REG_LC
100290075Sobrien *	UNW_REG_PFS
100390075Sobrien *	UNW_REG_PR
100490075Sobrien *	UNW_REG_RNAT
100590075Sobrien *	UNW_REG_PSP
100690075Sobrien *	UNW_REG_RP
100790075Sobrien *	UNW_REG_UNAT
100890075Sobrien *
100990075Sobrien *  Decoder action macros:
101090075Sobrien *	UNW_DEC_BAD_CODE(code)
101190075Sobrien *	UNW_DEC_ABI(fmt,abi,context,arg)
101290075Sobrien *	UNW_DEC_BR_GR(fmt,brmask,gr,arg)
101390075Sobrien *	UNW_DEC_BR_MEM(fmt,brmask,arg)
101490075Sobrien *	UNW_DEC_COPY_STATE(fmt,label,arg)
101590075Sobrien *	UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
101690075Sobrien *	UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
101790075Sobrien *	UNW_DEC_FR_MEM(fmt,frmask,arg)
101890075Sobrien *	UNW_DEC_GR_GR(fmt,grmask,gr,arg)
101990075Sobrien *	UNW_DEC_GR_MEM(fmt,grmask,arg)
102090075Sobrien *	UNW_DEC_LABEL_STATE(fmt,label,arg)
102190075Sobrien *	UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
102290075Sobrien *	UNW_DEC_MEM_STACK_V(fmt,t,arg)
102390075Sobrien *	UNW_DEC_PRIUNAT_GR(fmt,r,arg)
102490075Sobrien *	UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
102590075Sobrien *	UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
102690075Sobrien *	UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
102790075Sobrien *	UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
102890075Sobrien *	UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
102990075Sobrien *	UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
103090075Sobrien *	UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
103190075Sobrien *	UNW_DEC_REG_REG(fmt,src,dst,arg)
103290075Sobrien *	UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
103390075Sobrien *	UNW_DEC_REG_WHEN(fmt,reg,t,arg)
103490075Sobrien *	UNW_DEC_RESTORE(fmt,t,abreg,arg)
103590075Sobrien *	UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
103690075Sobrien *	UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
103790075Sobrien *	UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
103890075Sobrien *	UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
103990075Sobrien *	UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
104090075Sobrien *	UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
104190075Sobrien *	UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
104290075Sobrien *	UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
104390075Sobrien *	UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
104490075Sobrien */
104590075Sobrien
104690075Sobrienstatic unw_word
104790075Sobrienunw_decode_uleb128 (unsigned char **dpp)
104890075Sobrien{
104990075Sobrien  unsigned shift = 0;
105090075Sobrien  unw_word byte, result = 0;
105190075Sobrien  unsigned char *bp = *dpp;
105290075Sobrien
105390075Sobrien  while (1)
105490075Sobrien    {
105590075Sobrien      byte = *bp++;
105690075Sobrien      result |= (byte & 0x7f) << shift;
105790075Sobrien      if ((byte & 0x80) == 0)
105890075Sobrien	break;
105990075Sobrien      shift += 7;
106090075Sobrien    }
106190075Sobrien  *dpp = bp;
106290075Sobrien  return result;
106390075Sobrien}
106490075Sobrien
106590075Sobrienstatic unsigned char *
106690075Sobrienunw_decode_x1 (unsigned char *dp,
106790075Sobrien	       unsigned char code __attribute__((unused)),
106890075Sobrien	       void *arg)
106990075Sobrien{
107090075Sobrien  unsigned char byte1, abreg;
107190075Sobrien  unw_word t, off;
107290075Sobrien
107390075Sobrien  byte1 = *dp++;
107490075Sobrien  t = unw_decode_uleb128 (&dp);
107590075Sobrien  off = unw_decode_uleb128 (&dp);
107690075Sobrien  abreg = (byte1 & 0x7f);
107790075Sobrien  if (byte1 & 0x80)
107890075Sobrien	  UNW_DEC_SPILL_SPREL(X1, t, abreg, off, arg);
107990075Sobrien  else
108090075Sobrien	  UNW_DEC_SPILL_PSPREL(X1, t, abreg, off, arg);
108190075Sobrien  return dp;
108290075Sobrien}
108390075Sobrien
108490075Sobrienstatic unsigned char *
108590075Sobrienunw_decode_x2 (unsigned char *dp,
108690075Sobrien	       unsigned char code __attribute__((unused)),
108790075Sobrien	       void *arg)
108890075Sobrien{
108990075Sobrien  unsigned char byte1, byte2, abreg, x, ytreg;
109090075Sobrien  unw_word t;
109190075Sobrien
109290075Sobrien  byte1 = *dp++; byte2 = *dp++;
109390075Sobrien  t = unw_decode_uleb128 (&dp);
109490075Sobrien  abreg = (byte1 & 0x7f);
109590075Sobrien  ytreg = byte2;
109690075Sobrien  x = (byte1 >> 7) & 1;
109790075Sobrien  if ((byte1 & 0x80) == 0 && ytreg == 0)
109890075Sobrien    UNW_DEC_RESTORE(X2, t, abreg, arg);
109990075Sobrien  else
110090075Sobrien    UNW_DEC_SPILL_REG(X2, t, abreg, x, ytreg, arg);
110190075Sobrien  return dp;
110290075Sobrien}
110390075Sobrien
110490075Sobrienstatic unsigned char *
110590075Sobrienunw_decode_x3 (unsigned char *dp,
110690075Sobrien	       unsigned char code __attribute__((unused)),
110790075Sobrien	       void *arg)
110890075Sobrien{
110990075Sobrien  unsigned char byte1, byte2, abreg, qp;
111090075Sobrien  unw_word t, off;
111190075Sobrien
111290075Sobrien  byte1 = *dp++; byte2 = *dp++;
111390075Sobrien  t = unw_decode_uleb128 (&dp);
111490075Sobrien  off = unw_decode_uleb128 (&dp);
111590075Sobrien
111690075Sobrien  qp = (byte1 & 0x3f);
111790075Sobrien  abreg = (byte2 & 0x7f);
111890075Sobrien
111990075Sobrien  if (byte1 & 0x80)
112090075Sobrien    UNW_DEC_SPILL_SPREL_P(X3, qp, t, abreg, off, arg);
112190075Sobrien  else
112290075Sobrien    UNW_DEC_SPILL_PSPREL_P(X3, qp, t, abreg, off, arg);
112390075Sobrien  return dp;
112490075Sobrien}
112590075Sobrien
112690075Sobrienstatic unsigned char *
112790075Sobrienunw_decode_x4 (unsigned char *dp,
112890075Sobrien	       unsigned char code __attribute__((unused)),
112990075Sobrien	       void *arg)
113090075Sobrien{
113190075Sobrien  unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
113290075Sobrien  unw_word t;
113390075Sobrien
113490075Sobrien  byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
113590075Sobrien  t = unw_decode_uleb128 (&dp);
113690075Sobrien
113790075Sobrien  qp = (byte1 & 0x3f);
113890075Sobrien  abreg = (byte2 & 0x7f);
113990075Sobrien  x = (byte2 >> 7) & 1;
114090075Sobrien  ytreg = byte3;
114190075Sobrien
114290075Sobrien  if ((byte2 & 0x80) == 0 && byte3 == 0)
114390075Sobrien    UNW_DEC_RESTORE_P(X4, qp, t, abreg, arg);
114490075Sobrien  else
114590075Sobrien    UNW_DEC_SPILL_REG_P(X4, qp, t, abreg, x, ytreg, arg);
114690075Sobrien  return dp;
114790075Sobrien}
114890075Sobrien
114990075Sobrienstatic unsigned char *
115090075Sobrienunw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
115190075Sobrien{
115290075Sobrien  int body = (code & 0x20) != 0;
115390075Sobrien  unw_word rlen;
115490075Sobrien
115590075Sobrien  rlen = (code & 0x1f);
115690075Sobrien  UNW_DEC_PROLOGUE(R1, body, rlen, arg);
115790075Sobrien  return dp;
115890075Sobrien}
115990075Sobrien
116090075Sobrienstatic unsigned char *
116190075Sobrienunw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
116290075Sobrien{
116390075Sobrien  unsigned char byte1, mask, grsave;
116490075Sobrien  unw_word rlen;
116590075Sobrien
116690075Sobrien  byte1 = *dp++;
116790075Sobrien
116890075Sobrien  mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
116990075Sobrien  grsave = (byte1 & 0x7f);
117090075Sobrien  rlen = unw_decode_uleb128 (&dp);
117190075Sobrien  UNW_DEC_PROLOGUE_GR(R2, rlen, mask, grsave, arg);
117290075Sobrien  return dp;
117390075Sobrien}
117490075Sobrien
117590075Sobrienstatic unsigned char *
117690075Sobrienunw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
117790075Sobrien{
117890075Sobrien  unw_word rlen;
117990075Sobrien
118090075Sobrien  rlen = unw_decode_uleb128 (&dp);
118190075Sobrien  UNW_DEC_PROLOGUE(R3, ((code & 0x3) == 1), rlen, arg);
118290075Sobrien  return dp;
118390075Sobrien}
118490075Sobrien
118590075Sobrienstatic unsigned char *
118690075Sobrienunw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
118790075Sobrien{
118890075Sobrien  unsigned char brmask = (code & 0x1f);
118990075Sobrien
119090075Sobrien  UNW_DEC_BR_MEM(P1, brmask, arg);
119190075Sobrien  return dp;
119290075Sobrien}
119390075Sobrien
119490075Sobrienstatic unsigned char *
119590075Sobrienunw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
119690075Sobrien{
119790075Sobrien  if ((code & 0x10) == 0)
119890075Sobrien    {
119990075Sobrien      unsigned char byte1 = *dp++;
120090075Sobrien
120190075Sobrien      UNW_DEC_BR_GR(P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
120290075Sobrien		    (byte1 & 0x7f), arg);
120390075Sobrien    }
120490075Sobrien  else if ((code & 0x08) == 0)
120590075Sobrien    {
120690075Sobrien      unsigned char byte1 = *dp++, r, dst;
120790075Sobrien
120890075Sobrien      r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
120990075Sobrien      dst = (byte1 & 0x7f);
121090075Sobrien      switch (r)
121190075Sobrien	{
121290075Sobrien	case 0: UNW_DEC_REG_GR(P3, UNW_REG_PSP, dst, arg); break;
121390075Sobrien	case 1: UNW_DEC_REG_GR(P3, UNW_REG_RP, dst, arg); break;
121490075Sobrien	case 2: UNW_DEC_REG_GR(P3, UNW_REG_PFS, dst, arg); break;
121590075Sobrien	case 3: UNW_DEC_REG_GR(P3, UNW_REG_PR, dst, arg); break;
121690075Sobrien	case 4: UNW_DEC_REG_GR(P3, UNW_REG_UNAT, dst, arg); break;
121790075Sobrien	case 5: UNW_DEC_REG_GR(P3, UNW_REG_LC, dst, arg); break;
121890075Sobrien	case 6: UNW_DEC_RP_BR(P3, dst, arg); break;
121990075Sobrien	case 7: UNW_DEC_REG_GR(P3, UNW_REG_RNAT, dst, arg); break;
122090075Sobrien	case 8: UNW_DEC_REG_GR(P3, UNW_REG_BSP, dst, arg); break;
122190075Sobrien	case 9: UNW_DEC_REG_GR(P3, UNW_REG_BSPSTORE, dst, arg); break;
122290075Sobrien	case 10: UNW_DEC_REG_GR(P3, UNW_REG_FPSR, dst, arg); break;
122390075Sobrien	case 11: UNW_DEC_PRIUNAT_GR(P3, dst, arg); break;
122490075Sobrien	default: UNW_DEC_BAD_CODE(r); break;
122590075Sobrien	}
122690075Sobrien    }
122790075Sobrien  else if ((code & 0x7) == 0)
122890075Sobrien    UNW_DEC_SPILL_MASK(P4, dp, arg);
122990075Sobrien  else if ((code & 0x7) == 1)
123090075Sobrien    {
123190075Sobrien      unw_word grmask, frmask, byte1, byte2, byte3;
123290075Sobrien
123390075Sobrien      byte1 = *dp++; byte2 = *dp++; byte3 = *dp++;
123490075Sobrien      grmask = ((byte1 >> 4) & 0xf);
123590075Sobrien      frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
123690075Sobrien      UNW_DEC_FRGR_MEM(P5, grmask, frmask, arg);
123790075Sobrien    }
123890075Sobrien  else
123990075Sobrien    UNW_DEC_BAD_CODE(code);
124090075Sobrien  return dp;
124190075Sobrien}
124290075Sobrien
124390075Sobrienstatic unsigned char *
124490075Sobrienunw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
124590075Sobrien{
124690075Sobrien  int gregs = (code & 0x10) != 0;
124790075Sobrien  unsigned char mask = (code & 0x0f);
124890075Sobrien
124990075Sobrien  if (gregs)
125090075Sobrien    UNW_DEC_GR_MEM(P6, mask, arg);
125190075Sobrien  else
125290075Sobrien    UNW_DEC_FR_MEM(P6, mask, arg);
125390075Sobrien  return dp;
125490075Sobrien}
125590075Sobrien
125690075Sobrienstatic unsigned char *
125790075Sobrienunw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
125890075Sobrien{
125990075Sobrien  unsigned char r, byte1, byte2;
126090075Sobrien  unw_word t, size;
126190075Sobrien
126290075Sobrien  if ((code & 0x10) == 0)
126390075Sobrien    {
126490075Sobrien      r = (code & 0xf);
126590075Sobrien      t = unw_decode_uleb128 (&dp);
126690075Sobrien      switch (r)
126790075Sobrien	{
126890075Sobrien	case 0:
126990075Sobrien	  size = unw_decode_uleb128 (&dp);
127090075Sobrien	  UNW_DEC_MEM_STACK_F(P7, t, size, arg);
127190075Sobrien	  break;
127290075Sobrien
127390075Sobrien	case 1: UNW_DEC_MEM_STACK_V(P7, t, arg); break;
127490075Sobrien	case 2: UNW_DEC_SPILL_BASE(P7, t, arg); break;
127590075Sobrien	case 3: UNW_DEC_REG_SPREL(P7, UNW_REG_PSP, t, arg); break;
127690075Sobrien	case 4: UNW_DEC_REG_WHEN(P7, UNW_REG_RP, t, arg); break;
127790075Sobrien	case 5: UNW_DEC_REG_PSPREL(P7, UNW_REG_RP, t, arg); break;
127890075Sobrien	case 6: UNW_DEC_REG_WHEN(P7, UNW_REG_PFS, t, arg); break;
127990075Sobrien	case 7: UNW_DEC_REG_PSPREL(P7, UNW_REG_PFS, t, arg); break;
128090075Sobrien	case 8: UNW_DEC_REG_WHEN(P7, UNW_REG_PR, t, arg); break;
128190075Sobrien	case 9: UNW_DEC_REG_PSPREL(P7, UNW_REG_PR, t, arg); break;
128290075Sobrien	case 10: UNW_DEC_REG_WHEN(P7, UNW_REG_LC, t, arg); break;
128390075Sobrien	case 11: UNW_DEC_REG_PSPREL(P7, UNW_REG_LC, t, arg); break;
128490075Sobrien	case 12: UNW_DEC_REG_WHEN(P7, UNW_REG_UNAT, t, arg); break;
128590075Sobrien	case 13: UNW_DEC_REG_PSPREL(P7, UNW_REG_UNAT, t, arg); break;
128690075Sobrien	case 14: UNW_DEC_REG_WHEN(P7, UNW_REG_FPSR, t, arg); break;
128790075Sobrien	case 15: UNW_DEC_REG_PSPREL(P7, UNW_REG_FPSR, t, arg); break;
128890075Sobrien	default: UNW_DEC_BAD_CODE(r); break;
128990075Sobrien	}
129090075Sobrien    }
129190075Sobrien  else
129290075Sobrien    {
129390075Sobrien      switch (code & 0xf)
129490075Sobrien	{
129590075Sobrien	case 0x0: /* p8 */
129690075Sobrien	  {
129790075Sobrien	    r = *dp++;
129890075Sobrien	    t = unw_decode_uleb128 (&dp);
129990075Sobrien	    switch (r)
130090075Sobrien	      {
130190075Sobrien	      case  1: UNW_DEC_REG_SPREL(P8, UNW_REG_RP, t, arg); break;
130290075Sobrien	      case  2: UNW_DEC_REG_SPREL(P8, UNW_REG_PFS, t, arg); break;
130390075Sobrien	      case  3: UNW_DEC_REG_SPREL(P8, UNW_REG_PR, t, arg); break;
130490075Sobrien	      case  4: UNW_DEC_REG_SPREL(P8, UNW_REG_LC, t, arg); break;
130590075Sobrien	      case  5: UNW_DEC_REG_SPREL(P8, UNW_REG_UNAT, t, arg); break;
130690075Sobrien	      case  6: UNW_DEC_REG_SPREL(P8, UNW_REG_FPSR, t, arg); break;
130790075Sobrien	      case  7: UNW_DEC_REG_WHEN(P8, UNW_REG_BSP, t, arg); break;
130890075Sobrien	      case  8: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSP, t, arg); break;
130990075Sobrien	      case  9: UNW_DEC_REG_SPREL(P8, UNW_REG_BSP, t, arg); break;
131090075Sobrien	      case 10: UNW_DEC_REG_WHEN(P8, UNW_REG_BSPSTORE, t, arg); break;
131190075Sobrien	      case 11: UNW_DEC_REG_PSPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
131290075Sobrien	      case 12: UNW_DEC_REG_SPREL(P8, UNW_REG_BSPSTORE, t, arg); break;
131390075Sobrien	      case 13: UNW_DEC_REG_WHEN(P8, UNW_REG_RNAT, t, arg); break;
131490075Sobrien	      case 14: UNW_DEC_REG_PSPREL(P8, UNW_REG_RNAT, t, arg); break;
131590075Sobrien	      case 15: UNW_DEC_REG_SPREL(P8, UNW_REG_RNAT, t, arg); break;
131690075Sobrien	      case 16: UNW_DEC_PRIUNAT_WHEN_GR(P8, t, arg); break;
131790075Sobrien	      case 17: UNW_DEC_PRIUNAT_PSPREL(P8, t, arg); break;
131890075Sobrien	      case 18: UNW_DEC_PRIUNAT_SPREL(P8, t, arg); break;
131990075Sobrien	      case 19: UNW_DEC_PRIUNAT_WHEN_MEM(P8, t, arg); break;
132090075Sobrien	      default: UNW_DEC_BAD_CODE(r); break;
132190075Sobrien	    }
132290075Sobrien	  }
132390075Sobrien	  break;
132490075Sobrien
132590075Sobrien	case 0x1:
132690075Sobrien	  byte1 = *dp++; byte2 = *dp++;
132790075Sobrien	  UNW_DEC_GR_GR(P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
132890075Sobrien	  break;
132990075Sobrien
133090075Sobrien	case 0xf: /* p10 */
133190075Sobrien	  byte1 = *dp++; byte2 = *dp++;
133290075Sobrien	  UNW_DEC_ABI(P10, byte1, byte2, arg);
133390075Sobrien	  break;
133490075Sobrien
133590075Sobrien	case 0x9:
133690075Sobrien	  return unw_decode_x1 (dp, code, arg);
133790075Sobrien
133890075Sobrien	case 0xa:
133990075Sobrien	  return unw_decode_x2 (dp, code, arg);
134090075Sobrien
134190075Sobrien	case 0xb:
134290075Sobrien	  return unw_decode_x3 (dp, code, arg);
134390075Sobrien
134490075Sobrien	case 0xc:
134590075Sobrien	  return unw_decode_x4 (dp, code, arg);
134690075Sobrien
134790075Sobrien	default:
134890075Sobrien	  UNW_DEC_BAD_CODE(code);
134990075Sobrien	  break;
135090075Sobrien	}
135190075Sobrien    }
135290075Sobrien  return dp;
135390075Sobrien}
135490075Sobrien
135590075Sobrienstatic unsigned char *
135690075Sobrienunw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
135790075Sobrien{
135890075Sobrien  unw_word label = (code & 0x1f);
135990075Sobrien
136090075Sobrien  if ((code & 0x20) != 0)
136190075Sobrien    UNW_DEC_COPY_STATE(B1, label, arg);
136290075Sobrien  else
136390075Sobrien    UNW_DEC_LABEL_STATE(B1, label, arg);
136490075Sobrien  return dp;
136590075Sobrien}
136690075Sobrien
136790075Sobrienstatic unsigned char *
136890075Sobrienunw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
136990075Sobrien{
137090075Sobrien  unw_word t;
137190075Sobrien
137290075Sobrien  t = unw_decode_uleb128 (&dp);
137390075Sobrien  UNW_DEC_EPILOGUE(B2, t, (code & 0x1f), arg);
137490075Sobrien  return dp;
137590075Sobrien}
137690075Sobrien
137790075Sobrienstatic unsigned char *
137890075Sobrienunw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
137990075Sobrien{
138090075Sobrien  unw_word t, ecount, label;
138190075Sobrien
138290075Sobrien  if ((code & 0x10) == 0)
138390075Sobrien    {
138490075Sobrien      t = unw_decode_uleb128 (&dp);
138590075Sobrien      ecount = unw_decode_uleb128 (&dp);
138690075Sobrien      UNW_DEC_EPILOGUE(B3, t, ecount, arg);
138790075Sobrien    }
138890075Sobrien  else if ((code & 0x07) == 0)
138990075Sobrien    {
139090075Sobrien      label = unw_decode_uleb128 (&dp);
139190075Sobrien      if ((code & 0x08) != 0)
139290075Sobrien	UNW_DEC_COPY_STATE(B4, label, arg);
139390075Sobrien      else
139490075Sobrien	UNW_DEC_LABEL_STATE(B4, label, arg);
139590075Sobrien    }
139690075Sobrien  else
139790075Sobrien    switch (code & 0x7)
139890075Sobrien      {
139990075Sobrien      case 1: return unw_decode_x1 (dp, code, arg);
140090075Sobrien      case 2: return unw_decode_x2 (dp, code, arg);
140190075Sobrien      case 3: return unw_decode_x3 (dp, code, arg);
140290075Sobrien      case 4: return unw_decode_x4 (dp, code, arg);
140390075Sobrien      default: UNW_DEC_BAD_CODE(code); break;
140490075Sobrien      }
140590075Sobrien  return dp;
140690075Sobrien}
140790075Sobrien
140890075Sobrientypedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
140990075Sobrien
1410117395Skanstatic const unw_decoder unw_decode_table[2][8] =
141190075Sobrien{
141290075Sobrien  /* prologue table: */
141390075Sobrien  {
141490075Sobrien    unw_decode_r1,	/* 0 */
141590075Sobrien    unw_decode_r1,
141690075Sobrien    unw_decode_r2,
141790075Sobrien    unw_decode_r3,
141890075Sobrien    unw_decode_p1,	/* 4 */
141990075Sobrien    unw_decode_p2_p5,
142090075Sobrien    unw_decode_p6,
142190075Sobrien    unw_decode_p7_p10
142290075Sobrien  },
142390075Sobrien  {
142490075Sobrien    unw_decode_r1,	/* 0 */
142590075Sobrien    unw_decode_r1,
142690075Sobrien    unw_decode_r2,
142790075Sobrien    unw_decode_r3,
142890075Sobrien    unw_decode_b1,	/* 4 */
142990075Sobrien    unw_decode_b1,
143090075Sobrien    unw_decode_b2,
143190075Sobrien    unw_decode_b3_x4
143290075Sobrien  }
143390075Sobrien};
143490075Sobrien
143590075Sobrien/*
143690075Sobrien * Decode one descriptor and return address of next descriptor.
143790075Sobrien */
143890075Sobrienstatic inline unsigned char *
143990075Sobrienunw_decode (unsigned char *dp, int inside_body, void *arg)
144090075Sobrien{
144190075Sobrien  unw_decoder decoder;
144290075Sobrien  unsigned char code;
144390075Sobrien
144490075Sobrien  code = *dp++;
144590075Sobrien  decoder = unw_decode_table[inside_body][code >> 5];
144690075Sobrien  dp = (*decoder) (dp, code, arg);
144790075Sobrien  return dp;
144890075Sobrien}
144990075Sobrien
145090075Sobrien
145190075Sobrien/* RSE helper functions.  */
145290075Sobrien
145390075Sobrienstatic inline unsigned long
145490075Sobrienia64_rse_slot_num (unsigned long *addr)
145590075Sobrien{
145690075Sobrien  return (((unsigned long) addr) >> 3) & 0x3f;
145790075Sobrien}
145890075Sobrien
145990075Sobrien/* Return TRUE if ADDR is the address of an RNAT slot.  */
146090075Sobrienstatic inline unsigned long
146190075Sobrienia64_rse_is_rnat_slot (unsigned long *addr)
146290075Sobrien{
146390075Sobrien  return ia64_rse_slot_num (addr) == 0x3f;
146490075Sobrien}
146590075Sobrien
146690075Sobrien/* Returns the address of the RNAT slot that covers the slot at
146790075Sobrien   address SLOT_ADDR.  */
146890075Sobrienstatic inline unsigned long *
146990075Sobrienia64_rse_rnat_addr (unsigned long *slot_addr)
147090075Sobrien{
147190075Sobrien  return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
147290075Sobrien}
147390075Sobrien
1474132718Skan/* Calculate the number of registers in the dirty partition starting at
147590075Sobrien   BSPSTORE with a size of DIRTY bytes.  This isn't simply DIRTY
147690075Sobrien   divided by eight because the 64th slot is used to store ar.rnat.  */
147790075Sobrienstatic inline unsigned long
147890075Sobrienia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp)
147990075Sobrien{
148090075Sobrien  unsigned long slots = (bsp - bspstore);
148190075Sobrien
148290075Sobrien  return slots - (ia64_rse_slot_num (bspstore) + slots)/0x40;
148390075Sobrien}
148490075Sobrien
148590075Sobrien/* The inverse of the above: given bspstore and the number of
148690075Sobrien   registers, calculate ar.bsp.  */
148790075Sobrienstatic inline unsigned long *
148890075Sobrienia64_rse_skip_regs (unsigned long *addr, long num_regs)
148990075Sobrien{
149090075Sobrien  long delta = ia64_rse_slot_num (addr) + num_regs;
149190075Sobrien
149290075Sobrien  if (num_regs < 0)
149390075Sobrien    delta -= 0x3e;
149490075Sobrien  return addr + num_regs + delta/0x3f;
149590075Sobrien}
149690075Sobrien
149790075Sobrien
1498132718Skan/* Copy register backing store from SRC to DST, LEN words
1499132718Skan   (which include both saved registers and nat collections).
1500132718Skan   DST_RNAT is a partial nat collection for DST.  SRC and DST
1501132718Skan   don't have to be equal modulo 64 slots, so it cannot be
1502132718Skan   done with a simple memcpy as the nat collections will be
1503132718Skan   at different relative offsets and need to be combined together.  */
1504132718Skanstatic void
1505132718Skania64_copy_rbs (struct _Unwind_Context *info, unsigned long dst,
1506132718Skan               unsigned long src, long len, unsigned long dst_rnat)
1507132718Skan{
1508132718Skan  long count;
1509132718Skan  unsigned long src_rnat;
1510132718Skan  unsigned long shift1, shift2;
1511132718Skan
1512132718Skan  len <<= 3;
1513132718Skan  dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1;
1514132718Skan  src_rnat = src >= info->regstk_top
1515132718Skan	     ? info->rnat : *(unsigned long *) (src | 0x1f8);
1516132718Skan  src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1);
1517132718Skan  /* Just to make sure.  */
1518132718Skan  src_rnat &= ~(1UL << 63);
1519132718Skan  shift1 = ((dst - src) >> 3) & 0x3f;
1520132718Skan  if ((dst & 0x1f8) < (src & 0x1f8))
1521132718Skan    shift1--;
1522132718Skan  shift2 = 0x3f - shift1;
1523132718Skan  if ((dst & 0x1f8) >= (src & 0x1f8))
1524132718Skan    {
1525132718Skan      count = ~dst & 0x1f8;
1526132718Skan      goto first;
1527132718Skan    }
1528132718Skan  count = ~src & 0x1f8;
1529132718Skan  goto second;
1530132718Skan  while (len > 0)
1531132718Skan    {
1532132718Skan      src_rnat = src >= info->regstk_top
1533132718Skan		 ? info->rnat : *(unsigned long *) (src | 0x1f8);
1534132718Skan      /* Just to make sure.  */
1535132718Skan      src_rnat &= ~(1UL << 63);
1536132718Skan      count = shift2 << 3;
1537132718Skanfirst:
1538132718Skan      if (count > len)
1539132718Skan        count = len;
1540132718Skan      memcpy ((char *) dst, (char *) src, count);
1541132718Skan      dst += count;
1542132718Skan      src += count;
1543132718Skan      len -= count;
1544132718Skan      dst_rnat |= (src_rnat << shift1) & ~(1UL << 63);
1545132718Skan      if (len <= 0)
1546132718Skan        break;
1547132718Skan      *(long *) dst = dst_rnat;
1548132718Skan      dst += 8;
1549132718Skan      dst_rnat = 0;
1550132718Skan      count = shift1 << 3;
1551132718Skansecond:
1552132718Skan      if (count > len)
1553132718Skan        count = len;
1554132718Skan      memcpy ((char *) dst, (char *) src, count);
1555132718Skan      dst += count;
1556132718Skan      src += count + 8;
1557132718Skan      len -= count + 8;
1558132718Skan      dst_rnat |= (src_rnat >> shift2);
1559132718Skan    }
1560132718Skan  if ((dst & 0x1f8) == 0x1f8)
1561132718Skan    {
1562132718Skan      *(long *) dst = dst_rnat;
1563132718Skan      dst += 8;
1564132718Skan      dst_rnat = 0;
1565132718Skan    }
1566132718Skan  /* Set info->regstk_top to lowest rbs address which will use
1567132718Skan     info->rnat collection.  */
1568132718Skan  info->regstk_top = dst & ~0x1ffUL;
1569132718Skan  info->rnat = dst_rnat;
1570132718Skan}
1571132718Skan
157290075Sobrien/* Unwind accessors.  */
157390075Sobrien
157490075Sobrienstatic void
157590075Sobrienunw_access_gr (struct _Unwind_Context *info, int regnum,
157690075Sobrien	       unsigned long *val, char *nat, int write)
157790075Sobrien{
157890075Sobrien  unsigned long *addr, *nat_addr = 0, nat_mask = 0, dummy_nat;
157990075Sobrien  struct unw_ireg *ireg;
158090075Sobrien
158190075Sobrien  if ((unsigned) regnum - 1 >= 127)
158290075Sobrien    abort ();
158390075Sobrien
158490075Sobrien  if (regnum < 1)
158590075Sobrien    {
158690075Sobrien      nat_addr = addr = &dummy_nat;
158790075Sobrien      dummy_nat = 0;
158890075Sobrien    }
158990075Sobrien  else if (regnum < 32)
159090075Sobrien    {
159190075Sobrien      /* Access a non-stacked register.  */
159290075Sobrien      ireg = &info->ireg[regnum - 2];
159390075Sobrien      addr = ireg->loc;
159490075Sobrien      if (addr)
159590075Sobrien	{
159690075Sobrien	  nat_addr = addr + ireg->nat.off;
159790075Sobrien	  switch (ireg->nat.type)
159890075Sobrien	    {
159990075Sobrien	    case UNW_NAT_VAL:
160090075Sobrien	      /* Simulate getf.sig/setf.sig.  */
160190075Sobrien	      if (write)
160290075Sobrien		{
160390075Sobrien		  if (*nat)
160490075Sobrien		    {
160590075Sobrien		      /* Write NaTVal and be done with it.  */
160690075Sobrien		      addr[0] = 0;
160790075Sobrien		      addr[1] = 0x1fffe;
160890075Sobrien		      return;
160990075Sobrien		    }
161090075Sobrien		  addr[1] = 0x1003e;
161190075Sobrien		}
161290075Sobrien	      else if (addr[0] == 0 && addr[1] == 0x1ffe)
161390075Sobrien		{
161490075Sobrien		  /* Return NaT and be done with it.  */
161590075Sobrien		  *val = 0;
161690075Sobrien		  *nat = 1;
161790075Sobrien		  return;
161890075Sobrien		}
161990075Sobrien	      /* FALLTHRU */
162090075Sobrien
162190075Sobrien	    case UNW_NAT_NONE:
162290075Sobrien	      dummy_nat = 0;
162390075Sobrien	      nat_addr = &dummy_nat;
162490075Sobrien	      break;
162590075Sobrien
162690075Sobrien	    case UNW_NAT_MEMSTK:
162790075Sobrien	      nat_mask = 1UL << ((long) addr & 0x1f8)/8;
162890075Sobrien	      break;
162990075Sobrien
163090075Sobrien	    case UNW_NAT_REGSTK:
1631132718Skan	      if ((unsigned long) addr >= info->regstk_top)
163290075Sobrien		nat_addr = &info->rnat;
1633132718Skan	      else
1634132718Skan		nat_addr = ia64_rse_rnat_addr (addr);
163590075Sobrien	      nat_mask = 1UL << ia64_rse_slot_num (addr);
163690075Sobrien	      break;
163790075Sobrien	    }
163890075Sobrien	}
163990075Sobrien    }
164090075Sobrien  else
164190075Sobrien    {
164290075Sobrien      /* Access a stacked register.  */
164390075Sobrien      addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32);
1644132718Skan      if ((unsigned long) addr >= info->regstk_top)
164590075Sobrien	nat_addr = &info->rnat;
1646132718Skan      else
1647132718Skan	nat_addr = ia64_rse_rnat_addr (addr);
164890075Sobrien      nat_mask = 1UL << ia64_rse_slot_num (addr);
164990075Sobrien    }
165090075Sobrien
165190075Sobrien  if (write)
165290075Sobrien    {
165390075Sobrien      *addr = *val;
165490075Sobrien      if (*nat)
165590075Sobrien	*nat_addr |= nat_mask;
165690075Sobrien      else
165790075Sobrien	*nat_addr &= ~nat_mask;
165890075Sobrien    }
165990075Sobrien  else
166090075Sobrien    {
166190075Sobrien      *val = *addr;
166290075Sobrien      *nat = (*nat_addr & nat_mask) != 0;
166390075Sobrien    }
166490075Sobrien}
166590075Sobrien
166690075Sobrien/* Get the value of register REG as saved in CONTEXT.  */
166790075Sobrien
166890075Sobrien_Unwind_Word
166990075Sobrien_Unwind_GetGR (struct _Unwind_Context *context, int index)
167090075Sobrien{
167190075Sobrien  _Unwind_Word ret;
167290075Sobrien  char nat;
167390075Sobrien
167490075Sobrien  if (index == 1)
167590075Sobrien    return context->gp;
167690075Sobrien  else if (index >= 15 && index <= 18)
167790075Sobrien    return context->eh_data[index - 15];
167890075Sobrien  else
167990075Sobrien    unw_access_gr (context, index, &ret, &nat, 0);
168090075Sobrien
168190075Sobrien  return ret;
168290075Sobrien}
168390075Sobrien
168490075Sobrien/* Overwrite the saved value for register REG in CONTEXT with VAL.  */
168590075Sobrien
168690075Sobrienvoid
168790075Sobrien_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
168890075Sobrien{
168990075Sobrien  char nat = 0;
169090075Sobrien
169190075Sobrien  if (index == 1)
169290075Sobrien    context->gp = val;
169390075Sobrien  else if (index >= 15 && index <= 18)
169490075Sobrien    context->eh_data[index - 15] = val;
169590075Sobrien  else
169690075Sobrien    unw_access_gr (context, index, &val, &nat, 1);
169790075Sobrien}
169890075Sobrien
169990075Sobrien/* Retrieve the return address for CONTEXT.  */
170090075Sobrien
170190075Sobrieninline _Unwind_Ptr
170290075Sobrien_Unwind_GetIP (struct _Unwind_Context *context)
170390075Sobrien{
170490075Sobrien  return context->rp;
170590075Sobrien}
170690075Sobrien
1707169689Skaninline _Unwind_Ptr
1708169689Skan_Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
1709169689Skan{
1710169689Skan  *ip_before_insn = 0;
1711169689Skan  return context->rp;
1712169689Skan}
1713169689Skan
171490075Sobrien/* Overwrite the return address for CONTEXT with VAL.  */
171590075Sobrien
171690075Sobrieninline void
171790075Sobrien_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
171890075Sobrien{
171990075Sobrien  context->rp = val;
172090075Sobrien}
172190075Sobrien
172290075Sobrienvoid *
172390075Sobrien_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
172490075Sobrien{
172590075Sobrien  return context->lsda;
172690075Sobrien}
172790075Sobrien
172890075Sobrien_Unwind_Ptr
172990075Sobrien_Unwind_GetRegionStart (struct _Unwind_Context *context)
173090075Sobrien{
173190075Sobrien  return context->region_start;
173290075Sobrien}
173390075Sobrien
1734117395Skanvoid *
1735117395Skan_Unwind_FindEnclosingFunction (void *pc)
1736117395Skan{
1737117395Skan  struct unw_table_entry *ent;
1738117395Skan  unsigned long segment_base, gp;
1739117395Skan
1740117395Skan  ent = _Unwind_FindTableEntry (pc, &segment_base, &gp);
1741117395Skan  if (ent == NULL)
1742117395Skan    return NULL;
1743117395Skan  else
1744117395Skan    return (void *)(segment_base + ent->start_offset);
1745117395Skan}
1746117395Skan
1747117395Skan/* Get the value of the CFA as saved in CONTEXT.  In GCC/Dwarf2 parlance,
1748117395Skan   the CFA is the value of the stack pointer on entry; In IA-64 unwind
1749117395Skan   parlance, this is the PSP.  */
1750117395Skan
1751117395Skan_Unwind_Word
1752117395Skan_Unwind_GetCFA (struct _Unwind_Context *context)
1753117395Skan{
1754117395Skan  return (_Unwind_Ptr) context->psp;
1755117395Skan}
1756117395Skan
1757122180Skan/* Get the value of the Backing Store Pointer as saved in CONTEXT.  */
1758122180Skan
1759122180Skan_Unwind_Word
1760122180Skan_Unwind_GetBSP (struct _Unwind_Context *context)
1761122180Skan{
1762122180Skan  return (_Unwind_Ptr) context->bsp;
1763122180Skan}
1764122180Skan
1765169689Skan#ifdef MD_UNWIND_SUPPORT
1766169689Skan#include MD_UNWIND_SUPPORT
1767169689Skan#endif
176890075Sobrien
176990075Sobrienstatic _Unwind_Reason_Code
177090075Sobrienuw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
177190075Sobrien{
177290075Sobrien  struct unw_table_entry *ent;
177390075Sobrien  unsigned long *unw, header, length;
177490075Sobrien  unsigned char *insn, *insn_end;
177590075Sobrien  unsigned long segment_base;
177696263Sobrien  struct unw_reg_info *r;
177790075Sobrien
177890075Sobrien  memset (fs, 0, sizeof (*fs));
177996263Sobrien  for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r)
178096263Sobrien    r->when = UNW_WHEN_NEVER;
178190075Sobrien  context->lsda = 0;
178290075Sobrien
178390075Sobrien  ent = _Unwind_FindTableEntry ((void *) context->rp,
178490075Sobrien				&segment_base, &context->gp);
178590075Sobrien  if (ent == NULL)
178690075Sobrien    {
178790075Sobrien      /* Couldn't find unwind info for this function.  Try an
178890075Sobrien	 os-specific fallback mechanism.  This will necessarily
178990075Sobrien	 not provide a personality routine or LSDA.  */
179090075Sobrien#ifdef MD_FALLBACK_FRAME_STATE_FOR
1791169689Skan      if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON)
1792169689Skan	return _URC_NO_REASON;
179390075Sobrien
179490075Sobrien      /* [SCRA 11.4.1] A leaf function with no memory stack, no exception
179590075Sobrien	 handlers, and which keeps the return value in B0 does not need
179690075Sobrien	 an unwind table entry.
179790075Sobrien
179890075Sobrien	 This can only happen in the frame after unwinding through a signal
1799132718Skan	 handler.  Avoid infinite looping by requiring that B0 != RP.
1800132718Skan	 RP == 0 terminates the chain.  */
1801132718Skan      if (context->br_loc[0] && *context->br_loc[0] != context->rp
1802132718Skan	  && context->rp != 0)
180390075Sobrien	{
180490075Sobrien	  fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
180590075Sobrien	  fs->curr.reg[UNW_REG_RP].when = -1;
180690075Sobrien	  fs->curr.reg[UNW_REG_RP].val = 0;
1807169689Skan	  return _URC_NO_REASON;
180890075Sobrien	}
1809169689Skan#endif
181090075Sobrien      return _URC_END_OF_STACK;
181190075Sobrien    }
181290075Sobrien
181390075Sobrien  context->region_start = ent->start_offset + segment_base;
1814132718Skan  fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3
1815132718Skan		    + (context->rp & 15);
181690075Sobrien
181790075Sobrien  unw = (unsigned long *) (ent->info_offset + segment_base);
181890075Sobrien  header = *unw;
181990075Sobrien  length = UNW_LENGTH (header);
182090075Sobrien
182190075Sobrien  /* ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK.  */
182290075Sobrien
182390075Sobrien  if (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header))
182490075Sobrien    {
182590075Sobrien      fs->personality =
182690075Sobrien	*(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp);
182790075Sobrien      context->lsda = unw + length + 2;
182890075Sobrien    }
182990075Sobrien
183090075Sobrien  insn = (unsigned char *) (unw + 1);
183190075Sobrien  insn_end = (unsigned char *) (unw + 1 + length);
183290075Sobrien  while (!fs->done && insn < insn_end)
183390075Sobrien    insn = unw_decode (insn, fs->in_body, fs);
183490075Sobrien
183596263Sobrien  free_label_states (fs->labeled_states);
183696263Sobrien  free_state_stack (&fs->curr);
183796263Sobrien
183896263Sobrien#ifdef ENABLE_MALLOC_CHECKING
183996263Sobrien  if (reg_state_alloced || labeled_state_alloced)
184096263Sobrien    abort ();
184196263Sobrien#endif
184296263Sobrien
184390075Sobrien  /* If we're in the epilogue, sp has been restored and all values
184490075Sobrien     on the memory stack below psp also have been restored.  */
184590075Sobrien  if (fs->when_target > fs->epilogue_start)
184690075Sobrien    {
184790075Sobrien      struct unw_reg_info *r;
184890075Sobrien
184990075Sobrien      fs->curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;
185090075Sobrien      fs->curr.reg[UNW_REG_PSP].val = 0;
185190075Sobrien      for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r)
185290075Sobrien	if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10)
185390075Sobrien	    || r->where == UNW_WHERE_SPREL)
185490075Sobrien	  r->where = UNW_WHERE_NONE;
185590075Sobrien    }
185690075Sobrien
185790075Sobrien  /* If RP did't get saved, generate entry for the return link register.  */
185890075Sobrien  if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target)
185990075Sobrien    {
186090075Sobrien      fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;
186190075Sobrien      fs->curr.reg[UNW_REG_RP].when = -1;
186290075Sobrien      fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg;
186390075Sobrien    }
186490075Sobrien
186590075Sobrien  return _URC_NO_REASON;
186690075Sobrien}
186790075Sobrien
186890075Sobrienstatic void
186990075Sobrienuw_update_reg_address (struct _Unwind_Context *context,
187090075Sobrien		       _Unwind_FrameState *fs,
187190075Sobrien		       enum unw_register_index regno)
187290075Sobrien{
187390075Sobrien  struct unw_reg_info *r = fs->curr.reg + regno;
187490075Sobrien  void *addr;
187590075Sobrien  unsigned long rval;
187690075Sobrien
187790075Sobrien  if (r->where == UNW_WHERE_NONE || r->when >= fs->when_target)
187890075Sobrien    return;
187990075Sobrien
188090075Sobrien  rval = r->val;
188190075Sobrien  switch (r->where)
188290075Sobrien    {
188390075Sobrien    case UNW_WHERE_GR:
188490075Sobrien      if (rval >= 32)
188590075Sobrien	addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32);
188690075Sobrien      else if (rval >= 2)
188790075Sobrien	addr = context->ireg[rval - 2].loc;
1888122180Skan      else if (rval == 0)
1889122180Skan	{
1890122180Skan	  static const unsigned long dummy;
1891122180Skan	  addr = (void *) &dummy;
1892122180Skan	}
189390075Sobrien      else
189490075Sobrien	abort ();
189590075Sobrien      break;
189690075Sobrien
189790075Sobrien    case UNW_WHERE_FR:
189890075Sobrien      if (rval >= 2 && rval < 32)
189990075Sobrien	addr = context->fr_loc[rval - 2];
190090075Sobrien      else
190190075Sobrien	abort ();
190290075Sobrien      break;
190390075Sobrien
190490075Sobrien    case UNW_WHERE_BR:
190590075Sobrien      /* Note that while RVAL can only be 1-5 from normal descriptors,
1906132718Skan	 we can want to look at B0, B6 and B7 due to having manually unwound a
190790075Sobrien	 signal frame.  */
1908132718Skan      if (rval < 8)
190990075Sobrien	addr = context->br_loc[rval];
191090075Sobrien      else
191190075Sobrien	abort ();
191290075Sobrien      break;
191390075Sobrien
191490075Sobrien    case UNW_WHERE_SPREL:
191590075Sobrien      addr = (void *)(context->sp + rval);
191690075Sobrien      break;
191790075Sobrien
191890075Sobrien    case UNW_WHERE_PSPREL:
191990075Sobrien      addr = (void *)(context->psp + rval);
192090075Sobrien      break;
192190075Sobrien
192290075Sobrien    default:
192390075Sobrien      abort ();
192490075Sobrien    }
192590075Sobrien
192690075Sobrien  switch (regno)
192790075Sobrien    {
192890075Sobrien    case UNW_REG_R2 ... UNW_REG_R31:
192990075Sobrien      context->ireg[regno - UNW_REG_R2].loc = addr;
193090075Sobrien      switch (r->where)
193190075Sobrien      {
193290075Sobrien      case UNW_WHERE_GR:
193390075Sobrien	if (rval >= 32)
193490075Sobrien	  {
193590075Sobrien	    context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK;
193690075Sobrien	    context->ireg[regno - UNW_REG_R2].nat.off
193790075Sobrien	      = context->pri_unat_loc - (unsigned long *) addr;
193890075Sobrien	  }
193990075Sobrien	else if (rval >= 2)
194090075Sobrien	  {
194190075Sobrien	    context->ireg[regno - UNW_REG_R2].nat
194290075Sobrien	      = context->ireg[rval - 2].nat;
194390075Sobrien	  }
1944122180Skan	else if (rval == 0)
1945122180Skan	  {
1946122180Skan	    context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE;
1947122180Skan	    context->ireg[regno - UNW_REG_R2].nat.off = 0;
1948122180Skan	  }
194990075Sobrien	else
195090075Sobrien	  abort ();
195190075Sobrien	break;
195290075Sobrien
195390075Sobrien      case UNW_WHERE_FR:
195490075Sobrien	context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_VAL;
195590075Sobrien	context->ireg[regno - UNW_REG_R2].nat.off = 0;
195690075Sobrien	break;
195790075Sobrien
195890075Sobrien      case UNW_WHERE_BR:
195990075Sobrien	context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_NONE;
196090075Sobrien	context->ireg[regno - UNW_REG_R2].nat.off = 0;
196190075Sobrien	break;
196290075Sobrien
196390075Sobrien      case UNW_WHERE_PSPREL:
196490075Sobrien      case UNW_WHERE_SPREL:
196590075Sobrien	context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK;
196690075Sobrien	context->ireg[regno - UNW_REG_R2].nat.off
196790075Sobrien	  = context->pri_unat_loc - (unsigned long *) addr;
196890075Sobrien	break;
196990075Sobrien
197090075Sobrien      default:
197190075Sobrien	abort ();
197290075Sobrien      }
197390075Sobrien      break;
197490075Sobrien
197590075Sobrien    case UNW_REG_F2 ... UNW_REG_F31:
197690075Sobrien      context->fr_loc[regno - UNW_REG_F2] = addr;
197790075Sobrien      break;
197890075Sobrien
197990075Sobrien    case UNW_REG_B1 ... UNW_REG_B5:
198090075Sobrien      context->br_loc[regno - UNW_REG_B0] = addr;
198190075Sobrien      break;
198290075Sobrien
198390075Sobrien    case UNW_REG_BSP:
198490075Sobrien      context->bsp_loc = addr;
198590075Sobrien      break;
198690075Sobrien    case UNW_REG_BSPSTORE:
198790075Sobrien      context->bspstore_loc = addr;
198890075Sobrien      break;
198990075Sobrien    case UNW_REG_PFS:
199090075Sobrien      context->pfs_loc = addr;
199190075Sobrien      break;
199290075Sobrien    case UNW_REG_RP:
199390075Sobrien      context->rp = *(unsigned long *)addr;
199490075Sobrien      break;
199590075Sobrien    case UNW_REG_UNAT:
199690075Sobrien      context->unat_loc = addr;
199790075Sobrien      break;
199890075Sobrien    case UNW_REG_PR:
199990075Sobrien      context->pr = *(unsigned long *) addr;
200090075Sobrien      break;
200190075Sobrien    case UNW_REG_LC:
200290075Sobrien      context->lc_loc = addr;
200390075Sobrien      break;
200490075Sobrien    case UNW_REG_FPSR:
200590075Sobrien      context->fpsr_loc = addr;
200690075Sobrien      break;
200790075Sobrien
200890075Sobrien    case UNW_REG_PSP:
200990075Sobrien      context->psp = *(unsigned long *)addr;
201090075Sobrien      break;
201190075Sobrien
201296263Sobrien    default:
201390075Sobrien      abort ();
201490075Sobrien    }
201590075Sobrien}
201690075Sobrien
201790075Sobrienstatic void
201890075Sobrienuw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
201990075Sobrien{
202090075Sobrien  long i;
202190075Sobrien
2022132718Skan#ifdef MD_HANDLE_UNWABI
2023132718Skan  MD_HANDLE_UNWABI (context, fs);
2024132718Skan#endif
2025132718Skan
202690075Sobrien  context->sp = context->psp;
202790075Sobrien
202890075Sobrien  /* First, set PSP.  Subsequent instructions may depend on this value.  */
202990075Sobrien  if (fs->when_target > fs->curr.reg[UNW_REG_PSP].when)
203090075Sobrien    {
203190075Sobrien      if (fs->curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE)
203290075Sobrien	context->psp = context->psp + fs->curr.reg[UNW_REG_PSP].val;
203390075Sobrien      else
203490075Sobrien	uw_update_reg_address (context, fs, UNW_REG_PSP);
203590075Sobrien    }
203690075Sobrien
203790075Sobrien  /* Determine the location of the primary UNaT.  */
203890075Sobrien  {
203990075Sobrien    int i;
204090075Sobrien    if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_GR].when)
204190075Sobrien      i = UNW_REG_PRI_UNAT_MEM;
204290075Sobrien    else if (fs->when_target < fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when)
204390075Sobrien      i = UNW_REG_PRI_UNAT_GR;
204490075Sobrien    else if (fs->curr.reg[UNW_REG_PRI_UNAT_MEM].when
204590075Sobrien	     > fs->curr.reg[UNW_REG_PRI_UNAT_GR].when)
204690075Sobrien      i = UNW_REG_PRI_UNAT_MEM;
204790075Sobrien    else
204890075Sobrien      i = UNW_REG_PRI_UNAT_GR;
204990075Sobrien    uw_update_reg_address (context, fs, i);
205090075Sobrien  }
205190075Sobrien
205290075Sobrien  /* Compute the addresses of all registers saved in this frame.  */
205390075Sobrien  for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i)
205490075Sobrien    uw_update_reg_address (context, fs, i);
205590075Sobrien
205690075Sobrien  /* Unwind BSP for the local registers allocated this frame.  */
205790075Sobrien  /* ??? What to do with stored BSP or BSPSTORE registers.  */
205896263Sobrien  /* We assert that we are either at a call site, or we have
205996263Sobrien     just unwound through a signal frame.  In either case
206096263Sobrien     pfs_loc is valid.	*/
206196263Sobrien  if (!(fs -> no_reg_stack_frame))
206290075Sobrien    {
206390075Sobrien      unsigned long pfs = *context->pfs_loc;
206490075Sobrien      unsigned long sol = (pfs >> 7) & 0x7f;
206590075Sobrien      context->bsp = (unsigned long)
206690075Sobrien	ia64_rse_skip_regs ((unsigned long *) context->bsp, -sol);
206790075Sobrien    }
206890075Sobrien}
206990075Sobrien
2070169689Skanstatic void
2071169689Skanuw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
2072169689Skan{
2073169689Skan  uw_update_context (context, fs);
2074169689Skan}
2075169689Skan
207690075Sobrien/* Fill in CONTEXT for top-of-stack.  The only valid registers at this
207790075Sobrien   level will be the return address and the CFA.  Note that CFA = SP+16.  */
207890075Sobrien
207990075Sobrien#define uw_init_context(CONTEXT)					\
208090075Sobrien  do {									\
208190075Sobrien    /* ??? There is a whole lot o code in uw_install_context that	\
208290075Sobrien       tries to avoid spilling the entire machine state here.  We	\
208390075Sobrien       should try to make that work again.  */				\
208490075Sobrien    __builtin_unwind_init();						\
208590075Sobrien    uw_init_context_1 (CONTEXT, __builtin_ia64_bsp ());			\
208690075Sobrien  } while (0)
208790075Sobrien
208890075Sobrienstatic void
208990075Sobrienuw_init_context_1 (struct _Unwind_Context *context, void *bsp)
209090075Sobrien{
209190075Sobrien  void *rp = __builtin_extract_return_addr (__builtin_return_address (0));
209290075Sobrien  /* Set psp to the caller's stack pointer.  */
209390075Sobrien  void *psp = __builtin_dwarf_cfa () - 16;
209490075Sobrien  _Unwind_FrameState fs;
2095132718Skan  unsigned long rnat, tmp1, tmp2;
209690075Sobrien
2097132718Skan  /* Flush the register stack to memory so that we can access it.
2098132718Skan     Get rse nat collection for the last incomplete rbs chunk of
2099132718Skan     registers at the same time.  For this RSE needs to be turned
2100132718Skan     into the mandatory only mode.  */
2101132718Skan  asm ("mov.m %1 = ar.rsc;;\n\t"
2102132718Skan       "and %2 = 0x1c, %1;;\n\t"
2103132718Skan       "mov.m ar.rsc = %2;;\n\t"
2104132718Skan       "flushrs;;\n\t"
2105132718Skan       "mov.m %0 = ar.rnat;;\n\t"
2106132718Skan       "mov.m ar.rsc = %1\n\t"
2107132718Skan       : "=r" (rnat), "=r" (tmp1), "=r" (tmp2));
210890075Sobrien
210990075Sobrien  memset (context, 0, sizeof (struct _Unwind_Context));
2110132718Skan  context->bsp = (unsigned long) bsp;
2111132718Skan  /* Set context->regstk_top to lowest rbs address which will use
2112132718Skan     context->rnat collection.  */
2113132718Skan  context->regstk_top = context->bsp & ~0x1ffULL;
2114132718Skan  context->rnat = rnat;
211590075Sobrien  context->psp = (unsigned long) psp;
211690075Sobrien  context->rp = (unsigned long) rp;
211790075Sobrien  asm ("mov %0 = sp" : "=r" (context->sp));
211890075Sobrien  asm ("mov %0 = pr" : "=r" (context->pr));
211990075Sobrien  context->pri_unat_loc = &context->initial_unat;	/* ??? */
212090075Sobrien
212190075Sobrien  if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
212290075Sobrien    abort ();
212390075Sobrien
212490075Sobrien  uw_update_context (context, &fs);
212590075Sobrien}
212690075Sobrien
2127169689Skan/* Install (i.e. longjmp to) the contents of TARGET.  */
212890075Sobrien
212990075Sobrienstatic void __attribute__((noreturn))
213090075Sobrienuw_install_context (struct _Unwind_Context *current __attribute__((unused)),
213190075Sobrien		    struct _Unwind_Context *target)
213290075Sobrien{
213390075Sobrien  unsigned long ireg_buf[4], ireg_nat = 0, ireg_pr = 0;
213490075Sobrien  long i;
213590075Sobrien
213690075Sobrien  /* Copy integer register data from the target context to a
213790075Sobrien     temporary buffer.  Do this so that we can frob AR.UNAT
213890075Sobrien     to get the NaT bits for these registers set properly.  */
213990075Sobrien  for (i = 4; i <= 7; ++i)
214090075Sobrien    {
214190075Sobrien      char nat;
214290075Sobrien      void *t = target->ireg[i - 2].loc;
214390075Sobrien      if (t)
214490075Sobrien	{
214590075Sobrien	  unw_access_gr (target, i, &ireg_buf[i - 4], &nat, 0);
214690075Sobrien          ireg_nat |= (long)nat << (((size_t)&ireg_buf[i - 4] >> 3) & 0x3f);
214790075Sobrien	  /* Set p6 - p9.  */
214890075Sobrien	  ireg_pr |= 4L << i;
214990075Sobrien	}
215090075Sobrien    }
215190075Sobrien
215290075Sobrien  /* The value in uc_bsp that we've computed is that for the
215390075Sobrien     target function.  The value that we install below will be
215490075Sobrien     adjusted by the BR.RET instruction based on the contents
215590075Sobrien     of AR.PFS.  So we must unadjust that here.  */
215690075Sobrien  target->bsp = (unsigned long)
215790075Sobrien    ia64_rse_skip_regs ((unsigned long *)target->bsp,
215890075Sobrien			(*target->pfs_loc >> 7) & 0x7f);
215990075Sobrien
2160132718Skan  if (target->bsp < target->regstk_top)
2161132718Skan    target->rnat = *ia64_rse_rnat_addr ((unsigned long *) target->bsp);
2162132718Skan
216390075Sobrien  /* Provide assembly with the offsets into the _Unwind_Context.  */
216490075Sobrien  asm volatile ("uc_rnat = %0"
216590075Sobrien		: : "i"(offsetof (struct _Unwind_Context, rnat)));
216690075Sobrien  asm volatile ("uc_bsp = %0"
216790075Sobrien		: : "i"(offsetof (struct _Unwind_Context, bsp)));
216890075Sobrien  asm volatile ("uc_psp = %0"
216990075Sobrien		: : "i"(offsetof (struct _Unwind_Context, psp)));
217090075Sobrien  asm volatile ("uc_rp = %0"
217190075Sobrien		: : "i"(offsetof (struct _Unwind_Context, rp)));
217290075Sobrien  asm volatile ("uc_pr = %0"
217390075Sobrien		: : "i"(offsetof (struct _Unwind_Context, pr)));
217490075Sobrien  asm volatile ("uc_gp = %0"
217590075Sobrien		: : "i"(offsetof (struct _Unwind_Context, gp)));
217690075Sobrien  asm volatile ("uc_pfs_loc = %0"
217790075Sobrien		: : "i"(offsetof (struct _Unwind_Context, pfs_loc)));
217890075Sobrien  asm volatile ("uc_unat_loc = %0"
217990075Sobrien		: : "i"(offsetof (struct _Unwind_Context, unat_loc)));
218090075Sobrien  asm volatile ("uc_lc_loc = %0"
218190075Sobrien		: : "i"(offsetof (struct _Unwind_Context, lc_loc)));
218290075Sobrien  asm volatile ("uc_fpsr_loc = %0"
218390075Sobrien		: : "i"(offsetof (struct _Unwind_Context, fpsr_loc)));
218490075Sobrien  asm volatile ("uc_eh_data = %0"
218590075Sobrien		: : "i"(offsetof (struct _Unwind_Context, eh_data)));
218690075Sobrien  asm volatile ("uc_br_loc = %0"
218790075Sobrien		: : "i"(offsetof (struct _Unwind_Context, br_loc)));
218890075Sobrien  asm volatile ("uc_fr_loc = %0"
218990075Sobrien		: : "i"(offsetof (struct _Unwind_Context, fr_loc)));
219090075Sobrien
219190075Sobrien  asm volatile (
219290075Sobrien	/* Load up call-saved non-window integer registers from ireg_buf.  */
219390075Sobrien	"add r20 = 8, %1			\n\t"
219490075Sobrien	"mov ar.unat = %2			\n\t"
219590075Sobrien	"mov pr = %3, 0x3c0			\n\t"
219690075Sobrien	";;					\n\t"
219790075Sobrien	"(p6) ld8.fill r4 = [%1]		\n\t"
219890075Sobrien	"(p7) ld8.fill r5 = [r20]		\n\t"
2199132718Skan	"add r21 = uc_br_loc + 16, %0		\n\t"
220090075Sobrien	"adds %1 = 16, %1			\n\t"
220190075Sobrien	"adds r20 = 16, r20			\n\t"
220290075Sobrien	";;					\n\t"
220390075Sobrien	"(p8) ld8.fill r6 = [%1]		\n\t"
220490075Sobrien	"(p9) ld8.fill r7 = [r20]		\n\t"
2205132718Skan	"add r20 = uc_br_loc + 8, %0		\n\t"
220690075Sobrien	";;					\n\t"
220790075Sobrien	/* Load up call-saved branch registers.  */
220890075Sobrien	"ld8 r22 = [r20], 16			\n\t"
220990075Sobrien	"ld8 r23 = [r21], 16			\n\t"
221090075Sobrien	";;					\n\t"
221190075Sobrien	"ld8 r24 = [r20], 16			\n\t"
2212132718Skan	"ld8 r25 = [r21], uc_fr_loc - (uc_br_loc + 32)\n\t"
221390075Sobrien	";;					\n\t"
2214132718Skan	"ld8 r26 = [r20], uc_fr_loc + 8 - (uc_br_loc + 40)\n\t"
221590075Sobrien	"ld8 r27 = [r21], 24			\n\t"
221690075Sobrien	"cmp.ne p6, p0 = r0, r22		\n\t"
221790075Sobrien	";;					\n\t"
221890075Sobrien	"ld8 r28 = [r20], 8			\n\t"
221990075Sobrien	"(p6) ld8 r22 = [r22]			\n\t"
222090075Sobrien	"cmp.ne p7, p0 = r0, r23		\n\t"
222190075Sobrien	";;					\n\t"
222290075Sobrien	"(p7) ld8 r23 = [r23]			\n\t"
222390075Sobrien	"cmp.ne p8, p0 = r0, r24		\n\t"
222490075Sobrien	";;					\n\t"
222590075Sobrien	"(p8) ld8 r24 = [r24]			\n\t"
222690075Sobrien	"(p6) mov b1 = r22			\n\t"
222790075Sobrien	"cmp.ne p9, p0 = r0, r25		\n\t"
222890075Sobrien	";;					\n\t"
222990075Sobrien	"(p9) ld8 r25 = [r25]			\n\t"
223090075Sobrien	"(p7) mov b2 = r23			\n\t"
223190075Sobrien	"cmp.ne p6, p0 = r0, r26		\n\t"
223290075Sobrien	";;					\n\t"
223390075Sobrien	"(p6) ld8 r26 = [r26]			\n\t"
223490075Sobrien	"(p8) mov b3 = r24			\n\t"
223590075Sobrien	"cmp.ne p7, p0 = r0, r27		\n\t"
223690075Sobrien	";;					\n\t"
223790075Sobrien	/* Load up call-saved fp registers.  */
223890075Sobrien	"(p7) ldf.fill f2 = [r27]		\n\t"
223990075Sobrien	"(p9) mov b4 = r25			\n\t"
224090075Sobrien	"cmp.ne p8, p0 = r0, r28		\n\t"
224190075Sobrien	";;					\n\t"
224290075Sobrien	"(p8) ldf.fill f3 = [r28]		\n\t"
224390075Sobrien	"(p6) mov b5 = r26			\n\t"
224490075Sobrien	";;					\n\t"
224590075Sobrien	"ld8 r29 = [r20], 16*8 - 4*8		\n\t"
224690075Sobrien	"ld8 r30 = [r21], 17*8 - 5*8		\n\t"
224790075Sobrien	";;					\n\t"
224890075Sobrien	"ld8 r22 = [r20], 16			\n\t"
224990075Sobrien	"ld8 r23 = [r21], 16			\n\t"
225090075Sobrien	";;					\n\t"
225190075Sobrien	"ld8 r24 = [r20], 16			\n\t"
225290075Sobrien	"ld8 r25 = [r21]			\n\t"
225390075Sobrien	"cmp.ne p6, p0 = r0, r29		\n\t"
225490075Sobrien	";;					\n\t"
225590075Sobrien	"ld8 r26 = [r20], 8			\n\t"
225690075Sobrien	"(p6) ldf.fill f4 = [r29]		\n\t"
225790075Sobrien	"cmp.ne p7, p0 = r0, r30		\n\t"
225890075Sobrien	";;					\n\t"
225990075Sobrien	"ld8 r27 = [r20], 8			\n\t"
226090075Sobrien	"(p7) ldf.fill f5 = [r30]		\n\t"
226190075Sobrien	"cmp.ne p6, p0 = r0, r22		\n\t"
226290075Sobrien	";;					\n\t"
226390075Sobrien	"ld8 r28 = [r20], 8			\n\t"
226490075Sobrien	"(p6) ldf.fill f16 = [r22]		\n\t"
226590075Sobrien	"cmp.ne p7, p0 = r0, r23		\n\t"
226690075Sobrien	";;					\n\t"
226790075Sobrien	"ld8 r29 = [r20], 8			\n\t"
226890075Sobrien	"(p7) ldf.fill f17 = [r23]		\n\t"
226990075Sobrien	"cmp.ne p6, p0 = r0, r24		\n\t"
227090075Sobrien	";;					\n\t"
227190075Sobrien	"ld8 r22 = [r20], 8			\n\t"
227290075Sobrien	"(p6) ldf.fill f18 = [r24]		\n\t"
227390075Sobrien	"cmp.ne p7, p0 = r0, r25		\n\t"
227490075Sobrien	";;					\n\t"
227590075Sobrien	"ld8 r23 = [r20], 8			\n\t"
227690075Sobrien	"(p7) ldf.fill f19 = [r25]		\n\t"
227790075Sobrien	"cmp.ne p6, p0 = r0, r26		\n\t"
227890075Sobrien	";;					\n\t"
227990075Sobrien	"ld8 r24 = [r20], 8			\n\t"
228090075Sobrien	"(p6) ldf.fill f20 = [r26]		\n\t"
228190075Sobrien	"cmp.ne p7, p0 = r0, r27		\n\t"
228290075Sobrien	";;					\n\t"
228390075Sobrien	"ld8 r25 = [r20], 8			\n\t"
228490075Sobrien	"(p7) ldf.fill f21 = [r27]		\n\t"
228590075Sobrien	"cmp.ne p6, p0 = r0, r28		\n\t"
228690075Sobrien	";;					\n\t"
228790075Sobrien	"ld8 r26 = [r20], 8			\n\t"
228890075Sobrien	"(p6) ldf.fill f22 = [r28]		\n\t"
228990075Sobrien	"cmp.ne p7, p0 = r0, r29		\n\t"
229090075Sobrien	";;					\n\t"
2291146895Skan	"ld8 r27 = [r20], 8			\n\t"
2292146895Skan	";;					\n\t"
229390075Sobrien	"ld8 r28 = [r20], 8			\n\t"
229490075Sobrien	"(p7) ldf.fill f23 = [r29]		\n\t"
229590075Sobrien	"cmp.ne p6, p0 = r0, r22		\n\t"
229690075Sobrien	";;					\n\t"
229790075Sobrien	"ld8 r29 = [r20], 8			\n\t"
229890075Sobrien	"(p6) ldf.fill f24 = [r22]		\n\t"
229990075Sobrien	"cmp.ne p7, p0 = r0, r23		\n\t"
230090075Sobrien	";;					\n\t"
230190075Sobrien	"(p7) ldf.fill f25 = [r23]		\n\t"
230290075Sobrien	"cmp.ne p6, p0 = r0, r24		\n\t"
230390075Sobrien	"cmp.ne p7, p0 = r0, r25		\n\t"
230490075Sobrien	";;					\n\t"
230590075Sobrien	"(p6) ldf.fill f26 = [r24]		\n\t"
230690075Sobrien	"(p7) ldf.fill f27 = [r25]		\n\t"
230790075Sobrien	"cmp.ne p6, p0 = r0, r26		\n\t"
230890075Sobrien	";;					\n\t"
230990075Sobrien	"(p6) ldf.fill f28 = [r26]		\n\t"
231090075Sobrien	"cmp.ne p7, p0 = r0, r27		\n\t"
231190075Sobrien	"cmp.ne p6, p0 = r0, r28		\n\t"
231290075Sobrien	";;					\n\t"
231390075Sobrien	"(p7) ldf.fill f29 = [r27]		\n\t"
231490075Sobrien	"(p6) ldf.fill f30 = [r28]		\n\t"
231590075Sobrien	"cmp.ne p7, p0 = r0, r29		\n\t"
231690075Sobrien	";;					\n\t"
231790075Sobrien	"(p7) ldf.fill f31 = [r29]		\n\t"
231890075Sobrien	"add r20 = uc_rnat, %0			\n\t"
231990075Sobrien	"add r21 = uc_bsp, %0			\n\t"
232090075Sobrien	";;					\n\t"
232190075Sobrien	/* Load the balance of the thread state from the context.  */
232290075Sobrien	"ld8 r22 = [r20], uc_psp - uc_rnat	\n\t"
232390075Sobrien	"ld8 r23 = [r21], uc_gp - uc_bsp	\n\t"
232490075Sobrien	";;					\n\t"
232590075Sobrien	"ld8 r24 = [r20], uc_pfs_loc - uc_psp	\n\t"
232690075Sobrien	"ld8 r1 = [r21], uc_rp - uc_gp		\n\t"
232790075Sobrien	";;					\n\t"
232890075Sobrien	"ld8 r25 = [r20], uc_unat_loc - uc_pfs_loc\n\t"
232990075Sobrien	"ld8 r26 = [r21], uc_pr - uc_rp		\n\t"
233090075Sobrien	";;					\n\t"
233190075Sobrien	"ld8 r27 = [r20], uc_lc_loc - uc_unat_loc\n\t"
233290075Sobrien	"ld8 r28 = [r21], uc_fpsr_loc - uc_pr	\n\t"
233390075Sobrien	";;					\n\t"
233490075Sobrien	"ld8 r29 = [r20], uc_eh_data - uc_lc_loc\n\t"
233590075Sobrien	"ld8 r30 = [r21], uc_eh_data + 8 - uc_fpsr_loc\n\t"
233690075Sobrien	";;					\n\t"
233790075Sobrien	/* Load data for the exception handler.  */
233890075Sobrien	"ld8 r15 = [r20], 16			\n\t"
233990075Sobrien	"ld8 r16 = [r21], 16			\n\t"
234090075Sobrien	";;					\n\t"
234190075Sobrien	"ld8 r17 = [r20]			\n\t"
234290075Sobrien	"ld8 r18 = [r21]			\n\t"
234390075Sobrien	";;					\n\t"
234490075Sobrien	/* Install the balance of the thread state loaded above.  */
234590075Sobrien	"cmp.ne p6, p0 = r0, r25		\n\t"
234690075Sobrien	"cmp.ne p7, p0 = r0, r27		\n\t"
234790075Sobrien	";;					\n\t"
234890075Sobrien	"(p6) ld8 r25 = [r25]			\n\t"
234990075Sobrien	"(p7) ld8 r27 = [r27]			\n\t"
235090075Sobrien	";;					\n\t"
235190075Sobrien	"(p7) mov.m ar.unat = r27		\n\t"
235290075Sobrien	"(p6) mov.i ar.pfs = r25		\n\t"
235390075Sobrien	"cmp.ne p9, p0 = r0, r29		\n\t"
235490075Sobrien	";;					\n\t"
235590075Sobrien	"(p9) ld8 r29 = [r29]			\n\t"
235690075Sobrien	"cmp.ne p6, p0 = r0, r30		\n\t"
235790075Sobrien	";;					\n\t"
235890075Sobrien	"(p6) ld8 r30 = [r30]			\n\t"
235990075Sobrien	/* Don't clobber p6-p9, which are in use at present.  */
236090075Sobrien	"mov pr = r28, ~0x3c0			\n\t"
236190075Sobrien	"(p9) mov.i ar.lc = r29			\n\t"
236290075Sobrien	";;					\n\t"
236390075Sobrien	"mov.m r25 = ar.rsc			\n\t"
2364132718Skan	"(p6) mov.m ar.fpsr = r30		\n\t"
236590075Sobrien	";;					\n\t"
2366132718Skan	"and r29 = 0x1c, r25			\n\t"
236790075Sobrien	"mov b0 = r26				\n\t"
236890075Sobrien	";;					\n\t"
2369132718Skan	"mov.m ar.rsc = r29			\n\t"
237090075Sobrien	";;					\n\t"
237190075Sobrien	/* This must be done before setting AR.BSPSTORE, otherwise
237290075Sobrien	   AR.BSP will be initialized with a random displacement
237390075Sobrien	   below the value we want, based on the current number of
237490075Sobrien	   dirty stacked registers.  */
237590075Sobrien	"loadrs					\n\t"
237690075Sobrien	"invala					\n\t"
237790075Sobrien	";;					\n\t"
237890075Sobrien	"mov.m ar.bspstore = r23		\n\t"
237990075Sobrien	";;					\n\t"
238090075Sobrien	"mov.m ar.rnat = r22			\n\t"
238190075Sobrien	";;					\n\t"
238290075Sobrien	"mov.m ar.rsc = r25			\n\t"
238390075Sobrien	"mov sp = r24				\n\t"
238490075Sobrien	"br.ret.sptk.few b0"
238590075Sobrien	: : "r"(target), "r"(ireg_buf), "r"(ireg_nat), "r"(ireg_pr)
238690075Sobrien	: "r15", "r16", "r17", "r18", "r20", "r21", "r22",
238790075Sobrien	  "r23", "r24", "r25", "r26", "r27", "r28", "r29",
238890075Sobrien	  "r30", "r31");
238990075Sobrien  /* NOTREACHED */
239090075Sobrien  while (1);
239190075Sobrien}
239290075Sobrien
239390075Sobrienstatic inline _Unwind_Ptr
239490075Sobrienuw_identify_context (struct _Unwind_Context *context)
239590075Sobrien{
239690075Sobrien  return _Unwind_GetIP (context);
239790075Sobrien}
239890075Sobrien
239990075Sobrien#include "unwind.inc"
2400146895Skan
2401146895Skan#if defined (USE_GAS_SYMVER) && defined (SHARED) && defined (USE_LIBUNWIND_EXCEPTIONS)
2402146895Skanalias (_Unwind_Backtrace);
2403146895Skanalias (_Unwind_DeleteException);
2404146895Skanalias (_Unwind_FindEnclosingFunction);
2405146895Skanalias (_Unwind_ForcedUnwind);
2406146895Skanalias (_Unwind_GetBSP);
2407146895Skanalias (_Unwind_GetCFA);
2408146895Skanalias (_Unwind_GetGR);
2409146895Skanalias (_Unwind_GetIP);
2410146895Skanalias (_Unwind_GetLanguageSpecificData);
2411146895Skanalias (_Unwind_GetRegionStart);
2412146895Skanalias (_Unwind_RaiseException);
2413146895Skanalias (_Unwind_Resume);
2414146895Skanalias (_Unwind_Resume_or_Rethrow);
2415146895Skanalias (_Unwind_SetGR);
2416146895Skanalias (_Unwind_SetIP);
241790075Sobrien#endif
2418146895Skan
2419146895Skan#endif
2420