|
|
4d44fe |
From acdd2e8d3d1551b41170a24951addb80b0b0d423 Mon Sep 17 00:00:00 2001
|
|
|
4d44fe |
From: "Dmitry V. Levin" <ldv@altlinux.org>
|
|
|
4d44fe |
Date: Tue, 14 Aug 2018 13:43:34 +0000
|
|
|
4d44fe |
Subject: [PATCH 04/27] strace.c: introduce struct tcb_wait_data
|
|
|
4d44fe |
|
|
|
4d44fe |
Introduce a new structure to pass information between next_event(),
|
|
|
4d44fe |
restart_delayed_tcb(), and dispatch_event().
|
|
|
4d44fe |
|
|
|
4d44fe |
This is going to be used by a subsequent change of next_event().
|
|
|
4d44fe |
|
|
|
4d44fe |
* strace.c (struct tcb_wait_data): New type.
|
|
|
4d44fe |
(next_event): Remove parameters, return a pointer
|
|
|
4d44fe |
to const struct tcb_wait_data. Return NULL instead of TE_BREAK.
|
|
|
4d44fe |
(dispatch_event): Replace all parameters with a pointer
|
|
|
4d44fe |
to const struct tcb_wait_data, obtain the trace event, siginfo,
|
|
|
4d44fe |
and status from its fields.
|
|
|
4d44fe |
(restart_delayed_tcb): Add local struct tcb_wait_data variable
|
|
|
4d44fe |
with te field set to TE_RESTART, pass it to dispatch_event().
|
|
|
4d44fe |
(main): Remove status and si variables, update next_event()
|
|
|
4d44fe |
and dispatch_event() invocations.
|
|
|
4d44fe |
|
|
|
4d44fe |
Co-Authored-by: Eugene Syromyatnikov <evgsyr@gmail.com>
|
|
|
4d44fe |
---
|
|
|
4d44fe |
strace.c | 107 ++++++++++++++++++++++++++++++++++++++++-----------------------
|
|
|
4d44fe |
1 file changed, 69 insertions(+), 38 deletions(-)
|
|
|
4d44fe |
|
|
|
4d44fe |
diff --git a/strace.c b/strace.c
|
|
|
4d44fe |
index cd04b98..6d70d20 100644
|
|
|
4d44fe |
--- a/strace.c
|
|
|
4d44fe |
+++ b/strace.c
|
|
|
4d44fe |
@@ -158,6 +158,12 @@ static bool open_append;
|
|
|
4d44fe |
struct tcb *printing_tcp;
|
|
|
4d44fe |
static struct tcb *current_tcp;
|
|
|
4d44fe |
|
|
|
4d44fe |
+struct tcb_wait_data {
|
|
|
4d44fe |
+ enum trace_event te; /**< Event passed to dispatch_event() */
|
|
|
4d44fe |
+ int status; /**< status, returned by wait4() */
|
|
|
4d44fe |
+ siginfo_t si; /**< siginfo, returned by PTRACE_GETSIGINFO */
|
|
|
4d44fe |
+};
|
|
|
4d44fe |
+
|
|
|
4d44fe |
static struct tcb **tcbtab;
|
|
|
4d44fe |
static unsigned int nprocs;
|
|
|
4d44fe |
static size_t tcbtabsize;
|
|
|
4d44fe |
@@ -2226,16 +2232,19 @@ print_event_exit(struct tcb *tcp)
|
|
|
4d44fe |
line_ended();
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
-static enum trace_event
|
|
|
4d44fe |
-next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
+static const struct tcb_wait_data *
|
|
|
4d44fe |
+next_event(void)
|
|
|
4d44fe |
{
|
|
|
4d44fe |
+ static struct tcb_wait_data wait_data;
|
|
|
4d44fe |
+
|
|
|
4d44fe |
int pid;
|
|
|
4d44fe |
int status;
|
|
|
4d44fe |
struct tcb *tcp;
|
|
|
4d44fe |
+ struct tcb_wait_data *wd = &wait_data;
|
|
|
4d44fe |
struct rusage ru;
|
|
|
4d44fe |
|
|
|
4d44fe |
if (interrupted)
|
|
|
4d44fe |
- return TE_BREAK;
|
|
|
4d44fe |
+ return NULL;
|
|
|
4d44fe |
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
* Used to exit simply when nprocs hits zero, but in this testcase:
|
|
|
4d44fe |
@@ -2255,7 +2264,7 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
* on exit. Oh well...
|
|
|
4d44fe |
*/
|
|
|
4d44fe |
if (nprocs == 0)
|
|
|
4d44fe |
- return TE_BREAK;
|
|
|
4d44fe |
+ return NULL;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
const bool unblock_delay_timer = is_delay_timer_armed();
|
|
|
4d44fe |
@@ -2278,7 +2287,7 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
* then the system call will be interrupted and
|
|
|
4d44fe |
* the expiration will be handled by the signal handler.
|
|
|
4d44fe |
*/
|
|
|
4d44fe |
- pid = wait4(-1, pstatus, __WALL, (cflag ? &ru : NULL));
|
|
|
4d44fe |
+ pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL));
|
|
|
4d44fe |
const int wait_errno = errno;
|
|
|
4d44fe |
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
@@ -2292,14 +2301,16 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
sigprocmask(SIG_BLOCK, &timer_set, NULL);
|
|
|
4d44fe |
|
|
|
4d44fe |
if (restart_failed)
|
|
|
4d44fe |
- return TE_BREAK;
|
|
|
4d44fe |
+ return NULL;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
if (pid < 0) {
|
|
|
4d44fe |
- if (wait_errno == EINTR)
|
|
|
4d44fe |
- return TE_NEXT;
|
|
|
4d44fe |
+ if (wait_errno == EINTR) {
|
|
|
4d44fe |
+ wd->te = TE_NEXT;
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
+ }
|
|
|
4d44fe |
if (nprocs == 0 && wait_errno == ECHILD)
|
|
|
4d44fe |
- return TE_BREAK;
|
|
|
4d44fe |
+ return NULL;
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
* If nprocs > 0, ECHILD is not expected,
|
|
|
4d44fe |
* treat it as any other error here:
|
|
|
4d44fe |
@@ -2308,12 +2319,13 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
perror_msg_and_die("wait4(__WALL)");
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
- status = *pstatus;
|
|
|
4d44fe |
+ wd->status = status;
|
|
|
4d44fe |
|
|
|
4d44fe |
if (pid == popen_pid) {
|
|
|
4d44fe |
if (!WIFSTOPPED(status))
|
|
|
4d44fe |
popen_pid = 0;
|
|
|
4d44fe |
- return TE_NEXT;
|
|
|
4d44fe |
+ wd->te = TE_NEXT;
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
if (debug_flag)
|
|
|
4d44fe |
@@ -2324,8 +2336,10 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
|
|
|
4d44fe |
if (!tcp) {
|
|
|
4d44fe |
tcp = maybe_allocate_tcb(pid, status);
|
|
|
4d44fe |
- if (!tcp)
|
|
|
4d44fe |
- return TE_NEXT;
|
|
|
4d44fe |
+ if (!tcp) {
|
|
|
4d44fe |
+ wd->te = TE_NEXT;
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
+ }
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
clear_regs(tcp);
|
|
|
4d44fe |
@@ -2342,11 +2356,15 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
tcp->stime = stime;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
- if (WIFSIGNALED(status))
|
|
|
4d44fe |
- return TE_SIGNALLED;
|
|
|
4d44fe |
+ if (WIFSIGNALED(status)) {
|
|
|
4d44fe |
+ wd->te = TE_SIGNALLED;
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
+ }
|
|
|
4d44fe |
|
|
|
4d44fe |
- if (WIFEXITED(status))
|
|
|
4d44fe |
- return TE_EXITED;
|
|
|
4d44fe |
+ if (WIFEXITED(status)) {
|
|
|
4d44fe |
+ wd->te = TE_EXITED;
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
+ }
|
|
|
4d44fe |
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
* As WCONTINUED flag has not been specified to wait4,
|
|
|
4d44fe |
@@ -2373,19 +2391,19 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
if (sig == SIGSTOP && (tcp->flags & TCB_IGNORE_ONE_SIGSTOP)) {
|
|
|
4d44fe |
debug_func_msg("ignored SIGSTOP on pid %d", tcp->pid);
|
|
|
4d44fe |
tcp->flags &= ~TCB_IGNORE_ONE_SIGSTOP;
|
|
|
4d44fe |
- return TE_RESTART;
|
|
|
4d44fe |
+ wd->te = TE_RESTART;
|
|
|
4d44fe |
} else if (sig == syscall_trap_sig) {
|
|
|
4d44fe |
- return TE_SYSCALL_STOP;
|
|
|
4d44fe |
+ wd->te = TE_SYSCALL_STOP;
|
|
|
4d44fe |
} else {
|
|
|
4d44fe |
- *si = (siginfo_t) {};
|
|
|
4d44fe |
+ memset(&wd->si, 0, sizeof(wd->si));
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
* True if tracee is stopped by signal
|
|
|
4d44fe |
* (as opposed to "tracee received signal").
|
|
|
4d44fe |
* TODO: shouldn't we check for errno == EINVAL too?
|
|
|
4d44fe |
* We can get ESRCH instead, you know...
|
|
|
4d44fe |
*/
|
|
|
4d44fe |
- bool stopped = ptrace(PTRACE_GETSIGINFO, pid, 0, si) < 0;
|
|
|
4d44fe |
- return stopped ? TE_GROUP_STOP : TE_SIGNAL_DELIVERY_STOP;
|
|
|
4d44fe |
+ bool stopped = ptrace(PTRACE_GETSIGINFO, pid, 0, &wd->si) < 0;
|
|
|
4d44fe |
+ wd->te = stopped ? TE_GROUP_STOP : TE_SIGNAL_DELIVERY_STOP;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
break;
|
|
|
4d44fe |
case PTRACE_EVENT_STOP:
|
|
|
4d44fe |
@@ -2398,16 +2416,23 @@ next_event(int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
case SIGTSTP:
|
|
|
4d44fe |
case SIGTTIN:
|
|
|
4d44fe |
case SIGTTOU:
|
|
|
4d44fe |
- return TE_GROUP_STOP;
|
|
|
4d44fe |
+ wd->te = TE_GROUP_STOP;
|
|
|
4d44fe |
+ break;
|
|
|
4d44fe |
+ default:
|
|
|
4d44fe |
+ wd->te = TE_RESTART;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
- return TE_RESTART;
|
|
|
4d44fe |
+ break;
|
|
|
4d44fe |
case PTRACE_EVENT_EXEC:
|
|
|
4d44fe |
- return TE_STOP_BEFORE_EXECVE;
|
|
|
4d44fe |
+ wd->te = TE_STOP_BEFORE_EXECVE;
|
|
|
4d44fe |
+ break;
|
|
|
4d44fe |
case PTRACE_EVENT_EXIT:
|
|
|
4d44fe |
- return TE_STOP_BEFORE_EXIT;
|
|
|
4d44fe |
+ wd->te = TE_STOP_BEFORE_EXIT;
|
|
|
4d44fe |
+ break;
|
|
|
4d44fe |
default:
|
|
|
4d44fe |
- return TE_RESTART;
|
|
|
4d44fe |
+ wd->te = TE_RESTART;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
+
|
|
|
4d44fe |
+ return wd;
|
|
|
4d44fe |
}
|
|
|
4d44fe |
|
|
|
4d44fe |
static int
|
|
|
4d44fe |
@@ -2436,12 +2461,18 @@ trace_syscall(struct tcb *tcp, unsigned int *sig)
|
|
|
4d44fe |
|
|
|
4d44fe |
/* Returns true iff the main trace loop has to continue. */
|
|
|
4d44fe |
static bool
|
|
|
4d44fe |
-dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
+dispatch_event(const struct tcb_wait_data *wd)
|
|
|
4d44fe |
{
|
|
|
4d44fe |
unsigned int restart_op = PTRACE_SYSCALL;
|
|
|
4d44fe |
unsigned int restart_sig = 0;
|
|
|
4d44fe |
+ enum trace_event te = wd ? wd->te : TE_BREAK;
|
|
|
4d44fe |
+ /*
|
|
|
4d44fe |
+ * Copy wd->status to a non-const variable to workaround glibc bugs
|
|
|
4d44fe |
+ * around union wait fixed by glibc commit glibc-2.24~391
|
|
|
4d44fe |
+ */
|
|
|
4d44fe |
+ int status = wd ? wd->status : 0;
|
|
|
4d44fe |
|
|
|
4d44fe |
- switch (ret) {
|
|
|
4d44fe |
+ switch (te) {
|
|
|
4d44fe |
case TE_BREAK:
|
|
|
4d44fe |
return false;
|
|
|
4d44fe |
|
|
|
4d44fe |
@@ -2469,17 +2500,17 @@ dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
break;
|
|
|
4d44fe |
|
|
|
4d44fe |
case TE_SIGNAL_DELIVERY_STOP:
|
|
|
4d44fe |
- restart_sig = WSTOPSIG(*pstatus);
|
|
|
4d44fe |
- print_stopped(current_tcp, si, restart_sig);
|
|
|
4d44fe |
+ restart_sig = WSTOPSIG(status);
|
|
|
4d44fe |
+ print_stopped(current_tcp, &wd->si, restart_sig);
|
|
|
4d44fe |
break;
|
|
|
4d44fe |
|
|
|
4d44fe |
case TE_SIGNALLED:
|
|
|
4d44fe |
- print_signalled(current_tcp, current_tcp->pid, *pstatus);
|
|
|
4d44fe |
+ print_signalled(current_tcp, current_tcp->pid, status);
|
|
|
4d44fe |
droptcb(current_tcp);
|
|
|
4d44fe |
return true;
|
|
|
4d44fe |
|
|
|
4d44fe |
case TE_GROUP_STOP:
|
|
|
4d44fe |
- restart_sig = WSTOPSIG(*pstatus);
|
|
|
4d44fe |
+ restart_sig = WSTOPSIG(status);
|
|
|
4d44fe |
print_stopped(current_tcp, NULL, restart_sig);
|
|
|
4d44fe |
if (use_seize) {
|
|
|
4d44fe |
/*
|
|
|
4d44fe |
@@ -2494,7 +2525,7 @@ dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
break;
|
|
|
4d44fe |
|
|
|
4d44fe |
case TE_EXITED:
|
|
|
4d44fe |
- print_exited(current_tcp, current_tcp->pid, *pstatus);
|
|
|
4d44fe |
+ print_exited(current_tcp, current_tcp->pid, status);
|
|
|
4d44fe |
droptcb(current_tcp);
|
|
|
4d44fe |
return true;
|
|
|
4d44fe |
|
|
|
4d44fe |
@@ -2577,13 +2608,15 @@ dispatch_event(enum trace_event ret, int *pstatus, siginfo_t *si)
|
|
|
4d44fe |
static bool
|
|
|
4d44fe |
restart_delayed_tcb(struct tcb *const tcp)
|
|
|
4d44fe |
{
|
|
|
4d44fe |
+ const struct tcb_wait_data wd = { .te = TE_RESTART };
|
|
|
4d44fe |
+
|
|
|
4d44fe |
debug_func_msg("pid %d", tcp->pid);
|
|
|
4d44fe |
|
|
|
4d44fe |
tcp->flags &= ~TCB_DELAYED;
|
|
|
4d44fe |
|
|
|
4d44fe |
struct tcb *const prev_tcp = current_tcp;
|
|
|
4d44fe |
current_tcp = tcp;
|
|
|
4d44fe |
- bool ret = dispatch_event(TE_RESTART, NULL, NULL);
|
|
|
4d44fe |
+ bool ret = dispatch_event(&wd;;
|
|
|
4d44fe |
current_tcp = prev_tcp;
|
|
|
4d44fe |
|
|
|
4d44fe |
return ret;
|
|
|
4d44fe |
@@ -2694,9 +2727,7 @@ main(int argc, char *argv[])
|
|
|
4d44fe |
|
|
|
4d44fe |
exit_code = !nprocs;
|
|
|
4d44fe |
|
|
|
4d44fe |
- int status;
|
|
|
4d44fe |
- siginfo_t si;
|
|
|
4d44fe |
- while (dispatch_event(next_event(&status, &si), &status, &si))
|
|
|
4d44fe |
+ while (dispatch_event(next_event()))
|
|
|
4d44fe |
;
|
|
|
4d44fe |
terminate();
|
|
|
4d44fe |
}
|
|
|
4d44fe |
--
|
|
|
4d44fe |
2.1.4
|
|
|
4d44fe |
|