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

📄 unwind.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
	prev_ip = info->ip;	prev_sp = info->sp;	prev_bsp = info->bsp;	/* restore the ip */	if (!info->rp_loc) {		/* FIXME: should really be level 0 but it occurs too often. KAO */		UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n",			   __FUNCTION__, info->ip);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	ip = info->ip = *info->rp_loc;#ifndef XEN	if (ip < GATE_ADDR) {#else	if (!is_hypervisor_virt(info->ip)) {#endif		UNW_DPRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	/* restore the cfm: */	if (!info->pfs_loc) {		UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	info->cfm_loc = info->pfs_loc;	/* restore the bsp: */	pr = info->pr;	num_regs = 0;	if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) {		info->pt = info->sp + 16;		if ((pr & (1UL << PRED_NON_SYSCALL)) != 0)			num_regs = *info->cfm_loc & 0x7f;		/* size of frame */		info->pfs_loc =			(unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs));		UNW_DPRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt);	} else		num_regs = (*info->cfm_loc >> 7) & 0x7f;	/* size of locals */	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -num_regs);	if (info->bsp < info->regstk.limit || info->bsp > info->regstk.top) {		UNW_DPRINT(0, "unwind.%s: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",			__FUNCTION__, info->bsp, info->regstk.limit, info->regstk.top);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	/* restore the sp: */	info->sp = info->psp;	if (info->sp < info->memstk.top || info->sp > info->memstk.limit) {		UNW_DPRINT(0, "unwind.%s: sp (0x%lx) out of range [0x%lx-0x%lx]\n",			__FUNCTION__, info->sp, info->memstk.top, info->memstk.limit);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	if (info->ip == prev_ip && info->sp == prev_sp && info->bsp == prev_bsp) {		UNW_DPRINT(0, "unwind.%s: ip, sp, bsp unchanged; stopping here (ip=0x%lx)\n",			   __FUNCTION__, ip);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	/* as we unwind, the saved ar.unat becomes the primary unat: */	info->pri_unat_loc = info->unat_loc;	/* finally, restore the predicates: */	unw_get_pr(info, &info->pr);	retval = find_save_locs(info);	STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));	return retval;}EXPORT_SYMBOL(unw_unwind);intunw_unwind_to_user (struct unw_frame_info *info){	unsigned long ip, sp, pr = 0;	while (unw_unwind(info) >= 0) {		unw_get_sp(info, &sp);		if ((long)((unsigned long)info->task + IA64_STK_OFFSET - sp)		    < IA64_PT_REGS_SIZE) {			UNW_DPRINT(0, "unwind.%s: ran off the top of the kernel stack\n",				   __FUNCTION__);			break;		}#ifndef XEN		if (unw_is_intr_frame(info) &&		    (pr & (1UL << PRED_USER_STACK)))			return 0;#else		if (unw_is_intr_frame(info) &&		    !is_hvm_vcpu(info->task) &&		    (pr & (1UL << PRED_USER_STACK)))			return 0;		/*		 * vmx fault handlers don't vcpu->on_stack and keep		 * (pr & (1UL << PRED_USER_STACK)) condition untouched.		 * we need to stop unwinding somehow.		 */		if (unw_is_intr_frame(info) &&		    is_hvm_vcpu(info->task) &&		    info->pr_loc == &vcpu_regs(info->task)->pr)			return 0;#endif		if (unw_get_pr (info, &pr) < 0) {			unw_get_rp(info, &ip);			UNW_DPRINT(0, "unwind.%s: failed to read "				   "predicate register (ip=0x%lx)\n",				__FUNCTION__, ip);			return -1;		}	}	unw_get_ip(info, &ip);	UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n",		   __FUNCTION__, ip);	return -1;}EXPORT_SYMBOL(unw_unwind_to_user);static voidinit_frame_info (struct unw_frame_info *info, struct task_struct *t,		 struct switch_stack *sw, unsigned long stktop){	unsigned long rbslimit, rbstop, stklimit;	STAT(unsigned long start, flags;)	STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc());	/*	 * Subtle stuff here: we _could_ unwind through the switch_stack frame but we	 * don't want to do that because it would be slow as each preserved register would	 * have to be processed.  Instead, what we do here is zero out the frame info and	 * start the unwind process at the function that created the switch_stack frame.	 * When a preserved value in switch_stack needs to be accessed, run_script() will	 * initialize the appropriate pointer on demand.	 */	memset(info, 0, sizeof(*info));	rbslimit = (unsigned long) t + IA64_RBS_OFFSET;	rbstop   = sw->ar_bspstore;	if (rbstop - (unsigned long) t >= IA64_STK_OFFSET)		rbstop = rbslimit;	stklimit = (unsigned long) t + IA64_STK_OFFSET;	if (stktop <= rbstop)		stktop = rbstop;	info->regstk.limit = rbslimit;	info->regstk.top   = rbstop;	info->memstk.limit = stklimit;	info->memstk.top   = stktop;	info->task = t;	info->sw  = sw;	info->sp = info->psp = stktop;	info->pr = sw->pr;	UNW_DPRINT(3, "unwind.%s:\n"		   "  task   0x%lx\n"		   "  rbs = [0x%lx-0x%lx)\n"		   "  stk = [0x%lx-0x%lx)\n"		   "  pr     0x%lx\n"		   "  sw     0x%lx\n"		   "  sp     0x%lx\n",		   __FUNCTION__, (unsigned long) t, rbslimit, rbstop, stktop, stklimit,		   info->pr, (unsigned long) info->sw, info->sp);	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));}voidunw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,			    struct pt_regs *pt, struct switch_stack *sw){	unsigned long sof;	init_frame_info(info, t, sw, pt->r12);	info->cfm_loc = &pt->cr_ifs;	info->unat_loc = &pt->ar_unat;	info->pfs_loc = &pt->ar_pfs;	sof = *info->cfm_loc & 0x7f;	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);	info->ip = pt->cr_iip + ia64_psr(pt)->ri;	info->pt = (unsigned long) pt;	UNW_DPRINT(3, "unwind.%s:\n"		   "  bsp    0x%lx\n"		   "  sof    0x%lx\n"		   "  ip     0x%lx\n",		   __FUNCTION__, info->bsp, sof, info->ip);	find_save_locs(info);}voidunw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw){	unsigned long sol;	init_frame_info(info, t, sw, (unsigned long) (sw + 1) - 16);	info->cfm_loc = &sw->ar_pfs;	sol = (*info->cfm_loc >> 7) & 0x7f;	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);	info->ip = sw->b0;	UNW_DPRINT(3, "unwind.%s:\n"		   "  bsp    0x%lx\n"		   "  sol    0x%lx\n"		   "  ip     0x%lx\n",		   __FUNCTION__, info->bsp, sol, info->ip);	find_save_locs(info);}EXPORT_SYMBOL(unw_init_frame_info);voidunw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t){#ifdef XEN	struct switch_stack *sw = (struct switch_stack *) (t->arch._thread.ksp + 16);#else	struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16);#endif	UNW_DPRINT(1, "unwind.%s\n", __FUNCTION__);	unw_init_frame_info(info, t, sw);}EXPORT_SYMBOL(unw_init_from_blocked_task);static voidinit_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base,		   unsigned long gp, const void *table_start, const void *table_end){	const struct unw_table_entry *start = table_start, *end = table_end;	table->name = name;	table->segment_base = segment_base;	table->gp = gp;	table->start = segment_base + start[0].start_offset;	table->end = segment_base + end[-1].end_offset;	table->array = start;	table->length = end - start;}#ifndef XENvoid *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,		      const void *table_start, const void *table_end){	const struct unw_table_entry *start = table_start, *end = table_end;	struct unw_table *table;	unsigned long flags;	if (end - start <= 0) {		UNW_DPRINT(0, "unwind.%s: ignoring attempt to insert empty unwind table\n",			   __FUNCTION__);		return NULL;	}	table = kmalloc(sizeof(*table), GFP_USER);	if (!table)		return NULL;	init_unwind_table(table, name, segment_base, gp, table_start, table_end);	spin_lock_irqsave(&unw.lock, flags);	{		/* keep kernel unwind table at the front (it's searched most commonly): */		table->next = unw.tables->next;		unw.tables->next = table;	}	spin_unlock_irqrestore(&unw.lock, flags);	return table;}voidunw_remove_unwind_table (void *handle){	struct unw_table *table, *prev;	struct unw_script *tmp;	unsigned long flags;	long index;	if (!handle) {		UNW_DPRINT(0, "unwind.%s: ignoring attempt to remove non-existent unwind table\n",			   __FUNCTION__);		return;	}	table = handle;	if (table == &unw.kernel_table) {		UNW_DPRINT(0, "unwind.%s: sorry, freeing the kernel's unwind table is a "			   "no-can-do!\n", __FUNCTION__);		return;	}	spin_lock_irqsave(&unw.lock, flags);	{		/* first, delete the table: */		for (prev = (struct unw_table *) &unw.tables; prev; prev = prev->next)			if (prev->next == table)				break;		if (!prev) {			UNW_DPRINT(0, "unwind.%s: failed to find unwind table %p\n",				   __FUNCTION__, (void *) table);			spin_unlock_irqrestore(&unw.lock, flags);			return;		}		prev->next = table->next;	}	spin_unlock_irqrestore(&unw.lock, flags);	/* next, remove hash table entries for this table */	for (index = 0; index <= UNW_HASH_SIZE; ++index) {		tmp = unw.cache + unw.hash[index];		if (unw.hash[index] >= UNW_CACHE_SIZE		    || tmp->ip < table->start || tmp->ip >= table->end)			continue;		write_lock(&tmp->lock);		{			if (tmp->ip >= table->start && tmp->ip < table->end) {				unw.hash[index] = tmp->coll_chain;				tmp->ip = 0;			}		}		write_unlock(&tmp->lock);	}	kfree(table);}static int __initcreate_gate_table (void){	const struct unw_table_entry *entry, *start, *end;	unsigned long *lp, segbase = GATE_ADDR;	size_t info_size, size;	char *info;	Elf64_Phdr *punw = NULL, *phdr = (Elf64_Phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);	int i;	for (i = 0; i < GATE_EHDR->e_phnum; ++i, ++phdr)		if (phdr->p_type == PT_IA_64_UNWIND) {			punw = phdr;			break;		}	if (!punw) {		printk("%s: failed to find gate DSO's unwind table!\n", __FUNCTION__);		return 0;	}	start = (const struct unw_table_entry *) punw->p_vaddr;	end = (struct unw_table_entry *) ((char *) start + punw->p_memsz);	size  = 0;	unw_add_unwind_table("linux-gate.so", segbase, 0, start, end);	for (entry = start; entry < end; ++entry)		size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));	size += 8;	/* reserve space for "end of table" marker */	unw.gate_table = kmalloc(size, GFP_KERNEL);	if (!unw.gate_table) {		unw.gate_table_size = 0;		printk(KERN_ERR "%s: unable to create unwind data for gate page!\n", __FUNCTION__);		return 0;	}	unw.gate_table_size = size;	lp = unw.gate_table;	info = (char *) unw.gate_table + size;	for (entry = start; entry < end; ++entry, lp += 3) {		info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));		info -= info_size;		memcpy(info, (char *) segbase + entry->info_offset, info_size);		lp[0] = segbase + entry->start_offset;		/* start */		lp[1] = segbase + entry->end_offset;		/* end */		lp[2] = info - (char *) unw.gate_table;		/* info */	}	*lp = 0;	/* end-of-table marker */	return 0;}__initcall(create_gate_table);#endif // !XENvoid __initunw_init (void){	extern char __gp[];	extern void unw_hash_index_t_is_too_narrow (void);	long i, off;	if (8*sizeof(unw_hash_index_t) < UNW_LOG_HASH_SIZE)		unw_hash_index_t_is_too_narrow();	unw.sw_off[unw.preg_index[UNW_REG_PRI_UNAT_GR]] = SW(CALLER_UNAT);	unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);	unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_PFS);	unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);	unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(CALLER_UNAT);	unw.sw_off[unw.preg_index[UNW_REG_PR]] = SW(PR);	unw.sw_off[unw.preg_index[UNW_REG_LC]] = SW(AR_LC);	unw.sw_off[unw.preg_index[UNW_REG_FPSR]] = SW(AR_FPSR);	for (i = UNW_REG_R4, off = SW(R4); i <= UNW_REG_R7; ++i, off += 8)		unw.sw_off[unw.preg_index[i]] = off;	for (i = UNW_REG_B1, off = SW(B1); i <= UNW_REG_B5; ++i, off += 8)		unw.sw_off[unw.preg_index[i]] = off;	for (i = UNW_REG_F2, off = SW(F2); i <= UNW_REG_F5; ++i, off += 16)		unw.sw_off[unw.preg_index[i]] = off;	for (i = UNW_REG_F16, off = SW(F16); i <= UNW_REG_F31; ++i, off += 16)		unw.sw_off[unw.preg_index[i]] = off;	for (i = 0; i < UNW_CACHE_SIZE; ++i) {		if (i > 0)			unw.cache[i].lru_chain = (i - 1);		unw.cache[i].coll_chain = -1;		rwlock_init(&unw.cache[i].lock);	}	unw.lru_head = UNW_CACHE_SIZE - 1;	unw.lru_tail = 0;	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp,			  __start_unwind, __end_unwind);}#ifndef XEN/* * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED * *	This system call has been deprecated.  The new and improved way to get *	at the kernel's unwind info is via the gate DSO.  The address of the *	ELF header for this DSO is passed to user-level via AT_SYSINFO_EHDR. * * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED * * This system call copies the unwind data into the buffer pointed to by BUF and returns * the size of the unwind data.  If BUF_SIZE is smaller than the size of the unwind data * or if BUF is NULL, nothing is copied, but the system call still returns the size of the * unwind data. * * The first portion of the unwind data contains an unwind table and rest contains the * associated unwind info (in no particular order).  The unwind table consists of a table * of entries of the form: * *	u64 start;	(64-bit address of start of function) *	u64 end;	(64-bit address of start of function) *	u64 info;	(BUF-relative offset to unwind info) * * The end of the unwind table is indicated by an entry with a START address of zero. * * Please see the IA-64 Software Conventions and Runtime Architecture manual for details * on the format of the unwind info. * * ERRORS *	EFAULT	BUF points outside your accessible address space. */asmlinkage longsys_getunwind (void __user *buf, size_t buf_size){	if (buf && buf_size >= unw.gate_table_size)		if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0)			return -EFAULT;	return unw.gate_table_size;}#endif

⌨️ 快捷键说明

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