diff options
author | Petr Tesarik <ptesarik@suse.cz> | 2007-12-12 09:24:25 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2008-02-08 15:01:29 -0500 |
commit | aa91a2e90044b88228bdb0620e771f2ea7798804 (patch) | |
tree | 935056068de330e73eaf39ba8284ae33ad6e145e | |
parent | 3b2ce0b17824c42bc2e46f7dd903b4acf5e9fff9 (diff) |
[IA64] Synchronize RBS on PTRACE_ATTACH
When attaching to a stopped process, the RSE must be explicitly
synced to user-space, so the debugger can read the correct values.
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
CC: Roland McGrath <roland@redhat.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 57 | ||||
-rw-r--r-- | include/asm-ia64/ptrace.h | 4 |
2 files changed, 61 insertions, 0 deletions
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 2de5a524a0ee..331d6768b5d5 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c | |||
@@ -613,6 +613,63 @@ void ia64_sync_krbs(void) | |||
613 | unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs); | 613 | unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs); |
614 | } | 614 | } |
615 | 615 | ||
616 | /* | ||
617 | * After PTRACE_ATTACH, a thread's register backing store area in user | ||
618 | * space is assumed to contain correct data whenever the thread is | ||
619 | * stopped. arch_ptrace_stop takes care of this on tracing stops. | ||
620 | * But if the child was already stopped for job control when we attach | ||
621 | * to it, then it might not ever get into ptrace_stop by the time we | ||
622 | * want to examine the user memory containing the RBS. | ||
623 | */ | ||
624 | void | ||
625 | ptrace_attach_sync_user_rbs (struct task_struct *child) | ||
626 | { | ||
627 | int stopped = 0; | ||
628 | struct unw_frame_info info; | ||
629 | |||
630 | /* | ||
631 | * If the child is in TASK_STOPPED, we need to change that to | ||
632 | * TASK_TRACED momentarily while we operate on it. This ensures | ||
633 | * that the child won't be woken up and return to user mode while | ||
634 | * we are doing the sync. (It can only be woken up for SIGKILL.) | ||
635 | */ | ||
636 | |||
637 | read_lock(&tasklist_lock); | ||
638 | if (child->signal) { | ||
639 | spin_lock_irq(&child->sighand->siglock); | ||
640 | if (child->state == TASK_STOPPED && | ||
641 | !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) { | ||
642 | tsk_set_notify_resume(child); | ||
643 | |||
644 | child->state = TASK_TRACED; | ||
645 | stopped = 1; | ||
646 | } | ||
647 | spin_unlock_irq(&child->sighand->siglock); | ||
648 | } | ||
649 | read_unlock(&tasklist_lock); | ||
650 | |||
651 | if (!stopped) | ||
652 | return; | ||
653 | |||
654 | unw_init_from_blocked_task(&info, child); | ||
655 | do_sync_rbs(&info, ia64_sync_user_rbs); | ||
656 | |||
657 | /* | ||
658 | * Now move the child back into TASK_STOPPED if it should be in a | ||
659 | * job control stop, so that SIGCONT can be used to wake it up. | ||
660 | */ | ||
661 | read_lock(&tasklist_lock); | ||
662 | if (child->signal) { | ||
663 | spin_lock_irq(&child->sighand->siglock); | ||
664 | if (child->state == TASK_TRACED && | ||
665 | (child->signal->flags & SIGNAL_STOP_STOPPED)) { | ||
666 | child->state = TASK_STOPPED; | ||
667 | } | ||
668 | spin_unlock_irq(&child->sighand->siglock); | ||
669 | } | ||
670 | read_unlock(&tasklist_lock); | ||
671 | } | ||
672 | |||
616 | static inline int | 673 | static inline int |
617 | thread_matches (struct task_struct *thread, unsigned long addr) | 674 | thread_matches (struct task_struct *thread, unsigned long addr) |
618 | { | 675 | { |
diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index 13435f778b0c..0bdce7dde1b0 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h | |||
@@ -310,6 +310,10 @@ struct switch_stack { | |||
310 | #define arch_ptrace_stop_needed(code, info) \ | 310 | #define arch_ptrace_stop_needed(code, info) \ |
311 | (!test_thread_flag(TIF_RESTORE_RSE)) | 311 | (!test_thread_flag(TIF_RESTORE_RSE)) |
312 | 312 | ||
313 | extern void ptrace_attach_sync_user_rbs (struct task_struct *); | ||
314 | #define arch_ptrace_attach(child) \ | ||
315 | ptrace_attach_sync_user_rbs(child) | ||
316 | |||
313 | #endif /* !__KERNEL__ */ | 317 | #endif /* !__KERNEL__ */ |
314 | 318 | ||
315 | /* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ | 319 | /* pt_all_user_regs is used for PTRACE_GETREGS PTRACE_SETREGS */ |