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