1d4e76214Sopenharmony_ci/* libunwind - a platform-independent unwind library 2d4e76214Sopenharmony_ci Copyright (C) 2001-2005 Hewlett-Packard Co 3d4e76214Sopenharmony_ci Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 4d4e76214Sopenharmony_ci 5d4e76214Sopenharmony_ciThis file is part of libunwind. 6d4e76214Sopenharmony_ci 7d4e76214Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining 8d4e76214Sopenharmony_cia copy of this software and associated documentation files (the 9d4e76214Sopenharmony_ci"Software"), to deal in the Software without restriction, including 10d4e76214Sopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish, 11d4e76214Sopenharmony_cidistribute, sublicense, and/or sell copies of the Software, and to 12d4e76214Sopenharmony_cipermit persons to whom the Software is furnished to do so, subject to 13d4e76214Sopenharmony_cithe following conditions: 14d4e76214Sopenharmony_ci 15d4e76214Sopenharmony_ciThe above copyright notice and this permission notice shall be 16d4e76214Sopenharmony_ciincluded in all copies or substantial portions of the Software. 17d4e76214Sopenharmony_ci 18d4e76214Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19d4e76214Sopenharmony_ciEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20d4e76214Sopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21d4e76214Sopenharmony_ciNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22d4e76214Sopenharmony_ciLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23d4e76214Sopenharmony_ciOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24d4e76214Sopenharmony_ciWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 25d4e76214Sopenharmony_ci 26d4e76214Sopenharmony_ci#include "offsets.h" 27d4e76214Sopenharmony_ci#include "unwind_i.h" 28d4e76214Sopenharmony_ci 29d4e76214Sopenharmony_cistatic inline int 30d4e76214Sopenharmony_cilinux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc, 31d4e76214Sopenharmony_ci unw_word_t *num_regsp) 32d4e76214Sopenharmony_ci{ 33d4e76214Sopenharmony_ci#if defined(UNW_LOCAL_ONLY) && !defined(__linux__) 34d4e76214Sopenharmony_ci return -UNW_EINVAL; 35d4e76214Sopenharmony_ci#else 36d4e76214Sopenharmony_ci unw_word_t sc_addr; 37d4e76214Sopenharmony_ci int ret; 38d4e76214Sopenharmony_ci 39d4e76214Sopenharmony_ci if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sp + 0x10 40d4e76214Sopenharmony_ci + LINUX_SIGFRAME_ARG2_OFF, 0), 41d4e76214Sopenharmony_ci &sc_addr)) < 0) 42d4e76214Sopenharmony_ci return ret; 43d4e76214Sopenharmony_ci 44d4e76214Sopenharmony_ci c->sigcontext_addr = sc_addr; 45d4e76214Sopenharmony_ci 46d4e76214Sopenharmony_ci if (!IA64_IS_REG_LOC (c->loc[IA64_REG_IP]) 47d4e76214Sopenharmony_ci && IA64_GET_ADDR (c->loc[IA64_REG_IP]) == sc_addr + LINUX_SC_BR_OFF + 8) 48d4e76214Sopenharmony_ci { 49d4e76214Sopenharmony_ci /* Linux kernels before 2.4.19 and 2.5.10 had buggy 50d4e76214Sopenharmony_ci unwind info for sigtramp. Fix it up here. */ 51d4e76214Sopenharmony_ci c->loc[IA64_REG_IP] = IA64_LOC_ADDR (sc_addr + LINUX_SC_IP_OFF, 0); 52d4e76214Sopenharmony_ci c->cfm_loc = IA64_LOC_ADDR (sc_addr + LINUX_SC_CFM_OFF, 0); 53d4e76214Sopenharmony_ci } 54d4e76214Sopenharmony_ci 55d4e76214Sopenharmony_ci /* do what can't be described by unwind directives: */ 56d4e76214Sopenharmony_ci c->loc[IA64_REG_PFS] = IA64_LOC_ADDR (sc_addr + LINUX_SC_AR_PFS_OFF, 0); 57d4e76214Sopenharmony_ci c->ec_loc = prev_cfm_loc; 58d4e76214Sopenharmony_ci *num_regsp = c->cfm & 0x7f; /* size of frame */ 59d4e76214Sopenharmony_ci return 0; 60d4e76214Sopenharmony_ci#endif 61d4e76214Sopenharmony_ci} 62d4e76214Sopenharmony_ci 63d4e76214Sopenharmony_cistatic inline int 64d4e76214Sopenharmony_cilinux_interrupt (struct cursor *c, ia64_loc_t prev_cfm_loc, 65d4e76214Sopenharmony_ci unw_word_t *num_regsp, int marker) 66d4e76214Sopenharmony_ci{ 67d4e76214Sopenharmony_ci#if defined(UNW_LOCAL_ONLY) && !(defined(__linux__) && defined(__KERNEL__)) 68d4e76214Sopenharmony_ci return -UNW_EINVAL; 69d4e76214Sopenharmony_ci#else 70d4e76214Sopenharmony_ci unw_word_t sc_addr, num_regs; 71d4e76214Sopenharmony_ci ia64_loc_t pfs_loc; 72d4e76214Sopenharmony_ci 73d4e76214Sopenharmony_ci sc_addr = c->sigcontext_addr = c->sp + 0x10; 74d4e76214Sopenharmony_ci 75d4e76214Sopenharmony_ci if ((c->pr & (1UL << LINUX_PT_P_NONSYS)) != 0) 76d4e76214Sopenharmony_ci num_regs = c->cfm & 0x7f; 77d4e76214Sopenharmony_ci else 78d4e76214Sopenharmony_ci num_regs = 0; 79d4e76214Sopenharmony_ci 80d4e76214Sopenharmony_ci /* do what can't be described by unwind directives: */ 81d4e76214Sopenharmony_ci if (marker == ABI_MARKER_OLD_LINUX_INTERRUPT) 82d4e76214Sopenharmony_ci pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_OLD_PT_PFS_OFF, 0); 83d4e76214Sopenharmony_ci else 84d4e76214Sopenharmony_ci pfs_loc = IA64_LOC_ADDR (sc_addr + LINUX_PT_PFS_OFF, 0); 85d4e76214Sopenharmony_ci c->loc[IA64_REG_PFS] = pfs_loc; 86d4e76214Sopenharmony_ci c->ec_loc = prev_cfm_loc; 87d4e76214Sopenharmony_ci *num_regsp = num_regs; /* size of frame */ 88d4e76214Sopenharmony_ci return 0; 89d4e76214Sopenharmony_ci#endif 90d4e76214Sopenharmony_ci} 91d4e76214Sopenharmony_ci 92d4e76214Sopenharmony_cistatic inline int 93d4e76214Sopenharmony_cihpux_sigtramp (struct cursor *c, ia64_loc_t prev_cfm_loc, 94d4e76214Sopenharmony_ci unw_word_t *num_regsp) 95d4e76214Sopenharmony_ci{ 96d4e76214Sopenharmony_ci#if defined(UNW_LOCAL_ONLY) && !defined(__hpux) 97d4e76214Sopenharmony_ci return -UNW_EINVAL; 98d4e76214Sopenharmony_ci#else 99d4e76214Sopenharmony_ci unw_word_t sc_addr, bsp, bspstore; 100d4e76214Sopenharmony_ci ia64_loc_t sc_loc; 101d4e76214Sopenharmony_ci int ret, i; 102d4e76214Sopenharmony_ci 103d4e76214Sopenharmony_ci /* HP-UX passes the address of ucontext_t in r32: */ 104d4e76214Sopenharmony_ci if ((ret = ia64_get_stacked (c, 32, &sc_loc, NULL)) < 0) 105d4e76214Sopenharmony_ci return ret; 106d4e76214Sopenharmony_ci if ((ret = ia64_get (c, sc_loc, &sc_addr)) < 0) 107d4e76214Sopenharmony_ci return ret; 108d4e76214Sopenharmony_ci 109d4e76214Sopenharmony_ci c->sigcontext_addr = sc_addr; 110d4e76214Sopenharmony_ci 111d4e76214Sopenharmony_ci /* Now mark all (preserved) registers as coming from the 112d4e76214Sopenharmony_ci signal context: */ 113d4e76214Sopenharmony_ci c->cfm_loc = IA64_LOC_UC_REG (UNW_IA64_CFM, sc_addr); 114d4e76214Sopenharmony_ci c->loc[IA64_REG_PRI_UNAT_MEM] = IA64_NULL_LOC; 115d4e76214Sopenharmony_ci c->loc[IA64_REG_PSP] = IA64_LOC_UC_REG (UNW_IA64_GR + 12, sc_addr); 116d4e76214Sopenharmony_ci c->loc[IA64_REG_BSP] = IA64_LOC_UC_REG (UNW_IA64_AR_BSP, sc_addr); 117d4e76214Sopenharmony_ci c->loc[IA64_REG_BSPSTORE] = IA64_LOC_UC_REG (UNW_IA64_AR_BSPSTORE, sc_addr); 118d4e76214Sopenharmony_ci c->loc[IA64_REG_PFS] = IA64_LOC_UC_REG (UNW_IA64_AR_PFS, sc_addr); 119d4e76214Sopenharmony_ci c->loc[IA64_REG_RNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_RNAT, sc_addr); 120d4e76214Sopenharmony_ci c->loc[IA64_REG_IP] = IA64_LOC_UC_REG (UNW_IA64_IP, sc_addr); 121d4e76214Sopenharmony_ci c->loc[IA64_REG_R4] = IA64_LOC_UC_REG (UNW_IA64_GR + 4, sc_addr); 122d4e76214Sopenharmony_ci c->loc[IA64_REG_R5] = IA64_LOC_UC_REG (UNW_IA64_GR + 5, sc_addr); 123d4e76214Sopenharmony_ci c->loc[IA64_REG_R6] = IA64_LOC_UC_REG (UNW_IA64_GR + 6, sc_addr); 124d4e76214Sopenharmony_ci c->loc[IA64_REG_R7] = IA64_LOC_UC_REG (UNW_IA64_GR + 7, sc_addr); 125d4e76214Sopenharmony_ci c->loc[IA64_REG_NAT4] = IA64_LOC_UC_REG (UNW_IA64_NAT + 4, sc_addr); 126d4e76214Sopenharmony_ci c->loc[IA64_REG_NAT5] = IA64_LOC_UC_REG (UNW_IA64_NAT + 5, sc_addr); 127d4e76214Sopenharmony_ci c->loc[IA64_REG_NAT6] = IA64_LOC_UC_REG (UNW_IA64_NAT + 6, sc_addr); 128d4e76214Sopenharmony_ci c->loc[IA64_REG_NAT7] = IA64_LOC_UC_REG (UNW_IA64_NAT + 7, sc_addr); 129d4e76214Sopenharmony_ci c->loc[IA64_REG_UNAT] = IA64_LOC_UC_REG (UNW_IA64_AR_UNAT, sc_addr); 130d4e76214Sopenharmony_ci c->loc[IA64_REG_PR] = IA64_LOC_UC_REG (UNW_IA64_PR, sc_addr); 131d4e76214Sopenharmony_ci c->loc[IA64_REG_LC] = IA64_LOC_UC_REG (UNW_IA64_AR_LC, sc_addr); 132d4e76214Sopenharmony_ci c->loc[IA64_REG_FPSR] = IA64_LOC_UC_REG (UNW_IA64_AR_FPSR, sc_addr); 133d4e76214Sopenharmony_ci c->loc[IA64_REG_B1] = IA64_LOC_UC_REG (UNW_IA64_BR + 1, sc_addr); 134d4e76214Sopenharmony_ci c->loc[IA64_REG_B2] = IA64_LOC_UC_REG (UNW_IA64_BR + 2, sc_addr); 135d4e76214Sopenharmony_ci c->loc[IA64_REG_B3] = IA64_LOC_UC_REG (UNW_IA64_BR + 3, sc_addr); 136d4e76214Sopenharmony_ci c->loc[IA64_REG_B4] = IA64_LOC_UC_REG (UNW_IA64_BR + 4, sc_addr); 137d4e76214Sopenharmony_ci c->loc[IA64_REG_B5] = IA64_LOC_UC_REG (UNW_IA64_BR + 5, sc_addr); 138d4e76214Sopenharmony_ci c->loc[IA64_REG_F2] = IA64_LOC_UC_REG (UNW_IA64_FR + 2, sc_addr); 139d4e76214Sopenharmony_ci c->loc[IA64_REG_F3] = IA64_LOC_UC_REG (UNW_IA64_FR + 3, sc_addr); 140d4e76214Sopenharmony_ci c->loc[IA64_REG_F4] = IA64_LOC_UC_REG (UNW_IA64_FR + 4, sc_addr); 141d4e76214Sopenharmony_ci c->loc[IA64_REG_F5] = IA64_LOC_UC_REG (UNW_IA64_FR + 5, sc_addr); 142d4e76214Sopenharmony_ci for (i = 0; i < 16; ++i) 143d4e76214Sopenharmony_ci c->loc[IA64_REG_F16 + i] = IA64_LOC_UC_REG (UNW_IA64_FR + 16 + i, sc_addr); 144d4e76214Sopenharmony_ci 145d4e76214Sopenharmony_ci c->pi.flags |= UNW_PI_FLAG_IA64_RBS_SWITCH; 146d4e76214Sopenharmony_ci 147d4e76214Sopenharmony_ci /* update the CFM cache: */ 148d4e76214Sopenharmony_ci if ((ret = ia64_get (c, c->cfm_loc, &c->cfm)) < 0) 149d4e76214Sopenharmony_ci return ret; 150d4e76214Sopenharmony_ci /* update the PSP cache: */ 151d4e76214Sopenharmony_ci if ((ret = ia64_get (c, c->loc[IA64_REG_PSP], &c->psp)) < 0) 152d4e76214Sopenharmony_ci return ret; 153d4e76214Sopenharmony_ci 154d4e76214Sopenharmony_ci if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &bsp)) < 0 155d4e76214Sopenharmony_ci || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &bspstore)) < 0) 156d4e76214Sopenharmony_ci return ret; 157d4e76214Sopenharmony_ci if (bspstore < bsp) 158d4e76214Sopenharmony_ci /* Dirty partition got spilled into the ucontext_t structure 159d4e76214Sopenharmony_ci itself. We'll need to access it via uc_access(3). */ 160d4e76214Sopenharmony_ci rbs_switch (c, bsp, bspstore, IA64_LOC_UC_ADDR (bsp | 0x1f8, 0)); 161d4e76214Sopenharmony_ci 162d4e76214Sopenharmony_ci c->ec_loc = prev_cfm_loc; 163d4e76214Sopenharmony_ci 164d4e76214Sopenharmony_ci *num_regsp = 0; 165d4e76214Sopenharmony_ci return 0; 166d4e76214Sopenharmony_ci#endif 167d4e76214Sopenharmony_ci} 168d4e76214Sopenharmony_ci 169d4e76214Sopenharmony_ci 170d4e76214Sopenharmony_cistatic inline int 171d4e76214Sopenharmony_cicheck_rbs_switch (struct cursor *c) 172d4e76214Sopenharmony_ci{ 173d4e76214Sopenharmony_ci unw_word_t saved_bsp, saved_bspstore, loadrs, ndirty; 174d4e76214Sopenharmony_ci int ret = 0; 175d4e76214Sopenharmony_ci 176d4e76214Sopenharmony_ci saved_bsp = c->bsp; 177d4e76214Sopenharmony_ci if (c->pi.flags & UNW_PI_FLAG_IA64_RBS_SWITCH) 178d4e76214Sopenharmony_ci { 179d4e76214Sopenharmony_ci /* Got ourselves a frame that has saved ar.bspstore, ar.bsp, 180d4e76214Sopenharmony_ci and ar.rnat, so we're all set for rbs-switching: */ 181d4e76214Sopenharmony_ci if ((ret = ia64_get (c, c->loc[IA64_REG_BSP], &saved_bsp)) < 0 182d4e76214Sopenharmony_ci || (ret = ia64_get (c, c->loc[IA64_REG_BSPSTORE], &saved_bspstore))) 183d4e76214Sopenharmony_ci return ret; 184d4e76214Sopenharmony_ci } 185d4e76214Sopenharmony_ci else if ((c->abi_marker == ABI_MARKER_LINUX_SIGTRAMP 186d4e76214Sopenharmony_ci || c->abi_marker == ABI_MARKER_OLD_LINUX_SIGTRAMP) 187d4e76214Sopenharmony_ci && !IA64_IS_REG_LOC (c->loc[IA64_REG_BSP]) 188d4e76214Sopenharmony_ci && (IA64_GET_ADDR (c->loc[IA64_REG_BSP]) 189d4e76214Sopenharmony_ci == c->sigcontext_addr + LINUX_SC_AR_BSP_OFF)) 190d4e76214Sopenharmony_ci { 191d4e76214Sopenharmony_ci /* When Linux delivers a signal on an alternate stack, it 192d4e76214Sopenharmony_ci does things a bit differently from what the unwind 193d4e76214Sopenharmony_ci conventions allow us to describe: instead of saving 194d4e76214Sopenharmony_ci ar.rnat, ar.bsp, and ar.bspstore, it saves the former two 195d4e76214Sopenharmony_ci plus the "loadrs" value. Because of this, we need to 196d4e76214Sopenharmony_ci detect & record a potential rbs-area switch 197d4e76214Sopenharmony_ci manually... */ 198d4e76214Sopenharmony_ci 199d4e76214Sopenharmony_ci /* If ar.bsp has been saved already AND the current bsp is 200d4e76214Sopenharmony_ci not equal to the saved value, then we know for sure that 201d4e76214Sopenharmony_ci we're past the point where the backing store has been 202d4e76214Sopenharmony_ci switched (and before the point where it's restored). */ 203d4e76214Sopenharmony_ci if ((ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr 204d4e76214Sopenharmony_ci + LINUX_SC_AR_BSP_OFF, 0), 205d4e76214Sopenharmony_ci &saved_bsp) < 0) 206d4e76214Sopenharmony_ci || (ret = ia64_get (c, IA64_LOC_ADDR (c->sigcontext_addr 207d4e76214Sopenharmony_ci + LINUX_SC_LOADRS_OFF, 0), 208d4e76214Sopenharmony_ci &loadrs) < 0)) 209d4e76214Sopenharmony_ci return ret; 210d4e76214Sopenharmony_ci loadrs >>= 16; 211d4e76214Sopenharmony_ci ndirty = rse_num_regs (c->bsp - loadrs, c->bsp); 212d4e76214Sopenharmony_ci saved_bspstore = rse_skip_regs (saved_bsp, -ndirty); 213d4e76214Sopenharmony_ci } 214d4e76214Sopenharmony_ci 215d4e76214Sopenharmony_ci if (saved_bsp == c->bsp) 216d4e76214Sopenharmony_ci return 0; 217d4e76214Sopenharmony_ci 218d4e76214Sopenharmony_ci return rbs_switch (c, saved_bsp, saved_bspstore, c->loc[IA64_REG_RNAT]); 219d4e76214Sopenharmony_ci} 220d4e76214Sopenharmony_ci 221d4e76214Sopenharmony_cistatic inline int 222d4e76214Sopenharmony_ciupdate_frame_state (struct cursor *c) 223d4e76214Sopenharmony_ci{ 224d4e76214Sopenharmony_ci unw_word_t prev_ip, prev_sp, prev_bsp, ip, num_regs; 225d4e76214Sopenharmony_ci ia64_loc_t prev_cfm_loc; 226d4e76214Sopenharmony_ci int ret; 227d4e76214Sopenharmony_ci 228d4e76214Sopenharmony_ci prev_cfm_loc = c->cfm_loc; 229d4e76214Sopenharmony_ci prev_ip = c->ip; 230d4e76214Sopenharmony_ci prev_sp = c->sp; 231d4e76214Sopenharmony_ci prev_bsp = c->bsp; 232d4e76214Sopenharmony_ci 233d4e76214Sopenharmony_ci /* Update the IP cache (do this first: if we reach the end of the 234d4e76214Sopenharmony_ci frame-chain, the rest of the info may not be valid/useful 235d4e76214Sopenharmony_ci anymore. */ 236d4e76214Sopenharmony_ci ret = ia64_get (c, c->loc[IA64_REG_IP], &ip); 237d4e76214Sopenharmony_ci if (ret < 0) 238d4e76214Sopenharmony_ci return ret; 239d4e76214Sopenharmony_ci c->ip = ip; 240d4e76214Sopenharmony_ci 241d4e76214Sopenharmony_ci if ((ip & 0xc) != 0) 242d4e76214Sopenharmony_ci { 243d4e76214Sopenharmony_ci /* don't let obviously bad addresses pollute the cache */ 244d4e76214Sopenharmony_ci Debug (1, "rejecting bad ip=0x%lx\n", (long) c->ip); 245d4e76214Sopenharmony_ci return -UNW_EINVALIDIP; 246d4e76214Sopenharmony_ci } 247d4e76214Sopenharmony_ci 248d4e76214Sopenharmony_ci c->cfm_loc = c->loc[IA64_REG_PFS]; 249d4e76214Sopenharmony_ci /* update the CFM cache: */ 250d4e76214Sopenharmony_ci ret = ia64_get (c, c->cfm_loc, &c->cfm); 251d4e76214Sopenharmony_ci if (ret < 0) 252d4e76214Sopenharmony_ci return ret; 253d4e76214Sopenharmony_ci 254d4e76214Sopenharmony_ci /* Normally, AR.EC is stored in the CFM save-location. That 255d4e76214Sopenharmony_ci save-location contains the full function-state as defined by 256d4e76214Sopenharmony_ci AR.PFS. However, interruptions only save the frame-marker, not 257d4e76214Sopenharmony_ci any other info in CFM. Instead, AR.EC gets saved on the first 258d4e76214Sopenharmony_ci call by the interruption-handler. Thus, interruption-related 259d4e76214Sopenharmony_ci frames need to track the _previous_ CFM save-location since 260d4e76214Sopenharmony_ci that's were AR.EC is saved. We support this by setting ec_loc to 261d4e76214Sopenharmony_ci cfm_loc by default and giving frames marked with an ABI-marker 262d4e76214Sopenharmony_ci the chance to override this value with prev_cfm_loc. */ 263d4e76214Sopenharmony_ci c->ec_loc = c->cfm_loc; 264d4e76214Sopenharmony_ci 265d4e76214Sopenharmony_ci num_regs = 0; 266d4e76214Sopenharmony_ci if (unlikely (c->abi_marker)) 267d4e76214Sopenharmony_ci { 268d4e76214Sopenharmony_ci c->last_abi_marker = c->abi_marker; 269d4e76214Sopenharmony_ci switch (ia64_get_abi_marker (c)) 270d4e76214Sopenharmony_ci { 271d4e76214Sopenharmony_ci case ABI_MARKER_LINUX_SIGTRAMP: 272d4e76214Sopenharmony_ci case ABI_MARKER_OLD_LINUX_SIGTRAMP: 273d4e76214Sopenharmony_ci ia64_set_abi (c, ABI_LINUX); 274d4e76214Sopenharmony_ci if ((ret = linux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0) 275d4e76214Sopenharmony_ci return ret; 276d4e76214Sopenharmony_ci break; 277d4e76214Sopenharmony_ci 278d4e76214Sopenharmony_ci case ABI_MARKER_OLD_LINUX_INTERRUPT: 279d4e76214Sopenharmony_ci case ABI_MARKER_LINUX_INTERRUPT: 280d4e76214Sopenharmony_ci ia64_set_abi (c, ABI_LINUX); 281d4e76214Sopenharmony_ci if ((ret = linux_interrupt (c, prev_cfm_loc, &num_regs, 282d4e76214Sopenharmony_ci c->abi_marker)) < 0) 283d4e76214Sopenharmony_ci return ret; 284d4e76214Sopenharmony_ci break; 285d4e76214Sopenharmony_ci 286d4e76214Sopenharmony_ci case ABI_MARKER_HP_UX_SIGTRAMP: 287d4e76214Sopenharmony_ci ia64_set_abi (c, ABI_HPUX); 288d4e76214Sopenharmony_ci if ((ret = hpux_sigtramp (c, prev_cfm_loc, &num_regs)) < 0) 289d4e76214Sopenharmony_ci return ret; 290d4e76214Sopenharmony_ci break; 291d4e76214Sopenharmony_ci 292d4e76214Sopenharmony_ci default: 293d4e76214Sopenharmony_ci Debug (1, "unknown ABI marker: ABI=%u, context=%u\n", 294d4e76214Sopenharmony_ci c->abi_marker >> 8, c->abi_marker & 0xff); 295d4e76214Sopenharmony_ci return -UNW_EINVAL; 296d4e76214Sopenharmony_ci } 297d4e76214Sopenharmony_ci Debug (12, "sigcontext_addr=%lx (ret=%d)\n", 298d4e76214Sopenharmony_ci (unsigned long) c->sigcontext_addr, ret); 299d4e76214Sopenharmony_ci 300d4e76214Sopenharmony_ci c->sigcontext_off = c->sigcontext_addr - c->sp; 301d4e76214Sopenharmony_ci 302d4e76214Sopenharmony_ci /* update the IP cache: */ 303d4e76214Sopenharmony_ci if ((ret = ia64_get (c, c->loc[IA64_REG_IP], &ip)) < 0) 304d4e76214Sopenharmony_ci return ret; 305d4e76214Sopenharmony_ci c->ip = ip; 306d4e76214Sopenharmony_ci if (ip == 0) 307d4e76214Sopenharmony_ci /* end of frame-chain reached */ 308d4e76214Sopenharmony_ci return 0; 309d4e76214Sopenharmony_ci } 310d4e76214Sopenharmony_ci else 311d4e76214Sopenharmony_ci num_regs = (c->cfm >> 7) & 0x7f; /* size of locals */ 312d4e76214Sopenharmony_ci 313d4e76214Sopenharmony_ci if (!IA64_IS_NULL_LOC (c->loc[IA64_REG_BSP])) 314d4e76214Sopenharmony_ci { 315d4e76214Sopenharmony_ci ret = check_rbs_switch (c); 316d4e76214Sopenharmony_ci if (ret < 0) 317d4e76214Sopenharmony_ci return ret; 318d4e76214Sopenharmony_ci } 319d4e76214Sopenharmony_ci 320d4e76214Sopenharmony_ci c->bsp = rse_skip_regs (c->bsp, -num_regs); 321d4e76214Sopenharmony_ci 322d4e76214Sopenharmony_ci c->sp = c->psp; 323d4e76214Sopenharmony_ci c->abi_marker = 0; 324d4e76214Sopenharmony_ci 325d4e76214Sopenharmony_ci if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp) 326d4e76214Sopenharmony_ci { 327d4e76214Sopenharmony_ci Dprintf ("%s: ip, sp, and bsp unchanged; stopping here (ip=0x%lx)\n", 328d4e76214Sopenharmony_ci __FUNCTION__, (long) ip); 329d4e76214Sopenharmony_ci return -UNW_EBADFRAME; 330d4e76214Sopenharmony_ci } 331d4e76214Sopenharmony_ci 332d4e76214Sopenharmony_ci /* as we unwind, the saved ar.unat becomes the primary unat: */ 333d4e76214Sopenharmony_ci c->loc[IA64_REG_PRI_UNAT_MEM] = c->loc[IA64_REG_UNAT]; 334d4e76214Sopenharmony_ci 335d4e76214Sopenharmony_ci /* restore the predicates: */ 336d4e76214Sopenharmony_ci ret = ia64_get (c, c->loc[IA64_REG_PR], &c->pr); 337d4e76214Sopenharmony_ci if (ret < 0) 338d4e76214Sopenharmony_ci return ret; 339d4e76214Sopenharmony_ci 340d4e76214Sopenharmony_ci c->pi_valid = 0; 341d4e76214Sopenharmony_ci return 0; 342d4e76214Sopenharmony_ci} 343d4e76214Sopenharmony_ci 344d4e76214Sopenharmony_ci 345d4e76214Sopenharmony_ciint 346d4e76214Sopenharmony_ciunw_step (unw_cursor_t *cursor) 347d4e76214Sopenharmony_ci{ 348d4e76214Sopenharmony_ci struct cursor *c = (struct cursor *) cursor; 349d4e76214Sopenharmony_ci int ret; 350d4e76214Sopenharmony_ci 351d4e76214Sopenharmony_ci Debug (1, "(cursor=%p, ip=0x%016lx)\n", c, (unsigned long) c->ip); 352d4e76214Sopenharmony_ci 353d4e76214Sopenharmony_ci if ((ret = ia64_find_save_locs (c)) >= 0 354d4e76214Sopenharmony_ci && (ret = update_frame_state (c)) >= 0) 355d4e76214Sopenharmony_ci ret = (c->ip == 0) ? 0 : 1; 356d4e76214Sopenharmony_ci 357d4e76214Sopenharmony_ci Debug (2, "returning %d (ip=0x%016lx)\n", ret, (unsigned long) c->ip); 358d4e76214Sopenharmony_ci return ret; 359d4e76214Sopenharmony_ci} 360