Commit 824c874a authored by David S. Miller's avatar David S. Miller
Browse files


Some ptrace fixes from Al.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7104e162 cf51e129
Loading
Loading
Loading
Loading
+98 −130
Original line number Diff line number Diff line
@@ -46,82 +46,79 @@ enum sparc_regset {
	REGSET_FP,
};

static int genregs32_get(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 void *kbuf, void __user *ubuf)
static int regwindow32_get(struct task_struct *target,
			   const struct pt_regs *regs,
			   u32 *uregs)
{
	const struct pt_regs *regs = target->thread.kregs;
	unsigned long __user *reg_window;
	unsigned long *k = kbuf;
	unsigned long __user *u = ubuf;
	unsigned long reg;

	if (target == current)
		flush_user_windows();

	pos /= sizeof(reg);
	count /= sizeof(reg);
	unsigned long reg_window = regs->u_regs[UREG_I6];
	int size = 16 * sizeof(u32);

	if (kbuf) {
		for (; count > 0 && pos < 16; count--)
			*k++ = regs->u_regs[pos++];

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (get_user(*k++, &reg_window[pos++]))
	if (target == current) {
		if (copy_from_user(uregs, (void __user *)reg_window, size))
			return -EFAULT;
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (put_user(regs->u_regs[pos++], u++))
		if (access_process_vm(target, reg_window, uregs, size,
				      FOLL_FORCE) != size)
			return -EFAULT;
	}
	return 0;
}

static int regwindow32_set(struct task_struct *target,
			   const struct pt_regs *regs,
			   u32 *uregs)
{
	unsigned long reg_window = regs->u_regs[UREG_I6];
	int size = 16 * sizeof(u32);

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (get_user(reg, &reg_window[pos++]) ||
			    put_user(reg, u++))
	if (target == current) {
		if (copy_to_user((void __user *)reg_window, uregs, size))
			return -EFAULT;
	} else {
		if (access_process_vm(target, reg_window, uregs, size,
				      FOLL_FORCE | FOLL_WRITE) != size)
			return -EFAULT;
	}
	return 0;
}
	while (count > 0) {
		switch (pos) {
		case 32: /* PSR */
			reg = regs->psr;
			break;
		case 33: /* PC */
			reg = regs->pc;
			break;
		case 34: /* NPC */
			reg = regs->npc;
			break;
		case 35: /* Y */
			reg = regs->y;
			break;
		case 36: /* WIM */
		case 37: /* TBR */
			reg = 0;
			break;
		default:
			goto finish;
		}

		if (kbuf)
			*k++ = reg;
		else if (put_user(reg, u++))
static int genregs32_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 uregs[16];
	int ret;

	if (target == current)
		flush_user_windows();

	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  regs->u_regs,
				  0, 16 * sizeof(u32));
	if (ret || !count)
		return ret;

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

	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
					38 * sizeof(reg), -1);
	uregs[0] = regs->psr;
	uregs[1] = regs->pc;
	uregs[2] = regs->npc;
	uregs[3] = regs->y;
	uregs[4] = 0;	/* WIM */
	uregs[5] = 0;	/* TBR */
	return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
				  uregs,
				  32 * sizeof(u32), 38 * sizeof(u32));
}

static int genregs32_set(struct task_struct *target,
@@ -130,82 +127,53 @@ static int genregs32_set(struct task_struct *target,
			 const void *kbuf, const void __user *ubuf)
{
	struct pt_regs *regs = target->thread.kregs;
	unsigned long __user *reg_window;
	const unsigned long *k = kbuf;
	const unsigned long __user *u = ubuf;
	unsigned long reg;
	u32 uregs[16];
	u32 psr;
	int ret;

	if (target == current)
		flush_user_windows();

	pos /= sizeof(reg);
	count /= sizeof(reg);

	if (kbuf) {
		for (; count > 0 && pos < 16; count--)
			regs->u_regs[pos++] = *k++;

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (put_user(*k++, &reg_window[pos++]))
				return -EFAULT;
		}
	} else {
		for (; count > 0 && pos < 16; count--) {
			if (get_user(reg, u++))
				return -EFAULT;
			regs->u_regs[pos++] = reg;
		}
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 regs->u_regs,
				 0, 16 * sizeof(u32));
	if (ret || !count)
		return ret;

		reg_window = (unsigned long __user *) regs->u_regs[UREG_I6];
		reg_window -= 16;
		for (; count > 0 && pos < 32; count--) {
			if (get_user(reg, u++) ||
			    put_user(reg, &reg_window[pos++]))
	if (pos < 32 * sizeof(u32)) {
		if (regwindow32_get(target, regs, uregs))
			return -EFAULT;
		}
	}
	while (count > 0) {
		unsigned long psr;

		if (kbuf)
			reg = *k++;
		else if (get_user(reg, u++))
		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
					 uregs,
					 16 * sizeof(u32), 32 * sizeof(u32));
		if (ret)
			return ret;
		if (regwindow32_set(target, regs, uregs))
			return -EFAULT;

		switch (pos) {
		case 32: /* PSR */
			psr = regs->psr;
			psr &= ~(PSR_ICC | PSR_SYSCALL);
			psr |= (reg & (PSR_ICC | PSR_SYSCALL));
			regs->psr = psr;
			break;
		case 33: /* PC */
			regs->pc = reg;
			break;
		case 34: /* NPC */
			regs->npc = reg;
			break;
		case 35: /* Y */
			regs->y = reg;
			break;
		case 36: /* WIM */
		case 37: /* TBR */
			break;
		default:
			goto finish;
		if (!count)
			return 0;
	}

		pos++;
		count--;
	}
finish:
	pos *= sizeof(reg);
	count *= sizeof(reg);

	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &psr,
				 32 * sizeof(u32), 33 * sizeof(u32));
	if (ret)
		return ret;
	regs->psr = (regs->psr & ~(PSR_ICC | PSR_SYSCALL)) |
		    (psr & (PSR_ICC | PSR_SYSCALL));
	if (!count)
		return 0;
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &regs->pc,
				 33 * sizeof(u32), 34 * sizeof(u32));
	if (ret || !count)
		return ret;
	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
				 &regs->y,
				 34 * sizeof(u32), 35 * sizeof(u32));
	if (ret || !count)
		return ret;
	return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
					 38 * sizeof(reg), -1);
					 35 * sizeof(u32), 38 * sizeof(u32));
}

static int fpregs32_get(struct task_struct *target,
+3 −14
Original line number Diff line number Diff line
@@ -572,19 +572,13 @@ static int genregs32_get(struct task_struct *target,
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      &reg_window[pos],
						      &reg_window[pos++],
						      &reg, sizeof(reg),
						      FOLL_FORCE)
				    != sizeof(reg))
					return -EFAULT;
				if (access_process_vm(target,
						      (unsigned long) u,
						      &reg, sizeof(reg),
						      FOLL_FORCE | FOLL_WRITE)
				    != sizeof(reg))
				if (put_user(reg, u++))
					return -EFAULT;
				pos++;
				u++;
			}
		}
	}
@@ -684,12 +678,7 @@ static int genregs32_set(struct task_struct *target,
			}
		} else {
			for (; count > 0 && pos < 32; count--) {
				if (access_process_vm(target,
						      (unsigned long)
						      u,
						      &reg, sizeof(reg),
						      FOLL_FORCE)
				    != sizeof(reg))
				if (get_user(reg, u++))
					return -EFAULT;
				if (access_process_vm(target,
						      (unsigned long)