⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unwind.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (r->where == UNW_WHERE_NONE || r->when >= sr->when_target)		return;	opc = UNW_INSN_MOVE;	val = rval = r->val;	need_nat_info = (i >= UNW_REG_R4 && i <= UNW_REG_R7);	switch (r->where) {	      case UNW_WHERE_GR:		if (rval >= 32) {			opc = UNW_INSN_MOVE_STACKED;			val = rval - 32;		} else if (rval >= 4 && rval <= 7) {			if (need_nat_info) {				opc = UNW_INSN_MOVE2;				need_nat_info = 0;			}			val = unw.preg_index[UNW_REG_R4 + (rval - 4)];		} else if (rval == 0) {			opc = UNW_INSN_MOVE_CONST;			val = 0;		} else {			/* register got spilled to a scratch register */			opc = UNW_INSN_MOVE_SCRATCH;			val = pt_regs_off(rval);		}		break;	      case UNW_WHERE_FR:		if (rval <= 5)			val = unw.preg_index[UNW_REG_F2  + (rval -  2)];		else if (rval >= 16 && rval <= 31)			val = unw.preg_index[UNW_REG_F16 + (rval - 16)];		else {			opc = UNW_INSN_MOVE_SCRATCH;			if (rval <= 11)				val = offsetof(struct pt_regs, f6) + 16*(rval - 6);			else				UNW_DPRINT(0, "unwind.%s: kernel may not touch f%lu\n",					   __FUNCTION__, rval);		}		break;	      case UNW_WHERE_BR:		if (rval >= 1 && rval <= 5)			val = unw.preg_index[UNW_REG_B1 + (rval - 1)];		else {			opc = UNW_INSN_MOVE_SCRATCH;			if (rval == 0)				val = offsetof(struct pt_regs, b0);			else if (rval == 6)				val = offsetof(struct pt_regs, b6);			else				val = offsetof(struct pt_regs, b7);		}		break;	      case UNW_WHERE_SPREL:		opc = UNW_INSN_ADD_SP;		break;	      case UNW_WHERE_PSPREL:		opc = UNW_INSN_ADD_PSP;		break;	      default:		UNW_DPRINT(0, "unwind%s: register %u has unexpected `where' value of %u\n",			   __FUNCTION__, i, r->where);		break;	}	insn.opc = opc;	insn.dst = unw.preg_index[i];	insn.val = val;	script_emit(script, insn);	if (need_nat_info)		emit_nat_info(sr, i, script);	if (i == UNW_REG_PSP) {		/*		 * info->psp must contain the _value_ of the previous		 * sp, not it's save location.  We get this by		 * dereferencing the value we just stored in		 * info->psp:		 */		insn.opc = UNW_INSN_LOAD;		insn.dst = insn.val = unw.preg_index[UNW_REG_PSP];		script_emit(script, insn);	}}static inline const struct unw_table_entry *lookup (struct unw_table *table, unsigned long rel_ip){	const struct unw_table_entry *e = NULL;	unsigned long lo, hi, mid;	/* do a binary search for right entry: */	for (lo = 0, hi = table->length; lo < hi; ) {		mid = (lo + hi) / 2;		e = &table->array[mid];		if (rel_ip < e->start_offset)			hi = mid;		else if (rel_ip >= e->end_offset)			lo = mid + 1;		else			break;	}	if (rel_ip < e->start_offset || rel_ip >= e->end_offset)		return NULL;	return e;}/* * Build an unwind script that unwinds from state OLD_STATE to the * entrypoint of the function that called OLD_STATE. */static inline struct unw_script *build_script (struct unw_frame_info *info){	const struct unw_table_entry *e = NULL;	struct unw_script *script = NULL;	struct unw_labeled_state *ls, *next;	unsigned long ip = info->ip;	struct unw_state_record sr;	struct unw_table *table;	struct unw_reg_info *r;	struct unw_insn insn;	u8 *dp, *desc_end;	u64 hdr;	int i;	STAT(unsigned long start, parse_start;)	STAT(++unw.stat.script.builds; start = ia64_get_itc());	/* build state record */	memset(&sr, 0, sizeof(sr));	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)		r->when = UNW_WHEN_NEVER;	sr.pr_val = info->pr;	UNW_DPRINT(3, "unwind.%s: ip 0x%lx\n", __FUNCTION__, ip);	script = script_new(ip);	if (!script) {		UNW_DPRINT(0, "unwind.%s: failed to create unwind script\n",  __FUNCTION__);		STAT(unw.stat.script.build_time += ia64_get_itc() - start);		return NULL;	}	unw.cache[info->prev_script].hint = script - unw.cache;	/* search the kernels and the modules' unwind tables for IP: */	STAT(parse_start = ia64_get_itc());	for (table = unw.tables; table; table = table->next) {		if (ip >= table->start && ip < table->end) {			e = lookup(table, ip - table->segment_base);			break;		}	}	if (!e) {		/* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */		UNW_DPRINT(1, "unwind.%s: no unwind info for ip=0x%lx (prev ip=0x%lx)\n",			__FUNCTION__, ip, unw.cache[info->prev_script].ip);		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;		sr.curr.reg[UNW_REG_RP].when = -1;		sr.curr.reg[UNW_REG_RP].val = 0;		compile_reg(&sr, UNW_REG_RP, script);		script_finalize(script, &sr);		STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);		STAT(unw.stat.script.build_time += ia64_get_itc() - start);		return script;	}	sr.when_target = (3*((ip & ~0xfUL) - (table->segment_base + e->start_offset))/16			  + (ip & 0xfUL));	hdr = *(u64 *) (table->segment_base + e->info_offset);	dp =   (u8 *)  (table->segment_base + e->info_offset + 8);	desc_end = dp + 8*UNW_LENGTH(hdr);	while (!sr.done && dp < desc_end)		dp = unw_decode(dp, sr.in_body, &sr);	if (sr.when_target > sr.epilogue_start) {		/*		 * sp has been restored and all values on the memory stack below		 * psp also have been restored.		 */		sr.curr.reg[UNW_REG_PSP].val = 0;		sr.curr.reg[UNW_REG_PSP].where = UNW_WHERE_NONE;		sr.curr.reg[UNW_REG_PSP].when = UNW_WHEN_NEVER;		for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r)			if ((r->where == UNW_WHERE_PSPREL && r->val <= 0x10)			    || r->where == UNW_WHERE_SPREL)			{				r->val = 0;				r->where = UNW_WHERE_NONE;				r->when = UNW_WHEN_NEVER;			}	}	script->flags = sr.flags;	/*	 * If RP did't get saved, generate entry for the return link	 * register.	 */	if (sr.curr.reg[UNW_REG_RP].when >= sr.when_target) {		sr.curr.reg[UNW_REG_RP].where = UNW_WHERE_BR;		sr.curr.reg[UNW_REG_RP].when = -1;		sr.curr.reg[UNW_REG_RP].val = sr.return_link_reg;		UNW_DPRINT(1, "unwind.%s: using default for rp at ip=0x%lx where=%d val=0x%lx\n",			   __FUNCTION__, ip, sr.curr.reg[UNW_REG_RP].where,			   sr.curr.reg[UNW_REG_RP].val);	}#ifdef UNW_DEBUG	UNW_DPRINT(1, "unwind.%s: state record for func 0x%lx, t=%u:\n",		__FUNCTION__, table->segment_base + e->start_offset, sr.when_target);	for (r = sr.curr.reg; r < sr.curr.reg + UNW_NUM_REGS; ++r) {		if (r->where != UNW_WHERE_NONE || r->when != UNW_WHEN_NEVER) {			UNW_DPRINT(1, "  %s <- ", unw.preg_name[r - sr.curr.reg]);			switch (r->where) {			      case UNW_WHERE_GR:     UNW_DPRINT(1, "r%lu", r->val); break;			      case UNW_WHERE_FR:     UNW_DPRINT(1, "f%lu", r->val); break;			      case UNW_WHERE_BR:     UNW_DPRINT(1, "b%lu", r->val); break;			      case UNW_WHERE_SPREL:  UNW_DPRINT(1, "[sp+0x%lx]", r->val); break;			      case UNW_WHERE_PSPREL: UNW_DPRINT(1, "[psp+0x%lx]", r->val); break;			      case UNW_WHERE_NONE:				UNW_DPRINT(1, "%s+0x%lx", unw.preg_name[r - sr.curr.reg], r->val);				break;			      default:				UNW_DPRINT(1, "BADWHERE(%d)", r->where);				break;			}			UNW_DPRINT(1, "\t\t%d\n", r->when);		}	}#endif	STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);	/* translate state record into unwinder instructions: */	/*	 * First, set psp if we're dealing with a fixed-size frame;	 * subsequent instructions may depend on this value.	 */	if (sr.when_target > sr.curr.reg[UNW_REG_PSP].when	    && (sr.curr.reg[UNW_REG_PSP].where == UNW_WHERE_NONE)	    && sr.curr.reg[UNW_REG_PSP].val != 0) {		/* new psp is sp plus frame size */		insn.opc = UNW_INSN_ADD;		insn.dst = offsetof(struct unw_frame_info, psp)/8;		insn.val = sr.curr.reg[UNW_REG_PSP].val;	/* frame size */		script_emit(script, insn);	}	/* determine where the primary UNaT is: */	if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)		i = UNW_REG_PRI_UNAT_MEM;	else if (sr.when_target < sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when)		i = UNW_REG_PRI_UNAT_GR;	else if (sr.curr.reg[UNW_REG_PRI_UNAT_MEM].when > sr.curr.reg[UNW_REG_PRI_UNAT_GR].when)		i = UNW_REG_PRI_UNAT_MEM;	else		i = UNW_REG_PRI_UNAT_GR;	compile_reg(&sr, i, script);	for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i)		compile_reg(&sr, i, script);	/* free labeled register states & stack: */	STAT(parse_start = ia64_get_itc());	for (ls = sr.labeled_states; ls; ls = next) {		next = ls->next;		free_state_stack(&ls->saved_state);		free_labeled_state(ls);	}	free_state_stack(&sr.curr);	STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);	script_finalize(script, &sr);	STAT(unw.stat.script.build_time += ia64_get_itc() - start);	return script;}/* * Apply the unwinding actions represented by OPS and update SR to * reflect the state that existed upon entry to the function that this * unwinder represents. */static inline voidrun_script (struct unw_script *script, struct unw_frame_info *state){	struct unw_insn *ip, *limit, next_insn;	unsigned long opc, dst, val, off;	unsigned long *s = (unsigned long *) state;	STAT(unsigned long start;)	STAT(++unw.stat.script.runs; start = ia64_get_itc());	state->flags = script->flags;	ip = script->insn;	limit = script->insn + script->count;	next_insn = *ip;	while (ip++ < limit) {		opc = next_insn.opc;		dst = next_insn.dst;		val = next_insn.val;		next_insn = *ip;	  redo:		switch (opc) {		      case UNW_INSN_ADD:			s[dst] += val;			break;		      case UNW_INSN_MOVE2:			if (!s[val])				goto lazy_init;			s[dst+1] = s[val+1];			s[dst] = s[val];			break;		      case UNW_INSN_MOVE:			if (!s[val])				goto lazy_init;			s[dst] = s[val];			break;		      case UNW_INSN_MOVE_SCRATCH:			if (state->pt) {				s[dst] = (unsigned long) get_scratch_regs(state) + val;			} else {				s[dst] = 0;				UNW_DPRINT(0, "unwind.%s: no state->pt, dst=%ld, val=%ld\n",					   __FUNCTION__, dst, val);			}			break;		      case UNW_INSN_MOVE_CONST:			if (val == 0)				s[dst] = (unsigned long) &unw.r0;			else {				s[dst] = 0;				UNW_DPRINT(0, "unwind.%s: UNW_INSN_MOVE_CONST bad val=%ld\n",					   __FUNCTION__, val);			}			break;		      case UNW_INSN_MOVE_STACKED:			s[dst] = (unsigned long) ia64_rse_skip_regs((unsigned long *)state->bsp,								    val);			break;		      case UNW_INSN_ADD_PSP:			s[dst] = state->psp + val;			break;		      case UNW_INSN_ADD_SP:			s[dst] = state->sp + val;			break;		      case UNW_INSN_SETNAT_MEMSTK:			if (!state->pri_unat_loc)				state->pri_unat_loc = &state->sw->caller_unat;			/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */			s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;			break;		      case UNW_INSN_SETNAT_TYPE:			s[dst+1] = val;			break;		      case UNW_INSN_LOAD:#ifdef UNW_DEBUG			if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0#ifndef XEN			    || s[val] < TASK_SIZE#endif				)			{				UNW_DPRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n",					   __FUNCTION__, s[val]);				break;			}#endif			s[dst] = *(unsigned long *) s[val];			break;		}	}	STAT(unw.stat.script.run_time += ia64_get_itc() - start);	return;  lazy_init:	off = unw.sw_off[val];	s[val] = (unsigned long) state->sw + off;	if (off >= offsetof(struct switch_stack, r4) && off <= offsetof(struct switch_stack, r7))		/*		 * We're initializing a general register: init NaT info, too.  Note that		 * the offset is a multiple of 8 which gives us the 3 bits needed for		 * the type field.		 */		s[val+1] = (offsetof(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK;	goto redo;}#ifdef XENstatic inline intis_hypervisor_virt(unsigned long addr){	return IS_VMM_ADDRESS(addr) &&		(HYPERVISOR_VIRT_START <= addr) &&		(addr < HYPERVISOR_VIRT_END);}#endifstatic intfind_save_locs (struct unw_frame_info *info){	int have_write_lock = 0;	struct unw_script *scr;	unsigned long flags = 0;	if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf))#ifndef XEN	    || info->ip < TASK_SIZE#else	    || !is_hypervisor_virt(info->ip)#endif		) {		/* don't let obviously bad addresses pollute the cache */		/* FIXME: should really be level 0 but it occurs too often. KAO */		UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip);		info->rp_loc = NULL;		return -1;	}	scr = script_lookup(info);	if (!scr) {		spin_lock_irqsave(&unw.lock, flags);		scr = build_script(info);		if (!scr) {			spin_unlock_irqrestore(&unw.lock, flags);			UNW_DPRINT(0,				   "unwind.%s: failed to locate/build unwind script for ip %lx\n",				   __FUNCTION__, info->ip);			return -1;		}		have_write_lock = 1;	}	info->hint = scr->hint;	info->prev_script = scr - unw.cache;	run_script(scr, info);	if (have_write_lock) {		write_unlock(&scr->lock);		spin_unlock_irqrestore(&unw.lock, flags);	} else		read_unlock(&scr->lock);	return 0;}intunw_unwind (struct unw_frame_info *info){	unsigned long prev_ip, prev_sp, prev_bsp;	unsigned long ip, pr, num_regs;	STAT(unsigned long start, flags;)	int retval;	STAT(local_irq_save(flags); ++unw.stat.api.unwinds; start = ia64_get_itc());

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -