Commit 1e56f6d2 authored by Al Viro's avatar Al Viro
Browse files

Merge branches 'regset.x86', 'regset.ia64', 'regset.sparc' and 'regset.arm64' into work.regset

Loading
Loading
Loading
Loading
+38 −29
Original line number Diff line number Diff line
@@ -1237,6 +1237,22 @@ enum compat_regset {
	REGSET_COMPAT_VFP,
};

static inline compat_ulong_t compat_get_user_reg(struct task_struct *task, int idx)
{
	struct pt_regs *regs = task_pt_regs(task);

	switch (idx) {
	case 15:
		return regs->pc;
	case 16:
		return pstate_to_compat_psr(regs->pstate);
	case 17:
		return regs->orig_x0;
	default:
		return regs->regs[idx];
	}
}

static int compat_gpr_get(struct task_struct *target,
			  const struct user_regset *regset,
			  unsigned int pos, unsigned int count,
@@ -1255,23 +1271,7 @@ static int compat_gpr_get(struct task_struct *target,
		return -EIO;

	for (i = 0; i < num_regs; ++i) {
		unsigned int idx = start + i;
		compat_ulong_t reg;

		switch (idx) {
		case 15:
			reg = task_pt_regs(target)->pc;
			break;
		case 16:
			reg = task_pt_regs(target)->pstate;
			reg = pstate_to_compat_psr(reg);
			break;
		case 17:
			reg = task_pt_regs(target)->orig_x0;
			break;
		default:
			reg = task_pt_regs(target)->regs[idx];
		}
		compat_ulong_t reg = compat_get_user_reg(target, start + i);

		if (kbuf) {
			memcpy(kbuf, &reg, sizeof(reg));
@@ -1541,9 +1541,7 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
	else if (off == COMPAT_PT_TEXT_END_ADDR)
		tmp = tsk->mm->end_code;
	else if (off < sizeof(compat_elf_gregset_t))
		return copy_regset_to_user(tsk, &user_aarch32_view,
					   REGSET_COMPAT_GPR, off,
					   sizeof(compat_ulong_t), ret);
		tmp = compat_get_user_reg(tsk, off >> 2);
	else if (off >= COMPAT_USER_SZ)
		return -EIO;
	else
@@ -1555,8 +1553,8 @@ static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
				    compat_ulong_t val)
{
	int ret;
	mm_segment_t old_fs = get_fs();
	struct pt_regs newregs = *task_pt_regs(tsk);
	unsigned int idx = off / 4;

	if (off & 3 || off >= COMPAT_USER_SZ)
		return -EIO;
@@ -1564,14 +1562,25 @@ static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off,
	if (off >= sizeof(compat_elf_gregset_t))
		return 0;

	set_fs(KERNEL_DS);
	ret = copy_regset_from_user(tsk, &user_aarch32_view,
				    REGSET_COMPAT_GPR, off,
				    sizeof(compat_ulong_t),
				    &val);
	set_fs(old_fs);
	switch (idx) {
	case 15:
		newregs.pc = val;
		break;
	case 16:
		newregs.pstate = compat_psr_to_pstate(val);
		break;
	case 17:
		newregs.orig_x0 = val;
		break;
	default:
		newregs.regs[idx] = val;
	}

	if (!valid_user_regs(&newregs.user_regs, tsk))
		return -EINVAL;

	return ret;
	*task_pt_regs(tsk) = newregs;
	return 0;
}

#ifdef CONFIG_HAVE_HW_BREAKPOINT
+98 −177
Original line number Diff line number Diff line
@@ -1273,52 +1273,43 @@ struct regset_getset {
	int ret;
};

static const ptrdiff_t pt_offsets[32] =
{
#define R(n) offsetof(struct pt_regs, r##n)
	[0] = -1, R(1), R(2), R(3),
	[4] = -1, [5] = -1, [6] = -1, [7] = -1,
	R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
	R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
	R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
#undef R
};

static int
access_elf_gpreg(struct task_struct *target, struct unw_frame_info *info,
		unsigned long addr, unsigned long *data, int write_access)
{
	struct pt_regs *pt;
	unsigned long *ptr = NULL;
	int ret;
	char nat = 0;
	struct pt_regs *pt = task_pt_regs(target);
	unsigned reg = addr / sizeof(unsigned long);
	ptrdiff_t d = pt_offsets[reg];

	pt = task_pt_regs(target);
	switch (addr) {
	case ELF_GR_OFFSET(1):
		ptr = &pt->r1;
		break;
	case ELF_GR_OFFSET(2):
	case ELF_GR_OFFSET(3):
		ptr = (void *)&pt->r2 + (addr - ELF_GR_OFFSET(2));
		break;
	case ELF_GR_OFFSET(4) ... ELF_GR_OFFSET(7):
	if (d >= 0) {
		unsigned long *ptr = (void *)pt + d;
		if (write_access)
			*ptr = *data;
		else
			*data = *ptr;
		return 0;
	} else {
		char nat = 0;
		if (write_access) {
			/* read NaT bit first: */
			unsigned long dummy;

			ret = unw_get_gr(info, addr/8, &dummy, &nat);
			int ret = unw_get_gr(info, reg, &dummy, &nat);
			if (ret < 0)
				return ret;
		}
		return unw_access_gr(info, addr/8, data, &nat, write_access);
	case ELF_GR_OFFSET(8) ... ELF_GR_OFFSET(11):
		ptr = (void *)&pt->r8 + addr - ELF_GR_OFFSET(8);
		break;
	case ELF_GR_OFFSET(12):
	case ELF_GR_OFFSET(13):
		ptr = (void *)&pt->r12 + addr - ELF_GR_OFFSET(12);
		break;
	case ELF_GR_OFFSET(14):
		ptr = &pt->r14;
		break;
	case ELF_GR_OFFSET(15):
		ptr = &pt->r15;
		return unw_access_gr(info, reg, data, &nat, write_access);
	}
	if (write_access)
		*ptr = *data;
	else
		*data = *ptr;
	return 0;
}

static int
@@ -1490,7 +1481,7 @@ static int
access_elf_reg(struct task_struct *target, struct unw_frame_info *info,
		unsigned long addr, unsigned long *data, int write_access)
{
	if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(15))
	if (addr >= ELF_GR_OFFSET(1) && addr <= ELF_GR_OFFSET(31))
		return access_elf_gpreg(target, info, addr, data, write_access);
	else if (addr >= ELF_BR_OFFSET(0) && addr <= ELF_BR_OFFSET(7))
		return access_elf_breg(target, info, addr, data, write_access);
@@ -1500,10 +1491,7 @@ access_elf_reg(struct task_struct *target, struct unw_frame_info *info,

void do_gpregs_get(struct unw_frame_info *info, void *arg)
{
	struct pt_regs *pt;
	struct regset_getset *dst = arg;
	elf_greg_t tmp[16];
	unsigned int i, index, min_copy;

	if (unw_unwind_to_user(info) < 0)
		return;
@@ -1526,160 +1514,70 @@ void do_gpregs_get(struct unw_frame_info *info, void *arg)
						      &dst->u.get.kbuf,
						      &dst->u.get.ubuf,
						      0, ELF_GR_OFFSET(1));
		if (dst->ret || dst->count == 0)
			return;
	}

	/* gr1 - gr15 */
	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
		min_copy = ELF_GR_OFFSET(16) > (dst->pos + dst->count) ?
			 (dst->pos + dst->count) : ELF_GR_OFFSET(16);
		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
				index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 0) < 0) {
				dst->ret = -EIO;
				return;
			}
		dst->ret = user_regset_copyout(&dst->pos, &dst->count,
				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
		if (dst->ret || dst->count == 0)
		if (dst->ret)
			return;
	}

	/* r16-r31 */
	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
		pt = task_pt_regs(dst->target);
		dst->ret = user_regset_copyout(&dst->pos, &dst->count,
				&dst->u.get.kbuf, &dst->u.get.ubuf, &pt->r16,
				ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
		if (dst->ret || dst->count == 0)
			return;
	}
	while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
		unsigned int n, from, to;
		elf_greg_t tmp[16];

	/* nat, pr, b0 - b7 */
	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
		min_copy = ELF_CR_IIP_OFFSET > (dst->pos + dst->count) ?
			 (dst->pos + dst->count) : ELF_CR_IIP_OFFSET;
		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
				index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 0) < 0) {
		from = dst->pos;
		to = from + min(dst->count, (unsigned)sizeof(tmp));
		if (to > ELF_AR_END_OFFSET)
			to = ELF_AR_END_OFFSET;
		for (n = 0; from < to; from += sizeof(elf_greg_t), n++) {
			if (access_elf_reg(dst->target, info, from,
						&tmp[n], 0) < 0) {
				dst->ret = -EIO;
				return;
			}
		dst->ret = user_regset_copyout(&dst->pos, &dst->count,
				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
		if (dst->ret || dst->count == 0)
			return;
	}

	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
	 */
	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
		min_copy = ELF_AR_END_OFFSET > (dst->pos + dst->count) ?
			 (dst->pos + dst->count) : ELF_AR_END_OFFSET;
		for (i = dst->pos; i < min_copy; i += sizeof(elf_greg_t),
				index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 0) < 0) {
				dst->ret = -EIO;
				return;
		}
		dst->ret = user_regset_copyout(&dst->pos, &dst->count,
				&dst->u.get.kbuf, &dst->u.get.ubuf, tmp,
				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
				dst->pos, to);
		if (dst->ret)
			return;
	}
}

