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