mirror of https://gitee.com/openkylin/linux.git
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: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
2264873540
commit
34d0b5af50
|
@ -124,6 +124,12 @@ struct task_struct;
|
||||||
extern void user_enable_single_step(struct task_struct *);
|
extern void user_enable_single_step(struct task_struct *);
|
||||||
extern void user_disable_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) \
|
#define task_pt_regs(task) \
|
||||||
((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
|
((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <asm/hw_breakpoint.h>
|
#include <asm/hw_breakpoint.h>
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
struct ubc_context {
|
struct ubc_context {
|
||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
|
@ -372,7 +373,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bp) {
|
if (bp && bp->overflow_handler != ptrace_triggered) {
|
||||||
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||||
|
|
||||||
__raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0);
|
__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)
|
BUILD_TRAP_HANDLER(breakpoint)
|
||||||
{
|
{
|
||||||
unsigned long ex = lookup_exception_vector();
|
unsigned long ex = lookup_exception_vector();
|
||||||
|
siginfo_t info;
|
||||||
|
int err;
|
||||||
TRAP_HANDLER_DECL;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SuperH process tracing
|
* SuperH process tracing
|
||||||
*
|
*
|
||||||
* Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
|
* 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>
|
* Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
|
||||||
*
|
*
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/tracehook.h>
|
#include <linux/tracehook.h>
|
||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
#include <linux/regset.h>
|
#include <linux/regset.h>
|
||||||
|
#include <linux/hw_breakpoint.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
@ -63,9 +64,59 @@ static inline int put_stack_long(struct task_struct *task, int offset,
|
||||||
return 0;
|
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)
|
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_tsk_thread_flag(child, TIF_SINGLESTEP);
|
||||||
|
|
||||||
|
set_single_step(child, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void user_disable_single_step(struct task_struct *child)
|
void user_disable_single_step(struct task_struct *child)
|
||||||
|
|
Loading…
Reference in New Issue