📄 unwind-ia64.c
字号:
return dp;}/* RSE helper functions. */static inline unsigned longia64_rse_slot_num (unsigned long *addr){ return (((unsigned long) addr) >> 3) & 0x3f;}/* Return TRUE if ADDR is the address of an RNAT slot. */static inline unsigned longia64_rse_is_rnat_slot (unsigned long *addr){ return ia64_rse_slot_num (addr) == 0x3f;}/* Returns the address of the RNAT slot that covers the slot at address SLOT_ADDR. */static inline unsigned long *ia64_rse_rnat_addr (unsigned long *slot_addr){ return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));}/* Calculate the number of registers in the dirty partition starting at BSPSTORE with a size of DIRTY bytes. This isn't simply DIRTY divided by eight because the 64th slot is used to store ar.rnat. */static inline unsigned longia64_rse_num_regs (unsigned long *bspstore, unsigned long *bsp){ unsigned long slots = (bsp - bspstore); return slots - (ia64_rse_slot_num (bspstore) + slots)/0x40;}/* The inverse of the above: given bspstore and the number of registers, calculate ar.bsp. */static inline unsigned long *ia64_rse_skip_regs (unsigned long *addr, long num_regs){ long delta = ia64_rse_slot_num (addr) + num_regs; if (num_regs < 0) delta -= 0x3e; return addr + num_regs + delta/0x3f;}/* Copy register backing store from SRC to DST, LEN words (which include both saved registers and nat collections). DST_RNAT is a partial nat collection for DST. SRC and DST don't have to be equal modulo 64 slots, so it cannot be done with a simple memcpy as the nat collections will be at different relative offsets and need to be combined together. */static voidia64_copy_rbs (struct _Unwind_Context *info, unsigned long dst, unsigned long src, long len, unsigned long dst_rnat){ long count; unsigned long src_rnat; unsigned long shift1, shift2; len <<= 3; dst_rnat &= (1UL << ((dst >> 3) & 0x3f)) - 1; src_rnat = src >= info->regstk_top ? info->rnat : *(unsigned long *) (src | 0x1f8); src_rnat &= ~((1UL << ((src >> 3) & 0x3f)) - 1); /* Just to make sure. */ src_rnat &= ~(1UL << 63); shift1 = ((dst - src) >> 3) & 0x3f; if ((dst & 0x1f8) < (src & 0x1f8)) shift1--; shift2 = 0x3f - shift1; if ((dst & 0x1f8) >= (src & 0x1f8)) { count = ~dst & 0x1f8; goto first; } count = ~src & 0x1f8; goto second; while (len > 0) { src_rnat = src >= info->regstk_top ? info->rnat : *(unsigned long *) (src | 0x1f8); /* Just to make sure. */ src_rnat &= ~(1UL << 63); count = shift2 << 3;first: if (count > len) count = len; memcpy ((char *) dst, (char *) src, count); dst += count; src += count; len -= count; dst_rnat |= (src_rnat << shift1) & ~(1UL << 63); if (len <= 0) break; *(long *) dst = dst_rnat; dst += 8; dst_rnat = 0; count = shift1 << 3;second: if (count > len) count = len; memcpy ((char *) dst, (char *) src, count); dst += count; src += count + 8; len -= count + 8; dst_rnat |= (src_rnat >> shift2); } if ((dst & 0x1f8) == 0x1f8) { *(long *) dst = dst_rnat; dst += 8; dst_rnat = 0; } /* Set info->regstk_top to lowest rbs address which will use info->rnat collection. */ info->regstk_top = dst & ~0x1ffUL; info->rnat = dst_rnat;}/* Unwind accessors. */static voidunw_access_gr (struct _Unwind_Context *info, int regnum, unsigned long *val, char *nat, int write){ unsigned long *addr, *nat_addr = 0, nat_mask = 0, dummy_nat; struct unw_ireg *ireg; if ((unsigned) regnum - 1 >= 127) abort (); if (regnum < 1) { nat_addr = addr = &dummy_nat; dummy_nat = 0; } else if (regnum < 32) { /* Access a non-stacked register. */ ireg = &info->ireg[regnum - 2]; addr = ireg->loc; if (addr) { nat_addr = addr + ireg->nat.off; switch (ireg->nat.type) { case UNW_NAT_VAL: /* Simulate getf.sig/setf.sig. */ if (write) { if (*nat) { /* Write NaTVal and be done with it. */ addr[0] = 0; addr[1] = 0x1fffe; return; } addr[1] = 0x1003e; } else if (addr[0] == 0 && addr[1] == 0x1ffe) { /* Return NaT and be done with it. */ *val = 0; *nat = 1; return; } /* FALLTHRU */ case UNW_NAT_NONE: dummy_nat = 0; nat_addr = &dummy_nat; break; case UNW_NAT_MEMSTK: nat_mask = 1UL << ((long) addr & 0x1f8)/8; break; case UNW_NAT_REGSTK: if ((unsigned long) addr >= info->regstk_top) nat_addr = &info->rnat; else nat_addr = ia64_rse_rnat_addr (addr); nat_mask = 1UL << ia64_rse_slot_num (addr); break; } } } else { /* Access a stacked register. */ addr = ia64_rse_skip_regs ((unsigned long *) info->bsp, regnum - 32); if ((unsigned long) addr >= info->regstk_top) nat_addr = &info->rnat; else nat_addr = ia64_rse_rnat_addr (addr); nat_mask = 1UL << ia64_rse_slot_num (addr); } if (write) { *addr = *val; if (*nat) *nat_addr |= nat_mask; else *nat_addr &= ~nat_mask; } else { *val = *addr; *nat = (*nat_addr & nat_mask) != 0; }}/* Get the value of register REG as saved in CONTEXT. */_Unwind_Word_Unwind_GetGR (struct _Unwind_Context *context, int index){ _Unwind_Word ret; char nat; if (index == 1) return context->gp; else if (index >= 15 && index <= 18) return context->eh_data[index - 15]; else unw_access_gr (context, index, &ret, &nat, 0); return ret;}/* Overwrite the saved value for register REG in CONTEXT with VAL. */void_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val){ char nat = 0; if (index == 1) context->gp = val; else if (index >= 15 && index <= 18) context->eh_data[index - 15] = val; else unw_access_gr (context, index, &val, &nat, 1);}/* Retrieve the return address for CONTEXT. */inline _Unwind_Ptr_Unwind_GetIP (struct _Unwind_Context *context){ return context->rp;}/* Overwrite the return address for CONTEXT with VAL. */inline void_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val){ context->rp = val;}void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context){ return context->lsda;}_Unwind_Ptr_Unwind_GetRegionStart (struct _Unwind_Context *context){ return context->region_start;}void *_Unwind_FindEnclosingFunction (void *pc){ struct unw_table_entry *ent; unsigned long segment_base, gp; ent = _Unwind_FindTableEntry (pc, &segment_base, &gp); if (ent == NULL) return NULL; else return (void *)(segment_base + ent->start_offset);}/* Get the value of the CFA as saved in CONTEXT. In GCC/Dwarf2 parlance, the CFA is the value of the stack pointer on entry; In IA-64 unwind parlance, this is the PSP. */_Unwind_Word_Unwind_GetCFA (struct _Unwind_Context *context){ return (_Unwind_Ptr) context->psp;}/* Get the value of the Backing Store Pointer as saved in CONTEXT. */_Unwind_Word_Unwind_GetBSP (struct _Unwind_Context *context){ return (_Unwind_Ptr) context->bsp;}#ifdef MD_UNWIND_SUPPORT#include MD_UNWIND_SUPPORT#endifstatic _Unwind_Reason_Codeuw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs){ struct unw_table_entry *ent; unsigned long *unw, header, length; unsigned char *insn, *insn_end; unsigned long segment_base; struct unw_reg_info *r; memset (fs, 0, sizeof (*fs)); for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) r->when = UNW_WHEN_NEVER; context->lsda = 0; ent = _Unwind_FindTableEntry ((void *) context->rp, &segment_base, &context->gp); if (ent == NULL) { /* Couldn't find unwind info for this function. Try an os-specific fallback mechanism. This will necessarily not provide a personality routine or LSDA. */#ifdef MD_FALLBACK_FRAME_STATE_FOR if (MD_FALLBACK_FRAME_STATE_FOR (context, fs) == _URC_NO_REASON) return _URC_NO_REASON; /* [SCRA 11.4.1] A leaf function with no memory stack, no exception handlers, and which keeps the return value in B0 does not need an unwind table entry. This can only happen in the frame after unwinding through a signal handler. Avoid infinite looping by requiring that B0 != RP. RP == 0 terminates the chain. */ if (context->br_loc[0] && *context->br_loc[0] != context->rp && context->rp != 0) { fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; fs->curr.reg[UNW_REG_RP].when = -1; fs->curr.reg[UNW_REG_RP].val = 0; return _URC_NO_REASON; }#endif return _URC_END_OF_STACK; } context->region_start = ent->start_offset + segment_base; fs->when_target = ((context->rp & -16) - context->region_start) / 16 * 3 + (context->rp & 15); unw = (unsigned long *) (ent->info_offset + segment_base); header = *unw; length = UNW_LENGTH (header); /* ??? Perhaps check UNW_VER / UNW_FLAG_OSMASK. */ if (UNW_FLAG_EHANDLER (header) | UNW_FLAG_UHANDLER (header)) { fs->personality = *(_Unwind_Personality_Fn *) (unw[length + 1] + context->gp); context->lsda = unw + length + 2; } insn = (unsigned char *) (unw + 1); insn_end = (unsigned char *) (unw + 1 + length); while (!fs->done && insn < insn_end) insn = unw_decode (insn, fs->in_body, fs); free_label_states (fs->labeled_states); free_state_stack (&fs->curr);#ifdef ENABLE_MALLOC_CHECKING if (reg_state_alloced || labeled_state_alloced) abort ();#endif /* If we're in the epilogue, sp has been restored and all values on the memory stack below psp also have been restored. */ if (fs->when_target > fs->epilogue_start) { struct unw_reg_info *r; fs->curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE; fs->curr.reg[UNW_REG_PSP].val = 0; for (r = fs->curr.reg; r < fs->curr.reg + UNW_NUM_REGS; ++r) if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10) || r->where == UNW_WHERE_SPREL) r->where = UNW_WHERE_NONE; } /* If RP did't get saved, generate entry for the return link register. */ if (fs->curr.reg[UNW_REG_RP].when >= fs->when_target) { fs->curr.reg[UNW_REG_RP].where = UNW_WHERE_BR; fs->curr.reg[UNW_REG_RP].when = -1; fs->curr.reg[UNW_REG_RP].val = fs->return_link_reg; } return _URC_NO_REASON;}static voiduw_update_reg_address (struct _Unwind_Context *context, _Unwind_FrameState *fs, enum unw_register_index regno){ struct unw_reg_info *r = fs->curr.reg + regno; void *addr; unsigned long rval; if (r->where == UNW_WHERE_NONE || r->when >= fs->when_target) return; rval = r->val; switch (r->where) { case UNW_WHERE_GR: if (rval >= 32) addr = ia64_rse_skip_regs ((unsigned long *) context->bsp, rval - 32); else if (rval >= 2) addr = context->ireg[rval - 2].loc; else if (rval == 0) { static const unsigned long dummy; addr = (void *) &dummy; } else abort (); break; case UNW_WHERE_FR: if (rval >= 2 && rval < 32) addr = context->fr_loc[rval - 2]; else abort (); break; case UNW_WHERE_BR: /* Note that while RVAL can only be 1-5 from normal descriptors, we can want to look at B0, B6 and B7 due to having manually unwound a signal frame. */ if (rval < 8) addr = context->br_loc[rval]; else abort (); break; case UNW_WHERE_SPREL: addr = (void *)(context->sp + rval); break; case UNW_WHERE_PSPREL: addr = (void *)(context->psp + rval); break; default: abort (); } switch (regno) { case UNW_REG_R2 ... UNW_REG_R31: context->ireg[regno - UNW_REG_R2].loc = addr; switch (r->where) { case UNW_WHERE_GR: if (rval >= 32) { context->ireg[regno - UNW_REG_R2].nat.type = UNW_NAT_MEMSTK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -