aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-07-30 06:09:31 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-08-01 15:39:33 -0400
commitc459dbf294b4a3d70490a468a7ca3907fb2c2f57 (patch)
treec78866944d8e03247b6d5072987cd7f7c558caef
parentc4637d475170ca0d99973efd07df727012db6cd1 (diff)
sh: ptrace single stepping cleanups.
This converts the single stepping done by sh/sh64 ptrace implementations to use the generic user_enable/disable_single_step(), and subsequently rips out a lot of ptrace request cases that are now handled generically. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/include/asm/ptrace.h9
-rw-r--r--arch/sh/kernel/ptrace_32.c93
-rw-r--r--arch/sh/kernel/ptrace_64.c77
3 files changed, 39 insertions, 140 deletions
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 643ab5a7cf3b..b86aeabba61a 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -104,6 +104,15 @@ struct pt_dspregs {
104 104
105extern void show_regs(struct pt_regs *); 105extern void show_regs(struct pt_regs *);
106 106
107/*
108 * These are defined as per linux/ptrace.h.
109 */
110struct task_struct;
111
112#define arch_has_single_step() (1)
113extern void user_enable_single_step(struct task_struct *);
114extern void user_disable_single_step(struct task_struct *);
115
107#ifdef CONFIG_SH_DSP 116#ifdef CONFIG_SH_DSP
108#define task_pt_regs(task) \ 117#define task_pt_regs(task) \
109 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \ 118 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index e9bd4b2aa9c2..ff66f97c564d 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -58,7 +58,23 @@ static inline int put_stack_long(struct task_struct *task, int offset,
58 return 0; 58 return 0;
59} 59}
60 60
61static void ptrace_disable_singlestep(struct task_struct *child) 61void user_enable_single_step(struct task_struct *child)
62{
63 struct pt_regs *regs = task_pt_regs(child);
64 long pc;
65
66 pc = get_stack_long(child, (long)&regs->pc);
67
68 /* Next scheduling will set up UBC */
69 if (child->thread.ubc_pc == 0)
70 ubc_usercnt += 1;
71
72 child->thread.ubc_pc = pc;
73
74 set_tsk_thread_flag(child, TIF_SINGLESTEP);
75}
76
77void user_disable_single_step(struct task_struct *child)
62{ 78{
63 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 79 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
64 80
@@ -82,7 +98,7 @@ static void ptrace_disable_singlestep(struct task_struct *child)
82 */ 98 */
83void ptrace_disable(struct task_struct *child) 99void ptrace_disable(struct task_struct *child)
84{ 100{
85 ptrace_disable_singlestep(child); 101 user_disable_single_step(child);
86} 102}
87 103
88long arch_ptrace(struct task_struct *child, long request, long addr, long data) 104long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -91,12 +107,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
91 int ret; 107 int ret;
92 108
93 switch (request) { 109 switch (request) {
94 /* when I and D space are separate, these will need to be fixed. */
95 case PTRACE_PEEKTEXT: /* read word at location addr. */
96 case PTRACE_PEEKDATA:
97 ret = generic_ptrace_peekdata(child, addr, data);
98 break;
99
100 /* read the word at location addr in the USER area. */ 110 /* read the word at location addr in the USER area. */
101 case PTRACE_PEEKUSR: { 111 case PTRACE_PEEKUSR: {
102 unsigned long tmp; 112 unsigned long tmp;
@@ -126,12 +136,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
126 break; 136 break;
127 } 137 }
128 138
129 /* when I and D space are separate, this will have to be fixed. */
130 case PTRACE_POKETEXT: /* write the word at location addr. */
131 case PTRACE_POKEDATA:
132 ret = generic_ptrace_pokedata(child, addr, data);
133 break;
134
135 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 139 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
136 ret = -EIO; 140 ret = -EIO;
137 if ((addr & 3) || addr < 0 || 141 if ((addr & 3) || addr < 0 ||
@@ -152,67 +156,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
152 } 156 }
153 break; 157 break;
154 158
155 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
156 case PTRACE_CONT: { /* restart after signal. */
157 ret = -EIO;
158 if (!valid_signal(data))
159 break;
160 if (request == PTRACE_SYSCALL)
161 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
162 else
163 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
164
165 ptrace_disable_singlestep(child);
166
167 child->exit_code = data;
168 wake_up_process(child);
169 ret = 0;
170 break;
171 }
172
173/*
174 * make the child exit. Best I can do is send it a sigkill.
175 * perhaps it should be put in the status that it wants to
176 * exit.
177 */
178 case PTRACE_KILL: {
179 ret = 0;
180 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
181 break;
182 ptrace_disable_singlestep(child);
183 child->exit_code = SIGKILL;
184 wake_up_process(child);
185 break;
186 }
187
188 case PTRACE_SINGLESTEP: { /* set the trap flag. */
189 long pc;
190 struct pt_regs *regs = NULL;
191
192 ret = -EIO;
193 if (!valid_signal(data))
194 break;
195 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
196 if ((child->ptrace & PT_DTRACE) == 0) {
197 /* Spurious delayed TF traps may occur */
198 child->ptrace |= PT_DTRACE;
199 }
200
201 pc = get_stack_long(child, (long)&regs->pc);
202
203 /* Next scheduling will set up UBC */
204 if (child->thread.ubc_pc == 0)
205 ubc_usercnt += 1;
206 child->thread.ubc_pc = pc;
207
208 set_tsk_thread_flag(child, TIF_SINGLESTEP);
209 child->exit_code = data;
210 /* give it a chance to run. */
211 wake_up_process(child);
212 ret = 0;
213 break;
214 }
215
216#ifdef CONFIG_SH_DSP 159#ifdef CONFIG_SH_DSP
217 case PTRACE_GETDSPREGS: { 160 case PTRACE_GETDSPREGS: {
218 unsigned long dp; 161 unsigned long dp;
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c
index 7d8776260953..108f3962e39a 100644
--- a/arch/sh/kernel/ptrace_64.c
+++ b/arch/sh/kernel/ptrace_64.c
@@ -121,18 +121,23 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data)
121 return 0; 121 return 0;
122} 122}
123 123
124void user_enable_single_step(struct task_struct *child)
125{
126 struct pt_regs *regs = child->thread.uregs;
127
128 regs->sr |= SR_SSTEP; /* auto-resetting upon exception */
129}
130
131void user_disable_single_step(struct task_struct *child)
132{
133 regs->sr &= ~SR_SSTEP;
134}
124 135
125long arch_ptrace(struct task_struct *child, long request, long addr, long data) 136long arch_ptrace(struct task_struct *child, long request, long addr, long data)
126{ 137{
127 int ret; 138 int ret;
128 139
129 switch (request) { 140 switch (request) {
130 /* when I and D space are separate, these will need to be fixed. */
131 case PTRACE_PEEKTEXT: /* read word at location addr. */
132 case PTRACE_PEEKDATA:
133 ret = generic_ptrace_peekdata(child, addr, data);
134 break;
135
136 /* read the word at location addr in the USER area. */ 141 /* read the word at location addr in the USER area. */
137 case PTRACE_PEEKUSR: { 142 case PTRACE_PEEKUSR: {
138 unsigned long tmp; 143 unsigned long tmp;
@@ -155,12 +160,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
155 break; 160 break;
156 } 161 }
157 162
158 /* when I and D space are separate, this will have to be fixed. */
159 case PTRACE_POKETEXT: /* write the word at location addr. */
160 case PTRACE_POKEDATA:
161 ret = generic_ptrace_pokedata(child, addr, data);
162 break;
163
164 case PTRACE_POKEUSR: 163 case PTRACE_POKEUSR:
165 /* write the word at location addr in the USER area. We must 164 /* write the word at location addr in the USER area. We must
166 disallow any changes to certain SR bits or u_fpvalid, since 165 disallow any changes to certain SR bits or u_fpvalid, since
@@ -192,58 +191,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
192 } 191 }
193 break; 192 break;
194 193
195 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
196 case PTRACE_CONT: { /* restart after signal. */
197 ret = -EIO;
198 if (!valid_signal(data))
199 break;
200 if (request == PTRACE_SYSCALL)
201 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
202 else
203 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
204 child->exit_code = data;
205 wake_up_process(child);
206 ret = 0;
207 break;
208 }
209
210/*
211 * make the child exit. Best I can do is send it a sigkill.
212 * perhaps it should be put in the status that it wants to
213 * exit.
214 */
215 case PTRACE_KILL: {
216 ret = 0;
217 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
218 break;
219 child->exit_code = SIGKILL;
220 wake_up_process(child);
221 break;
222 }
223
224 case PTRACE_SINGLESTEP: { /* set the trap flag. */
225 struct pt_regs *regs;
226
227 ret = -EIO;
228 if (!valid_signal(data))
229 break;
230 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
231 if ((child->ptrace & PT_DTRACE) == 0) {
232 /* Spurious delayed TF traps may occur */
233 child->ptrace |= PT_DTRACE;
234 }
235
236 regs = child->thread.uregs;
237
238 regs->sr |= SR_SSTEP; /* auto-resetting upon exception */
239
240 child->exit_code = data;
241 /* give it a chance to run. */
242 wake_up_process(child);
243 ret = 0;
244 break;
245 }
246
247 default: 194 default:
248 ret = ptrace_request(child, request, addr, data); 195 ret = ptrace_request(child, request, addr, data);
249 break; 196 break;
@@ -341,5 +288,5 @@ asmlinkage void do_software_break_point(unsigned long long vec,
341 */ 288 */
342void ptrace_disable(struct task_struct *child) 289void ptrace_disable(struct task_struct *child)
343{ 290{
344 /* nothing to do.. */ 291 user_disable_single_step(child);
345} 292}