Fix multiple personalities support in parser of io_submit syscall
Introduce a new helper function to fetch tracee's long integers
and use it to fix multiple personalities support in io_submit parser.
* defs.h (umove_long_or_printaddr): New prototype.
* util.c (umove_long_or_printaddr): New function.
* aio.c (sys_io_submit): Use it to fetch tracee's pointers.
* tests/aio.c: New file.
* tests/aio.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add aio.
(TESTS): Add aio.test.
* tests/.gitignore: Add aio.
diff --git a/aio.c b/aio.c
index 83bb671..5822a4f 100644
--- a/aio.c
+++ b/aio.c
@@ -109,26 +109,30 @@
tprintf("%lu, %ld, [", tcp->u_arg[0], tcp->u_arg[1]);
{
long i;
- struct iocb **iocbs = (void *)tcp->u_arg[2];
-//FIXME: decoding of 32-bit call by 64-bit strace
+ long iocbs = tcp->u_arg[2];
- for (i = 0; i < nr; i++, iocbs++) {
+ for (i = 0; i < nr; ++i, iocbs += current_wordsize) {
enum iocb_sub sub;
- struct iocb *iocbp;
+ long iocbp;
struct iocb iocb;
+
if (i)
tprints(", ");
- if (umove_or_printaddr(tcp, (unsigned long)iocbs, &iocbp)) {
- /* No point in trying to read iocbs+1 etc */
- /* (nr can be ridiculously large): */
+ if (umove_long_or_printaddr(tcp, iocbs, &iocbp)) {
+ /*
+ * No point in trying to read the whole array
+ * because nr can be ridiculously large.
+ */
break;
}
+
tprints("{");
- if (umove_or_printaddr(tcp, (unsigned long)iocbp, &iocb)) {
+ if (umove_or_printaddr(tcp, iocbp, &iocb)) {
tprints("}");
continue;
}
+
if (iocb.data) {
tprints("data=");
printaddr((long) iocb.data);
diff --git a/defs.h b/defs.h
index 20587c7..7f9c3a3 100644
--- a/defs.h
+++ b/defs.h
@@ -476,6 +476,7 @@
extern int umoven_or_printaddr(struct tcb *, long, unsigned int, void *);
#define umove_or_printaddr(pid, addr, objp) \
umoven_or_printaddr((pid), (addr), sizeof(*(objp)), (void *) (objp))
+extern int umove_long_or_printaddr(struct tcb *, long, long *);
extern int umovestr(struct tcb *, long, unsigned int, char *);
extern int upeek(int pid, long, long *);
diff --git a/tests/.gitignore b/tests/.gitignore
index b272ceb..6326d40 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,3 +1,4 @@
+aio
bpf
caps
epoll_create1
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0876a46..9b1703c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -9,6 +9,7 @@
-I$(top_srcdir)/$(OS)
check_PROGRAMS = \
+ aio \
bpf \
caps \
epoll_create1 \
@@ -78,6 +79,7 @@
strace-f.test \
qual_syscall.test \
bexecve.test \
+ aio.test \
bpf.test \
caps.test \
dumpio.test \
diff --git a/tests/aio.c b/tests/aio.c
new file mode 100644
index 0000000..a59ae8e
--- /dev/null
+++ b/tests/aio.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/syscall.h>
+
+#if defined __NR_io_setup \
+ && defined __NR_io_submit \
+ && defined __NR_io_getevents \
+ && defined __NR_io_destroy
+# include <linux/aio_abi.h>
+
+int
+main(void)
+{
+ static char data0[4096];
+ static char data1[8192];
+
+ struct iocb cb[2] = {
+ {
+ .aio_data = 0x11111111,
+ .aio_reqprio = 11,
+ .aio_buf = (unsigned long) data0,
+ .aio_offset = 0xdefacedfacefeed,
+ .aio_nbytes = sizeof(data0)
+ },
+ {
+ .aio_data = 0x22222222,
+ .aio_reqprio = 22,
+ .aio_buf = (unsigned long) data1,
+ .aio_offset = 0xdefacedcafef00d,
+ .aio_nbytes = sizeof(data1)
+ }
+ };
+
+ long cbs[4] = {
+ (long) &cb[0], (long) &cb[1],
+ 0xdeadbeef, 0xbadc0ded
+ };
+
+ unsigned long ctx = 0;
+ const unsigned int nr = sizeof(cb) / sizeof(*cb);
+ const unsigned long lnr = (unsigned long) (0xdeadbeef00000000ULL | nr);
+
+ struct io_event ev[nr];
+ struct timespec ts = { .tv_nsec = 123456789 };
+
+ (void) close(0);
+ if (open("/dev/zero", O_RDONLY))
+ return 77;
+
+ if (syscall(__NR_io_setup, lnr, &ctx))
+ return 77;
+ printf("io_setup(%u, [%lu]) = 0\n", nr, ctx);
+
+ if (syscall(__NR_io_submit, ctx, nr, cbs) != (long) nr)
+ return 77;
+ printf("io_submit(%lu, %u, ["
+ "{data=%#llx, pread, reqprio=11, filedes=0, "
+ "buf=%p, nbytes=%u, offset=%lld}, "
+ "{data=%#llx, pread, reqprio=22, filedes=0, "
+ "buf=%p, nbytes=%u, offset=%lld}"
+ "]) = %u\n",
+ ctx, nr,
+ (unsigned long long) cb[0].aio_data, data0,
+ (unsigned int) sizeof(data0), (long long) cb[0].aio_offset,
+ (unsigned long long) cb[1].aio_data, data1,
+ (unsigned int) sizeof(data1), (long long) cb[1].aio_offset,
+ nr);
+
+ if (syscall(__NR_io_getevents, ctx, nr, nr, ev, &ts) != (long) nr)
+ return 77;
+ printf("io_getevents(%lu, %u, %u, ["
+ "{data=%#llx, obj=%p, res=%u, res2=0}, "
+ "{data=%#llx, obj=%p, res=%u, res2=0}"
+ "], {0, 123456789}) = %u\n",
+ ctx, nr, nr,
+ (unsigned long long) cb[0].aio_data, &cb[0],
+ (unsigned int) sizeof(data0),
+ (unsigned long long) cb[1].aio_data, &cb[1],
+ (unsigned int) sizeof(data1),
+ nr);
+
+ if (syscall(__NR_io_destroy, ctx))
+ return 77;
+ printf("io_destroy(%lu) = 0\n", ctx);
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
+
+#else
+
+int
+main(void)
+{
+ return 77;
+}
+
+#endif
diff --git a/tests/aio.test b/tests/aio.test
new file mode 100755
index 0000000..f5907e4
--- /dev/null
+++ b/tests/aio.test
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Check io_* syscalls decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog > /dev/null
+OUT="$LOG.out"
+syscalls=io_setup,io_submit,io_getevents,io_destroy
+run_strace -a14 -e trace=$syscalls $args > "$OUT"
+match_diff "$LOG" "$OUT"
+rm -f "$OUT"
+
+exit 0
diff --git a/util.c b/util.c
index 94d9265..d40eafc 100644
--- a/util.c
+++ b/util.c
@@ -1132,6 +1132,19 @@
return 0;
}
+int
+umove_long_or_printaddr(struct tcb *tcp, const long addr, long *ptr)
+{
+ if (current_wordsize < sizeof(*ptr)) {
+ uint32_t val32;
+ int r = umove_or_printaddr(tcp, addr, &val32);
+ if (!r)
+ *ptr = (unsigned long) val32;
+ return r;
+ }
+ return umove_or_printaddr(tcp, addr, ptr);
+}
+
/*
* Like `umove' but make the additional effort of looking
* for a terminating zero byte.