Gregs.c revision cf2a44ca4934c5c5a91959240d48b37937730c4b
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 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 222static inline ia64_loc_t 223hpux_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 232HIDDEN ia64_loc_t 233ia64_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 248static inline int 249update_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 272static int 273access_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 359HIDDEN int 360tdep_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 return -UNW_EREADONLYREG; 375 *valp = c->bsp; 376 return 0; 377 378 case UNW_REG_SP: 379 if (write) 380 return -UNW_EREADONLYREG; 381 *valp = c->sp; 382 return 0; 383 384 case UNW_REG_IP: 385 if (write) 386 { 387 c->ip = *valp; /* also update the IP cache */ 388 if (c->pi_valid && (*valp < c->pi.start_ip || *valp >= c->pi.end_ip)) 389 c->pi_valid = 0; /* new IP outside of current proc */ 390 } 391 loc = c->loc[IA64_REG_IP]; 392 break; 393 394 /* preserved registers: */ 395 396 case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7: 397 loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_GR + 4))]; 398 break; 399 400 case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7: 401 loc = c->loc[IA64_REG_NAT4 + (reg - (UNW_IA64_NAT + 4))]; 402 reg_loc = c->loc[IA64_REG_R4 + (reg - (UNW_IA64_NAT + 4))]; 403 nat_bitnr = c->nat_bitnr[reg - (UNW_IA64_NAT + 4)]; 404 return access_nat (c, loc, reg_loc, nat_bitnr, valp, write); 405 406 case UNW_IA64_AR_BSP: loc = c->loc[IA64_REG_BSP]; break; 407 case UNW_IA64_AR_BSPSTORE: loc = c->loc[IA64_REG_BSPSTORE]; break; 408 case UNW_IA64_AR_PFS: loc = c->loc[IA64_REG_PFS]; break; 409 case UNW_IA64_AR_RNAT: loc = c->loc[IA64_REG_RNAT]; break; 410 case UNW_IA64_AR_UNAT: loc = c->loc[IA64_REG_UNAT]; break; 411 case UNW_IA64_AR_LC: loc = c->loc[IA64_REG_LC]; break; 412 case UNW_IA64_AR_FPSR: loc = c->loc[IA64_REG_FPSR]; break; 413 case UNW_IA64_BR + 1: loc = c->loc[IA64_REG_B1]; break; 414 case UNW_IA64_BR + 2: loc = c->loc[IA64_REG_B2]; break; 415 case UNW_IA64_BR + 3: loc = c->loc[IA64_REG_B3]; break; 416 case UNW_IA64_BR + 4: loc = c->loc[IA64_REG_B4]; break; 417 case UNW_IA64_BR + 5: loc = c->loc[IA64_REG_B5]; break; 418 419 case UNW_IA64_CFM: 420 if (write) 421 c->cfm = *valp; /* also update the CFM cache */ 422 loc = c->cfm_loc; 423 break; 424 425 case UNW_IA64_PR: 426 /* 427 * Note: broad-side access to the predicates is NOT rotated 428 * (i.e., it is done as if CFM.rrb.pr == 0. 429 */ 430 if (write) 431 { 432 c->pr = *valp; /* update the predicate cache */ 433 return ia64_put (c, c->loc[IA64_REG_PR], *valp); 434 } 435 else 436 return ia64_get (c, c->loc[IA64_REG_PR], valp); 437 438 case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */ 439 reg = rotate_gr (c, reg - UNW_IA64_GR); 440 if (reg < 0) 441 return -UNW_EBADREG; 442 ret = ia64_get_stacked (c, reg, &loc, NULL); 443 if (ret < 0) 444 return ret; 445 break; 446 447 case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */ 448 reg = rotate_gr (c, reg - UNW_IA64_NAT); 449 if (reg < 0) 450 return -UNW_EBADREG; 451 ret = ia64_get_stacked (c, reg, &loc, &nat_loc); 452 if (ret < 0) 453 return ret; 454 assert (!IA64_IS_REG_LOC (loc)); 455 mask = (unw_word_t) 1 << rse_slot_num (IA64_GET_ADDR (loc)); 456 return update_nat (c, nat_loc, mask, valp, write); 457 458 case UNW_IA64_AR_EC: 459 if ((ret = ia64_get (c, c->ec_loc, &val)) < 0) 460 return ret; 461 462 if (write) 463 { 464 val = ((val & ~((unw_word_t) 0x3f << 52)) | ((*valp & 0x3f) << 52)); 465 return ia64_put (c, c->ec_loc, val); 466 } 467 else 468 { 469 *valp = (val >> 52) & 0x3f; 470 return 0; 471 } 472 473 /* scratch & special registers: */ 474 475 case UNW_IA64_GR + 0: 476 if (write) 477 return -UNW_EREADONLYREG; 478 *valp = 0; 479 return 0; 480 481 case UNW_IA64_NAT + 0: 482 if (write) 483 return -UNW_EREADONLYREG; 484 *valp = 0; 485 return 0; 486 487 case UNW_IA64_NAT + 1: 488 case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3: 489 case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31: 490 loc = ia64_scratch_loc (c, reg, &nat_bitnr); 491 if (IA64_IS_NULL_LOC (loc) && reg == UNW_IA64_NAT + 1) 492 { 493 /* access to GP */ 494 if (write) 495 return -UNW_EREADONLYREG; 496 *valp = 0; 497 return 0; 498 } 499 if (!(IA64_IS_REG_LOC (loc) || IA64_IS_UC_LOC (loc) 500 || IA64_IS_FP_LOC (loc))) 501 /* We're dealing with a NaT bit stored in memory. */ 502 return update_nat(c, loc, (unw_word_t) 1 << nat_bitnr, valp, write); 503 break; 504 505 case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18: 506 mask = 1 << (reg - (UNW_IA64_GR + 15)); 507 if (write) 508 { 509 c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp; 510 c->eh_valid_mask |= mask; 511 return 0; 512 } 513 else if ((c->eh_valid_mask & mask) != 0) 514 { 515 *valp = c->eh_args[reg - (UNW_IA64_GR + 15)]; 516 return 0; 517 } 518 else 519 loc = ia64_scratch_loc (c, reg, NULL); 520 break; 521 522 case UNW_IA64_GR + 1: /* global pointer */ 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 if (IA64_IS_NULL_LOC (loc) && reg == UNW_IA64_GR + 1) 535 { 536 /* access to GP */ 537 if (write) 538 return -UNW_EREADONLYREG; 539 540 /* ensure c->pi is up-to-date: */ 541 if ((ret = ia64_make_proc_info (c)) < 0) 542 return ret; 543 *valp = c->pi.gp; 544 return 0; 545 } 546 break; 547 548 default: 549 Debug (1, "bad register number %d\n", reg); 550 return -UNW_EBADREG; 551 } 552 553 if (write) 554 return ia64_put (c, loc, *valp); 555 else 556 return ia64_get (c, loc, valp); 557} 558 559HIDDEN int 560tdep_access_fpreg (struct cursor *c, int reg, unw_fpreg_t *valp, 561 int write) 562{ 563 ia64_loc_t loc; 564 565 switch (reg) 566 { 567 case UNW_IA64_FR + 0: 568 if (write) 569 return -UNW_EREADONLYREG; 570 *valp = unw.read_only.f0; 571 return 0; 572 573 case UNW_IA64_FR + 1: 574 if (write) 575 return -UNW_EREADONLYREG; 576 577 if (ia64_is_big_endian (c)) 578 *valp = unw.read_only.f1_be; 579 else 580 *valp = unw.read_only.f1_le; 581 return 0; 582 583 case UNW_IA64_FR + 2: loc = c->loc[IA64_REG_F2]; break; 584 case UNW_IA64_FR + 3: loc = c->loc[IA64_REG_F3]; break; 585 case UNW_IA64_FR + 4: loc = c->loc[IA64_REG_F4]; break; 586 case UNW_IA64_FR + 5: loc = c->loc[IA64_REG_F5]; break; 587 588 case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31: 589 loc = c->loc[IA64_REG_F16 + (reg - (UNW_IA64_FR + 16))]; 590 break; 591 592 case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15: 593 loc = ia64_scratch_loc (c, reg, NULL); 594 break; 595 596 case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127: 597 reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR; 598 loc = ia64_scratch_loc (c, reg, NULL); 599 break; 600 601 default: 602 Debug (1, "bad register number %d\n", reg); 603 return -UNW_EBADREG; 604 } 605 606 if (write) 607 return ia64_putfp (c, loc, *valp); 608 else 609 return ia64_getfp (c, loc, valp); 610} 611