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 /arch | |
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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/kernel/ptrace.c | 57 |
1 files changed, 57 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 | { |