void do_gpregs_set(struct unw_frame_info *info, void *arg)
{
	struct pt_regs *pt;
	struct regset_getset *dst = arg;
	elf_greg_t tmp[16];
	unsigned int i, index;

	if (unw_unwind_to_user(info) < 0)
		return;

	if (!dst->count)
		return;
	/* Skip r0 */
	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(1)) {
	if (dst->pos < ELF_GR_OFFSET(1)) {
		dst->ret = user_regset_copyin_ignore(&dst->pos, &dst->count,
						       &dst->u.set.kbuf,
						       &dst->u.set.ubuf,
						       0, ELF_GR_OFFSET(1));
		if (dst->ret || dst->count == 0)
			return;
	}

	/* gr1-gr15 */
	if (dst->count > 0 && dst->pos < ELF_GR_OFFSET(16)) {
		i = dst->pos;
		index = (dst->pos - ELF_GR_OFFSET(1)) / sizeof(elf_greg_t);
		dst->ret = user_regset_copyin(&dst->pos, &dst->count,
				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
				ELF_GR_OFFSET(1), ELF_GR_OFFSET(16));
		if (dst->ret)
			return;
		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 1) < 0) {
				dst->ret = -EIO;
				return;
			}
		if (dst->count == 0)
			return;
	}

	/* gr16-gr31 */
	if (dst->count > 0 && dst->pos < ELF_NAT_OFFSET) {
		pt = task_pt_regs(dst->target);
		dst->ret = user_regset_copyin(&dst->pos, &dst->count,
				&dst->u.set.kbuf, &dst->u.set.ubuf, &pt->r16,
				ELF_GR_OFFSET(16), ELF_NAT_OFFSET);
		if (dst->ret || dst->count == 0)
			return;
	}

	/* nat, pr, b0 - b7 */
	if (dst->count > 0 && dst->pos < ELF_CR_IIP_OFFSET) {
		i = dst->pos;
		index = (dst->pos - ELF_NAT_OFFSET) / sizeof(elf_greg_t);
		dst->ret = user_regset_copyin(&dst->pos, &dst->count,
				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
				ELF_NAT_OFFSET, ELF_CR_IIP_OFFSET);
		if (dst->ret)
			return;
		for (; i < dst->pos; i += sizeof(elf_greg_t), index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 1) < 0) {
				dst->ret = -EIO;
				return;
			}
		if (dst->count == 0)
			return;
	}
	while (dst->count && dst->pos < ELF_AR_END_OFFSET) {
		unsigned int n, from, to;
		elf_greg_t tmp[16];

	/* ip cfm psr ar.rsc ar.bsp ar.bspstore ar.rnat
	 * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd
	 */
	if (dst->count > 0 && dst->pos < (ELF_AR_END_OFFSET)) {
		i = dst->pos;
		index = (dst->pos - ELF_CR_IIP_OFFSET) / sizeof(elf_greg_t);
		from = dst->pos;
		to = from + sizeof(tmp);
		if (to > ELF_AR_END_OFFSET)
			to = ELF_AR_END_OFFSET;
		/* get up to 16 values */
		dst->ret = user_regset_copyin(&dst->pos, &dst->count,
				&dst->u.set.kbuf, &dst->u.set.ubuf, tmp,
				ELF_CR_IIP_OFFSET, ELF_AR_END_OFFSET);
				from, to);
		if (dst->ret)
			return;
		for ( ; i < dst->pos; i += sizeof(elf_greg_t), index++)
			if (access_elf_reg(dst->target, info, i,
						&tmp[index], 1) < 0) {
		/* now copy them into registers */
		for (n = 0; from < dst->pos; from += sizeof(elf_greg_t), n++)
			if (access_elf_reg(dst->target, info, from,
						&tmp[n], 1) < 0) {
				dst->ret = -EIO;
				return;
			}
@@ -1913,7 +1811,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
	      unsigned long *data, int write_access)
{
	unsigned int pos = -1; /* an invalid value */
	int ret;
	unsigned long *ptr, regnum;

	if ((addr & 0x7) != 0) {
@@ -1945,14 +1842,39 @@ access_uarea(struct task_struct *child, unsigned long addr,
	}

	if (pos != -1) {
		unsigned reg = pos / sizeof(elf_fpreg_t);
		int which_half = (pos / sizeof(unsigned long)) & 1;

		if (reg < 32) { /* fr2-fr31 */
			struct unw_frame_info info;
			elf_fpreg_t fpreg;

			memset(&info, 0, sizeof(info));
			unw_init_from_blocked_task(&info, child);
			if (unw_unwind_to_user(&info) < 0)
				return 0;

			if (unw_get_fr(&info, reg, &fpreg))
				return -1;
			if (write_access) {
				fpreg.u.bits[which_half] = *data;
				if (unw_set_fr(&info, reg, fpreg))
					return -1;
			} else {
				*data = fpreg.u.bits[which_half];
			}
		} else { /* fph */
			elf_fpreg_t *p = &child->thread.fph[reg - 32];
			unsigned long *bits = &p->u.bits[which_half];

			ia64_sync_fph(child);
			if (write_access)
			ret = fpregs_set(child, NULL, pos,
				sizeof(unsigned long), data, NULL);
				*bits = *data;
			else if (child->thread.flags & IA64_THREAD_FPH_VALID)
				*data = *bits;
			else
			ret = fpregs_get(child, NULL, pos,
				sizeof(unsigned long), data, NULL);
		if (ret != 0)
			return -1;
				*data = 0;
		}
		return 0;
	}

@@ -2038,15 +1960,14 @@ access_uarea(struct task_struct *child, unsigned long addr,
	}

	if (pos != -1) {
		if (write_access)
			ret = gpregs_set(child, NULL, pos,
				sizeof(unsigned long), data, NULL);
		else
			ret = gpregs_get(child, NULL, pos,
				sizeof(unsigned long), data, NULL);
		if (ret != 0)
			return -1;
		struct unw_frame_info info;

		memset(&info, 0, sizeof(info));
		unw_init_from_blocked_task(&info, child);
		if (unw_unwind_to_user(&info) < 0)
			return 0;

		return access_elf_reg(child, &info, pos, data, write_access);
	}

	/* access debug registers */
+155 −71
Original line number Diff line number Diff line
@@ -99,15 +99,13 @@ static int genregs32_get(struct task_struct *target,
	if (ret || !count)
		return ret;

	if (pos < 32 * sizeof(u32)) {
	if (regwindow32_get(target, regs, uregs))
		return -EFAULT;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  uregs,
				  16 * sizeof(u32), 32 * sizeof(u32));
		if (ret || !count)
	if (ret)
		return ret;
	}

	uregs[0] = regs->psr;
	uregs[1] = regs->pc;
@@ -139,7 +137,6 @@ static int genregs32_set(struct task_struct *target,
	if (ret || !count)
		return ret;

	if (pos < 32 * sizeof(u32)) {
	if (regwindow32_get(target, regs, uregs))
		return -EFAULT;
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -151,7 +148,7 @@ static int genregs32_set(struct task_struct *target,
		return -EFAULT;
	if (!count)
		return 0;
	}

	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &psr,
				 32 * sizeof(u32), 33 * sizeof(u32));
@@ -243,13 +240,11 @@ static int fpregs32_set(struct task_struct *target,
		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
					  32 * sizeof(u32),
					  33 * sizeof(u32));
	if (!ret && count > 0) {
	if (!ret)
		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
					 &target->thread.fsr,
					 33 * sizeof(u32),
					 34 * sizeof(u32));
	}

	if (!ret)
		ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
						34 * sizeof(u32), -1);
@@ -288,6 +283,125 @@ static const struct user_regset sparc32_regsets[] = {
	},
};

static int getregs_get(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 void *kbuf, void __user *ubuf)
{
	const struct pt_regs *regs = target->thread.kregs;
	u32 v[4];
	int ret;

	if (target == current)
		flush_user_windows();

	v[0] = regs->psr;
	v[1] = regs->pc;
	v[2] = regs->npc;
	v[3] = regs->y;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  v,
				  0 * sizeof(u32), 4 * sizeof(u32));
	if (ret)
		return ret;

	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs->u_regs + 1,
				  4 * sizeof(u32), 19 * sizeof(u32));
}

static int setregs_set(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 const void *kbuf, const void __user *ubuf)
{
	struct pt_regs *regs = target->thread.kregs;
	u32 v[4];
	int ret;

	if (target == current)
		flush_user_windows();

	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 v,
				 0, 4 * sizeof(u32));
	if (ret)
		return ret;
	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
		    (v[0] & (PSR_ICC | PSR_SYSCALL));
	regs->pc = v[1];
	regs->npc = v[2];
	regs->y = v[3];
	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 regs->u_regs + 1,
				 4 * sizeof(u32) , 19 * sizeof(u32));
}

static int getfpregs_get(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			void *kbuf, void __user *ubuf)
{
	const unsigned long *fpregs = target->thread.float_regs;
	int ret = 0;

#if 0
	if (target == current)
		save_and_clear_fpu();
#endif

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  fpregs,
				  0, 32 * sizeof(u32));
	if (ret)
		return ret;
	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  &target->thread.fsr,
				  32 * sizeof(u32), 33 * sizeof(u32));
	if (ret)
		return ret;
	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
				  33 * sizeof(u32), 68 * sizeof(u32));
}

static int setfpregs_set(struct task_struct *target,
			const struct user_regset *regset,
			unsigned int pos, unsigned int count,
			const void *kbuf, const void __user *ubuf)
{
	unsigned long *fpregs = target->thread.float_regs;
	int ret;

#if 0
	if (target == current)
		save_and_clear_fpu();
#endif
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 fpregs,
				 0, 32 * sizeof(u32));
	if (ret)
		return ret;
	return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &target->thread.fsr,
				 32 * sizeof(u32),
				 33 * sizeof(u32));
}

