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 <[email protected]> Date: Sat Nov 9 19:39:21 2013 +0100 Handle T-stopped detach for old kernels. Signed-off-by: Jan Kratochvil <[email protected]> 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 <[email protected]> + + 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 <[email protected]> Mark Wielaard <[email protected]> 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)) {
