process.c: move waitpid, wait4, osf_wait4, and waitid parsers to a separate file

* wait.c: New file.
* Makefile.am (strace_SOURCES): Add it.
* process.c: Move sys_waitpid, sys_wait4, sys_osf_wait4, sys_waitid and
related code to wait.c.
diff --git a/wait.c b/wait.c
new file mode 100644
index 0000000..5380864
--- /dev/null
+++ b/wait.c
@@ -0,0 +1,167 @@
+#include "defs.h"
+
+#include <sys/wait.h>
+
+#ifndef __WNOTHREAD
+# define __WNOTHREAD	0x20000000
+#endif
+#ifndef __WALL
+# define __WALL		0x40000000
+#endif
+#ifndef __WCLONE
+# define __WCLONE	0x80000000
+#endif
+
+#include "xlat/wait4_options.h"
+
+#if !defined WCOREFLAG && defined WCOREFLG
+# define WCOREFLAG WCOREFLG
+#endif
+#ifndef WCOREFLAG
+# define WCOREFLAG 0x80
+#endif
+#ifndef WCOREDUMP
+# define WCOREDUMP(status)  ((status) & 0200)
+#endif
+#ifndef W_STOPCODE
+# define W_STOPCODE(sig)  ((sig) << 8 | 0x7f)
+#endif
+#ifndef W_EXITCODE
+# define W_EXITCODE(ret, sig)  ((ret) << 8 | (sig))
+#endif
+
+static int
+printstatus(int status)
+{
+	int exited = 0;
+
+	/*
+	 * Here is a tricky presentation problem.  This solution
+	 * is still not entirely satisfactory but since there
+	 * are no wait status constructors it will have to do.
+	 */
+	if (WIFSTOPPED(status)) {
+		tprintf("[{WIFSTOPPED(s) && WSTOPSIG(s) == %s}",
+			signame(WSTOPSIG(status)));
+		status &= ~W_STOPCODE(WSTOPSIG(status));
+	}
+	else if (WIFSIGNALED(status)) {
+		tprintf("[{WIFSIGNALED(s) && WTERMSIG(s) == %s%s}",
+			signame(WTERMSIG(status)),
+			WCOREDUMP(status) ? " && WCOREDUMP(s)" : "");
+		status &= ~(W_EXITCODE(0, WTERMSIG(status)) | WCOREFLAG);
+	}
+	else if (WIFEXITED(status)) {
+		tprintf("[{WIFEXITED(s) && WEXITSTATUS(s) == %d}",
+			WEXITSTATUS(status));
+		exited = 1;
+		status &= ~W_EXITCODE(WEXITSTATUS(status), 0);
+	}
+	else {
+		tprintf("[%#x]", status);
+		return 0;
+	}
+
+	if (status == 0)
+		tprints("]");
+	else
+		tprintf(" | %#x]", status);
+
+	return exited;
+}
+
+static int
+printwaitn(struct tcb *tcp, int n, int bitness)
+{
+	int status;
+
+	if (entering(tcp)) {
+		/* On Linux, kernel-side pid_t is typedef'ed to int
+		 * on all arches. Also, glibc-2.8 truncates wait3 and wait4
+		 * pid argument to int on 64bit arches, producing,
+		 * for example, wait4(4294967295, ...) instead of -1
+		 * in strace. We have to use int here, not long.
+		 */
+		int pid = tcp->u_arg[0];
+		tprintf("%d, ", pid);
+	} else {
+		/* status */
+		if (!tcp->u_arg[1])
+			tprints("NULL");
+		else if (syserror(tcp) || tcp->u_rval == 0)
+			tprintf("%#lx", tcp->u_arg[1]);
+		else if (umove(tcp, tcp->u_arg[1], &status) < 0)
+			tprints("[?]");
+		else
+			printstatus(status);
+		/* options */
+		tprints(", ");
+		printflags(wait4_options, tcp->u_arg[2], "W???");
+		if (n == 4) {
+			tprints(", ");
+			/* usage */
+			if (!tcp->u_arg[3])
+				tprints("NULL");
+			else if (tcp->u_rval > 0) {
+#ifdef ALPHA
+				if (bitness)
+					printrusage32(tcp, tcp->u_arg[3]);
+				else
+#endif
+					printrusage(tcp, tcp->u_arg[3]);
+			}
+			else
+				tprintf("%#lx", tcp->u_arg[3]);
+		}
+	}
+	return 0;
+}
+
+int
+sys_waitpid(struct tcb *tcp)
+{
+	return printwaitn(tcp, 3, 0);
+}
+
+int
+sys_wait4(struct tcb *tcp)
+{
+	return printwaitn(tcp, 4, 0);
+}
+
+#ifdef ALPHA
+int
+sys_osf_wait4(struct tcb *tcp)
+{
+	return printwaitn(tcp, 4, 1);
+}
+#endif
+
+#include "xlat/waitid_types.h"
+
+int
+sys_waitid(struct tcb *tcp)
+{
+	if (entering(tcp)) {
+		printxval(waitid_types, tcp->u_arg[0], "P_???");
+		tprintf(", %ld, ", tcp->u_arg[1]);
+	}
+	else {
+		/* siginfo */
+		printsiginfo_at(tcp, tcp->u_arg[2]);
+		/* options */
+		tprints(", ");
+		printflags(wait4_options, tcp->u_arg[3], "W???");
+		if (tcp->s_ent->nargs > 4) {
+			/* usage */
+			tprints(", ");
+			if (!tcp->u_arg[4])
+				tprints("NULL");
+			else if (tcp->u_error)
+				tprintf("%#lx", tcp->u_arg[4]);
+			else
+				printrusage(tcp, tcp->u_arg[4]);
+		}
+	}
+	return 0;
+}