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

📄 unwind.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			if (!s[val])				goto lazy_init;			s[dst] = s[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->ar_unat;			/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */			s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;			break;		      case UNW_INSN_SETNAT_TYPE:			s[dst+1] = val;			break;		      case UNW_INSN_LOAD:#if UNW_DEBUG			if ((s[val] & (my_cpu_data.unimpl_va_mask | 0x7)) || s[val] < TASK_SIZE) {				debug(1, "unwind: rejecting bad psp=0x%lx\n", 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 >= struct_offset(struct switch_stack, r4)	    && off <= struct_offset(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] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK;	goto redo;}static intfind_save_locs (struct unw_frame_info *info){	int have_write_lock = 0;	struct unw_script *scr;	if ((info->ip & (my_cpu_data.unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) {		/* don't let obviously bad addresses pollute the cache */		debug(1, "unwind: rejecting bad ip=0x%lx\n", info->ip);		info->rp_loc = 0;		return -1;	}	scr = script_lookup(info);	if (!scr) {		scr = build_script(info);		if (!scr) {			dprintk("unwind: failed to locate/build unwind script for ip %lx\n",				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);	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());	prev_ip = info->ip;	prev_sp = info->sp;	prev_bsp = info->bsp;	/* restore the ip */	if (!info->rp_loc) {		debug(1, "unwind: failed to locate return link (ip=0x%lx)!\n", info->ip);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	ip = info->ip = *info->rp_loc;	if (ip < GATE_ADDR + PAGE_SIZE) {		/*		 * We don't have unwind info for the gate page, so we consider that part		 * of user-space for the purpose of unwinding.		 */		debug(1, "unwind: reached user-space (ip=0x%lx)\n", ip);		STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags));		return -1;	}	/* restore the cfm: */	if (!info->pfs_loc) {		dprintk("unwind: failed to locate ar.pfs!\n");		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)) {		if ((pr & (1UL << pNonSys)) != 0)			num_regs = *info->cfm_loc & 0x7f;		/* size of frame */		info->pfs_loc =			(unsigned long *) (info->sp + 16 + struct_offset(struct pt_regs, ar_pfs));	} 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) {		dprintk("unwind: bsp (0x%lx) out of range [0x%lx-0x%lx]\n",			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) {		dprintk("unwind: sp (0x%lx) out of range [0x%lx-0x%lx]\n",			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) {		dprintk("unwind: ip, sp, bsp remain unchanged; stopping here (ip=0x%lx)\n", 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;}intunw_unwind_to_user (struct unw_frame_info *info){	unsigned long ip;	while (unw_unwind(info) >= 0) {		if (unw_get_rp(info, &ip) < 0) {			unw_get_ip(info, &ip);			dprintk("unwind: failed to read return pointer (ip=0x%lx)\n", ip);			return -1;		}		/*		 * We don't have unwind info for the gate page, so we consider that part		 * of user-space for the purpose of unwinding.		 */		if (ip < GATE_ADDR + PAGE_SIZE)			return 0;	}	unw_get_ip(info, &ip);	dprintk("unwind: failed to unwind to user-level (ip=0x%lx)\n", ip);	return -1;}voidunw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw){	unsigned long rbslimit, rbstop, stklimit, stktop, sol;	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;	stktop   = (unsigned long) sw - 16;	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 = (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;	info->pr = sw->pr;	find_save_locs(info);	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));}#endif /* CONFIG_IA64_NEW_UNWIND */voidunw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t){	struct switch_stack *sw = (struct switch_stack *) (t->thread.ksp + 16);#ifdef CONFIG_IA64_NEW_UNWIND	unw_init_frame_info(info, t, sw);#else	unsigned long sol, limit, top;	memset(info, 0, sizeof(*info));	sol = (sw->ar_pfs >> 7) & 0x7f;	/* size of locals */	limit = (unsigned long) t + IA64_RBS_OFFSET;	top   = sw->ar_bspstore;	if (top - (unsigned long) t >= IA64_STK_OFFSET)		top = limit;	info->regstk.limit = limit;	info->regstk.top   = top;	info->sw  = sw;	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);	info->cfm_loc = &sw->ar_pfs;	info->ip  = sw->b0;#endif}voidunw_init_from_current (struct unw_frame_info *info, struct pt_regs *regs){#ifdef CONFIG_IA64_NEW_UNWIND	struct switch_stack *sw = (struct switch_stack *) regs - 1;	unw_init_frame_info(info, current, sw);	/* skip over interrupt frame: */	unw_unwind(info);#else	struct switch_stack *sw = (struct switch_stack *) regs - 1;	unsigned long sol, sof, *bsp, limit, top;	limit = (unsigned long) current + IA64_RBS_OFFSET;	top   = sw->ar_bspstore;	if (top - (unsigned long) current >= IA64_STK_OFFSET)		top = limit;	memset(info, 0, sizeof(*info));	sol = (sw->ar_pfs >> 7) & 0x7f;	/* size of frame */	/* this gives us the bsp top level frame (kdb interrupt frame): */	bsp = ia64_rse_skip_regs((unsigned long *) top, -sol);	/* now skip past the interrupt frame: */	sof = regs->cr_ifs & 0x7f;	/* size of frame */	info->regstk.limit = limit;	info->regstk.top   = top;	info->sw = sw;	info->bsp = (unsigned long) ia64_rse_skip_regs(bsp, -sof);	info->cfm_loc = &regs->cr_ifs;	info->ip  = regs->cr_iip;#endif}#ifndef CONFIG_IA64_NEW_UNWINDstatic unsigned longread_reg (struct unw_frame_info *info, int regnum, int *is_nat){	unsigned long *addr, *rnat_addr, rnat;	addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);	if ((unsigned long) addr < info->regstk.limit	    || (unsigned long) addr >= info->regstk.top || ((long) addr & 0x7) != 0)	{		*is_nat = 1;		return 0xdeadbeefdeadbeef;	}	rnat_addr = ia64_rse_rnat_addr(addr);	if ((unsigned long) rnat_addr >= info->regstk.top)		rnat = info->sw->ar_rnat;	else		rnat = *rnat_addr;	*is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0;	return *addr;}/* * On entry, info->regstk.top should point to the register backing * store for r32. */intunw_unwind (struct unw_frame_info *info){	unsigned long sol, cfm = *info->cfm_loc;	int is_nat;	sol = (cfm >> 7) & 0x7f;	/* size of locals */	/*	 * In general, we would have to make use of unwind info to	 * unwind an IA-64 stack, but for now gcc uses a special	 * convention that makes this possible without full-fledged	 * unwindo info.  Specifically, we expect "rp" in the second	 * last, and "ar.pfs" in the last local register, so the	 * number of locals in a frame must be at least two.  If it's	 * less than that, we reached the end of the C call stack.	 */	if (sol < 2)		return -1;	info->ip = read_reg(info, sol - 2, &is_nat);	if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)))		/* reject let obviously bad addresses */		return -1;	info->cfm_loc = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);	cfm = read_reg(info, sol - 1, &is_nat);	if (is_nat)		return -1;	sol = (cfm >> 7) & 0x7f;	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol);	return 0;}#endif /* !CONFIG_IA64_NEW_UNWIND */#ifdef CONFIG_IA64_NEW_UNWINDstatic voidinit_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base,		   unsigned long gp, void *table_start, void *table_end){	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;}void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,		      void *table_start, void *table_end){	struct unw_table_entry *start = table_start, *end = table_end;	struct unw_table *table;	unsigned long flags;	if (end - start <= 0) {		dprintk("unwind: ignoring attempt to insert empty unwind table\n");		return 0;	}		table = kmalloc(sizeof(*table), GFP_USER);	if (!table)		return 0;	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) {		dprintk("unwind: ignoring attempt to remove non-existent unwind table\n");		return;	}	table = handle;	if (table == &unw.kernel_table) {		dprintk("unwind: sorry, freeing the kernel's unwind table is a no-can-do!\n");		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) {			dprintk("unwind: failed to find unwind table %p\n", (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);}#endif /* CONFIG_IA64_NEW_UNWIND */voidunw_init (void){#ifdef CONFIG_IA64_NEW_UNWIND	extern int ia64_unw_start, ia64_unw_end, __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(AR_UNAT);	unw.sw_off[unw.preg_index[UNW_REG_BSPSTORE]] = SW(AR_BSPSTORE);	unw.sw_off[unw.preg_index[UNW_REG_PFS]] = SW(AR_UNAT);	unw.sw_off[unw.preg_index[UNW_REG_RP]] = SW(B0);	unw.sw_off[unw.preg_index[UNW_REG_UNAT]] = SW(AR_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;		unw.cache[i].lock = RW_LOCK_UNLOCKED;	}	unw.lru_head = UNW_CACHE_SIZE - 1;	unw.lru_tail = 0;	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp,			  &ia64_unw_start, &ia64_unw_end);#endif /* CONFIG_IA64_NEW_UNWIND */}

⌨️ 快捷键说明

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