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 (®s[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