unwind_i.h revision 8fee91bd1365ad85e524144645ca2a59a45e91d4
1/* libunwind - a platform-independent unwind library 2 Copyright (C) 2001-2003 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#ifndef unwind_i_h 27#define unwind_i_h 28 29#include <memory.h> 30#include <inttypes.h> 31 32#include <libunwind-ia64.h> 33 34#include "config.h" 35#include "internal.h" 36#include "rse.h" 37 38#define IA64_UNW_VER(x) ((x) >> 48) 39#define IA64_UNW_FLAG_MASK 0x0000ffff00000000 40#define IA64_UNW_FLAG_OSMASK 0x0000f00000000000 41#define IA64_UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L) 42#define IA64_UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L) 43#define IA64_UNW_LENGTH(x) ((x) & 0x00000000ffffffffL) 44 45#ifdef MIN 46# undef MIN 47#endif 48#define MIN(a,b) ((a) < (b) ? (a) : (b)) 49 50#include "tdep.h" 51 52/* Bits 0 and 1 of an location are used to encode its type: 53 bit 0: set if location uses floating-point format. 54 bit 1: set if location is a NaT bit on memory stack. */ 55 56#define IA64_LOC_TYPE_FP (1 << 0) 57#define IA64_LOC_TYPE_MEMSTK_NAT (1 << 1) 58 59#ifdef UNW_LOCAL_ONLY 60 61#define IA64_LOC_REG(r,t) (((r) << 2) | (t)) 62#define IA64_LOC_ADDR(a,t) (((a) & ~0x3) | (t)) 63#define IA64_LOC_UC_ADDR(a,t) IA64_LOC_ADDR(a, t) 64#define IA64_LOC_UC_REG(a,t) 65#define IA64_NULL_LOC (0) 66 67#define IA64_GET_REG(l) ((l) >> 2) 68#define IA64_GET_ADDR(l) ((l) & ~0x3) 69#define IA64_IS_NULL_LOC(l) ((l) == 0) 70#define IA64_IS_FP_LOC(l) (((l) & IA64_LOC_TYPE_FP) != 0) 71#define IA64_IS_MEMSTK_NAT(l) (((l) & IA64_LOC_TYPE_MEMSTK_NAT) != 0) 72#define IA64_IS_REG_LOC(l) 0 73#define IA64_IS_UC_LOC(l) 0 74 75#define IA64_REG_LOC(c,r) ((unw_word_t) tdep_uc_addr((c)->as_arg, (r))) 76#define IA64_FPREG_LOC(c,r) \ 77 ((unw_word_t) tdep_uc_addr((c)->as_arg, (r)) | IA64_LOC_TYPE_FP) 78 79# define ia64_find_proc_info(c,ip,n) \ 80 tdep_find_proc_info(unw_local_addr_space, (ip), &(c)->pi, (n), \ 81 (c)->as_arg) 82# define ia64_put_unwind_info(c, pi) do { ; } while (0) 83 84/* Note: the register accessors (ia64_{get,set}{,fp}()) must check for 85 NULL locations because tdep_uc_addr() returns NULL for unsaved 86 registers. */ 87 88static inline int 89ia64_getfp (struct cursor *c, unw_word_t loc, unw_fpreg_t *val) 90{ 91 if (!loc) 92 { 93 debug (150, "%s: access to unsaved register\n", __FUNCTION__); 94 return -UNW_EBADREG; 95 } 96 *val = *(unw_fpreg_t *) IA64_GET_ADDR (loc); 97 return 0; 98} 99 100static inline int 101ia64_putfp (struct cursor *c, unw_word_t loc, unw_fpreg_t val) 102{ 103 if (!loc) 104 { 105 debug (150, "%s: access to unsaved register\n", __FUNCTION__); 106 return -UNW_EBADREG; 107 } 108 *(unw_fpreg_t *) IA64_GET_ADDR (loc) = val; 109 return 0; 110} 111 112static inline int 113ia64_get (struct cursor *c, unw_word_t loc, unw_word_t *val) 114{ 115 if (!loc) 116 { 117 debug (150, "%s: access to unsaved register\n", __FUNCTION__); 118 return -UNW_EBADREG; 119 } 120 *val = *(unw_word_t *) IA64_GET_ADDR (loc); 121 return 0; 122} 123 124static inline int 125ia64_put (struct cursor *c, unw_word_t loc, unw_word_t val) 126{ 127 if (!loc) 128 { 129 debug (150, "%s: access to unsaved register\n", __FUNCTION__); 130 return -UNW_EBADREG; 131 } 132 *(unw_word_t *) IA64_GET_ADDR (loc) = (val); 133 return 0; 134} 135 136#else /* !UNW_LOCAL_ONLY */ 137 138/* Bits 0 and 1 of the second word (w1) of a location are used 139 to further distinguish what location we're dealing with: 140 141 bit 0: set if the location is a register 142 bit 1: set of the location is accessed via uc_access(3) */ 143#define IA64_LOC_TYPE_REG (1 << 0) 144#define IA64_LOC_TYPE_UC (1 << 1) 145 146#define IA64_LOC_REG(r,t) ((ia64_loc_t) { ((r) << 2) | (t), \ 147 IA64_LOC_TYPE_REG }) 148#define IA64_LOC_ADDR(a,t) ((ia64_loc_t) { ((a) & ~0x3) | (t), 0 }) 149#define IA64_LOC_UC_ADDR(a,t) ((ia64_loc_t) { ((a) & ~0x3) | (t), \ 150 IA64_LOC_TYPE_UC }) 151#define IA64_LOC_UC_REG(r,a) ((ia64_loc_t) { ((r) << 2), \ 152 ((a) | IA64_LOC_TYPE_REG \ 153 | IA64_LOC_TYPE_UC) }) 154#define IA64_NULL_LOC ((ia64_loc_t) { 0, 0 }) 155 156#define IA64_GET_REG(l) ((l).w0 >> 2) 157#define IA64_GET_ADDR(l) ((l).w0 & ~0x3) 158#define IA64_GET_AUX_ADDR(l) ((l).w1 & ~0x3) 159#define IA64_IS_NULL_LOC(l) (((l).w0 | (l).w1) == 0) 160#define IA64_IS_FP_LOC(l) (((l).w0 & IA64_LOC_TYPE_FP) != 0) 161#define IA64_IS_MEMSTK_NAT(l) (((l).w0 & IA64_LOC_TYPE_MEMSTK_NAT) != 0) 162#define IA64_IS_REG_LOC(l) (((l).w1 & IA64_LOC_TYPE_REG) != 0) 163#define IA64_IS_UC_LOC(l) (((l).w1 & IA64_LOC_TYPE_UC) != 0) 164 165#define IA64_REG_LOC(c,r) IA64_LOC_REG ((r), 0) 166#define IA64_FPREG_LOC(c,r) IA64_LOC_REG ((r), IA64_LOC_TYPE_FP) 167 168# define ia64_find_proc_info(c,ip,n) \ 169 (*(c)->as->acc.find_proc_info)((c)->as, (ip), &(c)->pi, (n), \ 170 (c)->as_arg) 171# define ia64_put_unwind_info(c,pi) \ 172 (*(c)->as->acc.put_unwind_info)((c)->as, (pi), (c)->as_arg) 173 174#define ia64_uc_access_reg UNW_OBJ(uc_access_reg) 175#define ia64_uc_access_fpreg UNW_OBJ(uc_access_fpreg) 176 177extern int ia64_uc_access_reg (struct cursor *c, ia64_loc_t loc, 178 unw_word_t *valp, int write); 179extern int ia64_uc_access_fpreg (struct cursor *c, ia64_loc_t loc, 180 unw_fpreg_t *valp, int write); 181 182static inline int 183ia64_getfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t *val) 184{ 185 unw_word_t addr; 186 int ret; 187 188 if (IA64_IS_UC_LOC (loc)) 189 return ia64_uc_access_fpreg (c, loc, val, 0); 190 191 if (IA64_IS_REG_LOC (loc)) 192 return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc), 193 val, 0, c->as_arg); 194 195 addr = IA64_GET_ADDR (loc); 196 ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val->raw.bits[0], 0, 197 c->as_arg); 198 if (ret < 0) 199 return ret; 200 201 return (*c->as->acc.access_mem) (c->as, addr + 8, &val->raw.bits[1], 0, 202 c->as_arg); 203} 204 205static inline int 206ia64_putfp (struct cursor *c, ia64_loc_t loc, unw_fpreg_t val) 207{ 208 unw_word_t addr; 209 int ret; 210 211 if (IA64_IS_UC_LOC (loc)) 212 return ia64_uc_access_fpreg (c, loc, &val, 1); 213 214 if (IA64_IS_REG_LOC (loc)) 215 return (*c->as->acc.access_fpreg) (c->as, IA64_GET_REG (loc), &val, 1, 216 c->as_arg); 217 218 addr = IA64_GET_ADDR (loc); 219 ret = (*c->as->acc.access_mem) (c->as, addr + 0, &val.raw.bits[0], 1, 220 c->as_arg); 221 if (ret < 0) 222 return ret; 223 224 return (*c->as->acc.access_mem) (c->as, addr + 8, &val.raw.bits[1], 1, 225 c->as_arg); 226} 227 228/* Get the 64 data bits from location LOC. If bit 0 is cleared, LOC 229 is a memory address, otherwise it is a register number. If the 230 register is a floating-point register, the 64 bits are read from 231 the significand bits. */ 232 233static inline int 234ia64_get (struct cursor *c, ia64_loc_t loc, unw_word_t *val) 235{ 236 if (IA64_IS_FP_LOC (loc)) 237 { 238 unw_fpreg_t tmp; 239 int ret; 240 241 ret = ia64_getfp (c, loc, &tmp); 242 if (ret < 0) 243 return ret; 244 245 if (c->as->big_endian) 246 *val = tmp.raw.bits[1]; 247 else 248 *val = tmp.raw.bits[0]; 249 return 0; 250 } 251 252 if (IA64_IS_UC_LOC (loc)) 253 return ia64_uc_access_reg (c, loc, val, 0); 254 255 if (IA64_IS_REG_LOC (loc)) 256 return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), val, 0, 257 c->as_arg); 258 else 259 return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), val, 0, 260 c->as_arg); 261} 262 263static inline int 264ia64_put (struct cursor *c, ia64_loc_t loc, unw_word_t val) 265{ 266 if (IA64_IS_FP_LOC (loc)) 267 { 268 unw_fpreg_t tmp; 269 270 memset (&tmp, 0, sizeof (tmp)); 271 if (c->as->big_endian) 272 tmp.raw.bits[1] = val; 273 else 274 tmp.raw.bits[0] = val; 275 return ia64_putfp (c, loc, tmp); 276 } 277 278 if (IA64_IS_UC_LOC (loc)) 279 return ia64_uc_access_reg (c, loc, &val, 1); 280 281 if (IA64_IS_REG_LOC (loc)) 282 return (*c->as->acc.access_reg)(c->as, IA64_GET_REG (loc), &val, 1, 283 c->as_arg); 284 else 285 return (*c->as->acc.access_mem)(c->as, IA64_GET_ADDR (loc), &val, 1, 286 c->as_arg); 287} 288 289#endif /* !UNW_LOCAL_ONLY */ 290 291struct ia64_unwind_block 292 { 293 unw_word_t header; 294 unw_word_t desc[0]; /* unwind descriptors */ 295 296 /* Personality routine and language-specific data follow behind 297 descriptors. */ 298 }; 299 300enum ia64_where 301 { 302 IA64_WHERE_NONE, /* register isn't saved at all */ 303 IA64_WHERE_GR, /* register is saved in a general register */ 304 IA64_WHERE_FR, /* register is saved in a floating-point register */ 305 IA64_WHERE_BR, /* register is saved in a branch register */ 306 IA64_WHERE_SPREL, /* register is saved on memstack (sp-relative) */ 307 IA64_WHERE_PSPREL, /* register is saved on memstack (psp-relative) */ 308 309 /* At the end of each prologue these locations get resolved to 310 IA64_WHERE_PSPREL and IA64_WHERE_GR, respectively: */ 311 312 IA64_WHERE_SPILL_HOME, /* register is saved in its spill home */ 313 IA64_WHERE_GR_SAVE /* register is saved in next general register */ 314 }; 315 316#define IA64_WHEN_NEVER 0x7fffffff 317 318struct ia64_reg_info 319 { 320 unw_word_t val; /* save location: register number or offset */ 321 enum ia64_where where; /* where the register gets saved */ 322 int when; /* when the register gets saved */ 323 }; 324 325struct ia64_labeled_state; /* opaque structure */ 326 327struct ia64_reg_state 328 { 329 struct ia64_reg_state *next; /* next (outer) element on state stack */ 330 struct ia64_reg_info reg[IA64_NUM_PREGS]; /* register save locations */ 331 }; 332 333struct ia64_state_record 334 { 335 unsigned int first_region : 1; /* is this the first region? */ 336 unsigned int done : 1; /* are we done scanning descriptors? */ 337 unsigned int any_spills : 1; /* got any register spills? */ 338 unsigned int in_body : 1; /* are we inside prologue or body? */ 339 uint8_t *imask; /* imask of spill_mask record or NULL */ 340 uint16_t abi_marker; 341 342 unw_word_t pr_val; /* predicate values */ 343 unw_word_t pr_mask; /* predicate mask */ 344 345 long spill_offset; /* psp-relative offset for spill base */ 346 int region_start; 347 int region_len; 348 int when_sp_restored; 349 int epilogue_count; 350 int when_target; 351 352 uint8_t gr_save_loc; /* next save register */ 353 uint8_t return_link_reg; /* branch register used as return pointer */ 354 355 struct ia64_labeled_state *labeled_states; 356 struct ia64_reg_state curr; 357 }; 358 359struct ia64_labeled_state 360 { 361 struct ia64_labeled_state *next; /* next label (or NULL) */ 362 unsigned long label; /* label for this state */ 363 struct ia64_reg_state saved_state; 364 }; 365 366/* Convenience macros: */ 367#define ia64_make_proc_info UNW_OBJ(make_proc_info) 368#define ia64_create_state_record UNW_OBJ(create_state_record) 369#define ia64_free_state_record UNW_OBJ(free_state_record) 370#define ia64_find_save_locs UNW_OBJ(find_save_locs) 371#define ia64_per_thread_cache UNW_OBJ(per_thread_cache) 372#define ia64_script_cache_init UNW_OBJ(script_cache_init) 373#define ia64_access_reg UNW_OBJ(access_reg) 374#define ia64_access_fpreg UNW_OBJ(access_fpreg) 375#define ia64_scratch_loc UNW_OBJ(scratch_loc) 376#define ia64_local_resume UNW_OBJ(local_resume) 377#define ia64_local_addr_space_init UNW_OBJ(local_addr_space_init) 378#define ia64_strloc UNW_OBJ(strloc) 379#define ia64_install_cursor UNW_OBJ(install_cursor) 380#define rbs_switch UNW_OBJ(rbs_switch) 381#define rbs_find_stacked UNW_OBJ(rbs_find_stacked) 382#define rbs_cover_and_flush UNW_OBJ(rbs_cover_and_flush) 383#define ia64_init UNW_ARCH_OBJ(init) 384 385extern int ia64_make_proc_info (struct cursor *c); 386extern int ia64_create_state_record (struct cursor *c, 387 struct ia64_state_record *sr); 388extern int ia64_free_state_record (struct ia64_state_record *sr); 389extern int ia64_find_save_locs (struct cursor *c); 390extern void ia64_script_cache_init (struct ia64_script_cache *cache); 391extern void ia64_local_addr_space_init (void); 392extern void ia64_init (void); 393extern int ia64_access_reg (struct cursor *c, unw_regnum_t reg, 394 unw_word_t *valp, int write); 395extern int ia64_access_fpreg (struct cursor *c, unw_regnum_t reg, 396 unw_fpreg_t *valp, int write); 397extern ia64_loc_t ia64_scratch_loc (struct cursor *c, unw_regnum_t reg); 398 399extern void ia64_install_cursor (struct cursor *c, unw_word_t pri_unat, 400 unw_word_t *extra) 401 __attribute__ ((noreturn)); 402extern int ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, 403 void *arg); 404extern int rbs_switch (struct cursor *c, 405 unw_word_t saved_bsp, unw_word_t saved_bspstore, 406 ia64_loc_t saved_rnat_loc); 407extern int rbs_find_stacked (struct cursor *c, unw_word_t regs_to_skip, 408 ia64_loc_t *locp, ia64_loc_t *rnat_locp); 409extern int rbs_cover_and_flush (struct cursor *c, unw_word_t nregs); 410 411/* Warning: ia64_strloc() is for debugging only and it is NOT re-entrant! */ 412extern const char *ia64_strloc (ia64_loc_t loc); 413 414/* Return true if the register-backing store is inside a ucontext_t 415 that needs to be accessed via uc_access(3). */ 416 417static inline int 418rbs_on_uc (struct rbs_area *rbs) 419{ 420 return IA64_IS_UC_LOC (rbs->rnat_loc) && !IA64_IS_REG_LOC (rbs->rnat_loc); 421} 422 423/* Return true if BSP points to a word that's stored on register 424 backing-store RBS. */ 425static inline int 426rbs_contains (struct rbs_area *rbs, unw_word_t bsp) 427{ 428 int result; 429 430 /* Caveat: this takes advantage of unsigned arithmetic. The full 431 test is (bsp >= rbs->end - rbs->size) && (bsp < rbs->end). We 432 take advantage of the fact that -n == ~n + 1. */ 433 result = bsp - rbs->end > ~rbs->size; 434 debug (150, "%s: 0x%lx in [0x%lx-0x%lx) => %d\n", __FUNCTION__, 435 (long) bsp, (long) (rbs->end - rbs->size), (long) rbs->end, result); 436 return result; 437} 438 439static ia64_loc_t 440rbs_get_rnat_loc (struct rbs_area *rbs, unw_word_t bsp) 441{ 442 unw_word_t rnat_addr = ia64_rse_rnat_addr (bsp); 443 ia64_loc_t rnat_loc; 444 445 if (rbs_contains (rbs, rnat_addr)) 446 { 447 if (rbs_on_uc (rbs)) 448 rnat_loc = IA64_LOC_UC_ADDR (rnat_addr, 0); 449 else 450 rnat_loc = IA64_LOC_ADDR (rnat_addr, 0); 451 } 452 else 453 rnat_loc = rbs->rnat_loc; 454 return rnat_loc; 455} 456 457static ia64_loc_t 458rbs_loc (struct rbs_area *rbs, unw_word_t bsp) 459{ 460 if (rbs_on_uc (rbs)) 461 return IA64_LOC_UC_ADDR (bsp, 0); 462 else 463 return IA64_LOC_ADDR (bsp, 0); 464} 465 466static inline int 467ia64_get_stacked (struct cursor *c, unw_word_t reg, 468 ia64_loc_t *locp, ia64_loc_t *rnat_locp) 469{ 470 struct rbs_area *rbs = c->rbs_area + c->rbs_curr; 471 unw_word_t addr, regs_to_skip = reg - 32; 472 int ret = 0; 473 474 assert (reg >= 32 && reg < 128); 475 476 addr = ia64_rse_skip_regs (c->bsp, regs_to_skip); 477 if (locp) 478 *locp = rbs_loc (rbs, addr); 479 if (rnat_locp) 480 *rnat_locp = rbs_get_rnat_loc (rbs, addr); 481 482 if (!rbs_contains (rbs, addr)) 483 ret = rbs_find_stacked (c, regs_to_skip, locp, rnat_locp); 484 return ret; 485} 486 487/* XXX should be in glibc: */ 488#ifndef IA64_SC_FLAG_ONSTACK 489# define IA64_SC_FLAG_ONSTACK_BIT 0 /* running on signal stack? */ 490# define IA64_SC_FLAG_IN_SYSCALL_BIT 1 /* did signal interrupt a syscall? */ 491# define IA64_SC_FLAG_FPH_VALID_BIT 2 /* is state in f[32]-f[127] valid? */ 492 493# define IA64_SC_FLAG_ONSTACK (1 << IA64_SC_FLAG_ONSTACK_BIT) 494# define IA64_SC_FLAG_IN_SYSCALL (1 << IA64_SC_FLAG_IN_SYSCALL_BIT) 495# define IA64_SC_FLAG_FPH_VALID (1 << IA64_SC_FLAG_FPH_VALID_BIT) 496#endif 497 498#endif /* unwind_i_h */ 499