|
|
668e95 |
diff -rup a/defs.h b/defs.h
|
|
|
668e95 |
--- a/defs.h 2017-04-24 19:14:57.000000000 -0400
|
|
|
668e95 |
+++ b/defs.h 2017-06-15 14:24:50.121965636 -0400
|
|
|
668e95 |
@@ -213,6 +213,9 @@ struct tcb {
|
|
|
668e95 |
int flags; /* See below for TCB_ values */
|
|
|
668e95 |
int pid; /* If 0, this tcb is free */
|
|
|
668e95 |
int qual_flg; /* qual_flags[scno] or DEFAULT_QUAL_FLAGS + RAW */
|
|
|
668e95 |
+ int wait_status; /* Status from last wait() */
|
|
|
668e95 |
+ struct tcb *next_need_service;
|
|
|
668e95 |
+ /* Linked list of tracees found by wait()s */
|
|
|
668e95 |
unsigned long u_error; /* Error code */
|
|
|
668e95 |
kernel_ulong_t scno; /* System call number */
|
|
|
668e95 |
kernel_ulong_t u_arg[MAX_ARGS]; /* System call arguments */
|
|
|
668e95 |
@@ -413,6 +416,7 @@ extern void count_syscall(struct tcb *,
|
|
|
668e95 |
extern void call_summary(FILE *);
|
|
|
668e95 |
|
|
|
668e95 |
extern void clear_regs(void);
|
|
|
668e95 |
+extern void get_regs(pid_t pid);
|
|
|
668e95 |
extern int get_scno(struct tcb *);
|
|
|
668e95 |
extern kernel_ulong_t get_rt_sigframe_addr(struct tcb *);
|
|
|
668e95 |
|
|
|
668e95 |
diff -rup a/strace.c b/strace.c
|
|
|
668e95 |
--- a/strace.c 2017-05-22 13:33:51.000000000 -0400
|
|
|
668e95 |
+++ b/strace.c 2017-06-15 18:32:19.985800720 -0400
|
|
|
668e95 |
@@ -2251,17 +2251,40 @@ print_event_exit(struct tcb *tcp)
|
|
|
668e95 |
line_ended();
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
+static int remembered_pid;
|
|
|
668e95 |
+static int remembered_status;
|
|
|
668e95 |
+
|
|
|
668e95 |
/* Returns true iff the main trace loop has to continue. */
|
|
|
668e95 |
static bool
|
|
|
668e95 |
trace(void)
|
|
|
668e95 |
{
|
|
|
668e95 |
int pid;
|
|
|
668e95 |
+ struct tcb *tcp;
|
|
|
668e95 |
+ struct tcb *found_tcps;
|
|
|
668e95 |
+ struct tcb **nextp;
|
|
|
668e95 |
+ struct tcb *next;
|
|
|
668e95 |
+ int wnohang = 0;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ if (remembered_pid) {
|
|
|
668e95 |
+ pid = remembered_pid;
|
|
|
668e95 |
+ remembered_pid = 0;
|
|
|
668e95 |
+ if (debug_flag)
|
|
|
668e95 |
+ fprintf(stderr, " [remembered wait(%#x) = %u]\n",
|
|
|
668e95 |
+ remembered_status, pid);
|
|
|
668e95 |
+ tcp = pid2tcb(pid); /* can't be NULL */
|
|
|
668e95 |
+ tcp->wait_status = remembered_status;
|
|
|
668e95 |
+ tcp->next_need_service = NULL;
|
|
|
668e95 |
+ found_tcps = tcp;
|
|
|
668e95 |
+ goto process_saved_tcbs;
|
|
|
668e95 |
+ }
|
|
|
668e95 |
+
|
|
|
668e95 |
+ nextp = &found_tcps;
|
|
|
668e95 |
+ found_tcps = NULL;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ while (1) { /* RH 851457 - collect tcbs */
|
|
|
668e95 |
int wait_errno;
|
|
|
668e95 |
int status;
|
|
|
668e95 |
- bool stopped;
|
|
|
668e95 |
- unsigned int sig;
|
|
|
668e95 |
unsigned int event;
|
|
|
668e95 |
- struct tcb *tcp;
|
|
|
668e95 |
struct rusage ru;
|
|
|
668e95 |
|
|
|
668e95 |
if (interrupted)
|
|
|
668e95 |
@@ -2290,14 +2313,24 @@ trace(void)
|
|
|
668e95 |
|
|
|
668e95 |
if (interactive)
|
|
|
668e95 |
sigprocmask(SIG_SETMASK, &empty_set, NULL);
|
|
|
668e95 |
- pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL));
|
|
|
668e95 |
+ pid = wait4(-1, &status, __WALL | wnohang, (cflag ? &ru : NULL));
|
|
|
668e95 |
wait_errno = errno;
|
|
|
668e95 |
if (interactive)
|
|
|
668e95 |
sigprocmask(SIG_BLOCK, &blocked_set, NULL);
|
|
|
668e95 |
|
|
|
668e95 |
+ if (pid <= 0 && wnohang) {
|
|
|
668e95 |
+ /* We had at least one successful
|
|
|
668e95 |
+ * wait() before. We waited
|
|
|
668e95 |
+ * with WNOHANG second time.
|
|
|
668e95 |
+ * Stop collecting more tracees,
|
|
|
668e95 |
+ * process what we already have.
|
|
|
668e95 |
+ */
|
|
|
668e95 |
+ break; /* out of collect tcbs */
|
|
|
668e95 |
+ }
|
|
|
668e95 |
+
|
|
|
668e95 |
if (pid < 0) {
|
|
|
668e95 |
if (wait_errno == EINTR)
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ break; /* out of collect tcbs */
|
|
|
668e95 |
if (nprocs == 0 && wait_errno == ECHILD)
|
|
|
668e95 |
return false;
|
|
|
668e95 |
/*
|
|
|
668e95 |
@@ -2311,7 +2344,7 @@ trace(void)
|
|
|
668e95 |
if (pid == popen_pid) {
|
|
|
668e95 |
if (!WIFSTOPPED(status))
|
|
|
668e95 |
popen_pid = 0;
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ break; /* out of collect tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
if (debug_flag)
|
|
|
668e95 |
@@ -2323,7 +2356,7 @@ trace(void)
|
|
|
668e95 |
if (!tcp) {
|
|
|
668e95 |
tcp = maybe_allocate_tcb(pid, status);
|
|
|
668e95 |
if (!tcp)
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ break; /* out of collect tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
clear_regs();
|
|
|
668e95 |
@@ -2354,29 +2387,83 @@ trace(void)
|
|
|
668e95 |
tcp->flags &= ~TCB_SKIP_DETACH_ON_FIRST_EXEC;
|
|
|
668e95 |
} else {
|
|
|
668e95 |
detach(tcp); /* do "-b execve" thingy */
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ break; /* out of collect tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
}
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
- /* Set current output file */
|
|
|
668e95 |
- current_tcp = tcp;
|
|
|
668e95 |
-
|
|
|
668e95 |
if (cflag) {
|
|
|
668e95 |
tv_sub(&tcp->dtime, &ru.ru_stime, &tcp->stime);
|
|
|
668e95 |
tcp->stime = ru.ru_stime;
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
+ /* If we waited and got a stopped task notification,
|
|
|
668e95 |
+ * subsequent wait may return the same pid again, for example,
|
|
|
668e95 |
+ * with SIGKILL notification. SIGKILL kills even stopped tasks.
|
|
|
668e95 |
+ * We must not add it to the list
|
|
|
668e95 |
+ * (one task can't be inserted twice in the list).
|
|
|
668e95 |
+ */
|
|
|
668e95 |
+ {
|
|
|
668e95 |
+ struct tcb *f = found_tcps;
|
|
|
668e95 |
+ while (f) {
|
|
|
668e95 |
+ if (f == tcp) {
|
|
|
668e95 |
+ remembered_pid = pid;
|
|
|
668e95 |
+ remembered_status = status;
|
|
|
668e95 |
+ goto process_saved_tcbs;
|
|
|
668e95 |
+ }
|
|
|
668e95 |
+ f = f->next_need_service;
|
|
|
668e95 |
+ }
|
|
|
668e95 |
+ }
|
|
|
668e95 |
+ /* It is important to not invert the order of tasks
|
|
|
668e95 |
+ * to process. For one, alloc_tcb() above picks newly forked
|
|
|
668e95 |
+ * threads in some order, processing of them and their parent
|
|
|
668e95 |
+ * should be in the same order, otherwise bad things happen
|
|
|
668e95 |
+ * (misinterpreted SIGSTOPs and such).
|
|
|
668e95 |
+ */
|
|
|
668e95 |
+ tcp->wait_status = status;
|
|
|
668e95 |
+ *nextp = tcp;
|
|
|
668e95 |
+ nextp = &tcp->next_need_service;
|
|
|
668e95 |
+ *nextp = NULL;
|
|
|
668e95 |
+ wnohang = WNOHANG;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ } /* RH 851457 - collect tcbs */
|
|
|
668e95 |
+
|
|
|
668e95 |
+process_saved_tcbs:
|
|
|
668e95 |
+
|
|
|
668e95 |
+ for (tcp = found_tcps;
|
|
|
668e95 |
+ tcp;
|
|
|
668e95 |
+ tcp = next) { /* RH 851457 - process tcbs */
|
|
|
668e95 |
+ int status;
|
|
|
668e95 |
+ bool stopped;
|
|
|
668e95 |
+ unsigned int sig;
|
|
|
668e95 |
+ unsigned int event;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ /* If the child exits, the TCP will get dropped and
|
|
|
668e95 |
+ thus we can't use it to find the next TCP needing
|
|
|
668e95 |
+ service. So we save the next TCP needing service
|
|
|
668e95 |
+ and used the saved value when the loop iterates. */
|
|
|
668e95 |
+ next = tcp->next_need_service;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ status = tcp->wait_status;
|
|
|
668e95 |
+ pid = tcp->pid;
|
|
|
668e95 |
+
|
|
|
668e95 |
+ event = ((unsigned)status >> 16);
|
|
|
668e95 |
+
|
|
|
668e95 |
+ clear_regs();
|
|
|
668e95 |
+
|
|
|
668e95 |
+ /* Set current output file */
|
|
|
668e95 |
+ current_tcp = tcp;
|
|
|
668e95 |
+
|
|
|
668e95 |
if (WIFSIGNALED(status)) {
|
|
|
668e95 |
print_signalled(tcp, pid, status);
|
|
|
668e95 |
droptcb(tcp);
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ continue; /* processing tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
if (WIFEXITED(status)) {
|
|
|
668e95 |
print_exited(tcp, pid, status);
|
|
|
668e95 |
droptcb(tcp);
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ continue; /* processing tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
if (!WIFSTOPPED(status)) {
|
|
|
668e95 |
@@ -2386,7 +2473,7 @@ trace(void)
|
|
|
668e95 |
*/
|
|
|
668e95 |
error_msg("pid %u not stopped!", pid);
|
|
|
668e95 |
droptcb(tcp);
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ continue; /* processing tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
/* Is this the very first time we see this tracee stopped? */
|
|
|
668e95 |
@@ -2467,7 +2554,7 @@ show_stopsig:
|
|
|
668e95 |
exit_code = 1;
|
|
|
668e95 |
return false;
|
|
|
668e95 |
}
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ continue; /* processing tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
/* We don't have PTRACE_LISTEN support... */
|
|
|
668e95 |
goto restart_tracee;
|
|
|
668e95 |
@@ -2494,7 +2581,7 @@ show_stopsig:
|
|
|
668e95 |
* we can let this process to report its death to us
|
|
|
668e95 |
* normally, via WIFEXITED or WIFSIGNALED wait status.
|
|
|
668e95 |
*/
|
|
|
668e95 |
- return true;
|
|
|
668e95 |
+ continue; /* processing tcbs */
|
|
|
668e95 |
}
|
|
|
668e95 |
goto restart_tracee;
|
|
|
668e95 |
|
|
|
668e95 |
@@ -2508,6 +2595,8 @@ restart_tracee:
|
|
|
668e95 |
return false;
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
+ } /* RH 851457 - process tcbs */
|
|
|
668e95 |
+
|
|
|
668e95 |
return true;
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
diff -rup a/syscall.c b/syscall.c
|
|
|
668e95 |
--- a/syscall.c 2017-05-22 13:33:51.000000000 -0400
|
|
|
668e95 |
+++ b/syscall.c 2017-06-15 14:25:56.153524001 -0400
|
|
|
668e95 |
@@ -568,7 +568,6 @@ clear_regs(void)
|
|
|
668e95 |
get_regs_error = -1;
|
|
|
668e95 |
}
|
|
|
668e95 |
|
|
|
668e95 |
-static void get_regs(pid_t pid);
|
|
|
668e95 |
static int get_syscall_args(struct tcb *);
|
|
|
668e95 |
static int get_syscall_result(struct tcb *);
|
|
|
668e95 |
static int arch_get_scno(struct tcb *tcp);
|
|
|
668e95 |
@@ -1163,7 +1162,7 @@ ptrace_setregs(pid_t pid)
|
|
|
668e95 |
|
|
|
668e95 |
#endif /* ARCH_REGS_FOR_GETREGSET || ARCH_REGS_FOR_GETREGS */
|
|
|
668e95 |
|
|
|
668e95 |
-static void
|
|
|
668e95 |
+void
|
|
|
668e95 |
get_regs(pid_t pid)
|
|
|
668e95 |
{
|
|
|
668e95 |
#undef USE_GET_SYSCALL_RESULT_REGS
|