Blame SOURCES/valgrind-3.15.0-preadv2-pwritev2.patch

01cf8b
commit b0861063a8d2a55bb7423e90d26806bab0f78a12
01cf8b
Author: Alexandra Hájková <ahajkova@redhat.com>
01cf8b
Date:   Tue Jun 4 13:47:14 2019 +0200
01cf8b
01cf8b
    Add support for preadv2 and pwritev2 syscalls
01cf8b
    
01cf8b
    Support for amd64, x86 - 64 and 32 bit, arm64, ppc64, ppc64le,
01cf8b
    s390x, mips64. This should work identically on all
01cf8b
    arches, tested on x86 32bit and 64bit one, but enabled on all.
01cf8b
    
01cf8b
    Refactor the code to be reusable between old/new syscalls. Resolve TODO
01cf8b
    items in the code. Add the testcase for the preadv2/pwritev2 and also
01cf8b
    add the (similar) testcase for the older preadv/pwritev syscalls.
01cf8b
    
01cf8b
    Trying to test handling an uninitialized flag argument for the v2 syscalls
01cf8b
    does not work because the flag always comes out as defined zero.
01cf8b
    Turns out glibc does this deliberately on 64bit architectures because
01cf8b
    the kernel does actually have a low_offset and high_offset argument, but
01cf8b
    ignores the high_offset/assumes it is zero.
01cf8b
    https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=601cc11d054ae4b5e9b5babec3d8e4667a2cb9b5
01cf8b
    
01cf8b
    https://bugs.kde.org/408414
01cf8b
01cf8b
diff --git a/configure.ac b/configure.ac
01cf8b
index 352892565..3596d2fec 100755
01cf8b
--- a/configure.ac
01cf8b
+++ b/configure.ac
01cf8b
@@ -4173,6 +4173,10 @@ AC_CHECK_FUNCS([     \
01cf8b
         process_vm_readv  \
01cf8b
         process_vm_writev \
01cf8b
         copy_file_range \
01cf8b
+        preadv \
01cf8b
+        pwritev \
01cf8b
+        preadv2 \
01cf8b
+        pwritev2 \
01cf8b
         ])
01cf8b
 
01cf8b
 # AC_CHECK_LIB adds any library found to the variable LIBS, and links these
01cf8b
@@ -4190,6 +4194,10 @@ AM_CONDITIONAL([HAVE_PTHREAD_SETNAME_NP],
01cf8b
                [test x$ac_cv_func_pthread_setname_np = xyes])
01cf8b
 AM_CONDITIONAL([HAVE_COPY_FILE_RANGE],
01cf8b
                [test x$ac_cv_func_copy_file_range = xyes])
01cf8b
+AM_CONDITIONAL([HAVE_PREADV_PWRITEV],
01cf8b
+               [test x$ac_cv_func_preadv = xyes && test x$ac_cv_func_pwritev = xyes])
01cf8b
+AM_CONDITIONAL([HAVE_PREADV2_PWRITEV2],
01cf8b
+               [test x$ac_cv_func_preadv2 = xyes && test x$ac_cv_func_pwritev2 = xyes])
01cf8b
 
01cf8b
 if test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \
01cf8b
      -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX ; then
