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

📄 unwind.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
		pop(&sr);	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_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] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0			    || 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 & (local_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));}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);	unw_init_frame_info(info, t, sw);}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;}void *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) {		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);}voidunw_create_gate_table (void){	extern char __start_gate_section[], __stop_gate_section[];	unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base;	const struct unw_table_entry *entry, *first;	size_t info_size, size;	char *info;	start = (unsigned long) __start_gate_section - segbase;	end   = (unsigned long) __stop_gate_section - segbase;	size  = 0;	first = lookup(&unw.kernel_table, start);	for (entry = first; entry->start_offset < 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 = alloc_bootmem(size);	if (!unw.gate_table) {		unw.gate_table_size = 0;		printk("unwind: unable to create unwind data for gate page!\n");		return;	}	unw.gate_table_size = size;	lp = unw.gate_table;	info = (char *) unw.gate_table + size;	for (entry = first; entry->start_offset < 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] = entry->start_offset - start + GATE_ADDR;	/* start */		lp[1] = entry->end_offset - start + GATE_ADDR;		/* end */		lp[2] = info - (char *) unw.gate_table;			/* info */	}	*lp = 0;	/* end-of-table marker */}voidunw_init (void){	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);}/* * 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 *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;}

⌨️ 快捷键说明

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