aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/ptrace.c')
-rw-r--r--arch/blackfin/kernel/ptrace.c215
1 files changed, 94 insertions, 121 deletions
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index bf1a51d8e608..140bf00e9974 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -46,7 +46,6 @@
46#include <asm/dma.h> 46#include <asm/dma.h>
47#include <asm/fixed_code.h> 47#include <asm/fixed_code.h>
48 48
49#define MAX_SHARED_LIBS 3
50#define TEXT_OFFSET 0 49#define TEXT_OFFSET 0
51/* 50/*
52 * does not yet catch signals sent when the child dies. 51 * does not yet catch signals sent when the child dies.
@@ -161,21 +160,32 @@ static inline int is_user_addr_valid(struct task_struct *child,
161 struct vm_list_struct *vml; 160 struct vm_list_struct *vml;
162 struct sram_list_struct *sraml; 161 struct sram_list_struct *sraml;
163 162
163 /* overflow */
164 if (start + len < start)
165 return -EIO;
166
164 for (vml = child->mm->context.vmlist; vml; vml = vml->next) 167 for (vml = child->mm->context.vmlist; vml; vml = vml->next)
165 if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end) 168 if (start >= vml->vma->vm_start && start + len < vml->vma->vm_end)
166 return 0; 169 return 0;
167 170
168 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next) 171 for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
169 if (start >= (unsigned long)sraml->addr 172 if (start >= (unsigned long)sraml->addr
170 && start + len <= (unsigned long)sraml->addr + sraml->length) 173 && start + len < (unsigned long)sraml->addr + sraml->length)
171 return 0; 174 return 0;
172 175
173 if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END) 176 if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
174 return 0; 177 return 0;
175 178
176 return -EIO; 179 return -EIO;
177} 180}
178 181
182void ptrace_enable(struct task_struct *child)
183{
184 unsigned long tmp;
185 tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
186 put_reg(child, PT_SYSCFG, tmp);
187}
188
179/* 189/*
180 * Called by kernel/ptrace.c when detaching.. 190 * Called by kernel/ptrace.c when detaching..
181 * 191 *
@@ -192,14 +202,12 @@ void ptrace_disable(struct task_struct *child)
192long arch_ptrace(struct task_struct *child, long request, long addr, long data) 202long arch_ptrace(struct task_struct *child, long request, long addr, long data)
193{ 203{
194 int ret; 204 int ret;
195 int add = 0;
196 unsigned long __user *datap = (unsigned long __user *)data; 205 unsigned long __user *datap = (unsigned long __user *)data;
197 206
198 switch (request) { 207 switch (request) {
199 /* when I and D space are separate, these will need to be fixed. */ 208 /* when I and D space are separate, these will need to be fixed. */
200 case PTRACE_PEEKDATA: 209 case PTRACE_PEEKDATA:
201 pr_debug("ptrace: PEEKDATA\n"); 210 pr_debug("ptrace: PEEKDATA\n");
202 add = MAX_SHARED_LIBS * 4; /* space between text and data */
203 /* fall through */ 211 /* fall through */
204 case PTRACE_PEEKTEXT: /* read word at location addr. */ 212 case PTRACE_PEEKTEXT: /* read word at location addr. */
205 { 213 {
@@ -207,40 +215,35 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
207 int copied; 215 int copied;
208 216
209 ret = -EIO; 217 ret = -EIO;
210 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add, 218 pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %ld\n", addr, sizeof(data));
211 sizeof(data)); 219 if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
212 if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
213 break; 220 break;
214 pr_debug("ptrace: user address is valid\n"); 221 pr_debug("ptrace: user address is valid\n");
215 222
216#if L1_CODE_LENGTH != 0 223 if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
217 if (addr + add >= L1_CODE_START 224 && addr + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
218 && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) { 225 safe_dma_memcpy (&tmp, (const void *)(addr), sizeof(tmp));
219 safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
220 copied = sizeof(tmp); 226 copied = sizeof(tmp);
221 } else 227
222#endif 228 } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
223#if L1_DATA_A_LENGTH != 0 229 && addr + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
224 if (addr + add >= L1_DATA_A_START 230 memcpy(&tmp, (const void *)(addr), sizeof(tmp));
225 && addr + add + sizeof(tmp) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
226 memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
227 copied = sizeof(tmp); 231 copied = sizeof(tmp);
228 } else 232
229#endif 233 } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
230#if L1_DATA_B_LENGTH != 0 234 && addr + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
231 if (addr + add >= L1_DATA_B_START 235 memcpy(&tmp, (const void *)(addr), sizeof(tmp));
232 && addr + add + sizeof(tmp) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
233 memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
234 copied = sizeof(tmp); 236 copied = sizeof(tmp);
235 } else 237
236#endif 238 } else if (addr >= FIXED_CODE_START
237 if (addr + add >= FIXED_CODE_START 239 && addr + sizeof(tmp) <= FIXED_CODE_END) {
238 && addr + add + sizeof(tmp) <= FIXED_CODE_END) { 240 memcpy(&tmp, (const void *)(addr), sizeof(tmp));
239 memcpy(&tmp, (const void *)(addr + add), sizeof(tmp));
240 copied = sizeof(tmp); 241 copied = sizeof(tmp);
242
241 } else 243 } else
242 copied = access_process_vm(child, addr + add, &tmp, 244 copied = access_process_vm(child, addr, &tmp,
243 sizeof(tmp), 0); 245 sizeof(tmp), 0);
246
244 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); 247 pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
245 if (copied != sizeof(tmp)) 248 if (copied != sizeof(tmp))
246 break; 249 break;
@@ -284,47 +287,43 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
284 287
285 /* when I and D space are separate, this will have to be fixed. */ 288 /* when I and D space are separate, this will have to be fixed. */
286 case PTRACE_POKEDATA: 289 case PTRACE_POKEDATA:
287 printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n"); 290 pr_debug("ptrace: PTRACE_PEEKDATA\n");
288 /* fall through */ 291 /* fall through */
289 case PTRACE_POKETEXT: /* write the word at location addr. */ 292 case PTRACE_POKETEXT: /* write the word at location addr. */
290 { 293 {
291 int copied; 294 int copied;
292 295
293 ret = -EIO; 296 ret = -EIO;
294 pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n", 297 pr_debug("ptrace: POKETEXT at addr 0x%08lx + %ld bytes %lx\n",
295 addr, add, sizeof(data), data); 298 addr, sizeof(data), data);
296 if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0) 299 if (is_user_addr_valid(child, addr, sizeof(data)) < 0)
297 break; 300 break;
298 pr_debug("ptrace: user address is valid\n"); 301 pr_debug("ptrace: user address is valid\n");
299 302
300#if L1_CODE_LENGTH != 0 303 if (L1_CODE_LENGTH != 0 && addr >= L1_CODE_START
301 if (addr + add >= L1_CODE_START 304 && addr + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
302 && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) { 305 safe_dma_memcpy ((void *)(addr), &data, sizeof(data));
303 safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
304 copied = sizeof(data); 306 copied = sizeof(data);
305 } else 307
306#endif 308 } else if (L1_DATA_A_LENGTH != 0 && addr >= L1_DATA_A_START
307#if L1_DATA_A_LENGTH != 0 309 && addr + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
308 if (addr + add >= L1_DATA_A_START 310 memcpy((void *)(addr), &data, sizeof(data));
309 && addr + add + sizeof(data) <= L1_DATA_A_START + L1_DATA_A_LENGTH) {
310 memcpy((void *)(addr + add), &data, sizeof(data));
311 copied = sizeof(data); 311 copied = sizeof(data);
312 } else 312
313#endif 313 } else if (L1_DATA_B_LENGTH != 0 && addr >= L1_DATA_B_START
314#if L1_DATA_B_LENGTH != 0 314 && addr + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
315 if (addr + add >= L1_DATA_B_START 315 memcpy((void *)(addr), &data, sizeof(data));
316 && addr + add + sizeof(data) <= L1_DATA_B_START + L1_DATA_B_LENGTH) {
317 memcpy((void *)(addr + add), &data, sizeof(data));
318 copied = sizeof(data); 316 copied = sizeof(data);
319 } else 317
320#endif 318 } else if (addr >= FIXED_CODE_START
321 if (addr + add >= FIXED_CODE_START 319 && addr + sizeof(data) <= FIXED_CODE_END) {
322 && addr + add + sizeof(data) <= FIXED_CODE_END) { 320 memcpy((void *)(addr), &data, sizeof(data));
323 memcpy((void *)(addr + add), &data, sizeof(data));
324 copied = sizeof(data); 321 copied = sizeof(data);
322
325 } else 323 } else
326 copied = access_process_vm(child, addr + add, &data, 324 copied = access_process_vm(child, addr, &data,
327 sizeof(data), 1); 325 sizeof(data), 1);
326
328 pr_debug("ptrace: copied size %d\n", copied); 327 pr_debug("ptrace: copied size %d\n", copied);
329 if (copied != sizeof(data)) 328 if (copied != sizeof(data))
330 break; 329 break;
@@ -351,29 +350,22 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
351 break; 350 break;
352 351
353 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 352 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
354 case PTRACE_CONT: 353 case PTRACE_CONT: /* restart after signal. */
355 { /* restart after signal. */ 354 pr_debug("ptrace: syscall/cont\n");
356 long tmp;
357 355
358 pr_debug("ptrace_cont\n"); 356 ret = -EIO;
359 357 if (!valid_signal(data))
360 ret = -EIO;
361 if (!valid_signal(data))
362 break;
363 if (request == PTRACE_SYSCALL)
364 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
365 else
366 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
367
368 child->exit_code = data;
369 /* make sure the single step bit is not set. */
370 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
371 put_reg(child, PT_SYSCFG, tmp);
372 pr_debug("before wake_up_process\n");
373 wake_up_process(child);
374 ret = 0;
375 break; 358 break;
376 } 359 if (request == PTRACE_SYSCALL)
360 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
361 else
362 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
363 child->exit_code = data;
364 ptrace_disable(child);
365 pr_debug("ptrace: before wake_up_process\n");
366 wake_up_process(child);
367 ret = 0;
368 break;
377 369
378 /* 370 /*
379 * make the child exit. Best I can do is send it a sigkill. 371 * make the child exit. Best I can do is send it a sigkill.
@@ -381,55 +373,37 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
381 * exit. 373 * exit.
382 */ 374 */
383 case PTRACE_KILL: 375 case PTRACE_KILL:
384 { 376 ret = 0;
385 long tmp; 377 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
386 ret = 0;
387 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
388 break;
389 child->exit_code = SIGKILL;
390 /* make sure the single step bit is not set. */
391 tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
392 put_reg(child, PT_SYSCFG, tmp);
393 wake_up_process(child);
394 break; 378 break;
395 } 379 child->exit_code = SIGKILL;
396 380 ptrace_disable(child);
397 case PTRACE_SINGLESTEP: 381 wake_up_process(child);
398 { /* set the trap flag. */ 382 break;
399 long tmp;
400
401 pr_debug("single step\n");
402 ret = -EIO;
403 if (!valid_signal(data))
404 break;
405 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
406
407 tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
408 put_reg(child, PT_SYSCFG, tmp);
409 383
410 child->exit_code = data; 384 case PTRACE_SINGLESTEP: /* set the trap flag. */
411 /* give it a chance to run. */ 385 pr_debug("ptrace: single step\n");
412 wake_up_process(child); 386 ret = -EIO;
413 ret = 0; 387 if (!valid_signal(data))
414 break; 388 break;
415 } 389 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
390 ptrace_enable(child);
391 child->exit_code = data;
392 wake_up_process(child);
393 ret = 0;
394 break;
416 395
417 case PTRACE_GETREGS: 396 case PTRACE_GETREGS:
418 { 397 /* Get all gp regs from the child. */
419 398 ret = ptrace_getregs(child, datap);
420 /* Get all gp regs from the child. */ 399 break;
421 ret = ptrace_getregs(child, datap);
422 break;
423 }
424 400
425 case PTRACE_SETREGS: 401 case PTRACE_SETREGS:
426 { 402 printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
427 printk(KERN_NOTICE 403 /* Set all gp regs in the child. */
428 "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); 404 ret = 0;
429 /* Set all gp regs in the child. */ 405 break;
430 ret = 0; 406
431 break;
432 }
433 default: 407 default:
434 ret = ptrace_request(child, request, addr, data); 408 ret = ptrace_request(child, request, addr, data);
435 break; 409 break;
@@ -440,7 +414,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
440 414
441asmlinkage void syscall_trace(void) 415asmlinkage void syscall_trace(void)
442{ 416{
443
444 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 417 if (!test_thread_flag(TIF_SYSCALL_TRACE))
445 return; 418 return;
446 419