fcntl(fd, F_SETFD, newflags); /* never fails */
}
+static void kill_save_errno(pid_t pid, int sig)
+{
+ int saved_errno = errno;
+
+ (void) kill(pid, sig);
+ errno = saved_errno;
+}
+
/*
* When strace is setuid executable, we have to swap uids
* before and after filesystem and process management operations.
* pidof uses space as delim, pgrep uses newline. :(
*/
int pid;
- struct tcb *tcp;
char *delim = opt + strcspn(opt, ", \n\t");
char c = *delim;
return;
}
*delim = c;
- tcp = alloc_tcb(pid, 0);
- tcp->flags |= TCB_ATTACHED;
+ alloc_tcb(pid, 0);
if (c == '\0')
break;
opt = delim + 1;
for (tcbi = 0; tcbi < tcbtabsize; tcbi++) {
tcp = tcbtab[tcbi];
+ if (!(tcp->flags & TCB_INUSE))
+ continue;
+
/* Is this a process we should attach to, but not yet attached? */
- if ((tcp->flags & (TCB_ATTACHED | TCB_STARTUP)) != TCB_ATTACHED)
- continue; /* no */
+ if (tcp->flags & TCB_ATTACHED)
+ continue; /* no, we already attached it */
/* Reinitialize the output since it may have changed */
tcp->outf = outf;
: "Process %u attached - interrupt to quit\n",
tcp->pid, ntid);
}
- if (!(tcp->flags & TCB_STARTUP)) {
+ if (!(tcp->flags & TCB_ATTACHED)) {
/* -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;
}
- tcp->flags |= TCB_STARTUP | post_attach_sigstop;
+ tcp->flags |= TCB_ATTACHED | TCB_STARTUP | post_attach_sigstop;
if (debug)
fprintf(stderr, "attach to pid %d (main) succeeded\n", tcp->pid);
* It is our grandparent we trace, not a -p PID.
* Don't want to just detach on exit, so...
*/
- tcp->flags &= ~TCB_ATTACHED;
+ tcp->flags |= TCB_STRACE_CHILD;
/*
* Make parent go away.
* Also makes grandparent's wait() unblock.
perror_msg_and_die("waitpid");
}
if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
- kill(pid, SIGKILL);
+ kill_save_errno(pid, SIGKILL);
perror_msg_and_die("Unexpected wait status %x", status);
}
}
*/
if (ptrace_attach_or_seize(pid)) {
- kill(pid, SIGKILL);
+ kill_save_errno(pid, SIGKILL);
perror_msg_and_die("Can't attach to %d", pid);
}
if (!strace_vforked)
}
tcp = alloctcb(pid);
if (!strace_vforked)
- tcp->flags |= TCB_STARTUP | post_attach_sigstop;
+ tcp->flags |= TCB_ATTACHED | TCB_STRACE_CHILD | TCB_STARTUP | post_attach_sigstop;
else
- tcp->flags |= TCB_STARTUP;
+ tcp->flags |= TCB_ATTACHED | TCB_STRACE_CHILD | TCB_STARTUP;
}
else {
/* With -D, *we* are child here, IOW: different pid. Fetch it: */
/* The tracee is our parent: */
pid = getppid();
tcp = alloctcb(pid);
- /* We want subsequent startup_attach() to attach to it: */
- tcp->flags |= TCB_ATTACHED;
}
}
-static void kill_save_errno(pid_t pid, int sig)
-{
- int saved_errno = errno;
-
- (void) kill(pid, sig);
- errno = saved_errno;
-}
-
/*
* Test whether the kernel support PTRACE_O_TRACECLONE et al options.
* First fork a new child, call ptrace with PTRACE_SETOPTIONS on it,
}
/* detach traced process; continue with sig
- Never call DETACH twice on the same process as both unattached and
- attached-unstopped processes give the same ESRCH. For unattached process we
- would SIGSTOP it and wait for its SIGSTOP notification forever. */
-
+ * Never call DETACH twice on the same process as both unattached and
+ * attached-unstopped processes give the same ESRCH. For unattached process we
+ * would SIGSTOP it and wait for its SIGSTOP notification forever.
+ */
static int
detach(struct tcb *tcp)
{
- int error = 0;
- int status, catch_sigstop;
+ int error;
+ int status, sigstop_expected;
if (tcp->flags & TCB_BPTSET)
clearbpt(tcp);
#undef PTRACE_DETACH
#define PTRACE_DETACH PTRACE_SUNDETACH
#endif
- /*
- * 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).
- */
- catch_sigstop = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
- error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0);
- if (error == 0) {
- /* On a clear day, you can see forever. */
- }
- else if (errno != ESRCH) {
- /* Shouldn't happen. */
- perror("detach: ptrace(PTRACE_DETACH, ...)");
- }
- else if (my_tkill(tcp->pid, 0) < 0) {
- if (errno != ESRCH)
- perror("detach: checking sanity");
- }
- else if (!catch_sigstop && my_tkill(tcp->pid, SIGSTOP) < 0) {
- if (errno != ESRCH)
- perror("detach: stopping child");
+
+ sigstop_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);
+ if (error == 0) {
+ /* On a clear day, you can see forever. */
+ }
+ else if (errno != ESRCH) {
+ /* Shouldn't happen. */
+ perror("detach: ptrace(PTRACE_DETACH, ...)");
+ }
+ else if (my_tkill(tcp->pid, 0) < 0) {
+ if (errno != ESRCH)
+ perror("detach: checking sanity");
+ }
+ else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) {
+ if (errno != ESRCH)
+ perror("detach: stopping child");
+ }
+ else
+ sigstop_expected = 1;
}
- else
- catch_sigstop = 1;
- if (catch_sigstop) {
+
+ if (sigstop_expected) {
for (;;) {
#ifdef __WALL
if (wait4(tcp->pid, &status, __WALL, NULL) < 0) {
}
}
- if (!qflag)
+ if (!qflag && (tcp->flags & TCB_ATTACHED))
fprintf(stderr, "Process %u detached\n", tcp->pid);
droptcb(tcp);
tprints(" <unfinished ...>\n");
printing_tcp = NULL;
}
- if (tcp->flags & TCB_ATTACHED)
+ if (!(tcp->flags & TCB_STRACE_CHILD))
detach(tcp);
else {
kill(tcp->pid, SIGCONT);
* Observed case: exit_group() terminating
* all processes in thread group.
*/
- if (tcp->flags & TCB_ATTACHED) {
+ if (!(tcp->flags & TCB_STRACE_CHILD)) {
+//TODO: why do we handle our child differently??
if (printing_tcp) {
/* Do we have dangling line "syscall(param, param"?
* Finish the line then.