Loading arch/sh/include/asm/ptrace.h +6 −0 Original line number Diff line number Diff line Loading @@ -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) Loading arch/sh/kernel/hw_breakpoint.c +13 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } /* Loading arch/sh/kernel/ptrace_32.c +52 −1 Original line number Diff line number Diff line Loading @@ -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> * Loading @@ -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> Loading Loading @@ -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) Loading Loading
arch/sh/include/asm/ptrace.h +6 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
arch/sh/kernel/hw_breakpoint.c +13 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } /* Loading
arch/sh/kernel/ptrace_32.c +52 −1 Original line number Diff line number Diff line Loading @@ -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> * Loading @@ -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> Loading Loading @@ -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) Loading