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

📄 unwind.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (C) 1999-2004 Hewlett-Packard Co *	David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2003 Fenghua Yu <fenghua.yu@intel.com> * 	- Change pt_regs_off() to make it less dependant on pt_regs structure. *//* * This file implements call frame unwind support for the Linux * kernel.  Parsing and processing the unwind information is * time-consuming, so this implementation translates the unwind * descriptors into unwind scripts.  These scripts are very simple * (basically a sequence of assignments) and efficient to execute. * They are cached for later re-use.  Each script is specific for a * given instruction pointer address and the set of predicate values * that the script depends on (most unwind descriptors are * unconditional and scripts often do not depend on predicates at * all).  This code is based on the unwind conventions described in * the "IA-64 Software Conventions and Runtime Architecture" manual. * * SMP conventions: *	o updates to the global unwind data (in structure "unw") are serialized *	  by the unw.lock spinlock *	o each unwind script has its own read-write lock; a thread must acquire *	  a read lock before executing a script and must acquire a write lock *	  before modifying a script *	o if both the unw.lock spinlock and a script's read-write lock must be *	  acquired, then the read-write lock must be acquired first. */#ifdef XEN#include <xen/types.h>#include <xen/elf.h>#include <xen/kernel.h>#include <xen/sched.h>#include <xen/xmalloc.h>#include <xen/spinlock.h>#include <xen/errno.h>// work around#ifdef CONFIG_SMP#define write_trylock(lock)	_raw_write_trylock(lock)#else#define write_trylock(lock)	({1;})#endif#else#include <linux/module.h>#include <linux/bootmem.h>#include <linux/elf.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#endif#include <asm/unwind.h>#include <asm/delay.h>#include <asm/page.h>#include <asm/ptrace.h>#include <asm/ptrace_offsets.h>#include <asm/rse.h>#include <asm/sections.h>#include <asm/system.h>#include <asm/uaccess.h>#include "entry.h"#include "unwind_i.h"#define UNW_LOG_CACHE_SIZE	7	/* each unw_script is ~256 bytes in size */#define UNW_CACHE_SIZE		(1 << UNW_LOG_CACHE_SIZE)#define UNW_LOG_HASH_SIZE	(UNW_LOG_CACHE_SIZE + 1)#define UNW_HASH_SIZE		(1 << UNW_LOG_HASH_SIZE)#define UNW_STATS	0	/* WARNING: this disabled interrupts for long time-spans!! */#ifdef UNW_DEBUG  static unsigned int unw_debug_level = UNW_DEBUG;#  define UNW_DEBUG_ON(n)	unw_debug_level >= n   /* Do not code a printk level, not all debug lines end in newline */#  define UNW_DPRINT(n, ...)  if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__)#  define inline#else /* !UNW_DEBUG */#  define UNW_DEBUG_ON(n)  0#  define UNW_DPRINT(n, ...)#endif /* UNW_DEBUG */#if UNW_STATS# define STAT(x...)	x#else# define STAT(x...)#endif#ifdef XEN#define alloc_reg_state()	xmalloc(struct unw_reg_state)#define free_reg_state(usr)	xfree(usr)#define alloc_labeled_state()	xmalloc(struct unw_labeled_state)#define free_labeled_state(usr)	xfree(usr)#else#define alloc_reg_state()	kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)#define free_reg_state(usr)	kfree(usr)#define alloc_labeled_state()	kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)#define free_labeled_state(usr)	kfree(usr)#endiftypedef unsigned long unw_word;typedef unsigned char unw_hash_index_t;static struct {	spinlock_t lock;			/* spinlock for unwind data */	/* list of unwind tables (one per load-module) */	struct unw_table *tables;	unsigned long r0;			/* constant 0 for r0 */	/* table of registers that prologues can save (and order in which they're saved): */	const unsigned char save_order[8];	/* maps a preserved register index (preg_index) to corresponding switch_stack offset: */	unsigned short sw_off[sizeof(struct unw_frame_info) / 8];	unsigned short lru_head;		/* index of lead-recently used script */	unsigned short lru_tail;		/* index of most-recently used script */	/* index into unw_frame_info for preserved register i */	unsigned short preg_index[UNW_NUM_REGS];	short pt_regs_offsets[32];	/* unwind table for the kernel: */	struct unw_table kernel_table;	/* unwind table describing the gate page (kernel code that is mapped into user space): */	size_t gate_table_size;	unsigned long *gate_table;	/* hash table that maps instruction pointer to script index: */	unsigned short hash[UNW_HASH_SIZE];	/* script cache: */	struct unw_script cache[UNW_CACHE_SIZE];# ifdef UNW_DEBUG	const char *preg_name[UNW_NUM_REGS];# endif# if UNW_STATS	struct {		struct {			int lookups;			int hinted_hits;			int normal_hits;			int collision_chain_traversals;		} cache;		struct {			unsigned long build_time;			unsigned long run_time;			unsigned long parse_time;			int builds;			int news;			int collisions;			int runs;		} script;		struct {			unsigned long init_time;			unsigned long unwind_time;			int inits;			int unwinds;		} api;	} stat;# endif} unw = {	.tables = &unw.kernel_table,	.lock = SPIN_LOCK_UNLOCKED,	.save_order = {		UNW_REG_RP, UNW_REG_PFS, UNW_REG_PSP, UNW_REG_PR,		UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR	},	.preg_index = {		offsetof(struct unw_frame_info, pri_unat_loc)/8,	/* PRI_UNAT_GR */		offsetof(struct unw_frame_info, pri_unat_loc)/8,	/* PRI_UNAT_MEM */		offsetof(struct unw_frame_info, bsp_loc)/8,		offsetof(struct unw_frame_info, bspstore_loc)/8,		offsetof(struct unw_frame_info, pfs_loc)/8,		offsetof(struct unw_frame_info, rnat_loc)/8,		offsetof(struct unw_frame_info, psp)/8,		offsetof(struct unw_frame_info, rp_loc)/8,		offsetof(struct unw_frame_info, r4)/8,		offsetof(struct unw_frame_info, r5)/8,		offsetof(struct unw_frame_info, r6)/8,		offsetof(struct unw_frame_info, r7)/8,		offsetof(struct unw_frame_info, unat_loc)/8,		offsetof(struct unw_frame_info, pr_loc)/8,		offsetof(struct unw_frame_info, lc_loc)/8,		offsetof(struct unw_frame_info, fpsr_loc)/8,		offsetof(struct unw_frame_info, b1_loc)/8,		offsetof(struct unw_frame_info, b2_loc)/8,		offsetof(struct unw_frame_info, b3_loc)/8,		offsetof(struct unw_frame_info, b4_loc)/8,		offsetof(struct unw_frame_info, b5_loc)/8,		offsetof(struct unw_frame_info, f2_loc)/8,		offsetof(struct unw_frame_info, f3_loc)/8,		offsetof(struct unw_frame_info, f4_loc)/8,		offsetof(struct unw_frame_info, f5_loc)/8,		offsetof(struct unw_frame_info, fr_loc[16 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[17 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[18 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[19 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[20 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[21 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[22 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[23 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[24 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[25 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[26 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[27 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[28 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[29 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[30 - 16])/8,		offsetof(struct unw_frame_info, fr_loc[31 - 16])/8,	},	.pt_regs_offsets = {		[0] = -1,		offsetof(struct pt_regs,  r1),		offsetof(struct pt_regs,  r2),		offsetof(struct pt_regs,  r3),		[4] = -1, [5] = -1, [6] = -1, [7] = -1,		offsetof(struct pt_regs,  r8),		offsetof(struct pt_regs,  r9),		offsetof(struct pt_regs, r10),		offsetof(struct pt_regs, r11),		offsetof(struct pt_regs, r12),		offsetof(struct pt_regs, r13),		offsetof(struct pt_regs, r14),		offsetof(struct pt_regs, r15),		offsetof(struct pt_regs, r16),		offsetof(struct pt_regs, r17),		offsetof(struct pt_regs, r18),		offsetof(struct pt_regs, r19),		offsetof(struct pt_regs, r20),		offsetof(struct pt_regs, r21),		offsetof(struct pt_regs, r22),		offsetof(struct pt_regs, r23),		offsetof(struct pt_regs, r24),		offsetof(struct pt_regs, r25),		offsetof(struct pt_regs, r26),		offsetof(struct pt_regs, r27),		offsetof(struct pt_regs, r28),		offsetof(struct pt_regs, r29),		offsetof(struct pt_regs, r30),		offsetof(struct pt_regs, r31),	},	.hash = { [0 ... UNW_HASH_SIZE - 1] = -1 },#ifdef UNW_DEBUG	.preg_name = {		"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat", "psp", "rp",		"r4", "r5", "r6", "r7",		"ar.unat", "pr", "ar.lc", "ar.fpsr",		"b1", "b2", "b3", "b4", "b5",		"f2", "f3", "f4", "f5",		"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",		"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"	}#endif};static inline intread_only (void *addr){	return (unsigned long) ((char *) addr - (char *) &unw.r0) < sizeof(unw.r0);}/* * Returns offset of rREG in struct pt_regs. */static inline unsigned longpt_regs_off (unsigned long reg){	short off = -1;	if (reg < ARRAY_SIZE(unw.pt_regs_offsets))		off = unw.pt_regs_offsets[reg];	if (off < 0) {		UNW_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg);		off = 0;	}	return (unsigned long) off;}static inline struct pt_regs *get_scratch_regs (struct unw_frame_info *info){	if (!info->pt) {		/* This should not happen with valid unwind info.  */		UNW_DPRINT(0, "unwind.%s: bad unwind info: resetting info->pt\n", __FUNCTION__);		if (info->flags & UNW_FLAG_INTERRUPT_FRAME)			info->pt = (unsigned long) ((struct pt_regs *) info->psp - 1);		else			info->pt = info->sp - 16;	}	UNW_DPRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", __FUNCTION__, info->sp, info->pt);	return (struct pt_regs *) info->pt;}/* Unwind accessors.  */intunw_access_gr (struct unw_frame_info *info, int regnum, unsigned long *val, char *nat, int write){	unsigned long *addr, *nat_addr, nat_mask = 0, dummy_nat;	struct unw_ireg *ireg;	struct pt_regs *pt;	if ((unsigned) regnum - 1 >= 127) {		if (regnum == 0 && !write) {			*val = 0;	/* read r0 always returns 0 */			*nat = 0;			return 0;		}		UNW_DPRINT(0, "unwind.%s: trying to access non-existent r%u\n",			   __FUNCTION__, regnum);		return -1;	}	if (regnum < 32) {		if (regnum >= 4 && regnum <= 7) {			/* access a preserved register */			ireg = &info->r4 + (regnum - 4);			addr = ireg->loc;			if (addr) {				nat_addr = addr + ireg->nat.off;				switch (ireg->nat.type) {				      case UNW_NAT_VAL:					/* simulate getf.sig/setf.sig */					if (write) {						if (*nat) {							/* write NaTVal and be done with it */							addr[0] = 0;							addr[1] = 0x1fffe;							return 0;						}						addr[1] = 0x1003e;					} else {						if (addr[0] == 0 && addr[1] == 0x1ffe) {							/* return NaT and be done with it */							*val = 0;							*nat = 1;							return 0;						}					}					/* fall through */				      case UNW_NAT_NONE:					dummy_nat = 0;					nat_addr = &dummy_nat;					break;				      case UNW_NAT_MEMSTK:					nat_mask = (1UL << ((long) addr & 0x1f8)/8);					break;				      case UNW_NAT_REGSTK:					nat_addr = ia64_rse_rnat_addr(addr);					if ((unsigned long) addr < info->regstk.limit					    || (unsigned long) addr >= info->regstk.top)					{						UNW_DPRINT(0, "unwind.%s: %p outside of regstk "							"[0x%lx-0x%lx)\n",							__FUNCTION__, (void *) addr,							info->regstk.limit,							info->regstk.top);						return -1;					}					if ((unsigned long) nat_addr >= info->regstk.top)						nat_addr = &info->sw->ar_rnat;					nat_mask = (1UL << ia64_rse_slot_num(addr));					break;				}			} else {				addr = &info->sw->r4 + (regnum - 4);				nat_addr = &info->sw->ar_unat;				nat_mask = (1UL << ((long) addr & 0x1f8)/8);			}		} else {			/* access a scratch register */			pt = get_scratch_regs(info);			addr = (unsigned long *) ((unsigned long)pt + pt_regs_off(regnum));			if (info->pri_unat_loc)				nat_addr = info->pri_unat_loc;			else				nat_addr = &info->sw->caller_unat;			nat_mask = (1UL << ((long) addr & 0x1f8)/8);		}	} else {		/* access a stacked register */		addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum - 32);		nat_addr = ia64_rse_rnat_addr(addr);		if ((unsigned long) addr < info->regstk.limit		    || (unsigned long) addr >= info->regstk.top)		{			UNW_DPRINT(0, "unwind.%s: ignoring attempt to access register outside "				   "of rbs\n",  __FUNCTION__);			return -1;		}		if ((unsigned long) nat_addr >= info->regstk.top)			nat_addr = &info->sw->ar_rnat;		nat_mask = (1UL << ia64_rse_slot_num(addr));	}	if (write) {		if (read_only(addr)) {			UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n",				__FUNCTION__);		} else {			*addr = *val;			if (*nat)				*nat_addr |= nat_mask;			else				*nat_addr &= ~nat_mask;		}	} else {		if ((*nat_addr & nat_mask) == 0) {			*val = *addr;			*nat = 0;		} else {			*val = 0;	/* if register is a NaT, *addr may contain kernel data! */			*nat = 1;		}	}	return 0;}EXPORT_SYMBOL(unw_access_gr);intunw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int write){	unsigned long *addr;	struct pt_regs *pt;	switch (regnum) {		/* scratch: */	      case 0: pt = get_scratch_regs(info); addr = &pt->b0; break;	      case 6: pt = get_scratch_regs(info); addr = &pt->b6; break;	      case 7: pt = get_scratch_regs(info); addr = &pt->b7; break;		/* preserved: */	      case 1: case 2: case 3: case 4: case 5:		addr = *(&info->b1_loc + (regnum - 1));		if (!addr)			addr = &info->sw->b1 + (regnum - 1);		break;	      default:		UNW_DPRINT(0, "unwind.%s: trying to access non-existent b%u\n",			   __FUNCTION__, regnum);		return -1;	}	if (write)		if (read_only(addr)) {			UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n",				__FUNCTION__);		} else			*addr = *val;	else		*val = *addr;	return 0;}EXPORT_SYMBOL(unw_access_br);intunw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write){	struct ia64_fpreg *addr = NULL;	struct pt_regs *pt;	if ((unsigned) (regnum - 2) >= 126) {		UNW_DPRINT(0, "unwind.%s: trying to access non-existent f%u\n",			   __FUNCTION__, regnum);		return -1;	}

⌨️ 快捷键说明

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