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