[PATCH] USE_SEIZE: fix detaching from stopped processes
Dmitry V. Levin
ldv at altlinux.org
Tue Jun 18 20:36:20 UTC 2013
On Tue, Jun 18, 2013 at 06:18:14PM +0200, Denys Vlasenko wrote:
> * 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 SIGTRAP.
>
> Signed-off-by: Denys Vlasenko <dvlasenk at redhat.com>
> ---
> strace.c | 33 ++++++++++++++++++++++-----------
> 1 file changed, 22 insertions(+), 11 deletions(-)
>
> diff --git a/strace.c b/strace.c
> index 87aad48..af8156d 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. */
> }
> @@ -769,15 +769,24 @@ detach(struct tcb *tcp)
> if (errno != ESRCH)
> perror_msg("detach: checking sanity");
> }
> - else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) {
> - if (errno != ESRCH)
> - perror_msg("detach: stopping child");
> + else if (!stop_expected) {
> + /* Process is running, need to stop it first */
> + if (use_seize)
> + 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");
> + }
> }
> - else
> - sigstop_expected = 1;
> }
>
> - if (sigstop_expected) {
> + if (stop_expected) {
> for (;;) {
> #ifdef __WALL
> if (waitpid(tcp->pid, &status, __WALL) < 0) {
> @@ -810,7 +819,9 @@ detach(struct tcb *tcp)
> /* Au revoir, mon ami. */
> break;
> }
> - if (WSTOPSIG(status) == SIGSTOP) {
> + if (WSTOPSIG(status) == SIGSTOP
> + || WSTOPSIG(status) == SIGTRAP /* may be generated by PTRACE_INTERRUPT stop */
> + ) {
In case of PTRACE_INTERRUPT this WSTOPSIG(status) is not plain SIGTRAP
but (SIGTRAP | 0x80), which also may happen in other !use_seize cases.
That is, the right check seems to be
WSTOPSIG(status) == SIGSTOP ||
(use_seize && WSTOPSIG(status) == (SIGTRAP | 0x80))
It also passes both tests/detach-sleeping and tests/detach-stopped.
--
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20130619/f1379273/attachment.bin>
More information about the Strace-devel
mailing list