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

Commit 34d0b5af authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: Convert ptrace to hw_breakpoint API.



This is the initial step for converting singlestep handling via ptrace
over to hw_breakpoints.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 22648735
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -124,6 +124,12 @@ struct task_struct;
extern void user_enable_single_step(struct task_struct *);
extern void user_disable_single_step(struct task_struct *);

struct perf_event;
struct perf_sample_data;

extern void ptrace_triggered(struct perf_event *bp, int nmi,
		      struct perf_sample_data *data, struct pt_regs *regs);

#define task_pt_regs(task) \
	((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)

+13 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <asm/hw_breakpoint.h>
#include <asm/mmu_context.h>
#include <asm/ptrace.h>

struct ubc_context {
	unsigned long pc;
@@ -372,7 +373,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
		rcu_read_unlock();
	}

	if (bp) {
	if (bp && bp->overflow_handler != ptrace_triggered) {
		struct arch_hw_breakpoint *info = counter_arch_bp(bp);

		__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0);
@@ -387,9 +388,19 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
BUILD_TRAP_HANDLER(breakpoint)
{
	unsigned long ex = lookup_exception_vector();
	siginfo_t info;
	int err;
	TRAP_HANDLER_DECL;

	notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP);
	err = notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP);
	if (err == NOTIFY_STOP)
		return;

	/* Deliver the signal to userspace */
	info.si_signo = SIGTRAP;
	info.si_errno = 0;
	info.si_code = TRAP_HWBKPT;
	force_sig_info(SIGTRAP, &info, current);
}

/*
+52 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
 * SuperH process tracing
 *
 * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
 * Copyright (C) 2002 - 2008  Paul Mundt
 * Copyright (C) 2002 - 2009  Paul Mundt
 *
 * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
 *
@@ -26,6 +26,7 @@
#include <linux/tracehook.h>
#include <linux/elf.h>
#include <linux/regset.h>
#include <linux/hw_breakpoint.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -63,9 +64,59 @@ static inline int put_stack_long(struct task_struct *task, int offset,
	return 0;
}

void ptrace_triggered(struct perf_event *bp, int nmi,
		      struct perf_sample_data *data, struct pt_regs *regs)
{
	struct perf_event_attr attr;

	/*
	 * Disable the breakpoint request here since ptrace has defined a
	 * one-shot behaviour for breakpoint exceptions.
	 */
	attr = bp->attr;
	attr.disabled = true;
	modify_user_hw_breakpoint(bp, &attr);
}

static int set_single_step(struct task_struct *tsk, unsigned long addr)
{
	struct thread_struct *thread = &tsk->thread;
	struct perf_event *bp;
	struct perf_event_attr attr;

	bp = thread->ptrace_bps[0];
	if (!bp) {
		hw_breakpoint_init(&attr);

		attr.bp_addr = addr;
		attr.bp_len = HW_BREAKPOINT_LEN_2;
		attr.bp_type = HW_BREAKPOINT_R;

		bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
		if (IS_ERR(bp))
			return PTR_ERR(bp);

		thread->ptrace_bps[0] = bp;
	} else {
		int err;

		attr = bp->attr;
		attr.bp_addr = addr;
		err = modify_user_hw_breakpoint(bp, &attr);
		if (unlikely(err))
			return err;
	}

	return 0;
}

void user_enable_single_step(struct task_struct *child)
{
	unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc));

	set_tsk_thread_flag(child, TIF_SINGLESTEP);

	set_single_step(child, pc);
}

void user_disable_single_step(struct task_struct *child)