diff --git a/NEWS b/NEWS index 6c588593..3ea553f9 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,9 @@ Noteworthy changes in release ?.?? (????-??-??) * Improvements * Enhanced decoding of sched_setattr syscall. +* Bug fixes + * Fixed decoding of flags argument of preadv2 and pwritev2 syscalls on x32. + Noteworthy changes in release 4.16 (2017-02-14) =============================================== diff --git a/io.c b/io.c index c41b66fa..a4f6b8e8 100644 --- a/io.c +++ b/io.c @@ -224,11 +224,6 @@ SYS_FUNC(preadv) return do_preadv(tcp, -1); } -SYS_FUNC(preadv2) -{ - return do_preadv(tcp, 5); -} - static int do_pwritev(struct tcb *tcp, const int flags_arg) { @@ -253,9 +248,29 @@ SYS_FUNC(pwritev) return do_pwritev(tcp, -1); } +/* + * x32 is the only architecture where preadv2 takes 5 arguments + * instead of 6, see preadv64v2 in kernel sources. + * Likewise, x32 is the only architecture where pwritev2 takes 5 arguments + * instead of 6, see pwritev64v2 in kernel sources. + */ + +#if defined X86_64 +# define PREADV2_PWRITEV2_FLAGS_ARG_NO (current_personality == 2 ? 4 : 5) +#elif defined X32 +# define PREADV2_PWRITEV2_FLAGS_ARG_NO (current_personality == 0 ? 4 : 5) +#else +# define PREADV2_PWRITEV2_FLAGS_ARG_NO 5 +#endif + +SYS_FUNC(preadv2) +{ + return do_preadv(tcp, PREADV2_PWRITEV2_FLAGS_ARG_NO); +} + SYS_FUNC(pwritev2) { - return do_pwritev(tcp, 5); + return do_pwritev(tcp, PREADV2_PWRITEV2_FLAGS_ARG_NO); } #include "xlat/splice_flags.h" diff --git a/linux/x32/syscallent.h b/linux/x32/syscallent.h index 0cda1a65..5f187642 100644 --- a/linux/x32/syscallent.h +++ b/linux/x32/syscallent.h @@ -369,5 +369,5 @@ [543] = { 2, CST|TM, SEN(io_setup), "io_setup" }, [544] = { 3, CST, SEN(io_submit), "io_submit" }, [545] = { 5, CST|TD|TF|TP|SE|SI, SEN(execveat), "execveat" }, -[546] = { 6, TD, SEN(preadv2), "preadv2" }, -[547] = { 6, TD, SEN(pwritev2), "pwritev2" }, +[546] = { 5, TD, SEN(preadv2), "preadv2" }, +[547] = { 5, TD, SEN(pwritev2), "pwritev2" }, diff --git a/tests/preadv2-pwritev2.c b/tests/preadv2-pwritev2.c index f7c46c0a..bcf8b77d 100644 --- a/tests/preadv2-pwritev2.c +++ b/tests/preadv2-pwritev2.c @@ -181,26 +181,45 @@ int main(void) { const kernel_ulong_t vlen = (kernel_ulong_t) 0xfac1fed2dad3bef4ULL; - const unsigned long long pos = 0xfac5fed6dad7bef8; + const unsigned long long pos = 0x7ac5fed6dad7bef8; const kernel_ulong_t pos_l = (kernel_ulong_t) pos; - const kernel_ulong_t pos_h = - (sizeof(kernel_ulong_t) == sizeof(long long)) ? - (kernel_ulong_t) 0xbadc0deddeadbeefULL : 0xfac5fed6UL; - int test_dumpio = 1; + long rc; + int test_dumpio; tprintf("%s", ""); - syscall(__NR_preadv2, -1, NULL, vlen, pos_l, pos_h, 1); - if (ENOSYS == errno) - test_dumpio = 0; - tprintf("preadv2(-1, NULL, %lu, %lld, RWF_HIPRI) = -1 %s (%m)\n", - (unsigned long) vlen, pos, errno2name()); +#if defined __x86_64__ && defined __ILP32__ + /* + * x32 is the only architecture where preadv2 takes 5 arguments, + * see preadv64v2 in kernel sources. + */ + rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, 1); +#else + const kernel_ulong_t pos_h = + (sizeof(pos_l) == sizeof(pos)) ? + (kernel_ulong_t) 0xbadc0deddeadbeefULL : + (kernel_ulong_t) (pos >> 32); + rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, pos_h, 1); +#endif + if (rc != -1 || (ENOSYS != errno && EBADF != errno)) + perror_msg_and_fail("preadv2"); + test_dumpio = EBADF == errno; + tprintf("preadv2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n", + (unsigned long) vlen, pos, sprintrc(rc)); - syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, pos_h, 1); - if (ENOSYS == errno) - test_dumpio = 0; - tprintf("pwritev2(-1, NULL, %lu, %lld, RWF_HIPRI) = -1 %s (%m)\n", - (unsigned long) vlen, pos, errno2name()); +#if defined __x86_64__ && defined __ILP32__ + /* + * x32 is the only architecture where pwritev2 takes 5 arguments, + * see pwritev64v2 in kernel sources. + */ + rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, 1); +#else + rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, pos_h, 1); +#endif + if (rc != -1 || (ENOSYS != errno && EBADF != errno)) + perror_msg_and_fail("pwritev2"); + tprintf("pwritev2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n", + (unsigned long) vlen, pos, sprintrc(rc)); if (test_dumpio) dumpio();