Enhance io_submit() decoding

strace didn't decode important fields in the iocb passed to io_submit.
This patch changes the code to dump them all.  Also it prefixes the fields
with names to make it easier to read.

* desc.c (iocb_cmd_lookup, print_common_flags): New functions.
(sys_io_submit): New iocb decoder.
diff --git a/desc.c b/desc.c
index 293bfa4..f9100c4 100644
--- a/desc.c
+++ b/desc.c
@@ -815,6 +815,51 @@
 	return 0;
 }
 
+enum iocb_sub {
+	SUB_NONE, SUB_COMMON, SUB_POLL, SUB_VECTOR
+};
+
+static const char *
+iocb_cmd_lookup(unsigned cmd, enum iocb_sub *sub)
+{
+	static char buf[64];
+	static struct {
+		const char *name;
+		enum iocb_sub sub;
+	} cmds[] = {
+		{ "pread", SUB_COMMON },
+		{ "pwrite", SUB_COMMON },
+		{ "fsync", SUB_NONE },
+		{ "fdsync", SUB_NONE },
+		{ "op4", SUB_NONE },
+		{ "poll", SUB_POLL },
+		{ "noop", SUB_NONE },
+		{ "preadv", SUB_VECTOR },
+		{ "pwritev", SUB_VECTOR },
+	};
+
+	if (cmd < ARRAY_SIZE(cmds)) {
+		*sub = cmds[cmd].sub;
+		return cmds[cmd].name;
+	}
+	*sub = SUB_NONE;
+	snprintf(buf, sizeof(buf), "%u /* SUB_??? */", cmd);
+	return buf;
+}
+
+/* Not defined in libaio.h */
+#ifndef IOCB_RESFD
+# define IOCB_RESFD (1 << 0)
+#endif
+
+static void
+print_common_flags(struct iocb *iocb)
+{
+	if (iocb->u.c.flags & IOCB_RESFD)
+		tprintf("resfd=%d, ", iocb->u.c.resfd);
+	if (iocb->u.c.flags & ~IOCB_RESFD)
+		tprintf("flags=%x, ", iocb->u.c.flags);
+}
 int
 sys_io_submit(struct tcb *tcp)
 {
@@ -831,6 +876,7 @@
 			struct iocb *iocbp, **iocbs = (void *)tcp->u_arg[2];
 
 			for (i = 0; i < nr; i++, iocbs++) {
+				enum iocb_sub sub;
 				struct iocb iocb;
 				if (i == 0)
 					tprintf("{");
@@ -842,15 +888,49 @@
 					tprintf("{...}");
 					continue;
 				}
-				tprintf("{%p, %u, %hu, %hu, %d}",
-					iocb.data, iocb.key,
-					iocb.aio_lio_opcode,
-					iocb.aio_reqprio, iocb.aio_fildes);
+				tprintf("{");
+				if (iocb.data)
+					tprintf("data:%p, ", iocb.data);
+				if (iocb.key)
+					tprintf("key:%u, ", iocb.key);
+				tprintf("%s, ", iocb_cmd_lookup(iocb.aio_lio_opcode, &sub));
+				if (iocb.aio_reqprio)
+					tprintf("reqprio:%d, ", iocb.aio_reqprio);
+				tprintf("filedes:%d", iocb.aio_fildes);
+				switch (sub) {
+				case SUB_COMMON:
+					if (iocb.aio_lio_opcode == IO_CMD_PWRITE) {
+						tprintf(", str:");
+						printstr(tcp, (unsigned long)iocb.u.c.buf,
+							 iocb.u.c.nbytes);
+					} else {
+						tprintf(", buf:%p", iocb.u.c.buf);
+					}
+					tprintf(", nbytes:%lu, offset:%llx",
+						iocb.u.c.nbytes,
+						iocb.u.c.offset);
+					print_common_flags(&iocb);
+					break;
+				case SUB_VECTOR:
+					tprintf(", %llx, ", iocb.u.v.offset);
+					print_common_flags(&iocb);
+					tprint_iov(tcp, iocb.u.v.nr,
+						   (unsigned long)iocb.u.v.vec,
+						   iocb.aio_lio_opcode == IO_CMD_PWRITEV);
+					break;
+				case SUB_POLL:
+					tprintf(", %x", iocb.u.poll.events);
+					break;
+				case SUB_NONE:
+				        break;
+				}
+				tprintf("}");
 			}
 			if (i)
 				tprintf("}");
 #else
-			tprintf("{...}");
+#warning "libaio-devel is not available => no io_submit decoding"
+			tprintf("%#lx", tcp->u_arg[2]);
 #endif
 		}
 	}