Do post-attach initialization earlier; fix "we ignore SIGSTOP on NOMMU" bug
We set ptrace options when we see post-attach SIGSTOP. This is wrong: it's better to set them right away on the very first stop (whichever it will be). It also will make adding SEIZE support easier, since SEIZE has no post-attach SIGSTOP. We do it by adding a new bit, TCB_IGNORE_ONE_SIGSTOP, and treating TCB_STARTUP and TCB_IGNORE_ONE_SIGSTOP as two slightly different things. * defs.h: Add a new flag bit, TCB_IGNORE_ONE_SIGSTOP. * process.c (internal_fork): Set TCB_IGNORE_ONE_SIGSTOP on a newly added child. * strace.c (startup_attach): Set TCB_IGNORE_ONE_SIGSTOP after attach. Fix a case when "strace -p PID" found PID dead but sone other of its threads still alive. (startup_child): Set TCB_IGNORE_ONE_SIGSTOP after attach, _if needed_. This fixes a bogus case where we can ignore a _real_ SIGSTOP on NOMMU. (detach): Perform anti-SIGSTOP dance only if TCB_IGNORE_ONE_SIGSTOP is set, not if TCB_STARTUP is set. (trace): Set TCB_IGNORE_ONE_SIGSTOP after attach. Clear TCB_STARTUP and initialize tracee on the very first tracee stop. Clear TCB_IGNORE_ONE_SIGSTOP when SIGSTOP is seen. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
This commit is contained in:
parent
d116a73386
commit
f88837a666
15
defs.h
15
defs.h
@ -436,8 +436,15 @@ struct tcb {
|
||||
};
|
||||
|
||||
/* TCB flags */
|
||||
#define TCB_STARTUP 00001 /* We have just begun ptracing this process */
|
||||
#define TCB_INUSE 00002 /* This table entry is in use */
|
||||
#define TCB_INUSE 00001 /* This table entry is in use */
|
||||
/* We have attached to this process, but did not see it stopping yet.
|
||||
* (If this bit is not set, we either didn't attach yet,
|
||||
* or we did attach to it, already saw it stopping at least once,
|
||||
* did some init work on it and cleared this bit. TODO: maybe it makes sense
|
||||
* to split these two states?)
|
||||
*/
|
||||
#define TCB_STARTUP 00002
|
||||
#define TCB_IGNORE_ONE_SIGSTOP 00004 /* Next SIGSTOP is to be ignored */
|
||||
/*
|
||||
* Are we in system call entry or in syscall exit?
|
||||
*
|
||||
@ -456,8 +463,8 @@ struct tcb {
|
||||
*
|
||||
* Use entering(tcp) / exiting(tcp) to check this bit to make code more readable.
|
||||
*/
|
||||
#define TCB_INSYSCALL 00004
|
||||
#define TCB_ATTACHED 00010 /* Process is not our own child */
|
||||
#define TCB_INSYSCALL 00010
|
||||
#define TCB_ATTACHED 00020 /* Process is not our own child */
|
||||
#define TCB_BPTSET 00100 /* "Breakpoint" set after fork(2) */
|
||||
#define TCB_SIGTRAPPED 00200 /* Process wanted to block SIGTRAP */
|
||||
#define TCB_REPRINT 01000 /* We should reprint this syscall on exit */
|
||||
|
@ -859,7 +859,7 @@ internal_fork(struct tcb *tcp)
|
||||
}
|
||||
#endif /* !oldway */
|
||||
#endif /* SUNOS4 */
|
||||
tcpchild->flags |= TCB_ATTACHED | TCB_STARTUP;
|
||||
tcpchild->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
|
||||
/* Child has BPT too, must be removed on first occasion */
|
||||
if (bpt) {
|
||||
tcpchild->flags |= TCB_BPTSET;
|
||||
|
69
strace.c
69
strace.c
@ -491,7 +491,7 @@ startup_attach(void)
|
||||
cur_tcp = tcp;
|
||||
if (tid != tcp->pid)
|
||||
cur_tcp = alloctcb(tid);
|
||||
cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
|
||||
cur_tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
|
||||
}
|
||||
closedir(dir);
|
||||
if (interactive) {
|
||||
@ -512,6 +512,13 @@ startup_attach(void)
|
||||
: "Process %u attached - interrupt to quit\n",
|
||||
tcp->pid, ntid);
|
||||
}
|
||||
if (!(tcp->flags & TCB_STARTUP)) {
|
||||
/* -p PID, we failed to attach to PID itself
|
||||
* but did attach to some of its sibling threads.
|
||||
* Drop PID's tcp.
|
||||
*/
|
||||
droptcb(tcp);
|
||||
}
|
||||
continue;
|
||||
} /* if (opendir worked) */
|
||||
} /* if (-f) */
|
||||
@ -521,7 +528,7 @@ startup_attach(void)
|
||||
droptcb(tcp);
|
||||
continue;
|
||||
}
|
||||
tcp->flags |= TCB_STARTUP;
|
||||
tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
|
||||
if (debug)
|
||||
fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
|
||||
|
||||
@ -707,6 +714,9 @@ startup_child(char **argv)
|
||||
|
||||
if (!daemonized_tracer) {
|
||||
tcp = alloctcb(pid);
|
||||
if (!strace_vforked)
|
||||
tcp->flags |= TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
|
||||
else
|
||||
tcp->flags |= TCB_STARTUP;
|
||||
}
|
||||
else {
|
||||
@ -1677,11 +1687,11 @@ detach(struct tcb *tcp, int sig)
|
||||
#define PTRACE_DETACH PTRACE_SUNDETACH
|
||||
#endif
|
||||
/*
|
||||
* On TCB_STARTUP we did PTRACE_ATTACH but still did not get the
|
||||
* expected SIGSTOP. We must catch exactly one as otherwise the
|
||||
* detached process would be left stopped (process state T).
|
||||
* We did PTRACE_ATTACH 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).
|
||||
*/
|
||||
catch_sigstop = (tcp->flags & TCB_STARTUP);
|
||||
catch_sigstop = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
|
||||
error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, sig);
|
||||
if (error == 0) {
|
||||
/* On a clear day, you can see forever. */
|
||||
@ -2411,7 +2421,7 @@ trace()
|
||||
child so that we know how to do clearbpt
|
||||
in the child. */
|
||||
tcp = alloctcb(pid);
|
||||
tcp->flags |= TCB_ATTACHED | TCB_STARTUP;
|
||||
tcp->flags |= TCB_ATTACHED | TCB_STARTUP | TCB_IGNORE_ONE_SIGSTOP;
|
||||
if (!qflag)
|
||||
fprintf(stderr, "Process %d attached\n",
|
||||
pid);
|
||||
@ -2478,28 +2488,10 @@ trace()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status >> 16) {
|
||||
/* Ptrace event (we ignore all of them for now) */
|
||||
goto restart_tracee_with_sig_0;
|
||||
}
|
||||
|
||||
sig = WSTOPSIG(status);
|
||||
|
||||
/*
|
||||
* Interestingly, the process may stop
|
||||
* with STOPSIG equal to some other signal
|
||||
* than SIGSTOP if we happend to attach
|
||||
* just before the process takes a signal.
|
||||
* A no-MMU vforked child won't send up a signal,
|
||||
* so skip the first (lost) execve notification.
|
||||
*/
|
||||
if ((tcp->flags & TCB_STARTUP) &&
|
||||
(sig == SIGSTOP || strace_vforked)) {
|
||||
/*
|
||||
* This flag is there to keep us in sync.
|
||||
* Next time this process stops it should
|
||||
* really be entering a system call.
|
||||
*/
|
||||
/* Is this the very first time we see this tracee stopped? */
|
||||
if (tcp->flags & TCB_STARTUP) {
|
||||
if (debug)
|
||||
fprintf(stderr, "pid %d has TCB_STARTUP, initializing it\n", tcp->pid);
|
||||
tcp->flags &= ~TCB_STARTUP;
|
||||
if (tcp->flags & TCB_BPTSET) {
|
||||
/*
|
||||
@ -2525,6 +2517,25 @@ trace()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (((unsigned)status >> 16) != 0) {
|
||||
/* Ptrace event (we ignore all of them for now) */
|
||||
goto restart_tracee_with_sig_0;
|
||||
}
|
||||
|
||||
sig = WSTOPSIG(status);
|
||||
|
||||
/* Is this post-attach SIGSTOP?
|
||||
* Interestingly, the process may stop
|
||||
* with STOPSIG equal to some other signal
|
||||
* than SIGSTOP if we happend to attach
|
||||
* just before the process takes a signal.
|
||||
*/
|
||||
if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
|
||||
if (debug)
|
||||
fprintf(stderr, "ignored SIGSTOP on pid %d\n", tcp->pid);
|
||||
tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
|
||||
goto restart_tracee_with_sig_0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user