📄 unwind.c
字号:
}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_t(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_t(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_t(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_labeled_state *ls; for (ls = sr->labeled_states; ls; ls = ls->next) { if (ls->label == label) { free_state_stack(&sr->curr); memcpy(&sr->curr, &ls->saved_state, sizeof(sr->curr)); sr->curr.next = dup_state_stack(ls->saved_state.next); return; } } printk(KERN_ERR "unwind: failed to find state labeled 0x%lx\n", label);}static inline voiddesc_label_state (unw_word label, struct unw_state_record *sr){ struct unw_labeled_state *ls; ls = alloc_labeled_state(); if (!ls) { printk(KERN_ERR "unwind.desc_label_state(): out of memory\n"); return; } ls->label = label; memcpy(&ls->saved_state, &sr->curr, sizeof(ls->saved_state)); ls->saved_state.next = dup_state_stack(sr->curr.next); /* insert into list of labeled states: */ ls->next = sr->labeled_states; sr->labeled_states = ls;}/* * 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_t(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 = UNW_WHEN_NEVER; 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_t(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_t(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_t(int, t, sr->region_len - 1); r->val = 4*spoff;}#define UNW_DEC_BAD_CODE(code) printk(KERN_ERR "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)#include "unwind_decoder.c"/* Unwind scripts. */static inline unw_hash_index_thash (unsigned long ip){# define hashmagic 0x9e3779b97f4a7c16UL /* based on (sqrt(5)/2-1)*2^64 */ return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE);#undef hashmagic}static inline longcache_match (struct unw_script *script, unsigned long ip, unsigned long pr){ read_lock(&script->lock); if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0) /* keep the read lock... */ return 1; read_unlock(&script->lock); return 0;}static inline struct unw_script *script_lookup (struct unw_frame_info *info){ struct unw_script *script = unw.cache + info->hint; unsigned short index; unsigned long ip, pr; if (UNW_DEBUG_ON(0)) return NULL; /* Always regenerate scripts in debug mode */ STAT(++unw.stat.cache.lookups); ip = info->ip; pr = info->pr; if (cache_match(script, ip, pr)) { STAT(++unw.stat.cache.hinted_hits); return script; } index = unw.hash[hash(ip)]; if (index >= UNW_CACHE_SIZE) return NULL; script = unw.cache + index; while (1) { if (cache_match(script, ip, pr)) { /* update hint; no locking required as single-word writes are atomic */ STAT(++unw.stat.cache.normal_hits); unw.cache[info->prev_script].hint = script - unw.cache; return script; } if (script->coll_chain >= UNW_HASH_SIZE) return NULL; script = unw.cache + script->coll_chain; STAT(++unw.stat.cache.collision_chain_traversals); }}/* * On returning, a write lock for the SCRIPT is still being held. */static inline struct unw_script *script_new (unsigned long ip){ struct unw_script *script, *prev, *tmp; unw_hash_index_t index; unsigned short head; STAT(++unw.stat.script.news); /* * Can't (easily) use cmpxchg() here because of ABA problem * that is intrinsic in cmpxchg()... */ head = unw.lru_head; script = unw.cache + head; unw.lru_head = script->lru_chain; /* * We'd deadlock here if we interrupted a thread that is holding a read lock on * script->lock. Thus, if the write_trylock() fails, we simply bail out. The * alternative would be to disable interrupts whenever we hold a read-lock, but * that seems silly. */ if (!write_trylock(&script->lock)) return NULL; /* re-insert script at the tail of the LRU chain: */ unw.cache[unw.lru_tail].lru_chain = head; unw.lru_tail = head; /* remove the old script from the hash table (if it's there): */ if (script->ip) { index = hash(script->ip); tmp = unw.cache + unw.hash[index]; prev = NULL; while (1) { if (tmp == script) { if (prev) prev->coll_chain = tmp->coll_chain; else unw.hash[index] = tmp->coll_chain; break; } else prev = tmp; if (tmp->coll_chain >= UNW_CACHE_SIZE) /* old script wasn't in the hash-table */ break; tmp = unw.cache + tmp->coll_chain; } } /* enter new script in the hash table */ index = hash(ip); script->coll_chain = unw.hash[index]; unw.hash[index] = script - unw.cache; script->ip = ip; /* set new IP while we're holding the locks */ STAT(if (script->coll_chain < UNW_CACHE_SIZE) ++unw.stat.script.collisions); script->flags = 0; script->hint = 0; script->count = 0; return script;}static voidscript_finalize (struct unw_script *script, struct unw_state_record *sr){ script->pr_mask = sr->pr_mask; script->pr_val = sr->pr_val; /* * We could down-grade our write-lock on script->lock here but * the rwlock API doesn't offer atomic lock downgrading, so * we'll just keep the write-lock and release it later when * we're done using the script. */}static inline voidscript_emit (struct unw_script *script, struct unw_insn insn){ if (script->count >= UNW_MAX_SCRIPT_LEN) { UNW_DPRINT(0, "unwind.%s: script exceeds maximum size of %u instructions!\n", __FUNCTION__, UNW_MAX_SCRIPT_LEN); return; } script->insn[script->count++] = insn;}static inline voidemit_nat_info (struct unw_state_record *sr, int i, struct unw_script *script){ struct unw_reg_info *r = sr->curr.reg + i; enum unw_insn_opcode opc; struct unw_insn insn; unsigned long val = 0; switch (r->where) { case UNW_WHERE_GR: if (r->val >= 32) { /* register got spilled to a stacked register */ opc = UNW_INSN_SETNAT_TYPE; val = UNW_NAT_REGSTK; } else /* register got spilled to a scratch register */ opc = UNW_INSN_SETNAT_MEMSTK; break; case UNW_WHERE_FR: opc = UNW_INSN_SETNAT_TYPE; val = UNW_NAT_VAL; break; case UNW_WHERE_BR: opc = UNW_INSN_SETNAT_TYPE; val = UNW_NAT_NONE; break; case UNW_WHERE_PSPREL: case UNW_WHERE_SPREL: opc = UNW_INSN_SETNAT_MEMSTK; break; default: UNW_DPRINT(0, "unwind.%s: don't know how to emit nat info for where = %u\n", __FUNCTION__, r->where); return; } insn.opc = opc; insn.dst = unw.preg_index[i]; insn.val = val; script_emit(script, insn);}static voidcompile_reg (struct unw_state_record *sr, int i, struct unw_script *script){ struct unw_reg_info *r = sr->curr.reg + i; enum unw_insn_opcode opc; unsigned long val, rval; struct unw_insn insn; long need_nat_info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -