aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/ptrace_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/ptrace_32.c')
-rw-r--r--arch/sh/kernel/ptrace_32.c83
1 files changed, 57 insertions, 26 deletions
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 9be35f348093..7759a9a93211 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 *
@@ -17,7 +17,6 @@
17#include <linux/errno.h> 17#include <linux/errno.h>
18#include <linux/ptrace.h> 18#include <linux/ptrace.h>
19#include <linux/user.h> 19#include <linux/user.h>
20#include <linux/slab.h>
21#include <linux/security.h> 20#include <linux/security.h>
22#include <linux/signal.h> 21#include <linux/signal.h>
23#include <linux/io.h> 22#include <linux/io.h>
@@ -26,6 +25,7 @@
26#include <linux/tracehook.h> 25#include <linux/tracehook.h>
27#include <linux/elf.h> 26#include <linux/elf.h>
28#include <linux/regset.h> 27#include <linux/regset.h>
28#include <linux/hw_breakpoint.h>
29#include <asm/uaccess.h> 29#include <asm/uaccess.h>
30#include <asm/pgtable.h> 30#include <asm/pgtable.h>
31#include <asm/system.h> 31#include <asm/system.h>
@@ -63,33 +63,64 @@ static inline int put_stack_long(struct task_struct *task, int offset,
63 return 0; 63 return 0;
64} 64}
65 65
66void user_enable_single_step(struct task_struct *child) 66void ptrace_triggered(struct perf_event *bp, int nmi,
67 struct perf_sample_data *data, struct pt_regs *regs)
67{ 68{
68 /* Next scheduling will set up UBC */ 69 struct perf_event_attr attr;
69 if (child->thread.ubc_pc == 0) 70
70 ubc_usercnt += 1; 71 /*
72 * Disable the breakpoint request here since ptrace has defined a
73 * one-shot behaviour for breakpoint exceptions.
74 */
75 attr = bp->attr;
76 attr.disabled = true;
77 modify_user_hw_breakpoint(bp, &attr);
78}
79
80static int set_single_step(struct task_struct *tsk, unsigned long addr)
81{
82 struct thread_struct *thread = &tsk->thread;
83 struct perf_event *bp;
84 struct perf_event_attr attr;
85
86 bp = thread->ptrace_bps[0];
87 if (!bp) {
88 hw_breakpoint_init(&attr);
89
90 attr.bp_addr = addr;
91 attr.bp_len = HW_BREAKPOINT_LEN_2;
92 attr.bp_type = HW_BREAKPOINT_R;
93
94 bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
95 if (IS_ERR(bp))
96 return PTR_ERR(bp);
97
98 thread->ptrace_bps[0] = bp;
99 } else {
100 int err;
101
102 attr = bp->attr;
103 attr.bp_addr = addr;
104 err = modify_user_hw_breakpoint(bp, &attr);
105 if (unlikely(err))
106 return err;
107 }
108
109 return 0;
110}
71 111
72 child->thread.ubc_pc = get_stack_long(child, 112void user_enable_single_step(struct task_struct *child)
73 offsetof(struct pt_regs, pc)); 113{
114 unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc));
74 115
75 set_tsk_thread_flag(child, TIF_SINGLESTEP); 116 set_tsk_thread_flag(child, TIF_SINGLESTEP);
117
118 set_single_step(child, pc);
76} 119}
77 120
78void user_disable_single_step(struct task_struct *child) 121void user_disable_single_step(struct task_struct *child)
79{ 122{
80 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 123 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
81
82 /*
83 * Ensure the UBC is not programmed at the next context switch.
84 *
85 * Normally this is not needed but there are sequences such as
86 * singlestep, signal delivery, and continue that leave the
87 * ubc_pc non-zero leading to spurious SIGTRAPs.
88 */
89 if (child->thread.ubc_pc != 0) {
90 ubc_usercnt -= 1;
91 child->thread.ubc_pc = 0;
92 }
93} 124}
94 125
95/* 126/*
@@ -163,10 +194,10 @@ int fpregs_get(struct task_struct *target,
163 194
164 if ((boot_cpu_data.flags & CPU_HAS_FPU)) 195 if ((boot_cpu_data.flags & CPU_HAS_FPU))
165 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 196 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
166 &target->thread.fpu.hard, 0, -1); 197 &target->thread.xstate->hardfpu, 0, -1);
167 198
168 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 199 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
169 &target->thread.fpu.soft, 0, -1); 200 &target->thread.xstate->softfpu, 0, -1);
170} 201}
171 202
172static int fpregs_set(struct task_struct *target, 203static int fpregs_set(struct task_struct *target,
@@ -184,10 +215,10 @@ static int fpregs_set(struct task_struct *target,
184 215
185 if ((boot_cpu_data.flags & CPU_HAS_FPU)) 216 if ((boot_cpu_data.flags & CPU_HAS_FPU))
186 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 217 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
187 &target->thread.fpu.hard, 0, -1); 218 &target->thread.xstate->hardfpu, 0, -1);
188 219
189 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 220 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
190 &target->thread.fpu.soft, 0, -1); 221 &target->thread.xstate->softfpu, 0, -1);
191} 222}
192 223
193static int fpregs_active(struct task_struct *target, 224static int fpregs_active(struct task_struct *target,
@@ -333,7 +364,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
333 else 364 else
334 tmp = 0; 365 tmp = 0;
335 } else 366 } else
336 tmp = ((long *)&child->thread.fpu) 367 tmp = ((long *)child->thread.xstate)
337 [(addr - (long)&dummy->fpu) >> 2]; 368 [(addr - (long)&dummy->fpu) >> 2];
338 } else if (addr == (long) &dummy->u_fpvalid) 369 } else if (addr == (long) &dummy->u_fpvalid)
339 tmp = !!tsk_used_math(child); 370 tmp = !!tsk_used_math(child);
@@ -362,7 +393,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
362 else if (addr >= (long) &dummy->fpu && 393 else if (addr >= (long) &dummy->fpu &&
363 addr < (long) &dummy->u_fpvalid) { 394 addr < (long) &dummy->u_fpvalid) {
364 set_stopped_child_used_math(child); 395 set_stopped_child_used_math(child);
365 ((long *)&child->thread.fpu) 396 ((long *)child->thread.xstate)
366 [(addr - (long)&dummy->fpu) >> 2] = data; 397 [(addr - (long)&dummy->fpu) >> 2] = data;
367 ret = 0; 398 ret = 0;
368 } else if (addr == (long) &dummy->u_fpvalid) { 399 } else if (addr == (long) &dummy->u_fpvalid) {