diff options
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c719bb9d79ab..fad5f1e8511f 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -366,6 +366,50 @@ static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) | |||
366 | return error; | 366 | return error; |
367 | } | 367 | } |
368 | 368 | ||
369 | |||
370 | #ifdef PTRACE_SINGLESTEP | ||
371 | #define is_singlestep(request) ((request) == PTRACE_SINGLESTEP) | ||
372 | #else | ||
373 | #define is_singlestep(request) 0 | ||
374 | #endif | ||
375 | |||
376 | #ifdef PTRACE_SYSEMU | ||
377 | #define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP) | ||
378 | #else | ||
379 | #define is_sysemu_singlestep(request) 0 | ||
380 | #endif | ||
381 | |||
382 | static int ptrace_resume(struct task_struct *child, long request, long data) | ||
383 | { | ||
384 | if (!valid_signal(data)) | ||
385 | return -EIO; | ||
386 | |||
387 | if (request == PTRACE_SYSCALL) | ||
388 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
389 | else | ||
390 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
391 | |||
392 | #ifdef TIF_SYSCALL_EMU | ||
393 | if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) | ||
394 | set_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
395 | else | ||
396 | clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); | ||
397 | #endif | ||
398 | |||
399 | if (is_singlestep(request) || is_sysemu_singlestep(request)) { | ||
400 | if (unlikely(!arch_has_single_step())) | ||
401 | return -EIO; | ||
402 | user_enable_single_step(child); | ||
403 | } | ||
404 | else | ||
405 | user_disable_single_step(child); | ||
406 | |||
407 | child->exit_code = data; | ||
408 | wake_up_process(child); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
369 | int ptrace_request(struct task_struct *child, long request, | 413 | int ptrace_request(struct task_struct *child, long request, |
370 | long addr, long data) | 414 | long addr, long data) |
371 | { | 415 | { |
@@ -390,6 +434,23 @@ int ptrace_request(struct task_struct *child, long request, | |||
390 | case PTRACE_DETACH: /* detach a process that was attached. */ | 434 | case PTRACE_DETACH: /* detach a process that was attached. */ |
391 | ret = ptrace_detach(child, data); | 435 | ret = ptrace_detach(child, data); |
392 | break; | 436 | break; |
437 | |||
438 | #ifdef PTRACE_SINGLESTEP | ||
439 | case PTRACE_SINGLESTEP: | ||
440 | #endif | ||
441 | #ifdef PTRACE_SYSEMU | ||
442 | case PTRACE_SYSEMU: | ||
443 | case PTRACE_SYSEMU_SINGLESTEP: | ||
444 | #endif | ||
445 | case PTRACE_SYSCALL: | ||
446 | case PTRACE_CONT: | ||
447 | return ptrace_resume(child, request, data); | ||
448 | |||
449 | case PTRACE_KILL: | ||
450 | if (child->exit_state) /* already dead */ | ||
451 | return 0; | ||
452 | return ptrace_resume(child, request, SIGKILL); | ||
453 | |||
393 | default: | 454 | default: |
394 | break; | 455 | break; |
395 | } | 456 | } |