Gregs.c revision fa2871946af3c3d696efacbbc529d834020d8b67
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 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 30static inline ia64_loc_t 31linux_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) 32{ 33#if !defined(UNW_LOCAL_ONLY) || defined(__linux) 34 unw_word_t addr = c->sigcontext_addr, flags, tmp_addr; 35 int i; 36 37 if (ia64_get_abi_marker (c) == ABI_MARKER_LINUX_SIGTRAMP 38 || ia64_get_abi_marker (c) == ABI_MARKER_OLD_LINUX_SIGTRAMP) 39 { 40 switch (reg) 41 { 42 case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: 43 case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: 44 /* Linux sigcontext contains the NaT bit of scratch register 45 N in bit position N of the sc_nat member. */ 46 *nat_bitnr = (reg - UNW_IA64_NAT); 47 addr += LINUX_SC_NAT_OFF; 48 break; 49 50 case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: 51 case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31: 52 addr += LINUX_SC_GR_OFF + 8 * (reg - UNW_IA64_GR); 53 break; 54 55 case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: 56 addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR); 57 return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); 58 59 case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: 60 if (ia64_get (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF, 0), 61 &flags) < 0) 62 return IA64_NULL_LOC; 63 64 if (!(flags & IA64_SC_FLAG_FPH_VALID)) 65 { 66 /* initialize fph partition: */ 67 tmp_addr = addr + LINUX_SC_FR_OFF + 32*16; 68 for (i = 32; i < 128; ++i, tmp_addr += 16) 69 if (ia64_putfp (c, IA64_LOC_ADDR (tmp_addr, 0), 70 unw.read_only.f0) < 0) 71 return IA64_NULL_LOC; 72 /* mark fph partition as valid: */ 73 if (ia64_put (c, IA64_LOC_ADDR (addr + LINUX_SC_FLAGS_OFF, 0), 74 flags | IA64_SC_FLAG_FPH_VALID) < 0) 75 return IA64_NULL_LOC; 76 } 77 78 addr += LINUX_SC_FR_OFF + 16 * (reg - UNW_IA64_FR); 79 return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); 80 81 case UNW_IA64_BR + 0: addr += LINUX_SC_BR_OFF + 0; break; 82 case UNW_IA64_BR + 6: addr += LINUX_SC_BR_OFF + 6*8; break; 83 case UNW_IA64_BR + 7: addr += LINUX_SC_BR_OFF + 7*8; break; 84 case UNW_IA64_AR_RSC: addr += LINUX_SC_AR_RSC_OFF; break; 85 case UNW_IA64_AR_CSD: addr += LINUX_SC_AR_CSD_OFF; break; 86 case UNW_IA64_AR_SSD: addr += LINUX_SC_AR_SSD_OFF; break; 87 case UNW_IA64_AR_CCV: addr += LINUX_SC_AR_CCV; break; 88 89 default: 90 if (unw_is_fpreg (reg)) 91 return IA64_FPREG_LOC (c, reg); 92 else 93 return IA64_REG_LOC (c, reg); 94 } 95 return IA64_LOC_ADDR (addr, 0); 96 } 97 else 98 { 99 int is_nat = 0; 100 101 if ((unsigned) (reg - UNW_IA64_NAT) < 128) 102 { 103 is_nat = 1; 104 reg -= (UNW_IA64_NAT - UNW_IA64_GR); 105 } 106 if (ia64_get_abi_marker (c) == ABI_MARKER_LINUX_INTERRUPT) 107 { 108 switch (reg) 109 { 110 case UNW_IA64_BR + 6 ... UNW_IA64_BR + 7: 111 addr += LINUX_PT_B6_OFF + 8 * (reg - (UNW_IA64_BR + 6)); 112 break; 113 114 case UNW_IA64_AR_CSD: addr += LINUX_PT_CSD_OFF; break; 115 case UNW_IA64_AR_SSD: addr += LINUX_PT_SSD_OFF; break; 116 117 case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11: 118 addr += LINUX_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8)); 119 break; 120 121 case UNW_IA64_IP: addr += LINUX_PT_IIP_OFF; break; 122 case UNW_IA64_CFM: addr += LINUX_PT_IFS_OFF; break; 123 case UNW_IA64_AR_UNAT: addr += LINUX_PT_UNAT_OFF; break; 124 case UNW_IA64_AR_PFS: addr += LINUX_PT_PFS_OFF; break; 125 case UNW_IA64_AR_RSC: addr += LINUX_PT_RSC_OFF; break; 126 case UNW_IA64_AR_RNAT: addr += LINUX_PT_RNAT_OFF; break; 127 case UNW_IA64_AR_BSPSTORE: addr += LINUX_PT_BSPSTORE_OFF; break; 128 case UNW_IA64_PR: addr += LINUX_PT_PR_OFF; break; 129 case UNW_IA64_BR + 0: addr += LINUX_PT_B0_OFF; break; 130 case UNW_IA64_GR + 1: addr += LINUX_PT_R1_OFF; break; 131 case UNW_IA64_GR + 12: addr += LINUX_PT_R12_OFF; break; 132 case UNW_IA64_GR + 13: addr += LINUX_PT_R13_OFF; break; 133 case UNW_IA64_AR_FPSR: addr += LINUX_PT_FPSR_OFF; break; 134 case UNW_IA64_GR + 15: addr += LINUX_PT_R15_OFF; break; 135 case UNW_IA64_GR + 14: addr += LINUX_PT_R14_OFF; break; 136 case UNW_IA64_GR + 2: addr += LINUX_PT_R2_OFF; break; 137 case UNW_IA64_GR + 3: addr += LINUX_PT_R3_OFF; break; 138 139 case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31: 140 addr += LINUX_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16)); 141 break; 142 143 case UNW_IA64_AR_CCV: addr += LINUX_PT_CCV_OFF; break; 144 145 case UNW_IA64_FR + 6 ... UNW_IA64_FR + 11: 146 addr += LINUX_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6)); 147 return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); 148 149 default: 150 if (unw_is_fpreg (reg)) 151 return IA64_FPREG_LOC (c, reg); 152 else 153 return IA64_REG_LOC (c, reg); 154 } 155 } 156 else if (ia64_get_abi_marker (c) == ABI_MARKER_OLD_LINUX_INTERRUPT) 157 { 158 switch (reg) 159 { 160 case UNW_IA64_GR + 1 ... UNW_IA64_GR + 3: 161 addr += LINUX_OLD_PT_R1_OFF + 8 * (reg - (UNW_IA64_GR + 1)); 162 break; 163 164 case UNW_IA64_GR + 8 ... UNW_IA64_GR + 11: 165 addr += LINUX_OLD_PT_R8_OFF + 8 * (reg - (UNW_IA64_GR + 8)); 166 break; 167 168 case UNW_IA64_GR + 16 ... UNW_IA64_GR + 31: 169 addr += LINUX_OLD_PT_R16_OFF + 8 * (reg - (UNW_IA64_GR + 16)); 170 break; 171 172 case UNW_IA64_FR + 6 ... UNW_IA64_FR + 9: 173 addr += LINUX_OLD_PT_F6_OFF + 16 * (reg - (UNW_IA64_FR + 6)); 174 return IA64_LOC_ADDR (addr, IA64_LOC_TYPE_FP); 175 176 case UNW_IA64_BR + 0: addr += LINUX_OLD_PT_B0_OFF; break; 177 case UNW_IA64_BR + 6: addr += LINUX_OLD_PT_B6_OFF; break; 178 case UNW_IA64_BR + 7: addr += LINUX_OLD_PT_B7_OFF; break; 179 180 case UNW_IA64_AR_RSC: addr += LINUX_OLD_PT_RSC_OFF; break; 181 case UNW_IA64_AR_CCV: addr += LINUX_OLD_PT_CCV_OFF; break; 182 183 default: 184 if (unw_is_fpreg (reg)) 185 return IA64_FPREG_LOC (c, reg); 186 else 187 return IA64_REG_LOC (c, reg); 188 } 189 } 190 if (is_nat) 191 { 192 /* For Linux pt-regs structure, bit number is determined by 193 the UNaT slot number (as determined by st8.spill) and the 194 bits are saved wherever the (primary) UNaT was saved. */ 195 *nat_bitnr = ia64_unat_slot_num (addr); 196 return c->loc[IA64_REG_PRI_UNAT_MEM]; 197 } 198 return IA64_LOC_ADDR (addr, 0); 199 } 200#endif 201 return IA64_NULL_LOC; 202} 203 204static inline ia64_loc_t 205hpux_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) 206{ 207#if !defined(UNW_LOCAL_ONLY) || defined(__hpux) 208 return IA64_LOC_UC_REG (reg, c->sigcontext_addr); 209#else 210 return IA64_NULL_LOC; 211#endif 212} 213 214HIDDEN ia64_loc_t 215ia64_scratch_loc (struct cursor *c, unw_regnum_t reg, uint8_t *nat_bitnr) 216{ 217 if (c->sigcontext_addr) 218 { 219 if (ia64_get_abi (c) == ABI_LINUX) 220 return linux_scratch_loc (c, reg, nat_bitnr); 221 else if (ia64_get_abi (c) == ABI_HPUX) 222 return hpux_scratch_loc (c, reg, nat_bitnr); 223 else 224 return IA64_NULL_LOC; 225 } 226 else 227 return IA64_REG_LOC (c, reg); 228} 229 230static inline int 231update_nat (struct cursor *c, ia64_loc_t nat_loc, unw_word_t mask, 232 unw_word_t *valp, int write) 233{ 234 unw_word_t nat_word; 235 int ret; 236 237 ret = ia64_get (c, nat_loc, &nat_word); 238 if (ret < 0) 239 return ret; 240 241 if (write) 242 { 243 if (*valp) 244 nat_word |= mask; 245 else 246 nat_word &= ~mask; 247 ret = ia64_put (c, nat_loc, nat_word); 248 } 249 else 250 *valp = (nat_word & mask) != 0; 251 return ret; 252} 253 254static int 255access_nat (struct cursor *c, 256 ia64_loc_t nat_loc, ia64_loc_t reg_loc, uint8_t nat_bitnr, 257 unw_word_t *valp, int write) 258{ 259 unw_word_t mask = 0; 260 unw_fpreg_t tmp; 261 int ret; 262 263 if (IA64_IS_FP_LOC (reg_loc)) 264 { 265 /* NaT bit is saved as a NaTVal. This happens when a general 266 register is saved to a floating-point register. */ 267 if (write) 268 { 269 if (*valp) 270 { 271 if (ia64_is_big_endian (c)) 272 ret = ia64_putfp (c, reg_loc, unw.nat_val_be); 273 else 274 ret = ia64_putfp (c, reg_loc, unw.nat_val_le); 275 } 276 else 277 { 278 unw_word_t *src, *dst; 279 unw_fpreg_t tmp; 280 281 ret = ia64_getfp (c, reg_loc, &tmp); 282 if (ret < 0) 283 return ret; 284 285 /* Reset the exponent to 0x1003e so that the significand 286 will be interpreted as an integer value. */ 287 src = (unw_word_t *) &unw.int_val_be; 288 dst = (unw_word_t *) &tmp; 289 if (!ia64_is_big_endian (c)) 290 ++src, ++dst; 291 *dst = *src; 292 293 ret = ia64_putfp (c, reg_loc, tmp); 294 } 295 } 296 else 297 { 298 ret = ia64_getfp (c, reg_loc, &tmp); 299 if (ret < 0) 300 return ret; 301 302 if (ia64_is_big_endian (c)) 303 *valp = (memcmp (&tmp, &unw.nat_val_be, sizeof (tmp)) == 0); 304 else 305 *valp = (memcmp (&tmp, &unw.nat_val_le, sizeof (tmp)) == 0); 306 } 307 return ret; 308 } 309 310 if ((IA64_IS_REG_LOC (nat_loc) 311 && (unsigned) (IA64_GET_REG (nat_loc) - UNW_IA64_NAT) < 128) 312 || IA64_IS_UC_LOC (reg_loc)) 313 { 314 if (write) 315 return ia64_put (c, nat_loc, *valp); 316 else 317 return ia64_get (c, nat_loc, valp); 318 } 319 320 if (IA64_IS_NULL_LOC (nat_loc)) 321 { 322 /* NaT bit is not saved. This happens if a general register is 323 saved to a branch register. Since the NaT bit gets lost, we 324 need to drop it here, too. Note that if the NaT bit had been 325 set when the save occurred, it would have caused a NaT 326 consumption fault. */ 327 if (write) 328 { 329 if (*valp) 330 return -UNW_EBADREG; /* can't set NaT bit */ 331 } 332 else 333 *valp = 0; 334 return 0; 335 } 336 337 mask = (unw_word_t) 1 << nat_bitnr; 338 return update_nat (c, nat_loc, mask, valp, write); 339} 340 341HIDDEN int 342tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp, 343 int write) 344{ 345 ia64_loc_t loc, reg_loc, nat_loc; 346 unw_word_t nat, mask, val; 347 int ret, readonly = 0; 348 uint8_t nat_bitnr; 349 350 switch (reg) 351 { 352 /* frame registers: */ 353 354 case UNW_IA64_BSP: 355 if (write) 356 return -UNW_EREADONLYREG; 357 *valp = c->bsp; 358 return 0; 359 360 case UNW_REG_SP: 361 if (write) 362 return -UNW_EREADONLYREG; 363 *valp = c->sp; 364 return 0; 365 366 case UNW_REG_IP: 367 if (write) 368 { 369 c->ip = *valp; /* also update the IP cache */ 370 if (c->pi_valid && (*valp < c->pi.start_ip || *valp >= c->pi.end_ip)) 371 c->pi_valid = 0; /* new IP outside of current proc */ 372 } 373 loc = c->loc[IA64_REG_IP]; 374 break; 375 376 /* preserved registers: */ 377 378 case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: 379 loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_GR + 4))]; 380 break; 381 382 case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: 383 loc = c->loc[IA64_REG_NAT4 + (reg - (UNW_IA64_NAT + 4))]; 384 reg_loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_NAT + 4))]; 385 nat_bitnr = c->nat_bitnr[reg - (UNW_IA64_NAT + 4)]; 386 return access_nat (c, loc, reg_loc, nat_bitnr, valp, write); 387 388 case UNW_IA64_AR_BSP: loc = c->loc[IA64_REG_BSP]; break; 389 case UNW_IA64_AR_BSPSTORE: loc = c->loc[IA64_REG_BSPSTORE]; break; 390 case UNW_IA64_AR_PFS: loc = c->loc[IA64_REG_PFS]; break; 391 case UNW_IA64_AR_RNAT: loc = c->loc[IA64_REG_RNAT]; break; 392 case UNW_IA64_AR_UNAT: loc = c->loc[IA64_REG_UNAT]; break; 393 case UNW_IA64_AR_LC: loc = c->loc[IA64_REG_LC]; break; 394 case UNW_IA64_AR_FPSR: loc = c->loc[IA64_REG_FPSR]; break; 395 case UNW_IA64_BR + 1: loc = c->loc[IA64_REG_B1]; break; 396 case UNW_IA64_BR + 2: loc = c->loc[IA64_REG_B2]; break; 397 case UNW_IA64_BR + 3: loc = c->loc[IA64_REG_B3]; break; 398 case UNW_IA64_BR + 4: loc = c->loc[IA64_REG_B4]; break; 399 case UNW_IA64_BR + 5: loc = c->loc[IA64_REG_B5]; break; 400 401 case UNW_IA64_CFM: 402 if (write) 403 c->cfm = *valp; /* also update the CFM cache */ 404 loc = c->cfm_loc; 405 break; 406 407 case UNW_IA64_PR: 408 /* 409 * Note: broad-side access to the predicates is NOT rotated 410 * (i.e., it is done as if CFM.rrb.pr == 0. 411 */ 412 if (write) 413 { 414 c->pr = *valp; /* update the predicate cache */ 415 return ia64_put (c, c->loc[IA64_REG_PR], *valp); 416 } 417 else 418 return ia64_get (c, c->loc[IA64_REG_PR], valp); 419 420 case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */ 421 reg = rotate_gr (c, reg - UNW_IA64_GR); 422 if (reg < 0) 423 return -UNW_EBADREG; 424 ret = ia64_get_stacked (c, reg, &loc, NULL); 425 if (ret < 0) 426 return ret; 427 break; 428 429 case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */ 430 reg = rotate_gr (c, reg - UNW_IA64_NAT); 431 if (reg < 0) 432 return -UNW_EBADREG; 433 ret = ia64_get_stacked (c, reg, &loc, &nat_loc); 434 if (ret < 0) 435 return ret; 436 assert (!IA64_IS_REG_LOC (loc)); 437 mask = (unw_word_t) 1 << rse_slot_num (IA64_GET_ADDR (loc)); 438 return update_nat (c, nat_loc, mask, valp, write); 439 440 case UNW_IA64_AR_EC: 441 if ((ret = ia64_get (c, c->ec_loc, &val)) < 0) 442 return ret; 443 444 if (write) 445 { 446 val = ((val & ~((unw_word_t) 0x3f << 52)) | ((*valp & 0x3f) << 52)); 447 return ia64_put (c, c->ec_loc, val); 448 } 449 else 450 { 451 *valp = (val >> 52) & 0x3f; 452 return 0; 453 } 454 455 /* scratch & special registers: */ 456 457 case UNW_IA64_GR + 0: 458 if (write) 459 return -UNW_EREADONLYREG; 460 *valp = 0; 461 return 0; 462 463 case UNW_IA64_GR + 1: /* global pointer */ 464 if (write) 465 return -UNW_EREADONLYREG; 466 467 /* ensure c->pi is up-to-date: */ 468 if ((ret = ia64_make_proc_info (c)) < 0) 469 return ret; 470 *valp = c->pi.gp; 471 return 0; 472 473 case UNW_IA64_NAT + 0: 474 case UNW_IA64_NAT + 1: /* global pointer */ 475 if (write) 476 return -UNW_EREADONLYREG; 477 *valp = 0; 478 return 0; 479 480 case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: 481 case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: 482 loc = ia64_scratch_loc (c, reg, &nat_bitnr); 483 if (!(IA64_IS_REG_LOC (loc) || IA64_IS_UC_LOC (loc) 484 || IA64_IS_FP_LOC (loc))) 485 { 486 /* We're dealing with a NaT bit stored in memory. */ 487 mask = (unw_word_t) 1 << nat_bitnr; 488 489 if ((ret = ia64_get (c, loc, &nat)) < 0) 490 return ret; 491 492 if (write) 493 { 494 if (*valp) 495 nat |= mask; 496 else 497 nat &= ~mask; 498 ret = ia64_put (c, loc, nat); 499 } 500 else 501 *valp = (nat & mask) != 0; 502 return ret; 503 } 504 break; 505 506 case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18: 507 mask = 1 << (reg - (UNW_IA64_GR + 15)); 508 if (write) 509 { 510 c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp; 511 c->eh_valid_mask |= mask; 512 return 0; 513 } 514 else if ((c->eh_valid_mask & mask) != 0) 515 { 516 *valp = c->eh_args[reg - (UNW_IA64_GR + 15)]; 517 return 0; 518 } 519 else 520 loc = ia64_scratch_loc (c, reg, NULL); 521 break; 522 523 case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3: 524 case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14: 525 case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31: 526 case UNW_IA64_BR + 0: 527 case UNW_IA64_BR + 6: 528 case UNW_IA64_BR + 7: 529 case UNW_IA64_AR_RSC: 530 case UNW_IA64_AR_CSD: 531 case UNW_IA64_AR_SSD: 532 case UNW_IA64_AR_CCV: 533 loc = ia64_scratch_loc (c, reg, NULL); 534 break; 535 536 default: 537 Debug (1, "bad register number %d\n", reg); 538 return -UNW_EBADREG; 539 } 540 541 if (write) 542 { 543 if (readonly) 544 return -UNW_EREADONLYREG; 545 return ia64_put (c, loc, *valp); 546 } 547 else 548 return ia64_get (c, loc, valp); 549} 550 551HIDDEN int 552tdep_access_fpreg (struct cursor *c, int reg, unw_fpreg_t *valp, 553 int write) 554{ 555 ia64_loc_t loc; 556 557 switch (reg) 558 { 559 case UNW_IA64_FR + 0: 560 if (write) 561 return -UNW_EREADONLYREG; 562 *valp = unw.read_only.f0; 563 return 0; 564 565 case UNW_IA64_FR + 1: 566 if (write) 567 return -UNW_EREADONLYREG; 568 569 if (ia64_is_big_endian (c)) 570 *valp = unw.read_only.f1_be; 571 else 572 *valp = unw.read_only.f1_le; 573 return 0; 574 575 case UNW_IA64_FR + 2: loc = c->loc[IA64_REG_F2]; break; 576 case UNW_IA64_FR + 3: loc = c->loc[IA64_REG_F3]; break; 577 case UNW_IA64_FR + 4: loc = c->loc[IA64_REG_F4]; break; 578 case UNW_IA64_FR + 5: loc = c->loc[IA64_REG_F5]; break; 579 580 case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31: 581 loc = c->loc[IA64_REG_F16 + (reg - (UNW_IA64_FR + 16))]; 582 break; 583 584 case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: 585 loc = ia64_scratch_loc (c, reg, NULL); 586 break; 587 588 case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: 589 reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR; 590 loc = ia64_scratch_loc (c, reg, NULL); 591 break; 592 593 default: 594 Debug (1, "bad register number %d\n", reg); 595 return -UNW_EBADREG; 596 } 597 598 if (write) 599 return ia64_putfp (c, loc, *valp); 600 else 601 return ia64_getfp (c, loc, valp); 602} 603