01cf8b
diff --git a/coregrind/m_syswrap/priv_syswrap-generic.h b/coregrind/m_syswrap/priv_syswrap-generic.h
01cf8b
index 3e1c8b682..73f9224f7 100644
01cf8b
--- a/coregrind/m_syswrap/priv_syswrap-generic.h
01cf8b
+++ b/coregrind/m_syswrap/priv_syswrap-generic.h
01cf8b
@@ -109,6 +109,19 @@ ML_(handle_auxv_open)(SyscallStatus *status, const HChar *filename,
01cf8b
 /* Helper function for generic mprotect and linux pkey_mprotect. */
01cf8b
 extern void handle_sys_mprotect (ThreadId tid, SyscallStatus *status,
01cf8b
                                  Addr *addr, SizeT *len, Int *prot);
01cf8b
+/* Helper functions for preadv/preadv2. */
01cf8b
+extern
01cf8b
+void handle_pre_sys_preadv(ThreadId tid, SyscallStatus* status,
01cf8b
+                           Int fd, Addr vector, Int count,
01cf8b
+                           const char *str);
01cf8b
+extern
01cf8b
+void handle_post_sys_preadv(ThreadId tid, SyscallStatus* status, Addr vector, Int count);
01cf8b
+
01cf8b
+/* Helper function for pwritev/pwritev2. */
01cf8b
+extern
01cf8b
+void handle_sys_pwritev(ThreadId tid, SyscallStatus* status,
01cf8b
+                        Int fd, Addr vector, Int count,
01cf8b
+                        const char *str);
01cf8b
 
01cf8b
 DECL_TEMPLATE(generic, sys_ni_syscall);            // * P -- unimplemented
01cf8b
 DECL_TEMPLATE(generic, sys_exit);
01cf8b
diff --git a/coregrind/m_syswrap/priv_syswrap-linux.h b/coregrind/m_syswrap/priv_syswrap-linux.h
01cf8b
index be2f9bdde..8ce8ef3d5 100644
01cf8b
--- a/coregrind/m_syswrap/priv_syswrap-linux.h
01cf8b
+++ b/coregrind/m_syswrap/priv_syswrap-linux.h
01cf8b
@@ -46,7 +46,9 @@ DECL_TEMPLATE(linux, sys_oldumount);
01cf8b
 DECL_TEMPLATE(linux, sys_umount);
01cf8b
 DECL_TEMPLATE(linux, sys_perf_event_open);
01cf8b
 DECL_TEMPLATE(linux, sys_preadv);
01cf8b
+DECL_TEMPLATE(linux, sys_preadv2);
01cf8b
 DECL_TEMPLATE(linux, sys_pwritev);
01cf8b
+DECL_TEMPLATE(linux, sys_pwritev2);
01cf8b
 DECL_TEMPLATE(linux, sys_sendmmsg);
01cf8b
 DECL_TEMPLATE(linux, sys_recvmmsg);
01cf8b
 DECL_TEMPLATE(linux, sys_dup3);
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c
01cf8b
index 382dc65cf..9b8068d0f 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-amd64-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-amd64-linux.c
01cf8b
@@ -857,6 +857,8 @@ static SyscallTableEntry syscall_table[] = {
01cf8b
 //   LIN__(__NR_kexec_file_load,   sys_ni_syscall),       // 320
01cf8b
    LINXY(__NR_bpf,               sys_bpf),              // 321
01cf8b
 
01cf8b
+   LINXY(__NR_preadv2,           sys_preadv2),           // 327
01cf8b
+   LINX_(__NR_pwritev2,          sys_pwritev2),          // 328
01cf8b
 
01cf8b
    LINXY(__NR_statx,             sys_statx),             // 332
01cf8b
 
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-arm64-linux.c b/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
index c700e3dbe..d12d40632 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
@@ -818,8 +818,8 @@ static SyscallTableEntry syscall_main_table[] = {
01cf8b
    LINX_(__NR_membarrier,        sys_membarrier),        // 283
01cf8b
    //   (__NR_mlock2,            sys_ni_syscall),        // 284
01cf8b
    LINX_(__NR_copy_file_range,   sys_copy_file_range),   // 285
01cf8b
-   //   (__NR_preadv2,           sys_ni_syscall),        // 286
01cf8b
-   //   (__NR_pwritev2,          sys_ni_syscall),        // 287
01cf8b
+   LINX_(__NR_preadv2,           sys_ni_syscall),        // 286
01cf8b
+   LINX_(__NR_pwritev2,          sys_ni_syscall),        // 287
01cf8b
    //   (__NR_pkey_mprotect,     sys_ni_syscall),        // 288
01cf8b
    //   (__NR_pkey_alloc,        sys_ni_syscall),        // 289
01cf8b
    //   (__NR_pkey_free,         sys_ni_syscall),        // 290
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
01cf8b
index 36d09d6e0..2fe15d97b 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-linux.c
01cf8b
@@ -5501,12 +5501,57 @@ POST(sys_open_by_handle_at)
01cf8b
 /* ---------------------------------------------------------------------
01cf8b
    p{read,write}v wrappers
01cf8b
    ------------------------------------------------------------------ */
01cf8b
+/* This handles the common part of the PRE macro for preadv and preadv2. */
01cf8b
+void handle_pre_sys_preadv(ThreadId tid, SyscallStatus* status,
01cf8b
+                           Int fd, Addr vector, Int count, const char *str)
01cf8b
+{
01cf8b
+   struct vki_iovec * vec;
01cf8b
+   Int i;
01cf8b
+   /* safe size for the "preadv/preadv2(vector[i])" string */
01cf8b
+   char tmp[30];
01cf8b
+
01cf8b
+   if (!ML_(fd_allowed)(fd, str, tid, False)) {
01cf8b
+      SET_STATUS_Failure( VKI_EBADF );
01cf8b
+   } else if (count > 0) {
01cf8b
+      VG_(strcpy) (tmp, str);
01cf8b
+      VG_(strcat) (tmp, "(vector)");
01cf8b
+      PRE_MEM_READ( tmp, vector, count * sizeof(struct vki_iovec) );
01cf8b
+
01cf8b
+      if (ML_(safe_to_deref) ((void *)(Addr)vector,
01cf8b
+                              count * sizeof(struct vki_iovec))) {
01cf8b
+         vec = (struct vki_iovec *)(Addr)vector;
01cf8b
+         for (i = 0; i < count; i++) {
01cf8b
+            VG_(snprintf) (tmp, 30, "%s(vector[%d])", str, i);
01cf8b
+            PRE_MEM_WRITE( tmp, (Addr)vec[i].iov_base, vec[i].iov_len );
01cf8b
+         }
01cf8b
+      }
01cf8b
+   }
01cf8b
+}
01cf8b
+
01cf8b
+/* This handles the common part of the POST macro for preadv and preadv2. */
01cf8b
+void handle_post_sys_preadv(ThreadId tid, SyscallStatus* status, Addr vector, Int count)
01cf8b
+{
01cf8b
+    vg_assert(SUCCESS);
01cf8b
+    if (RES > 0) {
01cf8b
+        Int i;
01cf8b
+        struct vki_iovec * vec = (struct vki_iovec *)(Addr)vector;
01cf8b
+        Int remains = RES;
01cf8b
+
01cf8b
+        /* RES holds the number of bytes read. */
01cf8b
+        for (i = 0; i < count; i++) {
01cf8b
+            Int nReadThisBuf = vec[i].iov_len;
01cf8b
+            if (nReadThisBuf > remains) nReadThisBuf = remains;
01cf8b
+            POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
01cf8b
+            remains -= nReadThisBuf;
01cf8b
+            if (remains < 0) VG_(core_panic)("preadv: remains < 0");
01cf8b
+        }
01cf8b
+    }
01cf8b
+}
01cf8b
 
01cf8b
 PRE(sys_preadv)
01cf8b
 {
01cf8b
-   Int i;
01cf8b
-   struct vki_iovec * vec;
01cf8b
    *flags |= SfMayBlock;
01cf8b
+   const char *str = "preadv";
01cf8b
 #if VG_WORDSIZE == 4
01cf8b
    /* Note that the offset argument here is in lo+hi order on both
01cf8b
       big and little endian platforms... */
01cf8b
@@ -5525,45 +5570,89 @@ PRE(sys_preadv)
01cf8b
 #else
01cf8b
 #  error Unexpected word size
01cf8b
 #endif
01cf8b
-   if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
01cf8b
-      SET_STATUS_Failure( VKI_EBADF );
01cf8b
-   } else {
01cf8b
-      PRE_MEM_READ( "preadv(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) );
01cf8b
+   Int fd = ARG1;
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
+
01cf8b
+   handle_pre_sys_preadv(tid, status, fd, vector, count, str);
01cf8b
 
01cf8b
-      if (ARG2 != 0) {
01cf8b
-         /* ToDo: don't do any of the following if the vector is invalid */
01cf8b
-         vec = (struct vki_iovec *)(Addr)ARG2;
01cf8b
-         for (i = 0; i < (Int)ARG3; i++)
01cf8b
-            PRE_MEM_WRITE( "preadv(vector[...])",
01cf8b
-                           (Addr)vec[i].iov_base, vec[i].iov_len );
01cf8b
-      }
01cf8b
-   }
01cf8b
 }
01cf8b
 
01cf8b
 POST(sys_preadv)
01cf8b
 {
01cf8b
-   vg_assert(SUCCESS);
01cf8b
-   if (RES > 0) {
01cf8b
-      Int i;
01cf8b
-      struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
01cf8b
-      Int remains = RES;
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
 
01cf8b
-      /* RES holds the number of bytes read. */
01cf8b
-      for (i = 0; i < (Int)ARG3; i++) {
01cf8b
-	 Int nReadThisBuf = vec[i].iov_len;
01cf8b
-	 if (nReadThisBuf > remains) nReadThisBuf = remains;
01cf8b
-	 POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
01cf8b
-	 remains -= nReadThisBuf;
01cf8b
-	 if (remains < 0) VG_(core_panic)("preadv: remains < 0");
01cf8b
+   handle_post_sys_preadv(tid, status, vector, count);
01cf8b
+}
01cf8b
+
01cf8b
+PRE(sys_preadv2)
01cf8b
+{
01cf8b
+   *flags |= SfMayBlock;
01cf8b
+   const char *str = "preadv2";
01cf8b
+#if VG_WORDSIZE == 4
01cf8b
+   /* Note that the offset argument here is in lo+hi order on both
01cf8b
+      big and little endian platforms... */
01cf8b
+   PRINT("sys_preadv2 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
01cf8b
+         "u, %lld, %" FMT_REGWORD "u )",
01cf8b
+         ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5), ARG6);
01cf8b
+   PRE_REG_READ6(ssize_t, "preadv2",
01cf8b
+                 unsigned long, fd, const struct iovec *, vector,
01cf8b
+                 unsigned long, count, vki_u32, offset_low,
01cf8b
+                 vki_u32, offset_high, unsigned long, flags);
01cf8b
+#elif VG_WORDSIZE == 8
01cf8b
+   PRINT("sys_preadv2 ( %lu, %#lx, %lu, %ld, %lu )", ARG1, ARG2, ARG3, SARG4, ARG5);
01cf8b
+   PRE_REG_READ5(ssize_t, "preadv2",
01cf8b
+                 unsigned long, fd, const struct iovec *, vector,
01cf8b
+                 unsigned long, count, Word, offset, unsigned long, flags);
01cf8b
+#else
01cf8b
+#  error Unexpected word size
01cf8b
+#endif
01cf8b
+   Int fd = ARG1;
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
+
01cf8b
+   handle_pre_sys_preadv(tid, status, fd, vector, count, str);
01cf8b
+}
01cf8b
+
01cf8b
+POST(sys_preadv2)
01cf8b
+{
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
+
01cf8b
+   handle_post_sys_preadv(tid, status, vector, count);
01cf8b
+}
01cf8b
+
01cf8b
+/* This handles the common part of the PRE macro for pwritev and pwritev2. */
01cf8b
+void handle_sys_pwritev(ThreadId tid, SyscallStatus* status,
01cf8b
+                        Int fd, Addr vector, Int count, const char *str)
01cf8b
+{
01cf8b
+   Int i;
01cf8b
+   struct vki_iovec * vec;
01cf8b
+   /* safe size for the "preadv/preadv2(vector[i])" string */
01cf8b
+   char tmp[30];
01cf8b
+
01cf8b
+   if (!ML_(fd_allowed)(fd, str, tid, False)) {
01cf8b
+      SET_STATUS_Failure( VKI_EBADF );
01cf8b
+   } else if (count > 0) {
01cf8b
+      VG_(strcpy) (tmp, str);
01cf8b
+      VG_(strcat) (tmp, "(vector)");
01cf8b
+      PRE_MEM_READ( tmp, vector, count * sizeof(struct vki_iovec) );
01cf8b
+      if (ML_(safe_to_deref) ((void *)(Addr)vector,
01cf8b
+                              count * sizeof(struct vki_iovec))) {
01cf8b
+         vec = (struct vki_iovec *)(Addr)vector;
01cf8b
+         for (i = 0; i < count; i++) {
01cf8b
+            VG_(snprintf) (tmp, 30, "%s(vector[%d])", str, i);
01cf8b
+            PRE_MEM_READ( tmp, (Addr)vec[i].iov_base, vec[i].iov_len );
01cf8b
+         }
01cf8b
       }
01cf8b
    }
01cf8b
 }
01cf8b
 
01cf8b
 PRE(sys_pwritev)
01cf8b
 {
01cf8b
-   Int i;
01cf8b
-   struct vki_iovec * vec;
01cf8b
    *flags |= SfMayBlock;
01cf8b
+   const char *str = "pwritev";
01cf8b
 #if VG_WORDSIZE == 4
01cf8b
    /* Note that the offset argument here is in lo+hi order on both
01cf8b
       big and little endian platforms... */
01cf8b
@@ -5581,19 +5670,41 @@ PRE(sys_pwritev)
01cf8b
 #else
01cf8b
 #  error Unexpected word size
01cf8b
 #endif
01cf8b
-   if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
01cf8b
-      SET_STATUS_Failure( VKI_EBADF );
01cf8b
-   } else {
01cf8b
-      PRE_MEM_READ( "pwritev(vector)", 
01cf8b
-		     ARG2, ARG3 * sizeof(struct vki_iovec) );
01cf8b
-      if (ARG2 != 0) {
01cf8b
-         /* ToDo: don't do any of the following if the vector is invalid */
01cf8b
-         vec = (struct vki_iovec *)(Addr)ARG2;
01cf8b
-         for (i = 0; i < (Int)ARG3; i++)
01cf8b
-            PRE_MEM_READ( "pwritev(vector[...])",
01cf8b
-                           (Addr)vec[i].iov_base, vec[i].iov_len );
01cf8b
-      }
01cf8b
-   }
01cf8b
+   Int fd = ARG1;
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
+
01cf8b
+   handle_sys_pwritev(tid, status, fd, vector, count, str);
01cf8b
+}
01cf8b
+
01cf8b
+PRE(sys_pwritev2)
01cf8b
+{
01cf8b
+   *flags |= SfMayBlock;
01cf8b
+   const char *str = "pwritev2";
01cf8b
+#if VG_WORDSIZE == 4
01cf8b
+   /* Note that the offset argument here is in lo+hi order on both
01cf8b
+      big and little endian platforms... */
01cf8b
+   PRINT("sys_pwritev2 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD
01cf8b
+         "u, %lld, %" FMT_REGWORD "u )",
01cf8b
+         ARG1, ARG2, ARG3, (Long)LOHI64(ARG4,ARG5), ARG6);
01cf8b
+   PRE_REG_READ6(ssize_t, "pwritev2",
01cf8b
+                 unsigned long, fd, const struct iovec *, vector,
01cf8b
+                 unsigned long, count, vki_u32, offset_low,
01cf8b
+                 vki_u32, offset_high, unsigned long, flags);
01cf8b
+#elif VG_WORDSIZE == 8
01cf8b
+   /* Note offset_high isn't actually used?  */
01cf8b
+   PRE_REG_READ6(ssize_t, "pwritev2",
01cf8b
+                 unsigned long, fd, const struct iovec *, vector,
01cf8b
+                 unsigned long, count, Word, offset,
01cf8b
+		 Word, offset_high, unsigned long, flags);
01cf8b
+#else
01cf8b
+#  error Unexpected word size
01cf8b
+#endif
01cf8b
+   Int fd = ARG1;
01cf8b
+   Addr vector = ARG2;
01cf8b
+   Int count = ARG3;
01cf8b
+
01cf8b
+   handle_sys_pwritev(tid, status, fd, vector, count, str);
01cf8b
 }
01cf8b
 
01cf8b
 /* ---------------------------------------------------------------------
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-ppc64-linux.c b/coregrind/m_syswrap/syswrap-ppc64-linux.c
01cf8b
index baa2934ab..d65a664dd 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-ppc64-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-ppc64-linux.c
01cf8b
@@ -1006,6 +1006,8 @@ static SyscallTableEntry syscall_table[] = {
01cf8b
    LINX_(__NR_membarrier,        sys_membarrier),       // 365
01cf8b
 
01cf8b
    LINX_(__NR_copy_file_range,   sys_copy_file_range),  // 379
01cf8b
+   LINX_(__NR_preadv2,           sys_preadv2),          // 380
01cf8b
+   LINX_(__NR_pwritev2,          sys_pwritev2),         // 381
01cf8b
 
01cf8b
    LINXY(__NR_statx,             sys_statx),            // 383
01cf8b
 };
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-s390x-linux.c b/coregrind/m_syswrap/syswrap-s390x-linux.c
01cf8b
index 1481e768b..3354d41c0 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-s390x-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-s390x-linux.c
01cf8b
@@ -853,6 +853,8 @@ static SyscallTableEntry syscall_table[] = {
01cf8b
    LINX_(__NR_shutdown, sys_shutdown),                                // 373
01cf8b
 
01cf8b
    LINX_(__NR_copy_file_range, sys_copy_file_range),                  // 375
01cf8b
+   LINXY(__NR_preadv2, sys_preadv2),                                  // 376
01cf8b
+   LINX_(__NR_pwritev2, sys_pwritev2),                                // 377
01cf8b
 
01cf8b
    LINXY(__NR_statx, sys_statx),                                      // 379
01cf8b
 };
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c
01cf8b
index 9ff53a92a..33d1213a3 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-x86-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-x86-linux.c
01cf8b
@@ -1607,6 +1607,8 @@ static SyscallTableEntry syscall_table[] = {
01cf8b
    LINX_(__NR_membarrier,        sys_membarrier),       // 375
01cf8b
 
01cf8b
    LINX_(__NR_copy_file_range,   sys_copy_file_range),   // 377
01cf8b
+   LINXY(__NR_preadv2,           sys_preadv2),           // 378
01cf8b
+   LINX_(__NR_pwritev2,          sys_pwritev2),          // 379
01cf8b
 
01cf8b
    LINXY(__NR_pkey_mprotect,     sys_pkey_mprotect),    // 380
01cf8b
    LINX_(__NR_pkey_alloc,        sys_pkey_alloc),       // 381
01cf8b
diff --git a/memcheck/tests/linux/Makefile.am b/memcheck/tests/linux/Makefile.am
01cf8b
index 00e99a52a..e13325869 100644
01cf8b
--- a/memcheck/tests/linux/Makefile.am
01cf8b
+++ b/memcheck/tests/linux/Makefile.am
01cf8b
@@ -26,7 +26,9 @@ EXTRA_DIST = \
01cf8b
 	timerfd-syscall.vgtest timerfd-syscall.stderr.exp \
01cf8b
 	with-space.stderr.exp with-space.stdout.exp with-space.vgtest \
01cf8b
 	proc-auxv.vgtest proc-auxv.stderr.exp getregset.vgtest \
01cf8b
-	getregset.stderr.exp getregset.stdout.exp
01cf8b
+	getregset.stderr.exp getregset.stdout.exp \
01cf8b
+	sys-preadv_pwritev.vgtest sys-preadv_pwritev.stderr.exp \
01cf8b
+	sys-preadv2_pwritev2.vgtest sys-preadv2_pwritev2.stderr.exp
01cf8b
 
01cf8b
 check_PROGRAMS = \
01cf8b
 	brk \
01cf8b
@@ -54,6 +56,14 @@ if HAVE_COPY_FILE_RANGE
01cf8b
         check_PROGRAMS += sys-copy_file_range
01cf8b
 endif
01cf8b
 
01cf8b
+if HAVE_PREADV_PWRITEV
01cf8b
+        check_PROGRAMS += sys-preadv_pwritev
01cf8b
+endif
01cf8b
+
01cf8b
+if HAVE_PREADV2_PWRITEV2
01cf8b
+        check_PROGRAMS += sys-preadv2_pwritev2
01cf8b
+endif
01cf8b
+
01cf8b
 AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
01cf8b
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
01cf8b
 
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv2_pwritev2.c b/memcheck/tests/linux/sys-preadv2_pwritev2.c
01cf8b
new file mode 100644
01cf8b
index 000000000..942eab68b
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv2_pwritev2.c
01cf8b
@@ -0,0 +1,79 @@
01cf8b
+#define _GNU_SOURCE
01cf8b
+#include <fcntl.h>
01cf8b
+#include <stdio.h>
01cf8b
+#include <stdlib.h>
01cf8b
+#include <sys/stat.h>
01cf8b
+#include <unistd.h>
01cf8b
+#include <sys/syscall.h>
01cf8b
+#include <sys/uio.h>
01cf8b
+#include <string.h>
01cf8b
+#include "../../memcheck.h"
01cf8b
+
01cf8b
+#include <errno.h>
01cf8b
+
01cf8b
+int main(int argc, char **argv)
01cf8b
+{
01cf8b
+    char str0[] = "hello ";
01cf8b
+    char str1[] = "world\n";
01cf8b
+    struct iovec iov[2];
01cf8b
+    int fd;
01cf8b
+
01cf8b
+    fd = open("prwv2_source", O_CREAT | O_RDWR, 0644);
01cf8b
+    if (fd == -1) {
01cf8b
+        perror("prwv2_source");
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    iov[0].iov_base = str0;
01cf8b
+    iov[0].iov_len = strlen(str0);
01cf8b
+    iov[1].iov_base = str1;
01cf8b
+    iov[1].iov_len = strlen(str1);
01cf8b
+
01cf8b
+    /* Check pwritev2 and preadv2 called with the correct arguments works. */
01cf8b
+    if (pwritev2(fd, iov, 2, 0, 0) == -1) {
01cf8b
+        perror("pwritev2");
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    if (preadv2(fd, iov, 2, 0, 0) == -1) {
01cf8b
+        perror("preadv2");
01cf8b
+        printf("errno: %d\n", errno);
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    /* Check valgrind will produce expected warnings for the
01cf8b
+       various wrong arguments. */
01cf8b
+    do {
01cf8b
+        /* always allocate 16 bytes to not to have different .exps for different reg sizes */
01cf8b
+        char *mem = malloc(16);
01cf8b
+        void *t = (void *) &mem[0];
01cf8b
+        void *z = (void *) -1;
01cf8b
+	int c = *((int *) &mem[4]);
01cf8b
+        int flag = *((int *) &mem[8]);
01cf8b
+        pwritev2(fd, NULL, 2, 0, 0);
01cf8b
+        pwritev2(fd, z, 2, 0, 0);
01cf8b
+        pwritev2(fd, t, 2, 0, 0);
01cf8b
+        pwritev2(fd, iov, -1, 0, 0);
01cf8b
+        pwritev2(fd, iov, c, 0, 0);
01cf8b
+        pwritev2(fd, iov, 2, -5, 0);
01cf8b
+        pwritev2(-1, iov, 2, -5, 0);
01cf8b
+        pwritev2(fd, iov, 2, -5, flag);
01cf8b
+
01cf8b
+        preadv2(fd, NULL, 2, 0, 0);
01cf8b
+        preadv2(fd, z, 2, 0, 0);
01cf8b
+        preadv2(fd, t, 2, 0, 0);
01cf8b
+        preadv2(fd, iov, -1, 0, 0);
01cf8b
+        preadv2(fd, iov, c, 0, 0);
01cf8b
+        preadv2(fd, iov, 2, -5, 0);
01cf8b
+        preadv2(-1, iov, 2, -5, 0);
01cf8b
+
01cf8b
+        iov[1].iov_base = (void *) -1;
01cf8b
+        pwritev2(fd, iov, 2, 0, 0);
01cf8b
+        preadv2(fd, iov, 2, 0, 0);
01cf8b
+        free(mem);
01cf8b
+    } while (0);
01cf8b
+
01cf8b
+    close(fd);
01cf8b
+    unlink("prwv2_source");
01cf8b
+    exit(EXIT_SUCCESS);
01cf8b
+}
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv2_pwritev2.stderr.exp b/memcheck/tests/linux/sys-preadv2_pwritev2.stderr.exp
01cf8b
new file mode 100644
01cf8b
index 000000000..e11f2a51d
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv2_pwritev2.stderr.exp
01cf8b
@@ -0,0 +1,56 @@
01cf8b
+Syscall param pwritev2(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:53)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param pwritev2(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:54)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param pwritev2(vector) points to uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:55)
01cf8b
+ Address 0x........ is 0 bytes inside a block of size 16 alloc'd
01cf8b
+   at 0x........: malloc (vg_replace_malloc.c:...)
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:48)
01cf8b
+
01cf8b
+Syscall param pwritev2(count) contains uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:57)
01cf8b
+
01cf8b
+Syscall param pwritev2(flags) contains uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:60)
01cf8b
+
01cf8b
+Syscall param preadv2(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:62)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv2(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:63)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv2(vector) points to uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:64)
01cf8b
+ Address 0x........ is 0 bytes inside a block of size 16 alloc'd
01cf8b
+   at 0x........: malloc (vg_replace_malloc.c:...)
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:48)
01cf8b
+
01cf8b
+Syscall param preadv2(count) contains uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:66)
01cf8b
+
01cf8b
+Syscall param pwritev2(vector[1]) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:71)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv2(vector[1]) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv2_pwritev2.c:72)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv2_pwritev2.vgtest b/memcheck/tests/linux/sys-preadv2_pwritev2.vgtest
01cf8b
new file mode 100644
01cf8b
index 000000000..5cd23aacd
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv2_pwritev2.vgtest
01cf8b
@@ -0,0 +1,3 @@
01cf8b
+prereq: test -e sys-preadv2_pwritev2
01cf8b
+prog: sys-preadv2_pwritev2
01cf8b
+vgopts: -q
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv_pwritev.c b/memcheck/tests/linux/sys-preadv_pwritev.c
01cf8b
new file mode 100644
01cf8b
index 000000000..f5087dddc
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv_pwritev.c
01cf8b
@@ -0,0 +1,77 @@
01cf8b
+#define _GNU_SOURCE
01cf8b
+#include <fcntl.h>
01cf8b
+#include <stdio.h>
01cf8b
+#include <stdlib.h>
01cf8b
+#include <sys/stat.h>
01cf8b
+#include <unistd.h>
01cf8b
+#include <sys/syscall.h>
01cf8b
+#include <sys/uio.h>
01cf8b
+#include <string.h>
01cf8b
+#include "../../memcheck.h"
01cf8b
+
01cf8b
+#include <errno.h>
01cf8b
+
01cf8b
+int main(int argc, char **argv)
01cf8b
+{
01cf8b
+    char str0[] = "hello ";
01cf8b
+    char str1[] = "world\n";
01cf8b
+    struct iovec iov[2];
01cf8b
+    int fd;
01cf8b
+
01cf8b
+    fd = open("prwv_source", O_CREAT | O_RDWR, 0644);
01cf8b
+    if (fd == -1) {
01cf8b
+        perror("prwv2_source");
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    iov[0].iov_base = str0;
01cf8b
+    iov[0].iov_len = strlen(str0);
01cf8b
+    iov[1].iov_base = str1;
01cf8b
+    iov[1].iov_len = strlen(str1);
01cf8b
+
01cf8b
+    /* Check pwritev and preadv called with the correct arguments works. */
01cf8b
+    if (pwritev(fd, iov, 2, 0) == -1) {
01cf8b
+        perror("pwritev");
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    if (preadv(fd, iov, 2, 0) == -1) {
01cf8b
+        perror("preadv");
01cf8b
+        printf("errno: %d\n", errno);
01cf8b
+        exit(EXIT_FAILURE);
01cf8b
+    }
01cf8b
+
01cf8b
+    /* Check valgrind will produce expected warnings for the
01cf8b
+       various wrong arguments. */
01cf8b
+    do {
01cf8b
+        /* always allocate 16 bytes to not to have different .exps for different reg sizes */
01cf8b
+        char *mem = malloc(16);
01cf8b
+        void *t = (void *) &mem[0];
01cf8b
+        void *z = (void *) -1;
01cf8b
+        int c = *((int *) &mem[4]);
01cf8b
+        pwritev(fd, NULL, 2, 0);
01cf8b
+        pwritev(fd, z, 2, 0);
01cf8b
+        pwritev(fd, t, 2, 0);
01cf8b
+        pwritev(fd, iov, -1, 0);
01cf8b
+        pwritev(fd, iov, c, 0);
01cf8b
+        pwritev(fd, iov, 2, -5);
01cf8b
+        pwritev(-1, iov, 2, -5);
01cf8b
+
01cf8b
+        preadv(fd, NULL, 2, 0);
01cf8b
+        preadv(fd, z, 2, 0);
01cf8b
+        preadv(fd, t, 2, 0);
01cf8b
+        preadv(fd, iov, -1, 0);
01cf8b
+        preadv(fd, iov, c, 0);
01cf8b
+        preadv(fd, iov, 2, -5);
01cf8b
+        preadv(-1, iov, 2, -5);
01cf8b
+
01cf8b
+        iov[1].iov_base = (void *) -1;
01cf8b
+        pwritev(fd, iov, 2, 0);
01cf8b
+        preadv(fd, iov, 2, 0);
01cf8b
+        free(mem);
01cf8b
+    } while (0);
01cf8b
+
01cf8b
+    close(fd);
01cf8b
+    unlink("prwv_source");
01cf8b
+    exit(EXIT_SUCCESS);
01cf8b
+}
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv_pwritev.stderr.exp b/memcheck/tests/linux/sys-preadv_pwritev.stderr.exp
01cf8b
new file mode 100644
01cf8b
index 000000000..4fede44d8
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv_pwritev.stderr.exp
01cf8b
@@ -0,0 +1,52 @@
01cf8b
+Syscall param pwritev(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:52)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param pwritev(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:53)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param pwritev(vector) points to uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:54)
01cf8b
+ Address 0x........ is 0 bytes inside a block of size 16 alloc'd
01cf8b
+   at 0x........: malloc (vg_replace_malloc.c:...)
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:48)
01cf8b
+
01cf8b
+Syscall param pwritev(count) contains uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:56)
01cf8b
+
01cf8b
+Syscall param preadv(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:60)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv(vector) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:61)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv(vector) points to uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:62)
01cf8b
+ Address 0x........ is 0 bytes inside a block of size 16 alloc'd
01cf8b
+   at 0x........: malloc (vg_replace_malloc.c:...)
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:48)
01cf8b
+
01cf8b
+Syscall param preadv(count) contains uninitialised byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:64)
01cf8b
+
01cf8b
+Syscall param pwritev(vector[1]) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:69)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
+Syscall param preadv(vector[1]) points to unaddressable byte(s)
01cf8b
+   ...
01cf8b
+   by 0x........: main (sys-preadv_pwritev.c:70)
01cf8b
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
01cf8b
+
01cf8b
diff --git a/memcheck/tests/linux/sys-preadv_pwritev.vgtest b/memcheck/tests/linux/sys-preadv_pwritev.vgtest
01cf8b
new file mode 100644
01cf8b
index 000000000..f07dc2935
01cf8b
--- /dev/null
01cf8b
+++ b/memcheck/tests/linux/sys-preadv_pwritev.vgtest
01cf8b
@@ -0,0 +1,3 @@
01cf8b
+prereq: test -e sys-preadv_pwritev
01cf8b
+prog: sys-preadv_pwritev
01cf8b
+vgopts: -q
01cf8b
01cf8b
commit 514f899388e05142513ff3f679a9e0131145e34e
01cf8b
Author: Mark Wielaard <mark@klomp.org>
01cf8b
Date:   Wed Jul 3 10:27:17 2019 +0200
01cf8b
01cf8b
    Hook up preadv2 and pwritev2 correctly for arm64.
