This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
[partial commit] [unwinder-portable patch 1/3] Handle T-stopped detach for old kernels
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Sat, 09 Nov 2013 19:40:30 +0100
- Subject: [partial commit] [unwinder-portable patch 1/3] Handle T-stopped detach for old kernels
On Wed, 06 Nov 2013 11:38:20 +0100, Mark Wielaard wrote:
> This looks good for the portable branch. Just one request. Please add
> the kernel version you tested the workaround against as a comment...
Done.
The tests/ part is sure not yet committed as it is not yet in master.
Thanks,
Jan
commit 154fab925e0d2f829b54c03b695015245ed000dd
Author: Jan Kratochvil <jan.kratochvil@redhat.com>
Date: Sat Nov 9 19:39:21 2013 +0100
Handle T-stopped detach for old kernels.
Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 7a9f3f9..be780d1 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,12 @@
+2013-11-09 Jan Kratochvil <jan.kratochvil@redhat.com>
+
+ Handle T-stopped detach for old kernels.
+ * linux-pid-attach.c (struct pid_arg): New field stopped.
+ (ptrace_attach): New parameter stoppedp. Set it appropriately.
+ (pid_set_initial_registers): Pass the new field.
+ (pid_thread_detach): Handle the case of STOPPED for old kernels.
+ (__libdwfl_attach_state_for_pid): Initialize STOPPED.
+
2013-11-07 Jan Kratochvil <jan.kratochvil@redhat.com>
Mark Wielaard <mjw@redhat.com>
diff --git a/libdwfl/linux-pid-attach.c b/libdwfl/linux-pid-attach.c
index 5ad58f6..efdeb9f 100644
--- a/libdwfl/linux-pid-attach.c
+++ b/libdwfl/linux-pid-attach.c
@@ -42,6 +42,8 @@ struct pid_arg
DIR *dir;
/* It is 0 if not used. */
pid_t tid_attached;
+ /* TRUE if the process (first of its threads) was State: T (stopped). */
+ bool stopped;
};
static bool
@@ -69,7 +71,7 @@ linux_proc_pid_is_stopped (pid_t pid)
}
static bool
-ptrace_attach (pid_t tid)
+ptrace_attach (pid_t tid, bool *stoppedp)
{
if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
{
@@ -84,6 +86,7 @@ ptrace_attach (pid_t tid)
above. Which would make the waitpid below wait forever. So emulate
it. Since there can only be one SIGSTOP notification pending this is
safe. See also gdb/linux-nat.c linux_nat_post_attach_wait. */
+ *stoppedp = true;
syscall (__NR_tkill, tid, SIGSTOP);
ptrace (PTRACE_CONT, tid, NULL, NULL);
}
@@ -213,7 +216,7 @@ pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
struct pid_arg *pid_arg = thread_arg;
assert (pid_arg->tid_attached == 0);
pid_t tid = INTUSE(dwfl_thread_tid) (thread);
- if (! ptrace_attach (tid))
+ if (! ptrace_attach (tid, &pid_arg->stopped))
return false;
pid_arg->tid_attached = tid;
Dwfl_Process *process = thread->process;
@@ -237,7 +240,20 @@ pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
pid_t tid = INTUSE(dwfl_thread_tid) (thread);
assert (pid_arg->tid_attached == tid);
pid_arg->tid_attached = 0;
- ptrace (PTRACE_DETACH, tid, NULL, NULL);
+ if (! pid_arg->stopped)
+ {
+ ptrace (PTRACE_DETACH, tid, NULL, NULL);
+ return;
+ }
+ // Older kernels (tested kernel-2.6.18-348.12.1.el5.x86_64) need special
+ // handling of the detachment to keep the process State: T (stopped).
+ syscall (__NR_tkill, tid, SIGSTOP);
+ ptrace (PTRACE_DETACH, tid, NULL, (void *) (intptr_t) SIGSTOP);
+ // Wait till the SIGSTOP settles down.
+ int i;
+ for (i = 0; i < 100000; i++)
+ if (linux_proc_pid_is_stopped (tid))
+ break;
}
static const Dwfl_Thread_Callbacks pid_thread_callbacks =
@@ -271,6 +287,7 @@ __libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid)
}
pid_arg->dir = dir;
pid_arg->tid_attached = 0;
+ pid_arg->stopped = false;
if (! INTUSE(dwfl_attach_state) (dwfl, EM_NONE, pid, &pid_thread_callbacks,
pid_arg))
{