static const struct user_regset ptrace32_regsets[] = {
	[REGSET_GENERAL] = {
		.n = 19, .size = sizeof(u32),
		.get = getregs_get, .set = setregs_set,
	},
	[REGSET_FP] = {
		.n = 68, .size = sizeof(u32),
		.get = getfpregs_get, .set = setfpregs_set,
	},
};

static const struct user_regset_view ptrace32_view = {
	.regsets = ptrace32_regsets, .n = ARRAY_SIZE(ptrace32_regsets)
};

static const struct user_regset_view user_sparc32_view = {
	.name = "sparc", .e_machine = EM_SPARC,
	.regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets)
@@ -315,74 +429,44 @@ long arch_ptrace(struct task_struct *child, long request,
{
	unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
	void __user *addr2p;
	const struct user_regset_view *view;
	struct pt_regs __user *pregs;
	struct fps __user *fps;
	int ret;

	view = task_user_regset_view(current);
	addr2p = (void __user *) addr2;
	pregs = (struct pt_regs __user *) addr;
	fps = (struct fps __user *) addr;

	switch(request) {
	case PTRACE_GETREGS: {
		ret = copy_regset_to_user(child, view, REGSET_GENERAL,
					  32 * sizeof(u32),
					  4 * sizeof(u32),
					  &pregs->psr);
		if (!ret)
			copy_regset_to_user(child, view, REGSET_GENERAL,
					    1 * sizeof(u32),
					    15 * sizeof(u32),
					    &pregs->u_regs[0]);
		ret = copy_regset_to_user(child, &ptrace32_view,
					  REGSET_GENERAL, 0,
					  19 * sizeof(u32),
					  pregs);
		break;
	}

	case PTRACE_SETREGS: {
		ret = copy_regset_from_user(child, view, REGSET_GENERAL,
					    32 * sizeof(u32),
					    4 * sizeof(u32),
					    &pregs->psr);
		if (!ret)
			copy_regset_from_user(child, view, REGSET_GENERAL,
					      1 * sizeof(u32),
					      15 * sizeof(u32),
					      &pregs->u_regs[0]);
		ret = copy_regset_from_user(child, &ptrace32_view,
					    REGSET_GENERAL, 0,
					    19 * sizeof(u32),
					    pregs);
		break;
	}

	case PTRACE_GETFPREGS: {
		ret = copy_regset_to_user(child, view, REGSET_FP,
					  0 * sizeof(u32),
					  32 * sizeof(u32),
					  &fps->regs[0]);
		if (!ret)
			ret = copy_regset_to_user(child, view, REGSET_FP,
						  33 * sizeof(u32),
						  1 * sizeof(u32),
						  &fps->fsr);

		if (!ret) {
			if (__put_user(0, &fps->fpqd) ||
			    __put_user(0, &fps->flags) ||
			    __put_user(0, &fps->extra) ||
			    clear_user(fps->fpq, sizeof(fps->fpq)))
				ret = -EFAULT;
		}
		ret = copy_regset_to_user(child, &ptrace32_view,
					  REGSET_FP, 0,
					  68 * sizeof(u32),
					  fps);
		break;
	}

	case PTRACE_SETFPREGS: {
		ret = copy_regset_from_user(child, view, REGSET_FP,
					    0 * sizeof(u32),
					    32 * sizeof(u32),
					    &fps->regs[0]);
		if (!ret)
			ret = copy_regset_from_user(child, view, REGSET_FP,
		ret = copy_regset_from_user(child, &ptrace32_view,
					  REGSET_FP, 0,
					  33 * sizeof(u32),
						    1 * sizeof(u32),
						    &fps->fsr);
					  fps);
		break;
	}

+291 −110

File changed.

Preview size limit exceeded, changes collapsed.

+0 −1
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ extern int fpu__copy(struct task_struct *dst, struct task_struct *src);
extern void fpu__clear_user_states(struct fpu *fpu);
extern void fpu__clear_all(struct fpu *fpu);
extern int  fpu__exception_code(struct fpu *fpu, int trap_nr);
extern int  dump_fpu(struct pt_regs *ptregs, struct user_i387_struct *fpstate);

/*
 * Boot time FPU initialization functions:
Loading