diff options
author | Christoph Hellwig <hch@lst.de> | 2010-03-10 18:23:01 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:39 -0500 |
commit | e34112e3966fc466ced2698e6c196bb50b1ee20e (patch) | |
tree | c013322641861cb4a41cd322f38efaf2ff0f8160 | |
parent | 290ba3aef58ff21c977585ff6b687e457f80bf54 (diff) |
m32r: use generic ptrace_resume code
Use the generic ptrace_resume code for PTRACE_SYSCALL, PTRACE_CONT,
PTRACE_KILL and PTRACE_SINGLESTEP. This implies defining
arch_has_single_step in <asm/ptrace.h> and implementing the
user_enable_single_step and user_disable_single_step functions, which also
causes the breakpoint information to be cleared on fork, which could be
considered a bug fix.
Also the TIF_SYSCALL_TRACE thread flag is now cleared on PTRACE_KILL which
it previously wasn't, which is consistent with all architectures using the
modern ptrace code.
The old code only disables the breakpoints on PTRACE_KILL, while after
this patch this also happens for PTRACE_CONT and PTRACE_SYSCALL which
matches the behaviour of the other architetures. I think this is a
bugfixes, but please double verify this is correct.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/m32r/include/asm/ptrace.h | 2 | ||||
-rw-r--r-- | arch/m32r/kernel/ptrace.c | 97 |
2 files changed, 31 insertions, 68 deletions
diff --git a/arch/m32r/include/asm/ptrace.h b/arch/m32r/include/asm/ptrace.h index a0755b982028..840a1231edeb 100644 --- a/arch/m32r/include/asm/ptrace.h +++ b/arch/m32r/include/asm/ptrace.h | |||
@@ -120,6 +120,8 @@ struct pt_regs { | |||
120 | 120 | ||
121 | #include <asm/m32r.h> /* M32R_PSW_BSM, M32R_PSW_BPM */ | 121 | #include <asm/m32r.h> /* M32R_PSW_BSM, M32R_PSW_BPM */ |
122 | 122 | ||
123 | #define arch_has_single_step() (1) | ||
124 | |||
123 | struct task_struct; | 125 | struct task_struct; |
124 | extern void init_debug_traps(struct task_struct *); | 126 | extern void init_debug_traps(struct task_struct *); |
125 | #define arch_ptrace_attach(child) \ | 127 | #define arch_ptrace_attach(child) \ |
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index 98682bba0ed9..e555091eb97c 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c | |||
@@ -580,6 +580,35 @@ init_debug_traps(struct task_struct *child) | |||
580 | } | 580 | } |
581 | } | 581 | } |
582 | 582 | ||
583 | void user_enable_single_step(struct task_struct *child) | ||
584 | { | ||
585 | unsigned long next_pc; | ||
586 | unsigned long pc, insn; | ||
587 | |||
588 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
589 | |||
590 | /* Compute next pc. */ | ||
591 | pc = get_stack_long(child, PT_BPC); | ||
592 | |||
593 | if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) | ||
594 | != sizeof(insn)) | ||
595 | break; | ||
596 | |||
597 | compute_next_pc(insn, pc, &next_pc, child); | ||
598 | if (next_pc & 0x80000000) | ||
599 | break; | ||
600 | |||
601 | if (embed_debug_trap(child, next_pc)) | ||
602 | break; | ||
603 | |||
604 | invalidate_cache(); | ||
605 | } | ||
606 | |||
607 | void user_disable_single_step(struct task_struct *child) | ||
608 | { | ||
609 | unregister_all_debug_traps(child); | ||
610 | invalidate_cache(); | ||
611 | } | ||
583 | 612 | ||
584 | /* | 613 | /* |
585 | * Called by kernel/ptrace.c when detaching.. | 614 | * Called by kernel/ptrace.c when detaching.. |
@@ -630,74 +659,6 @@ arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
630 | ret = ptrace_write_user(child, addr, data); | 659 | ret = ptrace_write_user(child, addr, data); |
631 | break; | 660 | break; |
632 | 661 | ||
633 | /* | ||
634 | * continue/restart and stop at next (return from) syscall | ||
635 | */ | ||
636 | case PTRACE_SYSCALL: | ||
637 | case PTRACE_CONT: | ||
638 | ret = -EIO; | ||
639 | if (!valid_signal(data)) | ||
640 | break; | ||
641 | if (request == PTRACE_SYSCALL) | ||
642 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
643 | else | ||
644 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
645 | child->exit_code = data; | ||
646 | wake_up_process(child); | ||
647 | ret = 0; | ||
648 | break; | ||
649 | |||
650 | /* | ||
651 | * make the child exit. Best I can do is send it a sigkill. | ||
652 | * perhaps it should be put in the status that it wants to | ||
653 | * exit. | ||
654 | */ | ||
655 | case PTRACE_KILL: { | ||
656 | ret = 0; | ||
657 | unregister_all_debug_traps(child); | ||
658 | invalidate_cache(); | ||
659 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
660 | break; | ||
661 | child->exit_code = SIGKILL; | ||
662 | wake_up_process(child); | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * execute single instruction. | ||
668 | */ | ||
669 | case PTRACE_SINGLESTEP: { | ||
670 | unsigned long next_pc; | ||
671 | unsigned long pc, insn; | ||
672 | |||
673 | ret = -EIO; | ||
674 | if (!valid_signal(data)) | ||
675 | break; | ||
676 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
677 | |||
678 | /* Compute next pc. */ | ||
679 | pc = get_stack_long(child, PT_BPC); | ||
680 | |||
681 | if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) | ||
682 | != sizeof(insn)) | ||
683 | break; | ||
684 | |||
685 | compute_next_pc(insn, pc, &next_pc, child); | ||
686 | if (next_pc & 0x80000000) | ||
687 | break; | ||
688 | |||
689 | if (embed_debug_trap(child, next_pc)) | ||
690 | break; | ||
691 | |||
692 | invalidate_cache(); | ||
693 | child->exit_code = data; | ||
694 | |||
695 | /* give it a chance to run. */ | ||
696 | wake_up_process(child); | ||
697 | ret = 0; | ||
698 | break; | ||
699 | } | ||
700 | |||
701 | case PTRACE_GETREGS: | 662 | case PTRACE_GETREGS: |
702 | ret = ptrace_getregs(child, (void __user *)data); | 663 | ret = ptrace_getregs(child, (void __user *)data); |
703 | break; | 664 | break; |