Hi Jan,
On Fri, 2013-11-01 at 17:05 +0100, Jan Kratochvil wrote:
this patch is for the branch 'portable' to be checked in
wotj
'jankratochvil/unwindx86', that is for RHEL-5 systems.
wotj?
I do agree this is too invasive (especially the "settle down" part) to
have enabled normally. So putting it in portable is a good idea.
RHEL-5 kernels were not enough with
ptrace (PTRACE_DETACH, tid, NULL, SIGSTOP);
and they need to explicitly
syscall (__NR_tkill, tid, SIGSTOP);
beforehand.
This wouldn't be that bad to do in general since we already have the
detection in place, and SIGSTOPs don't stack/nest, but...
Moreover for a short time after such PTRACE_DETACH the TID's
/proc/PID/status
State may be R (running), so if one tries to PTRACE_ATTACH that time again the
attacher will not notice the process in fact should be T (stopped). Therefore
it detaches the process without __NR_tkill SIGSTOP and the process is no
longer stopped, as it should have been.
this is nasty :{ What a pity this is necessary.
But good you found out.
2013-11-01 Jan Kratochvil <jan.kratochvil(a)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.
tests/
2013-11-01 Jan Kratochvil <jan.kratochvil(a)redhat.com>
Handle T-stopped detach for old kernels.
* backtrace.c: Include sys/syscall.h.
(linux_proc_pid_is_stopped): New function.
(ptrace_detach_stopped): Handle old kernels.
This looks good for the portable branch. Just one request. Please add
the kernel version you tested the workaround against as a comment...
// Here...
+ 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;
}
// And here...
+ syscall (__NR_tkill, pid, SIGSTOP);
errno = 0;
long l = ptrace (PTRACE_DETACH, pid, NULL, (void *) (intptr_t) SIGSTOP);
assert_perror (errno);
assert (l == 0);
+ // Wait till the SIGSTOP settles down.
+ int i;
+ for (i = 0; i < 100000; i++)
+ if (linux_proc_pid_is_stopped (pid))
+ break;
Thanks,
Mark