Blame SOURCES/strace-rhbz1610774-0000-strace.c-introduce-struct-tcb_wait_data.patch

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