Imported Upstream version 1.2
[platform/upstream/libunwind.git] / src / ia64 / Gscript.c
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2001-2005 Hewlett-Packard Co
3         Contributed by David Mosberger-Tang <davidm@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 }