Home | History | Annotate | Download | only in ia64
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2001-2005 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com>
      4 
      5 This file is part of libunwind.
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining
      8 a copy of this software and associated documentation files (the
      9 "Software"), to deal in the Software without restriction, including
     10 without limitation the rights to use, copy, modify, merge, publish,
     11 distribute, sublicense, and/or sell copies of the Software, and to
     12 permit persons to whom the Software is furnished to do so, subject to
     13 the following conditions:
     14 
     15 The above copyright notice and this permission notice shall be
     16 included in all copies or substantial portions of the Software.
     17 
     18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     25 
     26 #include "offsets.h"
     27 #include "regs.h"
     28 #include "unwind_i.h"
     29 
     30 enum ia64_script_insn_opcode
     31   {
     32     IA64_INSN_INC_PSP,		/* psp += val */
     33     IA64_INSN_LOAD_PSP,		/* psp = *psp_loc */
     34     IA64_INSN_ADD_PSP,		/* s[dst] = (s.psp + val) */
     35     IA64_INSN_ADD_PSP_NAT,	/* like above, but with NaT info */
     36     IA64_INSN_ADD_SP,		/* s[dst] = (s.sp + val) */
     37     IA64_INSN_ADD_SP_NAT,	/* like above, but with NaT info */
     38     IA64_INSN_MOVE,		/* s[dst] = s[val] */
     39     IA64_INSN_MOVE_NAT,		/* like above, but with NaT info */
     40     IA64_INSN_MOVE_NO_NAT,	/* like above, but clear NaT info */
     41     IA64_INSN_MOVE_STACKED,	/* s[dst] = rse_skip(*s.bsp_loc, val) */
     42     IA64_INSN_MOVE_STACKED_NAT,	/* like above, but with NaT info */
     43     IA64_INSN_MOVE_SCRATCH,	/* s[dst] = scratch reg "val" */
     44     IA64_INSN_MOVE_SCRATCH_NAT,	/* like above, but with NaT info */
     45     IA64_INSN_MOVE_SCRATCH_NO_NAT /* like above, but clear NaT info */
     46   };
     47 
     48 #ifdef HAVE___THREAD
     49 static __thread struct ia64_script_cache ia64_per_thread_cache =
     50   {
     51 #ifdef HAVE_ATOMIC_OPS_H
     52     .busy = AO_TS_INITIALIZER
     53 #else
     54     .lock = PTHREAD_MUTEX_INITIALIZER
     55 #endif
     56   };
     57 #endif
     58 
     59 static inline unw_hash_index_t CONST_ATTR
     60 hash (unw_word_t ip)
     61 {
     62   /* based on (sqrt(5)/2-1)*2^64 */
     63 # define magic	((unw_word_t) 0x9e3779b97f4a7c16ULL)
     64 
     65   return (ip >> 4) * magic >> (64 - IA64_LOG_UNW_HASH_SIZE);
     66 }
     67 
     68 static inline long
     69 cache_match (struct ia64_script *script, unw_word_t ip, unw_word_t pr)
     70 {
     71   if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0)
     72     return 1;
     73   return 0;
     74 }
     75 
     76 static inline void
     77 flush_script_cache (struct ia64_script_cache *cache)
     78 {
     79   int i;
     80 
     81   cache->lru_head = IA64_UNW_CACHE_SIZE - 1;
     82   cache->lru_tail = 0;
     83 
     84   for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i)
     85     {
     86       if (i > 0)
     87 	cache->buckets[i].lru_chain = (i - 1);
     88       cache->buckets[i].coll_chain = -1;
     89       cache->buckets[i].ip = 0;
     90     }
     91   for (i = 0; i<IA64_UNW_HASH_SIZE; ++i)
     92     cache->hash[i] = -1;
     93 }
     94 
     95 static inline struct ia64_script_cache *
     96 get_script_cache (unw_addr_space_t as, intrmask_t *saved_maskp)
     97 {
     98   struct ia64_script_cache *cache = &as->global_cache;
     99   unw_caching_policy_t caching = as->caching_policy;
    100 
    101   if (caching == UNW_CACHE_NONE)
    102     return NULL;
    103 
    104 #ifdef HAVE_ATOMIC_H
    105   if (!spin_trylock_irqsave (&cache->busy, *saved_maskp))
    106     return NULL;
    107 #else
    108 # ifdef HAVE___THREAD
    109   if (as->caching_policy == UNW_CACHE_PER_THREAD)
    110     cache = &ia64_per_thread_cache;
    111 # endif
    112 # ifdef HAVE_ATOMIC_OPS_H
    113   if (AO_test_and_set (&cache->busy) == AO_TS_SET)
    114     return NULL;
    115 # else
    116   if (likely (caching == UNW_CACHE_GLOBAL))
    117     {
    118       Debug (16, "acquiring lock\n");
    119       lock_acquire (&cache->lock, *saved_maskp);
    120     }
    121 # endif
    122 #endif
    123 
    124   if (atomic_read (&as->cache_generation) != atomic_read (&cache->generation))
    125     {
    126       flush_script_cache (cache);
    127       cache->generation = as->cache_generation;
    128     }
    129   return cache;
    130 }
    131 
    132 static inline void
    133 put_script_cache (unw_addr_space_t as, struct ia64_script_cache *cache,
    134 		  intrmask_t *saved_maskp)
    135 {
    136   assert (as->caching_policy != UNW_CACHE_NONE);
    137 
    138   Debug (16, "unmasking signals/interrupts and releasing lock\n");
    139 #ifdef HAVE_ATOMIC_H
    140   spin_unlock_irqrestore (&cache->busy, *saved_maskp);
    141 #else
    142 # ifdef HAVE_ATOMIC_OPS_H
    143   AO_CLEAR (&cache->busy);
    144 # else
    145   if (likely (as->caching_policy == UNW_CACHE_GLOBAL))
    146     lock_release (&cache->lock, *saved_maskp);
    147 # endif
    148 #endif
    149 }
    150 
    151 static struct ia64_script *
    152 script_lookup (struct ia64_script_cache *cache, struct cursor *c)
    153 {
    154   struct ia64_script *script = cache->buckets + c->hint;
    155   unsigned short index;
    156   unw_word_t ip, pr;
    157 
    158   ip = c->ip;
    159   pr = c->pr;
    160 
    161   if (cache_match (script, ip, pr))
    162     return script;
    163 
    164   index = cache->hash[hash (ip)];
    165   if (index >= IA64_UNW_CACHE_SIZE)
    166     return 0;
    167 
    168   script = cache->buckets + index;
    169   while (1)
    170     {
    171       if (cache_match (script, ip, pr))
    172 	{
    173 	  /* update hint; no locking needed: single-word writes are atomic */
    174 	  c->hint = cache->buckets[c->prev_script].hint =
    175 	    (script - cache->buckets);
    176 	  return script;
    177 	}
    178       if (script->coll_chain >= IA64_UNW_HASH_SIZE)
    179 	return 0;
    180       script = cache->buckets + script->coll_chain;
    181     }
    182 }
    183 
    184 static inline void
    185 script_init (struct ia64_script *script, unw_word_t ip)
    186 {
    187   script->ip = ip;
    188   script->hint = 0;
    189   script->count = 0;
    190   script->abi_marker = 0;
    191 }
    192 
    193 static inline struct ia64_script *
    194 script_new (struct ia64_script_cache *cache, unw_word_t ip)
    195 {
    196   struct ia64_script *script, *prev, *tmp;
    197   unw_hash_index_t index;
    198   unsigned short head;
    199 
    200   head = cache->lru_head;
    201   script = cache->buckets + head;
    202   cache->lru_head = script->lru_chain;
    203 
    204   /* re-insert script at the tail of the LRU chain: */
    205   cache->buckets[cache->lru_tail].lru_chain = head;
    206   cache->lru_tail = head;
    207 
    208   /* remove the old script from the hash table (if it's there): */
    209   if (script->ip)
    210     {
    211       index = hash (script->ip);
    212       tmp = cache->buckets + cache->hash[index];
    213       prev = 0;
    214       while (1)
    215 	{
    216 	  if (tmp == script)
    217 	    {
    218 	      if (prev)
    219 		prev->coll_chain = tmp->coll_chain;
    220 	      else
    221 		cache->hash[index] = tmp->coll_chain;
    222 	      break;
    223 	    }
    224 	  else
    225 	    prev = tmp;
    226 	  if (tmp->coll_chain >= IA64_UNW_CACHE_SIZE)
    227 	    /* old script wasn't in the hash-table */
    228 	    break;
    229 	  tmp = cache->buckets + tmp->coll_chain;
    230 	}
    231     }
    232 
    233   /* enter new script in the hash table */
    234   index = hash (ip);
    235   script->coll_chain = cache->hash[index];
    236   cache->hash[index] = script - cache->buckets;
    237 
    238   script_init (script, ip);
    239   return script;
    240 }
    241 
    242 static inline void
    243 script_finalize (struct ia64_script *script, struct cursor *c,
    244 		 struct ia64_state_record *sr)
    245 {
    246   script->pr_mask = sr->pr_mask;
    247   script->pr_val = sr->pr_val;
    248   script->pi = c->pi;
    249 }
    250 
    251 static inline void
    252 script_emit (struct ia64_script *script, struct ia64_script_insn insn)
    253 {
    254   if (script->count >= IA64_MAX_SCRIPT_LEN)
    255     {
    256       Dprintf ("%s: script exceeds maximum size of %u instructions!\n",
    257 	       __FUNCTION__, IA64_MAX_SCRIPT_LEN);
    258       return;
    259     }
    260   script->insn[script->count++] = insn;
    261 }
    262 
    263 static void
    264 compile_reg (struct ia64_state_record *sr, int i, struct ia64_reg_info *r,
    265 	     struct ia64_script *script)
    266 {
    267   enum ia64_script_insn_opcode opc;
    268   unsigned long val, rval;
    269   struct ia64_script_insn insn;
    270   long is_preserved_gr;
    271 
    272   if (r->where == IA64_WHERE_NONE || r->when >= sr->when_target)
    273     return;
    274 
    275   opc = IA64_INSN_MOVE;
    276   val = rval = r->val;
    277   is_preserved_gr = (i >= IA64_REG_R4 && i <= IA64_REG_R7);
    278 
    279   if (r->where == IA64_WHERE_GR)
    280     {
    281       /* Handle most common case first... */
    282       if (rval >= 32)
    283 	{
    284 	  /* register got spilled to a stacked register */
    285 	  if (is_preserved_gr)
    286 	    opc = IA64_INSN_MOVE_STACKED_NAT;
    287 	  else
    288 	    opc = IA64_INSN_MOVE_STACKED;
    289 	  val = rval;
    290 	}
    291       else if (rval >= 4 && rval <= 7)
    292 	{
    293 	  /* register got spilled to a preserved register */
    294 	  val = IA64_REG_R4 + (rval - 4);
    295 	  if (is_preserved_gr)
    296 	    opc = IA64_INSN_MOVE_NAT;
    297 	}
    298       else
    299 	{
    300 	  /* register got spilled to a scratch register */
    301 	  if (is_preserved_gr)
    302 	    opc = IA64_INSN_MOVE_SCRATCH_NAT;
    303 	  else
    304 	    opc = IA64_INSN_MOVE_SCRATCH;
    305 	  val = UNW_IA64_GR + rval;
    306 	}
    307     }
    308   else
    309     {
    310       switch (r->where)
    311 	{
    312 	case IA64_WHERE_FR:
    313 	  /* Note: There is no need to handle NaT-bit info here
    314 	     (indepent of is_preserved_gr), because for floating-point
    315 	     NaTs are represented as NaTVal, so the NaT-info never
    316 	     needs to be consulated.  */
    317 	  if (rval >= 2 && rval <= 5)
    318 	    val = IA64_REG_F2 + (rval - 2);
    319 	  else if (rval >= 16 && rval <= 31)
    320 	    val = IA64_REG_F16 + (rval - 16);
    321 	  else
    322 	    {
    323 	      opc = IA64_INSN_MOVE_SCRATCH;
    324 	      val = UNW_IA64_FR + rval;
    325 	    }
    326 	  break;
    327 
    328 	case IA64_WHERE_BR:
    329 	  if (rval >= 1 && rval <= 5)
    330 	    {
    331 	      val = IA64_REG_B1 + (rval - 1);
    332 	      if (is_preserved_gr)
    333 		opc = IA64_INSN_MOVE_NO_NAT;
    334 	    }
    335 	  else
    336 	    {
    337 	      opc = IA64_INSN_MOVE_SCRATCH;
    338 	      if (is_preserved_gr)
    339 		opc = IA64_INSN_MOVE_SCRATCH_NO_NAT;
    340 	      val = UNW_IA64_BR + rval;
    341 	    }
    342 	  break;
    343 
    344 	case IA64_WHERE_SPREL:
    345 	  if (is_preserved_gr)
    346 	    opc = IA64_INSN_ADD_SP_NAT;
    347 	  else
    348 	    {
    349 	      opc = IA64_INSN_ADD_SP;
    350 	      if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
    351 		val |= IA64_LOC_TYPE_FP;
    352 	    }
    353 	  break;
    354 
    355 	case IA64_WHERE_PSPREL:
    356 	  if (is_preserved_gr)
    357 	    opc = IA64_INSN_ADD_PSP_NAT;
    358 	  else
    359 	    {
    360 	      opc = IA64_INSN_ADD_PSP;
    361 	      if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
    362 		val |= IA64_LOC_TYPE_FP;
    363 	    }
    364 	  break;
    365 
    366 	default:
    367 	  Dprintf ("%s: register %u has unexpected `where' value of %u\n",
    368 		   __FUNCTION__, i, r->where);
    369 	  break;
    370 	}
    371     }
    372   insn.opc = opc;
    373   insn.dst = i;
    374   insn.val = val;
    375   script_emit (script, insn);
    376 
    377   if (i == IA64_REG_PSP)
    378     {
    379       /* c->psp must contain the _value_ of the previous sp, not it's
    380 	 save-location.  We get this by dereferencing the value we
    381 	 just stored in loc[IA64_REG_PSP]: */
    382       insn.opc = IA64_INSN_LOAD_PSP;
    383       script_emit (script, insn);
    384     }
    385 }
    386 
    387 /* Sort the registers which got saved in decreasing order of WHEN
    388    value.  This is needed to ensure that the save-locations are
    389    updated in the proper order.  For example, suppose r4 gets spilled
    390    to memory and then r5 gets saved in r4.  In this case, we need to
    391    update the save location of r5 before the one of r4.  */
    392 
    393 static inline int
    394 sort_regs (struct ia64_state_record *sr, int regorder[])
    395 {
    396   int r, i, j, max, max_reg, max_when, num_regs = 0;
    397 
    398   assert (IA64_REG_BSP == 3);
    399 
    400   for (r = IA64_REG_BSP; r < IA64_NUM_PREGS; ++r)
    401     {
    402       if (sr->curr.reg[r].where == IA64_WHERE_NONE
    403 	  || sr->curr.reg[r].when >= sr->when_target)
    404 	continue;
    405 
    406       regorder[num_regs++] = r;
    407     }
    408 
    409   /* Simple insertion-sort.  Involves about N^2/2 comparisons and N
    410      exchanges.  N is often small (say, 2-5) so a fancier sorting
    411      algorithm may not be worthwhile.  */
    412 
    413   for (i = max = 0; i < num_regs - 1; ++i)
    414     {
    415       max_reg = regorder[max];
    416       max_when = sr->curr.reg[max_reg].when;
    417 
    418       for (j = i + 1; j < num_regs; ++j)
    419 	if (sr->curr.reg[regorder[j]].when > max_when)
    420 	  {
    421 	    max = j;
    422 	    max_reg = regorder[j];
    423 	    max_when = sr->curr.reg[max_reg].when;
    424 	  }
    425       if (i != max)
    426 	{
    427 	  regorder[max] = regorder[i];
    428 	  regorder[i] = max_reg;
    429 	}
    430     }
    431   return num_regs;
    432 }
    433 
    434 /* Build an unwind script that unwinds from state OLD_STATE to the
    435    entrypoint of the function that called OLD_STATE.  */
    436 
    437 static inline int
    438 build_script (struct cursor *c, struct ia64_script *script)
    439 {
    440   int num_regs, i, ret, regorder[IA64_NUM_PREGS - 3];
    441   struct ia64_reg_info *pri_unat;
    442   struct ia64_state_record sr;
    443   struct ia64_script_insn insn;
    444 
    445   ret = ia64_create_state_record (c, &sr);
    446   if (ret < 0)
    447     return ret;
    448 
    449   /* First, compile the update for IA64_REG_PSP.  This is important
    450      because later save-locations may depend on it's correct (updated)
    451      value.  Fixed-size frames are handled specially and variable-size
    452      frames get handled via the normal compile_reg().  */
    453 
    454   if (sr.when_target > sr.curr.reg[IA64_REG_PSP].when
    455       && (sr.curr.reg[IA64_REG_PSP].where == IA64_WHERE_NONE)
    456       && sr.curr.reg[IA64_REG_PSP].val != 0)
    457     {
    458       /* new psp is psp plus frame size */
    459       insn.opc = IA64_INSN_INC_PSP;
    460       insn.val = sr.curr.reg[IA64_REG_PSP].val;	/* frame size */
    461       script_emit (script, insn);
    462     }
    463   else
    464     compile_reg (&sr, IA64_REG_PSP, sr.curr.reg + IA64_REG_PSP, script);
    465 
    466   /* Second, compile the update for the primary UNaT, if any: */
    467 
    468   if (sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_GR].when
    469       || sr.when_target >= sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
    470     {
    471       if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
    472 	/* (primary) NaT bits were saved to memory only */
    473 	pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM;
    474       else if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
    475 	/* (primary) NaT bits were saved to a register only */
    476 	pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR;
    477       else if (sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when >
    478 	       sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
    479 	/* (primary) NaT bits were last saved to memory */
    480 	pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_MEM;
    481       else
    482 	/* (primary) NaT bits were last saved to a register */
    483 	pri_unat = sr.curr.reg + IA64_REG_PRI_UNAT_GR;
    484 
    485       /* Note: we always store the final primary-UNaT location in UNAT_MEM.  */
    486       compile_reg (&sr, IA64_REG_PRI_UNAT_MEM, pri_unat, script);
    487     }
    488 
    489   /* Third, compile the other register in decreasing order of WHEN values.  */
    490 
    491   num_regs = sort_regs (&sr, regorder);
    492   for (i = 0; i < num_regs; ++i)
    493     compile_reg (&sr, regorder[i], sr.curr.reg + regorder[i], script);
    494 
    495   script->abi_marker = sr.abi_marker;
    496   script_finalize (script, c, &sr);
    497 
    498   ia64_free_state_record (&sr);
    499   return 0;
    500 }
    501 
    502 static inline void
    503 set_nat_info (struct cursor *c, unsigned long dst,
    504 	      ia64_loc_t nat_loc, uint8_t bitnr)
    505 {
    506   assert (dst >= IA64_REG_R4 && dst <= IA64_REG_R7);
    507 
    508   c->loc[dst - IA64_REG_R4 + IA64_REG_NAT4] = nat_loc;
    509   c->nat_bitnr[dst - IA64_REG_R4] = bitnr;
    510 }
    511 
    512 /* Apply the unwinding actions represented by OPS and update SR to
    513    reflect the state that existed upon entry to the function that this
    514    unwinder represents.  */
    515 
    516 static inline int
    517 run_script (struct ia64_script *script, struct cursor *c)
    518 {
    519   struct ia64_script_insn *ip, *limit, next_insn;
    520   ia64_loc_t loc, nat_loc;
    521   unsigned long opc, dst;
    522   uint8_t nat_bitnr;
    523   unw_word_t val;
    524   int ret;
    525 
    526   c->pi = script->pi;
    527   ip = script->insn;
    528   limit = script->insn + script->count;
    529   next_insn = *ip;
    530   c->abi_marker = script->abi_marker;
    531 
    532   while (ip++ < limit)
    533     {
    534       opc = next_insn.opc;
    535       dst = next_insn.dst;
    536       val = next_insn.val;
    537       next_insn = *ip;
    538 
    539       /* This is by far the most common operation: */
    540       if (likely (opc == IA64_INSN_MOVE_STACKED))
    541 	{
    542 	  if ((ret = ia64_get_stacked (c, val, &loc, NULL)) < 0)
    543 	    return ret;
    544 	}
    545       else
    546 	switch (opc)
    547 	  {
    548 	  case IA64_INSN_INC_PSP:
    549 	    c->psp += val;
    550 	    continue;
    551 
    552 	  case IA64_INSN_LOAD_PSP:
    553 	    if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0)
    554 	      return ret;
    555 	    continue;
    556 
    557 	  case IA64_INSN_ADD_PSP:
    558 	    loc = IA64_LOC_ADDR (c->psp + val, (val & IA64_LOC_TYPE_FP));
    559 	    break;
    560 
    561 	  case IA64_INSN_ADD_SP:
    562 	    loc = IA64_LOC_ADDR (c->sp + val, (val & IA64_LOC_TYPE_FP));
    563 	    break;
    564 
    565 	  case IA64_INSN_MOVE_NO_NAT:
    566 	    set_nat_info (c, dst, IA64_NULL_LOC, 0);
    567 	  case IA64_INSN_MOVE:
    568 	    loc = c->loc[val];
    569 	    break;
    570 
    571 	  case IA64_INSN_MOVE_SCRATCH_NO_NAT:
    572 	    set_nat_info (c, dst, IA64_NULL_LOC, 0);
    573 	  case IA64_INSN_MOVE_SCRATCH:
    574 	    loc = ia64_scratch_loc (c, val, NULL);
    575 	    break;
    576 
    577 	  case IA64_INSN_ADD_PSP_NAT:
    578 	    loc = IA64_LOC_ADDR (c->psp + val, 0);
    579 	    assert (!IA64_IS_REG_LOC (loc));
    580 	    set_nat_info (c, dst,
    581 			  c->loc[IA64_REG_PRI_UNAT_MEM],
    582 			  ia64_unat_slot_num (IA64_GET_ADDR (loc)));
    583 	    break;
    584 
    585 	  case IA64_INSN_ADD_SP_NAT:
    586 	    loc = IA64_LOC_ADDR (c->sp + val, 0);
    587 	    assert (!IA64_IS_REG_LOC (loc));
    588 	    set_nat_info (c, dst,
    589 			  c->loc[IA64_REG_PRI_UNAT_MEM],
    590 			  ia64_unat_slot_num (IA64_GET_ADDR (loc)));
    591 	    break;
    592 
    593 	  case IA64_INSN_MOVE_NAT:
    594 	    loc = c->loc[val];
    595 	    set_nat_info (c, dst,
    596 			  c->loc[val - IA64_REG_R4 + IA64_REG_NAT4],
    597 			  c->nat_bitnr[val - IA64_REG_R4]);
    598 	    break;
    599 
    600 	  case IA64_INSN_MOVE_STACKED_NAT:
    601 	    if ((ret = ia64_get_stacked (c, val, &loc, &nat_loc)) < 0)
    602 	      return ret;
    603 	    assert (!IA64_IS_REG_LOC (loc));
    604 	    set_nat_info (c, dst, nat_loc, rse_slot_num (IA64_GET_ADDR (loc)));
    605 	    break;
    606 
    607 	  case IA64_INSN_MOVE_SCRATCH_NAT:
    608 	    loc = ia64_scratch_loc (c, val, NULL);
    609 	    nat_loc = ia64_scratch_loc (c, val + (UNW_IA64_NAT - UNW_IA64_GR),
    610 					&nat_bitnr);
    611 	    set_nat_info (c, dst, nat_loc, nat_bitnr);
    612 	    break;
    613 	  }
    614       c->loc[dst] = loc;
    615     }
    616   return 0;
    617 }
    618 
    619 static int
    620 uncached_find_save_locs (struct cursor *c)
    621 {
    622   struct ia64_script script;
    623   int ret = 0;
    624 
    625   if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0)
    626     return ret;
    627 
    628   script_init (&script, c->ip);
    629   if ((ret = build_script (c, &script)) < 0)
    630     {
    631       if (ret != -UNW_ESTOPUNWIND)
    632 	Dprintf ("%s: failed to build unwind script for ip %lx\n",
    633 		 __FUNCTION__, (long) c->ip);
    634       return ret;
    635     }
    636   return run_script (&script, c);
    637 }
    638 
    639 HIDDEN int
    640 ia64_find_save_locs (struct cursor *c)
    641 {
    642   struct ia64_script_cache *cache = NULL;
    643   struct ia64_script *script = NULL;
    644   intrmask_t saved_mask;
    645   int ret = 0;
    646 
    647   if (c->as->caching_policy == UNW_CACHE_NONE)
    648     return uncached_find_save_locs (c);
    649 
    650   cache = get_script_cache (c->as, &saved_mask);
    651   if (!cache)
    652     {
    653       Debug (1, "contention on script-cache; doing uncached lookup\n");
    654       return uncached_find_save_locs (c);
    655     }
    656   {
    657     script = script_lookup (cache, c);
    658     Debug (8, "ip %lx %s in script cache\n", (long) c->ip,
    659 	   script ? "hit" : "missed");
    660 
    661     if (!script || (script->count == 0 && !script->pi.unwind_info))
    662       {
    663 	if ((ret = ia64_fetch_proc_info (c, c->ip, 1)) < 0)
    664 	  goto out;
    665       }
    666 
    667     if (!script)
    668       {
    669 	script = script_new (cache, c->ip);
    670 	if (!script)
    671 	  {
    672 	    Dprintf ("%s: failed to create unwind script\n", __FUNCTION__);
    673 	    ret = -UNW_EUNSPEC;
    674 	    goto out;
    675 	  }
    676       }
    677     cache->buckets[c->prev_script].hint = script - cache->buckets;
    678 
    679     if (script->count == 0)
    680       ret = build_script (c, script);
    681 
    682     assert (script->count > 0);
    683 
    684     c->hint = script->hint;
    685     c->prev_script = script - cache->buckets;
    686 
    687     if (ret < 0)
    688       {
    689 	if (ret != -UNW_ESTOPUNWIND)
    690 	  Dprintf ("%s: failed to locate/build unwind script for ip %lx\n",
    691 		   __FUNCTION__, (long) c->ip);
    692 	goto out;
    693       }
    694 
    695     ret = run_script (script, c);
    696   }
    697  out:
    698   put_script_cache (c->as, cache, &saved_mask);
    699   return ret;
    700 }
    701 
    702 HIDDEN void
    703 ia64_validate_cache (unw_addr_space_t as, void *arg)
    704 {
    705 #ifndef UNW_REMOTE_ONLY
    706   if (as == unw_local_addr_space && ia64_local_validate_cache (as, arg) == 1)
    707     return;
    708 #endif
    709 
    710 #ifndef UNW_LOCAL_ONLY
    711   /* local info is up-to-date, check dynamic info.  */
    712   unwi_dyn_validate_cache (as, arg);
    713 #endif
    714 }
    715 
    716 HIDDEN int
    717 ia64_cache_proc_info (struct cursor *c)
    718 {
    719   struct ia64_script_cache *cache;
    720   struct ia64_script *script;
    721   intrmask_t saved_mask;
    722   int ret = 0;
    723 
    724   cache = get_script_cache (c->as, &saved_mask);
    725   if (!cache)
    726     return ret;	/* cache is busy */
    727 
    728   /* Re-check to see if a cache entry has been added in the meantime: */
    729   script = script_lookup (cache, c);
    730   if (script)
    731     goto out;
    732 
    733   script = script_new (cache, c->ip);
    734   if (!script)
    735     {
    736       Dprintf ("%s: failed to create unwind script\n", __FUNCTION__);
    737       ret = -UNW_EUNSPEC;
    738       goto out;
    739     }
    740 
    741   script->pi = c->pi;
    742 
    743  out:
    744   put_script_cache (c->as, cache, &saved_mask);
    745   return ret;
    746 }
    747 
    748 HIDDEN int
    749 ia64_get_cached_proc_info (struct cursor *c)
    750 {
    751   struct ia64_script_cache *cache;
    752   struct ia64_script *script;
    753   intrmask_t saved_mask;
    754 
    755   cache = get_script_cache (c->as, &saved_mask);
    756   if (!cache)
    757     return -UNW_ENOINFO;	/* cache is busy */
    758   {
    759     script = script_lookup (cache, c);
    760     if (script)
    761       c->pi = script->pi;
    762   }
    763   put_script_cache (c->as, cache, &saved_mask);
    764   return script ? 0 : -UNW_ENOINFO;
    765 }
    766