01cf8b
    
01cf8b
    Use the correct generic linux sys wrapper.
01cf8b
    
01cf8b
    Followup for https://bugs.kde.org/408414
01cf8b
01cf8b
diff --git a/coregrind/m_syswrap/syswrap-arm64-linux.c b/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
index d12d40632..91329b682 100644
01cf8b
--- a/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
+++ b/coregrind/m_syswrap/syswrap-arm64-linux.c
01cf8b
@@ -818,8 +818,8 @@ static SyscallTableEntry syscall_main_table[] = {
01cf8b
    LINX_(__NR_membarrier,        sys_membarrier),        // 283
01cf8b
    //   (__NR_mlock2,            sys_ni_syscall),        // 284
01cf8b
    LINX_(__NR_copy_file_range,   sys_copy_file_range),   // 285
01cf8b
-   LINX_(__NR_preadv2,           sys_ni_syscall),        // 286
01cf8b
-   LINX_(__NR_pwritev2,          sys_ni_syscall),        // 287
01cf8b
+   LINXY(__NR_preadv2,           sys_preadv2),           // 286
01cf8b
+   LINX_(__NR_pwritev2,          sys_pwritev2),          // 287
01cf8b
    //   (__NR_pkey_mprotect,     sys_ni_syscall),        // 288
01cf8b
    //   (__NR_pkey_alloc,        sys_ni_syscall),        // 289
01cf8b
    //   (__NR_pkey_free,         sys_ni_syscall),        // 290