Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9afe33ad authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds
Browse files

ptrace/x86: introduce ptrace_register_breakpoint()



No functional changes, preparation.

Extract the "register breakpoint" code from ptrace_get_debugreg() into
the new/generic helper, ptrace_register_breakpoint().  It will have more
users.

The patch also adds another simple helper, ptrace_fill_bp_fields(), to
factor out the arch_bp_generic_fields() logic in register/modify.

Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jan Kratochvil <jan.kratochvil@redhat.com>
Cc: Michael Neuling <mikey@neuling.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Prasad <prasad@linux.vnet.ibm.com>
Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 29a55513
Loading
Loading
Loading
Loading
+50 −36
Original line number Original line Diff line number Diff line
@@ -601,22 +601,48 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[])
	return dr7;
	return dr7;
}
}


static int
static int ptrace_fill_bp_fields(struct perf_event_attr *attr,
ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
					int len, int type, bool disabled)
			 struct task_struct *tsk, int disabled)
{
	int err, bp_len, bp_type;

	err = arch_bp_generic_fields(len, type, &bp_len, &bp_type);
	if (!err) {
		attr->bp_len = bp_len;
		attr->bp_type = bp_type;
		attr->disabled = disabled;
	}

	return err;
}

static struct perf_event *
ptrace_register_breakpoint(struct task_struct *tsk, int len, int type,
				unsigned long addr, bool disabled)
{
{
	int err;
	int gen_len, gen_type;
	struct perf_event_attr attr;
	struct perf_event_attr attr;
	int err;


	err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
	ptrace_breakpoint_init(&attr);
	attr.bp_addr = addr;

	err = ptrace_fill_bp_fields(&attr, len, type, disabled);
	if (err)
	if (err)
		return err;
		return ERR_PTR(err);


	attr = bp->attr;
	return register_user_hw_breakpoint(&attr, ptrace_triggered,
	attr.bp_len = gen_len;
						 NULL, tsk);
	attr.bp_type = gen_type;
}
	attr.disabled = disabled;

static int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
					int disabled)
{
	struct perf_event_attr attr = bp->attr;
	int err;

	err = ptrace_fill_bp_fields(&attr, len, type, disabled);
	if (err)
		return err;


	return modify_user_hw_breakpoint(bp, &attr);
	return modify_user_hw_breakpoint(bp, &attr);
}
}
@@ -653,7 +679,7 @@ static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
			break;
			break;
		}
		}


		rc = ptrace_modify_breakpoint(bp, len, type, tsk, disabled);
		rc = ptrace_modify_breakpoint(bp, len, type, disabled);
		if (rc)
		if (rc)
			break;
			break;
	}
	}
@@ -693,26 +719,14 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
				      unsigned long addr)
				      unsigned long addr)
{
{
	struct perf_event *bp;
	struct thread_struct *t = &tsk->thread;
	struct thread_struct *t = &tsk->thread;
	struct perf_event_attr attr;
	struct perf_event *bp = t->ptrace_bps[nr];
	int err = 0;
	int err = 0;


	if (!t->ptrace_bps[nr]) {
	if (!bp) {
		ptrace_breakpoint_init(&attr);
		/*
		 * Put stub len and type to register (reserve) an inactive but
		 * correct bp
		 */
		attr.bp_addr = addr;
		attr.bp_len = HW_BREAKPOINT_LEN_1;
		attr.bp_type = HW_BREAKPOINT_W;
		attr.disabled = 1;

		bp = register_user_hw_breakpoint(&attr, ptrace_triggered,
						 NULL, tsk);

		/*
		/*
		 * Put stub len and type to create an inactive but correct bp.
		 *
		 * CHECKME: the previous code returned -EIO if the addr wasn't
		 * CHECKME: the previous code returned -EIO if the addr wasn't
		 * a valid task virtual addr. The new one will return -EINVAL in
		 * a valid task virtual addr. The new one will return -EINVAL in
		 *  this case.
		 *  this case.
@@ -721,20 +735,20 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
		 * writing for the user. And anyway this is the previous
		 * writing for the user. And anyway this is the previous
		 * behaviour.
		 * behaviour.
		 */
		 */
		if (IS_ERR(bp)) {
		bp = ptrace_register_breakpoint(tsk,
				X86_BREAKPOINT_LEN_1, X86_BREAKPOINT_WRITE,
				addr, true);
		if (IS_ERR(bp))
			err = PTR_ERR(bp);
			err = PTR_ERR(bp);
			goto out;
		else
		}

			t->ptrace_bps[nr] = bp;
			t->ptrace_bps[nr] = bp;
	} else {
	} else {
		bp = t->ptrace_bps[nr];
		struct perf_event_attr attr = bp->attr;


		attr = bp->attr;
		attr.bp_addr = addr;
		attr.bp_addr = addr;
		err = modify_user_hw_breakpoint(bp, &attr);
		err = modify_user_hw_breakpoint(bp, &attr);
	}
	}
out:

	return err;
	return err;
}
}