[PATCH] USE_SEIZE: fix detaching from stopped processes
Denys Vlasenko
dvlasenk at redhat.com
Wed Jun 19 10:32:37 UTC 2013
On 06/18/2013 10:36 PM, Dmitry V. Levin wrote:
> 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.
Right, I forgot about that!
It's because of TRACESYSGOOD, not SEIZE.
The check should be:
WSTOPSIG(status) == syscall_trap_sig
I'll test and resend the patch.
More information about the Strace-devel
mailing list