aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-09-12 06:52:36 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-09-12 06:52:36 -0400
commit934135c19d8a1be435bae75aefc09b8ae1698b16 (patch)
tree825be606c643ed792a2973263cade41d05171cde /arch/sh/kernel
parent09558748464a9afafe2848a3ad4cfd509c9b0fb6 (diff)
sh: ptrace: Introduce user_regset interface for gp regs.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/ptrace_32.c116
1 files changed, 99 insertions, 17 deletions
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 84bf3420597c..5e3ba10255cd 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -1,12 +1,14 @@
1/* 1/*
2 * linux/arch/sh/kernel/ptrace.c 2 * SuperH process tracing
3 * 3 *
4 * Original x86 implementation: 4 * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
5 * By Ross Biro 1/23/92 5 * Copyright (C) 2002 - 2008 Paul Mundt
6 * edited by Linus Torvalds
7 * 6 *
8 * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka 7 * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
9 * Audit support: Yuichi Nakamura <ynakam@hitachisoft.jp> 8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file "COPYING" in the main directory of this archive
11 * for more details.
10 */ 12 */
11#include <linux/kernel.h> 13#include <linux/kernel.h>
12#include <linux/sched.h> 14#include <linux/sched.h>
@@ -22,6 +24,8 @@
22#include <linux/audit.h> 24#include <linux/audit.h>
23#include <linux/seccomp.h> 25#include <linux/seccomp.h>
24#include <linux/tracehook.h> 26#include <linux/tracehook.h>
27#include <linux/elf.h>
28#include <linux/regset.h>
25#include <asm/uaccess.h> 29#include <asm/uaccess.h>
26#include <asm/pgtable.h> 30#include <asm/pgtable.h>
27#include <asm/system.h> 31#include <asm/system.h>
@@ -30,11 +34,6 @@
30#include <asm/syscalls.h> 34#include <asm/syscalls.h>
31 35
32/* 36/*
33 * does not yet catch signals sent when the child dies.
34 * in exit.c or in signal.c.
35 */
36
37/*
38 * This routine will get a word off of the process kernel stack. 37 * This routine will get a word off of the process kernel stack.
39 */ 38 */
40static inline int get_stack_long(struct task_struct *task, int offset) 39static inline int get_stack_long(struct task_struct *task, int offset)
@@ -62,16 +61,12 @@ static inline int put_stack_long(struct task_struct *task, int offset,
62 61
63void user_enable_single_step(struct task_struct *child) 62void user_enable_single_step(struct task_struct *child)
64{ 63{
65 struct pt_regs *regs = task_pt_regs(child);
66 long pc;
67
68 pc = get_stack_long(child, (long)&regs->pc);
69
70 /* Next scheduling will set up UBC */ 64 /* Next scheduling will set up UBC */
71 if (child->thread.ubc_pc == 0) 65 if (child->thread.ubc_pc == 0)
72 ubc_usercnt += 1; 66 ubc_usercnt += 1;
73 67
74 child->thread.ubc_pc = pc; 68 child->thread.ubc_pc = get_stack_long(child,
69 offsetof(struct pt_regs, pc));
75 70
76 set_tsk_thread_flag(child, TIF_SINGLESTEP); 71 set_tsk_thread_flag(child, TIF_SINGLESTEP);
77} 72}
@@ -103,6 +98,83 @@ void ptrace_disable(struct task_struct *child)
103 user_disable_single_step(child); 98 user_disable_single_step(child);
104} 99}
105 100
101static int genregs_get(struct task_struct *target,
102 const struct user_regset *regset,
103 unsigned int pos, unsigned int count,
104 void *kbuf, void __user *ubuf)
105{
106 const struct pt_regs *regs = task_pt_regs(target);
107 int ret;
108
109 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
110 regs->regs,
111 0, 16 * sizeof(unsigned long));
112 if (!ret)
113 /* PC, PR, SR, GBR, MACH, MACL, TRA */
114 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
115 &regs->pc,
116 offsetof(struct pt_regs, pc),
117 sizeof(struct pt_regs));
118 if (!ret)
119 ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
120 sizeof(struct pt_regs), -1);
121
122 return ret;
123}
124
125static int genregs_set(struct task_struct *target,
126 const struct user_regset *regset,
127 unsigned int pos, unsigned int count,
128 const void *kbuf, const void __user *ubuf)
129{
130 struct pt_regs *regs = task_pt_regs(target);
131 int ret;
132
133 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
134 regs->regs,
135 0, 16 * sizeof(unsigned long));
136 if (!ret && count > 0)
137 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
138 &regs->pc,
139 offsetof(struct pt_regs, pc),
140 sizeof(struct pt_regs));
141 if (!ret)
142 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
143 sizeof(struct pt_regs), -1);
144
145 return ret;
146}
147
148/*
149 * These are our native regset flavours.
150 */
151enum sh_regset {
152 REGSET_GENERAL,
153};
154
155static const struct user_regset sh_regsets[] = {
156 /*
157 * Format is:
158 * R0 --> R15
159 * PC, PR, SR, GBR, MACH, MACL, TRA
160 */
161 [REGSET_GENERAL] = {
162 .core_note_type = NT_PRSTATUS,
163 .n = ELF_NGREG,
164 .size = sizeof(long),
165 .align = sizeof(long),
166 .get = genregs_get,
167 .set = genregs_set,
168 },
169};
170
171static const struct user_regset_view user_sh_native_view = {
172 .name = "sh",
173 .e_machine = EM_SH,
174 .regsets = sh_regsets,
175 .n = ARRAY_SIZE(sh_regsets),
176};
177
106long arch_ptrace(struct task_struct *child, long request, long addr, long data) 178long arch_ptrace(struct task_struct *child, long request, long addr, long data)
107{ 179{
108 struct user * dummy = NULL; 180 struct user * dummy = NULL;
@@ -159,6 +231,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
159 } 231 }
160 break; 232 break;
161 233
234 case PTRACE_GETREGS:
235 return copy_regset_to_user(child, &user_sh_native_view,
236 REGSET_GENERAL,
237 0, sizeof(struct pt_regs),
238 (void __user *)data);
239 case PTRACE_SETREGS:
240 return copy_regset_from_user(child, &user_sh_native_view,
241 REGSET_GENERAL,
242 0, sizeof(struct pt_regs),
243 (const void __user *)data);
162#ifdef CONFIG_SH_DSP 244#ifdef CONFIG_SH_DSP
163 case PTRACE_GETDSPREGS: { 245 case PTRACE_GETDSPREGS: {
164 unsigned long dp; 246 unsigned long dp;