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>
5 This file is part of libunwind.
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:
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
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. */
30 static inline ia64_loc_t
31 linux_scratch_loc (struct cursor
*c
, unw_regnum_t reg
, uint8_t *nat_bitnr
)
33 #if !defined(UNW_LOCAL_ONLY) || defined(__linux)
34 unw_word_t addr
= c
->sigcontext_addr
, flags
, tmp_addr
;
37 if (ia64_get_abi_marker (c
) == ABI_MARKER_LINUX_SIGTRAMP
38 || ia64_get_abi_marker (c
) == ABI_MARKER_OLD_LINUX_SIGTRAMP
)
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
;
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
);
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
);
59 case UNW_IA64_FR
+ 32 ... UNW_IA64_FR
+ 127:
60 if (ia64_get (c
, IA64_LOC_ADDR (addr
+ LINUX_SC_FLAGS_OFF
, 0),
64 if (!(flags
& IA64_SC_FLAG_FPH_VALID
))
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)
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)
78 addr
+= LINUX_SC_FR_OFF
+ 16 * (reg
- UNW_IA64_FR
);
79 return IA64_LOC_ADDR (addr
, IA64_LOC_TYPE_FP
);
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;
90 if (unw_is_fpreg (reg
))
91 return IA64_FPREG_LOC (c
, reg
);
93 return IA64_REG_LOC (c
, reg
);
95 return IA64_LOC_ADDR (addr
, 0);
101 if ((unsigned) (reg
- UNW_IA64_NAT
) < 128)
104 reg
-= (UNW_IA64_NAT
- UNW_IA64_GR
);
106 if (ia64_get_abi_marker (c
) == ABI_MARKER_LINUX_INTERRUPT
)
110 case UNW_IA64_BR
+ 6 ... UNW_IA64_BR
+ 7:
111 addr
+= LINUX_PT_B6_OFF
+ 8 * (reg
- (UNW_IA64_BR
+ 6));
114 case UNW_IA64_AR_CSD
: addr
+= LINUX_PT_CSD_OFF
; break;
115 case UNW_IA64_AR_SSD
: addr
+= LINUX_PT_SSD_OFF
; break;
117 case UNW_IA64_GR
+ 8 ... UNW_IA64_GR
+ 11:
118 addr
+= LINUX_PT_R8_OFF
+ 8 * (reg
- (UNW_IA64_GR
+ 8));
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;
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
;
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;
148 case UNW_IA64_GR
+ 16 ... UNW_IA64_GR
+ 31:
149 addr
+= LINUX_PT_R16_OFF
+ 8 * (reg
- (UNW_IA64_GR
+ 16));
152 case UNW_IA64_AR_CCV
: addr
+= LINUX_PT_CCV_OFF
; break;
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
);
159 if (unw_is_fpreg (reg
))
160 return IA64_FPREG_LOC (c
, reg
);
162 return IA64_REG_LOC (c
, reg
);
165 else if (ia64_get_abi_marker (c
) == ABI_MARKER_OLD_LINUX_INTERRUPT
)
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
;
178 case UNW_IA64_GR
+ 2 ... UNW_IA64_GR
+ 3:
179 addr
+= LINUX_OLD_PT_R2_OFF
+ 8 * (reg
- (UNW_IA64_GR
+ 2));
182 case UNW_IA64_GR
+ 8 ... UNW_IA64_GR
+ 11:
183 addr
+= LINUX_OLD_PT_R8_OFF
+ 8 * (reg
- (UNW_IA64_GR
+ 8));
186 case UNW_IA64_GR
+ 16 ... UNW_IA64_GR
+ 31:
187 addr
+= LINUX_OLD_PT_R16_OFF
+ 8 * (reg
- (UNW_IA64_GR
+ 16));
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
);
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;
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;
202 if (unw_is_fpreg (reg
))
203 return IA64_FPREG_LOC (c
, reg
);
205 return IA64_REG_LOC (c
, reg
);
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
];
216 return IA64_LOC_ADDR (addr
, 0);
219 return IA64_NULL_LOC
;
222 static inline ia64_loc_t
223 hpux_scratch_loc (struct cursor
*c
, unw_regnum_t reg
, uint8_t *nat_bitnr
)
225 #if !defined(UNW_LOCAL_ONLY) || defined(__hpux)
226 return IA64_LOC_UC_REG (reg
, c
->sigcontext_addr
);
228 return IA64_NULL_LOC
;
233 ia64_scratch_loc (struct cursor
*c
, unw_regnum_t reg
, uint8_t *nat_bitnr
)
235 if (c
->sigcontext_addr
)
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
);
242 return IA64_NULL_LOC
;
245 return IA64_REG_LOC (c
, reg
);
249 update_nat (struct cursor
*c
, ia64_loc_t nat_loc
, unw_word_t mask
,
250 unw_word_t
*valp
, int write
)
255 ret
= ia64_get (c
, nat_loc
, &nat_word
);
265 ret
= ia64_put (c
, nat_loc
, nat_word
);
268 *valp
= (nat_word
& mask
) != 0;
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
)
281 if (IA64_IS_FP_LOC (reg_loc
))
283 /* NaT bit is saved as a NaTVal. This happens when a general
284 register is saved to a floating-point register. */
289 if (ia64_is_big_endian (c
))
290 ret
= ia64_putfp (c
, reg_loc
, unw
.nat_val_be
);
292 ret
= ia64_putfp (c
, reg_loc
, unw
.nat_val_le
);
296 unw_word_t
*src
, *dst
;
299 ret
= ia64_getfp (c
, reg_loc
, &tmp
);
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
))
311 ret
= ia64_putfp (c
, reg_loc
, tmp
);
316 ret
= ia64_getfp (c
, reg_loc
, &tmp
);
320 if (ia64_is_big_endian (c
))
321 *valp
= (memcmp (&tmp
, &unw
.nat_val_be
, sizeof (tmp
)) == 0);
323 *valp
= (memcmp (&tmp
, &unw
.nat_val_le
, sizeof (tmp
)) == 0);
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
))
333 return ia64_put (c
, nat_loc
, *valp
);
335 return ia64_get (c
, nat_loc
, valp
);
338 if (IA64_IS_NULL_LOC (nat_loc
))
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. */
348 return -UNW_EBADREG
; /* can't set NaT bit */
355 mask
= (unw_word_t
) 1 << nat_bitnr
;
356 return update_nat (c
, nat_loc
, mask
, valp
, write
);
360 tdep_access_reg (struct cursor
*c
, unw_regnum_t reg
, unw_word_t
*valp
,
363 ia64_loc_t loc
, reg_loc
, nat_loc
;
364 unw_word_t mask
, val
;
370 /* frame registers: */
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 */
393 loc
= c
->loc
[IA64_REG_IP
];
396 /* preserved registers: */
398 case UNW_IA64_GR
+ 4 ... UNW_IA64_GR
+ 7:
399 loc
= c
->loc
[IA64_REG_R4
+ (reg
- (UNW_IA64_GR
+ 4))];
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
);
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;
423 c
->cfm
= *valp
; /* also update the CFM cache */
429 * Note: broad-side access to the predicates is NOT rotated
430 * (i.e., it is done as if CFM.rrb.pr == 0.
434 c
->pr
= *valp
; /* update the predicate cache */
435 return ia64_put (c
, c
->loc
[IA64_REG_PR
], *valp
);
438 return ia64_get (c
, c
->loc
[IA64_REG_PR
], valp
);
440 case UNW_IA64_GR
+ 32 ... UNW_IA64_GR
+ 127: /* stacked reg */
441 reg
= rotate_gr (c
, reg
- UNW_IA64_GR
);
444 ret
= ia64_get_stacked (c
, reg
, &loc
, NULL
);
449 case UNW_IA64_NAT
+ 32 ... UNW_IA64_NAT
+ 127: /* stacked reg */
450 reg
= rotate_gr (c
, reg
- UNW_IA64_NAT
);
453 ret
= ia64_get_stacked (c
, reg
, &loc
, &nat_loc
);
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
);
461 if ((ret
= ia64_get (c
, c
->ec_loc
, &val
)) < 0)
466 val
= ((val
& ~((unw_word_t
) 0x3f << 52)) | ((*valp
& 0x3f) << 52));
467 return ia64_put (c
, c
->ec_loc
, val
);
471 *valp
= (val
>> 52) & 0x3f;
475 /* scratch & special registers: */
477 case UNW_IA64_GR
+ 0:
479 return -UNW_EREADONLYREG
;
483 case UNW_IA64_NAT
+ 0:
485 return -UNW_EREADONLYREG
;
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)
497 return -UNW_EREADONLYREG
;
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
);
507 case UNW_IA64_GR
+ 15 ... UNW_IA64_GR
+ 18:
508 mask
= 1 << (reg
- (UNW_IA64_GR
+ 15));
511 c
->eh_args
[reg
- (UNW_IA64_GR
+ 15)] = *valp
;
512 c
->eh_valid_mask
|= mask
;
515 else if ((c
->eh_valid_mask
& mask
) != 0)
517 *valp
= c
->eh_args
[reg
- (UNW_IA64_GR
+ 15)];
521 loc
= ia64_scratch_loc (c
, reg
, NULL
);
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)
540 return -UNW_EREADONLYREG
;
542 /* ensure c->pi is up-to-date: */
543 if ((ret
= ia64_make_proc_info (c
)) < 0)
551 Debug (1, "bad register number %d\n", reg
);
556 return ia64_put (c
, loc
, *valp
);
558 return ia64_get (c
, loc
, valp
);
562 tdep_access_fpreg (struct cursor
*c
, int reg
, unw_fpreg_t
*valp
,
569 case UNW_IA64_FR
+ 0:
571 return -UNW_EREADONLYREG
;
572 *valp
= unw
.read_only
.f0
;
575 case UNW_IA64_FR
+ 1:
577 return -UNW_EREADONLYREG
;
579 if (ia64_is_big_endian (c
))
580 *valp
= unw
.read_only
.f1_be
;
582 *valp
= unw
.read_only
.f1_le
;
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;
590 case UNW_IA64_FR
+ 16 ... UNW_IA64_FR
+ 31:
591 loc
= c
->loc
[IA64_REG_F16
+ (reg
- (UNW_IA64_FR
+ 16))];
594 case UNW_IA64_FR
+ 6 ... UNW_IA64_FR
+ 15:
595 loc
= ia64_scratch_loc (c
, reg
, NULL
);
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
);
604 Debug (1, "bad register number %d\n", reg
);
609 return ia64_putfp (c
, loc
, *valp
);
611 return ia64_getfp (c
, loc
, valp
);