aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/ptrace.h6
-rw-r--r--arch/sh/kernel/hw_breakpoint.c15
-rw-r--r--arch/sh/kernel/ptrace_32.c53
3 files changed, 71 insertions, 3 deletions
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 1dc12cb44a2d..201d11ef211f 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -124,6 +124,12 @@ struct task_struct;
124extern void user_enable_single_step(struct task_struct *); 124extern void user_enable_single_step(struct task_struct *);
125extern void user_disable_single_step(struct task_struct *); 125extern void user_disable_single_step(struct task_struct *);
126 126
127struct perf_event;
128struct perf_sample_data;
129
130extern void ptrace_triggered(struct perf_event *bp, int nmi,
131 struct perf_sample_data *data, struct pt_regs *regs);
132
127#define task_pt_regs(task) \ 133#define task_pt_regs(task) \
128 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1) 134 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
129 135
diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c
index 022d8ed66bd6..c515a3ecf562 100644
--- a/arch/sh/kernel/hw_breakpoint.c
+++ b/arch/sh/kernel/hw_breakpoint.c
@@ -20,6 +20,7 @@
20#include <linux/io.h> 20#include <linux/io.h>
21#include <asm/hw_breakpoint.h> 21#include <asm/hw_breakpoint.h>
22#include <asm/mmu_context.h> 22#include <asm/mmu_context.h>
23#include <asm/ptrace.h>
23 24
24struct ubc_context { 25struct ubc_context {
25 unsigned long pc; 26 unsigned long pc;
@@ -372,7 +373,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
372 rcu_read_unlock(); 373 rcu_read_unlock();
373 } 374 }
374 375
375 if (bp) { 376 if (bp && bp->overflow_handler != ptrace_triggered) {
376 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 377 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
377 378
378 __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR0); 379 __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)
387BUILD_TRAP_HANDLER(breakpoint) 388BUILD_TRAP_HANDLER(breakpoint)
388{ 389{
389 unsigned long ex = lookup_exception_vector(); 390 unsigned long ex = lookup_exception_vector();
391 siginfo_t info;
392 int err;
390 TRAP_HANDLER_DECL; 393 TRAP_HANDLER_DECL;
391 394
392 notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP); 395 err = notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP);
396 if (err == NOTIFY_STOP)
397 return;
398
399 /* Deliver the signal to userspace */
400 info.si_signo = SIGTRAP;
401 info.si_errno = 0;
402 info.si_code = TRAP_HWBKPT;
403 force_sig_info(SIGTRAP, &info, current);
393} 404}
394 405
395/* 406/*
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index bdb10446cbac..8e094c4c7bb4 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -2,7 +2,7 @@
2 * SuperH process tracing 2 * SuperH process tracing
3 * 3 *
4 * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka 4 * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
5 * Copyright (C) 2002 - 2008 Paul Mundt 5 * Copyright (C) 2002 - 2009 Paul Mundt
6 * 6 *
7 * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp> 7 * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
8 * 8 *
@@ -26,6 +26,7 @@
26#include <linux/tracehook.h> 26#include <linux/tracehook.h>
27#include <linux/elf.h> 27#include <linux/elf.h>
28#include <linux/regset.h> 28#include <linux/regset.h>
29#include <linux/hw_breakpoint.h>
29#include <asm/uaccess.h> 30#include <asm/uaccess.h>
30#include <asm/pgtable.h> 31#include <asm/pgtable.h>
31#include <asm/system.h> 32#include <asm/system.h>
@@ -63,9 +64,59 @@ static inline int put_stack_long(struct task_struct *task, int offset,
63 return 0; 64 return 0;
64} 65}
65 66
67void ptrace_triggered(struct perf_event *bp, int nmi,
68 struct perf_sample_data *data, struct pt_regs *regs)
69{
70 struct perf_event_attr attr;
71
72 /*
73 * Disable the breakpoint request here since ptrace has defined a
74 * one-shot behaviour for breakpoint exceptions.
75 */
76 attr = bp->attr;
77 attr.disabled = true;
78 modify_user_hw_breakpoint(bp, &attr);
79}
80
81static int set_single_step(struct task_struct *tsk, unsigned long addr)
82{
83 struct thread_struct *thread = &tsk->thread;
84 struct perf_event *bp;
85 struct perf_event_attr attr;
86
87 bp = thread->ptrace_bps[0];
88 if (!bp) {
89 hw_breakpoint_init(&attr);
90
91 attr.bp_addr = addr;
92 attr.bp_len = HW_BREAKPOINT_LEN_2;
93 attr.bp_type = HW_BREAKPOINT_R;
94
95 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
96 if (IS_ERR(bp))
97 return PTR_ERR(bp);
98
99 thread->ptrace_bps[0] = bp;
100 } else {
101 int err;
102
103 attr = bp->attr;
104 attr.bp_addr = addr;
105 err = modify_user_hw_breakpoint(bp, &attr);
106 if (unlikely(err))
107 return err;
108 }
109
110 return 0;
111}
112
66void user_enable_single_step(struct task_struct *child) 113void user_enable_single_step(struct task_struct *child)
67{ 114{
115 unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc));
116
68 set_tsk_thread_flag(child, TIF_SINGLESTEP); 117 set_tsk_thread_flag(child, TIF_SINGLESTEP);
118
119 set_single_step(child, pc);
69} 120}
70 121
71void user_disable_single_step(struct task_struct *child) 122void user_disable_single_step(struct task_struct *child)