📄 unwind.c
字号:
return; } memcpy(rs, &sr->curr, sizeof(*rs)); rs->next = sr->stack; sr->stack = rs;}static voidpop (struct unw_state_record *sr){ struct unw_reg_state *rs; if (!sr->stack) { printk ("unwind: stack underflow!\n"); return; } rs = sr->stack; sr->stack = rs->next; free_reg_state(rs);}static enum unw_register_index __attribute__((const))decode_abreg (unsigned char abreg, int memory){ switch (abreg) { case 0x04 ... 0x07: return UNW_REG_R4 + (abreg - 0x04); case 0x22 ... 0x25: return UNW_REG_F2 + (abreg - 0x22); case 0x30 ... 0x3f: return UNW_REG_F16 + (abreg - 0x30); case 0x41 ... 0x45: return UNW_REG_B1 + (abreg - 0x41); case 0x60: return UNW_REG_PR; case 0x61: return UNW_REG_PSP; case 0x62: return memory ? UNW_REG_PRI_UNAT_MEM : UNW_REG_PRI_UNAT_GR; case 0x63: return UNW_REG_RP; case 0x64: return UNW_REG_BSP; case 0x65: return UNW_REG_BSPSTORE; case 0x66: return UNW_REG_RNAT; case 0x67: return UNW_REG_UNAT; case 0x68: return UNW_REG_FPSR; case 0x69: return UNW_REG_PFS; case 0x6a: return UNW_REG_LC; default: break; } dprintk("unwind: bad abreg=0x%x\n", abreg); return UNW_REG_LC;}static voidset_reg (struct unw_reg_info *reg, enum unw_where where, int when, unsigned long val){ reg->val = val; reg->where = where; if (reg->when == UNW_WHEN_NEVER) reg->when = when;}static voidalloc_spill_area (unsigned long *offp, unsigned long regsize, struct unw_reg_info *lo, struct unw_reg_info *hi){ struct unw_reg_info *reg; for (reg = hi; reg >= lo; --reg) { if (reg->where == UNW_WHERE_SPILL_HOME) { reg->where = UNW_WHERE_PSPREL; reg->val = 0x10 - *offp; *offp += regsize; } }}static inline voidspill_next_when (struct unw_reg_info **regp, struct unw_reg_info *lim, unw_word t){ struct unw_reg_info *reg; for (reg = *regp; reg <= lim; ++reg) { if (reg->where == UNW_WHERE_SPILL_HOME) { reg->when = t; *regp = reg + 1; return; } } dprintk("unwind: excess spill!\n");}static inline voidfinish_prologue (struct unw_state_record *sr){ struct unw_reg_info *reg; unsigned long off; int i; /* * First, resolve implicit register save locations (see Section "11.4.2.3 Rules * for Using Unwind Descriptors", rule 3): */ for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) { reg = sr->curr.reg + unw.save_order[i]; if (reg->where == UNW_WHERE_GR_SAVE) { reg->where = UNW_WHERE_GR; reg->val = sr->gr_save_loc++; } } /* * Next, compute when the fp, general, and branch registers get * saved. This must come before alloc_spill_area() because * we need to know which registers are spilled to their home * locations. */ if (sr->imask) { unsigned char kind, mask = 0, *cp = sr->imask; unsigned long t; static const unsigned char limit[3] = { UNW_REG_F31, UNW_REG_R7, UNW_REG_B5 }; struct unw_reg_info *(regs[3]); regs[0] = sr->curr.reg + UNW_REG_F2; regs[1] = sr->curr.reg + UNW_REG_R4; regs[2] = sr->curr.reg + UNW_REG_B1; for (t = 0; t < sr->region_len; ++t) { if ((t & 3) == 0) mask = *cp++; kind = (mask >> 2*(3-(t & 3))) & 3; if (kind > 0) spill_next_when(®s[kind - 1], sr->curr.reg + limit[kind - 1], sr->region_start + t); } } /* * Next, lay out the memory stack spill area: */ if (sr->any_spills) { off = sr->spill_offset; alloc_spill_area(&off, 16, sr->curr.reg + UNW_REG_F2, sr->curr.reg + UNW_REG_F31); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_B1, sr->curr.reg + UNW_REG_B5); alloc_spill_area(&off, 8, sr->curr.reg + UNW_REG_R4, sr->curr.reg + UNW_REG_R7); }}/* * Region header descriptors. */static voiddesc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave, struct unw_state_record *sr){ int i; if (!(sr->in_body || sr->first_region)) finish_prologue(sr); sr->first_region = 0; /* check if we're done: */ if (body && sr->when_target < sr->region_start + sr->region_len) { sr->done = 1; return; } for (i = 0; i < sr->epilogue_count; ++i) pop(sr); sr->epilogue_count = 0; sr->epilogue_start = UNW_WHEN_NEVER; if (!body) push(sr); sr->region_start += sr->region_len; sr->region_len = rlen; sr->in_body = body; if (!body) { for (i = 0; i < 4; ++i) { if (mask & 0x8) set_reg(sr->curr.reg + unw.save_order[i], UNW_WHERE_GR, sr->region_start + sr->region_len - 1, grsave++); mask <<= 1; } sr->gr_save_loc = grsave; sr->any_spills = 0; sr->imask = 0; sr->spill_offset = 0x10; /* default to psp+16 */ }}/* * Prologue descriptors. */static inline voiddesc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr){ if (abi == 0 && context == 'i') sr->flags |= UNW_FLAG_INTERRUPT_FRAME; else dprintk("unwind: ignoring unwabi(abi=0x%x,context=0x%x)\n", abi, context);}static inline voiddesc_br_gr (unsigned char brmask, unsigned char gr, struct unw_state_record *sr){ int i; for (i = 0; i < 5; ++i) { if (brmask & 1) set_reg(sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_GR, sr->region_start + sr->region_len - 1, gr++); brmask >>= 1; }}static inline voiddesc_br_mem (unsigned char brmask, struct unw_state_record *sr){ int i; for (i = 0; i < 5; ++i) { if (brmask & 1) { set_reg(sr->curr.reg + UNW_REG_B1 + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } brmask >>= 1; }}static inline voiddesc_frgr_mem (unsigned char grmask, unw_word frmask, struct unw_state_record *sr){ int i; for (i = 0; i < 4; ++i) { if ((grmask & 1) != 0) { set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } grmask >>= 1; } for (i = 0; i < 20; ++i) { if ((frmask & 1) != 0) { set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } frmask >>= 1; }}static inline voiddesc_fr_mem (unsigned char frmask, struct unw_state_record *sr){ int i; for (i = 0; i < 4; ++i) { if ((frmask & 1) != 0) { set_reg(sr->curr.reg + UNW_REG_F2 + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } frmask >>= 1; }}static inline voiddesc_gr_gr (unsigned char grmask, unsigned char gr, struct unw_state_record *sr){ int i; for (i = 0; i < 4; ++i) { if ((grmask & 1) != 0) set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_GR, sr->region_start + sr->region_len - 1, gr++); grmask >>= 1; }}static inline voiddesc_gr_mem (unsigned char grmask, struct unw_state_record *sr){ int i; for (i = 0; i < 4; ++i) { if ((grmask & 1) != 0) { set_reg(sr->curr.reg + UNW_REG_R4 + i, UNW_WHERE_SPILL_HOME, sr->region_start + sr->region_len - 1, 0); sr->any_spills = 1; } grmask >>= 1; }}static inline voiddesc_mem_stack_f (unw_word t, unw_word size, struct unw_state_record *sr){ set_reg(sr->curr.reg + UNW_REG_PSP, UNW_WHERE_NONE, sr->region_start + MIN((int)t, sr->region_len - 1), 16*size);}static inline voiddesc_mem_stack_v (unw_word t, struct unw_state_record *sr){ sr->curr.reg[UNW_REG_PSP].when = sr->region_start + MIN((int)t, sr->region_len - 1);}static inline voiddesc_reg_gr (unsigned char reg, unsigned char dst, struct unw_state_record *sr){ set_reg(sr->curr.reg + reg, UNW_WHERE_GR, sr->region_start + sr->region_len - 1, dst);}static inline voiddesc_reg_psprel (unsigned char reg, unw_word pspoff, struct unw_state_record *sr){ set_reg(sr->curr.reg + reg, UNW_WHERE_PSPREL, sr->region_start + sr->region_len - 1, 0x10 - 4*pspoff);}static inline voiddesc_reg_sprel (unsigned char reg, unw_word spoff, struct unw_state_record *sr){ set_reg(sr->curr.reg + reg, UNW_WHERE_SPREL, sr->region_start + sr->region_len - 1, 4*spoff);}static inline voiddesc_rp_br (unsigned char dst, struct unw_state_record *sr){ sr->return_link_reg = dst;}static inline voiddesc_reg_when (unsigned char regnum, unw_word t, struct unw_state_record *sr){ struct unw_reg_info *reg = sr->curr.reg + regnum; if (reg->where == UNW_WHERE_NONE) reg->where = UNW_WHERE_GR_SAVE; reg->when = sr->region_start + MIN((int)t, sr->region_len - 1);}static inline voiddesc_spill_base (unw_word pspoff, struct unw_state_record *sr){ sr->spill_offset = 0x10 - 4*pspoff;}static inline unsigned char *desc_spill_mask (unsigned char *imaskp, struct unw_state_record *sr){ sr->imask = imaskp; return imaskp + (2*sr->region_len + 7)/8;}/* * Body descriptors. */static inline voiddesc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr){ sr->epilogue_start = sr->region_start + sr->region_len - 1 - t; sr->epilogue_count = ecount + 1;}static inline voiddesc_copy_state (unw_word label, struct unw_state_record *sr){ struct unw_reg_state *rs; for (rs = sr->reg_state_list; rs; rs = rs->next) { if (rs->label == label) { memcpy (&sr->curr, rs, sizeof(sr->curr)); return; } } printk("unwind: failed to find state labelled 0x%lx\n", label);}static inline voiddesc_label_state (unw_word label, struct unw_state_record *sr){ struct unw_reg_state *rs; rs = alloc_reg_state(); memcpy(rs, &sr->curr, sizeof(*rs)); rs->label = label; rs->next = sr->reg_state_list; sr->reg_state_list = rs;}/* * General descriptors. */static inline intdesc_is_active (unsigned char qp, unw_word t, struct unw_state_record *sr){ if (sr->when_target <= sr->region_start + MIN((int)t, sr->region_len - 1)) return 0; if (qp > 0) { if ((sr->pr_val & (1UL << qp)) == 0) return 0; sr->pr_mask |= (1UL << qp); } return 1;}static inline voiddesc_restore_p (unsigned char qp, unw_word t, unsigned char abreg, struct unw_state_record *sr){ struct unw_reg_info *r; if (!desc_is_active(qp, t, sr)) return; r = sr->curr.reg + decode_abreg(abreg, 0); r->where = UNW_WHERE_NONE; r->when = sr->region_start + MIN((int)t, sr->region_len - 1); r->val = 0;}static inline voiddesc_spill_reg_p (unsigned char qp, unw_word t, unsigned char abreg, unsigned char x, unsigned char ytreg, struct unw_state_record *sr){ enum unw_where where = UNW_WHERE_GR; struct unw_reg_info *r; if (!desc_is_active(qp, t, sr)) return; if (x) where = UNW_WHERE_BR; else if (ytreg & 0x80) where = UNW_WHERE_FR; r = sr->curr.reg + decode_abreg(abreg, 0); r->where = where; r->when = sr->region_start + MIN((int)t, sr->region_len - 1); r->val = (ytreg & 0x7f);}static inline voiddesc_spill_psprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word pspoff, struct unw_state_record *sr){ struct unw_reg_info *r; if (!desc_is_active(qp, t, sr)) return; r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_PSPREL; r->when = sr->region_start + MIN((int)t, sr->region_len - 1); r->val = 0x10 - 4*pspoff;}static inline voiddesc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word spoff, struct unw_state_record *sr){ struct unw_reg_info *r; if (!desc_is_active(qp, t, sr)) return; r = sr->curr.reg + decode_abreg(abreg, 1); r->where = UNW_WHERE_SPREL; r->when = sr->region_start + MIN((int)t, sr->region_len - 1); r->val = 4*spoff;}#define UNW_DEC_BAD_CODE(code) printk("unwind: unknown code 0x%02x\n", code);/* * region headers: */#define UNW_DEC_PROLOGUE_GR(fmt,r,m,gr,arg) desc_prologue(0,r,m,gr,arg)#define UNW_DEC_PROLOGUE(fmt,b,r,arg) desc_prologue(b,r,0,32,arg)/* * prologue descriptors: */#define UNW_DEC_ABI(fmt,a,c,arg) desc_abi(a,c,arg)#define UNW_DEC_BR_GR(fmt,b,g,arg) desc_br_gr(b,g,arg)#define UNW_DEC_BR_MEM(fmt,b,arg) desc_br_mem(b,arg)#define UNW_DEC_FRGR_MEM(fmt,g,f,arg) desc_frgr_mem(g,f,arg)#define UNW_DEC_FR_MEM(fmt,f,arg) desc_fr_mem(f,arg)#define UNW_DEC_GR_GR(fmt,m,g,arg) desc_gr_gr(m,g,arg)#define UNW_DEC_GR_MEM(fmt,m,arg) desc_gr_mem(m,arg)#define UNW_DEC_MEM_STACK_F(fmt,t,s,arg) desc_mem_stack_f(t,s,arg)#define UNW_DEC_MEM_STACK_V(fmt,t,arg) desc_mem_stack_v(t,arg)#define UNW_DEC_REG_GR(fmt,r,d,arg) desc_reg_gr(r,d,arg)#define UNW_DEC_REG_PSPREL(fmt,r,o,arg) desc_reg_psprel(r,o,arg)#define UNW_DEC_REG_SPREL(fmt,r,o,arg) desc_reg_sprel(r,o,arg)#define UNW_DEC_REG_WHEN(fmt,r,t,arg) desc_reg_when(r,t,arg)#define UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_GR,t,arg)#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) desc_reg_when(UNW_REG_PRI_UNAT_MEM,t,arg)#define UNW_DEC_PRIUNAT_GR(fmt,r,arg) desc_reg_gr(UNW_REG_PRI_UNAT_GR,r,arg)#define UNW_DEC_PRIUNAT_PSPREL(fmt,o,arg) desc_reg_psprel(UNW_REG_PRI_UNAT_MEM,o,arg)#define UNW_DEC_PRIUNAT_SPREL(fmt,o,arg) desc_reg_sprel(UNW_REG_PRI_UNAT_MEM,o,arg)#define UNW_DEC_RP_BR(fmt,d,arg) desc_rp_br(d,arg)#define UNW_DEC_SPILL_BASE(fmt,o,arg) desc_spill_base(o,arg)#define UNW_DEC_SPILL_MASK(fmt,m,arg) (m = desc_spill_mask(m,arg))/* * body descriptors: */#define UNW_DEC_EPILOGUE(fmt,t,c,arg) desc_epilogue(t,c,arg)#define UNW_DEC_COPY_STATE(fmt,l,arg) desc_copy_state(l,arg)#define UNW_DEC_LABEL_STATE(fmt,l,arg) desc_label_state(l,arg)/* * general unwind descriptors: */#define UNW_DEC_SPILL_REG_P(f,p,t,a,x,y,arg) desc_spill_reg_p(p,t,a,x,y,arg)#define UNW_DEC_SPILL_REG(f,t,a,x,y,arg) desc_spill_reg_p(0,t,a,x,y,arg)#define UNW_DEC_SPILL_PSPREL_P(f,p,t,a,o,arg) desc_spill_psprel_p(p,t,a,o,arg)#define UNW_DEC_SPILL_PSPREL(f,t,a,o,arg) desc_spill_psprel_p(0,t,a,o,arg)#define UNW_DEC_SPILL_SPREL_P(f,p,t,a,o,arg) desc_spill_sprel_p(p,t,a,o,arg)#define UNW_DEC_SPILL_SPREL(f,t,a,o,arg) desc_spill_sprel_p(0,t,a,o,arg)#define UNW_DEC_RESTORE_P(f,p,t,a,arg) desc_restore_p(p,t,a,arg)#define UNW_DEC_RESTORE(f,t,a,arg) desc_restore_p(0,t,a,arg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -