V2: check WSTOPSIG(status) == syscall_trap_sig, not SIGTRAP. Add comments explaining what we think about the process status in detach() at various steps. Simplify PTRACE_CONT in wait loop since now syscall_trap_sig can't be seen there. Verified that tests/detach works.
* strace.c (detach) [USE_SEIZE]: If PTRACE_SEIZE API is in use, stop the tracee using PTRACE_INTERRUPT instead of sending it a SIGSTOP. In a subsequent waitpid loop, wait for either SIGSTOP or syscall_trap_sig. Signed-off-by: Denys Vlasenko <dvlas...@redhat.com> --- strace.c | 52 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/strace.c b/strace.c index 87aad48..1c6e81b 100644 --- a/strace.c +++ b/strace.c @@ -733,7 +733,7 @@ static int detach(struct tcb *tcp) { int error; - int status, sigstop_expected; + int status, stop_expected; if (tcp->flags & TCB_BPTSET) clearbpt(tcp); @@ -749,15 +749,15 @@ detach(struct tcb *tcp) #endif error = 0; - sigstop_expected = 0; + stop_expected = 0; if (tcp->flags & TCB_ATTACHED) { /* * We attached but possibly didn't see the expected SIGSTOP. * We must catch exactly one as otherwise the detached process * would be left stopped (process state T). */ - sigstop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP); - error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0); + stop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP); + error = ptrace(PTRACE_DETACH, tcp->pid, 0, 0); if (error == 0) { /* On a clear day, you can see forever. */ } @@ -765,19 +765,40 @@ detach(struct tcb *tcp) /* Shouldn't happen. */ perror_msg("detach: ptrace(PTRACE_DETACH, ...)"); } - else if (my_tkill(tcp->pid, 0) < 0) { + else + /* ESRCH: process is either not stopped or doesn't exist. */ + if (my_tkill(tcp->pid, 0) < 0) { if (errno != ESRCH) + /* Shouldn't happen. */ perror_msg("detach: checking sanity"); - } - else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) { - if (errno != ESRCH) - perror_msg("detach: stopping child"); + /* else: process doesn't exist. */ } else - sigstop_expected = 1; + /* Process is not stopped. */ + if (!stop_expected) { + /* We need to stop it. */ + if (use_seize) + /* + * With SEIZE, tracee can be in group-stop already. + * In this state sending it another SIGSTOP does nothing. + * Need to use INTERRUPT. + * Testcase: trying to ^C a "strace -p <stopped_process>". + */ + error = ptrace(PTRACE_INTERRUPT, tcp->pid, 0, 0); + else + error = my_tkill(tcp->pid, SIGSTOP); + if (!error) + stop_expected = 1; + else if (errno != ESRCH) { + if (use_seize) + perror_msg("detach: ptrace(PTRACE_INTERRUPT, ...)"); + else + perror_msg("detach: stopping child"); + } + } } - if (sigstop_expected) { + if (stop_expected) { for (;;) { #ifdef __WALL if (waitpid(tcp->pid, &status, __WALL) < 0) { @@ -810,13 +831,14 @@ detach(struct tcb *tcp) /* Au revoir, mon ami. */ break; } - if (WSTOPSIG(status) == SIGSTOP) { + if (WSTOPSIG(status) == SIGSTOP + /* generated by PTRACE_INTERRUPT stop: */ + || WSTOPSIG(status) == syscall_trap_sig + ) { ptrace_restart(PTRACE_DETACH, tcp, 0); break; } - error = ptrace_restart(PTRACE_CONT, tcp, - WSTOPSIG(status) == syscall_trap_sig ? 0 - : WSTOPSIG(status)); + error = ptrace_restart(PTRACE_CONT, tcp, WSTOPSIG(status)); if (error < 0) break; } -- 1.8.1.4 ------------------------------------------------------------------------------ This SF.net email is sponsored by Windows: Build for Windows Store. http://p.sf.net/sfu/windows-dev2dev _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel