]> granicus.if.org Git - strace/commitdiff
Implement copy_file_range syscall decoding
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 13 Feb 2016 03:45:32 +0000 (03:45 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 14 Feb 2016 00:36:38 +0000 (00:36 +0000)
* copy_file_range.c: New file.
* Makefile.am (strace_SOURCES): Add it.
* linux/32/syscallent.h (copy_file_range): New entry.
* linux/64/syscallent.h: Likewise.
* linux/arm/syscallent.h: Likewise.
* linux/i386/syscallent.h: Likewise.
* linux/ia64/syscallent.h: Likewise.
* linux/m68k/syscallent.h: Likewise.
* linux/powerpc/syscallent.h: Likewise.
* linux/powerpc64/syscallent.h: Likewise.
* linux/s390/syscallent.h: Likewise.
* linux/s390x/syscallent.h: Likewise.
* linux/sparc/syscallent.h: Likewise.
* linux/sparc64/syscallent.h: Likewise.
* linux/x32/syscallent.h: Likewise.
* linux/x86_64/syscallent.h: Likewise.
* pathtrace.c (pathtrace_match): Add SEN_copy_file_range.
* NEWS: Mention new syscall parser.
* tests/copy_file_range.c: New file.
* tests/copy_file_range.test: New test.
* tests/.gitignore: Add copy_file_range.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(TESTS): Add copy_file_range.test.

22 files changed:
Makefile.am
NEWS
copy_file_range.c [new file with mode: 0644]
linux/32/syscallent.h
linux/64/syscallent.h
linux/arm/syscallent.h
linux/i386/syscallent.h
linux/ia64/syscallent.h
linux/m68k/syscallent.h
linux/powerpc/syscallent.h
linux/powerpc64/syscallent.h
linux/s390/syscallent.h
linux/s390x/syscallent.h
linux/sparc/syscallent.h
linux/sparc64/syscallent.h
linux/x32/syscallent.h
linux/x86_64/syscallent.h
pathtrace.c
tests/.gitignore
tests/Makefile.am
tests/copy_file_range.c [new file with mode: 0644]
tests/copy_file_range.test [new file with mode: 0755]

index 944a1f5e23634b790aa885271c5536ac2c1ebaae..e15c2d910188f4b54567cfbebe6fa25a343eec45 100644 (file)
@@ -82,6 +82,7 @@ strace_SOURCES =      \
        chdir.c         \
        chmod.c         \
        clone.c         \
        chdir.c         \
        chmod.c         \
        clone.c         \
+       copy_file_range.c \
        count.c         \
        defs.h          \
        desc.c          \
        count.c         \
        defs.h          \
        desc.c          \
diff --git a/NEWS b/NEWS
index 0fae1ea18b4df866e7129ec06bd7e7c158299d9c..c51938297ab7cc6fd7efe8c7856c148b88641267 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Noteworthy changes in release ?.?? (????-??-??)
   * Added decoding of bind, listen, and setsockopt direct syscalls on sparc.
   * Implemented caching of netlink conversations to reduce amount of time
     spent in decoding socket details in -yy mode.
   * Added decoding of bind, listen, and setsockopt direct syscalls on sparc.
   * Implemented caching of netlink conversations to reduce amount of time
     spent in decoding socket details in -yy mode.
+  * Implemented decoding of copy_file_range syscall.
 
 * Bug fixes
   * Fixed build on arc, metag, nios2, or1k, and tile architectures.
 
 * Bug fixes
   * Fixed build on arc, metag, nios2, or1k, and tile architectures.
diff --git a/copy_file_range.c b/copy_file_range.c
new file mode 100644 (file)
index 0000000..8e711d1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 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.
+ */
+
+#include "defs.h"
+
+SYS_FUNC(copy_file_range)
+{
+       /* int fd_in */
+       printfd(tcp, tcp->u_arg[0]);
+       tprints(", ");
+       /* loff_t *off_in */
+       printnum_int64(tcp, tcp->u_arg[1], "%" PRId64);
+       tprints(", ");
+       /* int fd_out */
+       printfd(tcp, tcp->u_arg[2]);
+       tprints(", ");
+       /* loff_t *off_out */
+       printnum_int64(tcp, tcp->u_arg[3], "%" PRId64);
+       tprints(", ");
+       /* size_t len */
+       tprintf("%lu, ", tcp->u_arg[4]);
+       /* unsigned int flags */
+       tprintf("%u", (unsigned int) tcp->u_arg[5]);
+
+       return RVAL_DECODED;
+}
index 6aaa02552f2f1a6ede4cc91c75f9345ab59d7270..03874ac81cfc8bf98d5a55630ffea7e36a9d33c6 100644 (file)
 [282] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [283] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [284] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [282] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [283] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [284] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
+[285] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
 
 #undef sys_ARCH_mmap
 #undef ARCH_WANT_SYNC_FILE_RANGE2
 
 #undef sys_ARCH_mmap
 #undef ARCH_WANT_SYNC_FILE_RANGE2
index 64cc86f8cf716df5697f9921e5cc84fc19369a13..fc78605fa5abb9b0aa6261371cc1b2984e8e153b 100644 (file)
 [282] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [283] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [284] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [282] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [283] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [284] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
+[285] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
index 2433df8f9240c5eee381e2fd17fc2eb1f80fbe06..a94bedc7bb5dad564bf8bbf453927a0720527479 100644 (file)
 [388] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [389] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [390] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [388] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [389] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [390] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[391 ... 399] = { },
+[391] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[392 ... 399] = { },
 
 #ifdef __ARM_EABI__
 # define ARM_FIRST_SHUFFLED_SYSCALL 400
 
 #ifdef __ARM_EABI__
 # define ARM_FIRST_SHUFFLED_SYSCALL 400
index ee8d23ba1f88869581136d376d2833530d06da2f..f91fe1db1c0b7126a2a264e7dedc0e72e9a2b3f2 100644 (file)
 [374] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [375] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [376] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [374] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [375] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [376] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[377 ... 399] = { },
+[377] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[378 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index 6f75f1cae3583edd14cd09c4f2d550db9298fb12..911e21f329dde389e8cc7f101149197df6bdc5e6 100644 (file)
 [1344] = { 2,  0,              SEN(membarrier),                "membarrier",           },
 [1345] = { 5,  0,              SEN(kcmp),                      "kcmp"                  },
 [1346] = { 3,  TM,             SEN(mlock2),                    "mlock2"                },
 [1344] = { 2,  0,              SEN(membarrier),                "membarrier",           },
 [1345] = { 5,  0,              SEN(kcmp),                      "kcmp"                  },
 [1346] = { 3,  TM,             SEN(mlock2),                    "mlock2"                },
+[1347] = { 6,  TD,             SEN(copy_file_range),           "copy_file_range"       },
index 20288412047e56d1687c497a272150c81a269c5e..23d507dd24d6f65ba06e9ff839183ac165e44ea0 100644 (file)
 [373] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [374] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [375] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [373] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [374] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [375] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[376 ... 399] = { },
+[376] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[377 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index afbd602ba25f8c27c673b399ef00de407b68672c..8a79c9f0aa560d6c0f6ebebb5fa669e632e7ea98 100644 (file)
 [376] = { 3,   TI,             SEN(shmget),                    "shmget"                },
 [377] = { 3,   TI,             SEN(shmctl),                    "shmctl"                },
 [378] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [376] = { 3,   TI,             SEN(shmget),                    "shmget"                },
 [377] = { 3,   TI,             SEN(shmctl),                    "shmctl"                },
 [378] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[379 ... 399] = { },
+[379] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[380 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index 486b3aea75bd888013f152373b8a96e58c41248f..685ee232a6ad4d13b1dd40cebaab2606db877df4 100644 (file)
 [376] = { 3,   TI,             SEN(shmget),                    "shmget"                },
 [377] = { 3,   TI,             SEN(shmctl),                    "shmctl"                },
 [378] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [376] = { 3,   TI,             SEN(shmget),                    "shmget"                },
 [377] = { 3,   TI,             SEN(shmctl),                    "shmctl"                },
 [378] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[379 ... 399] = { },
+[379] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[380 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index 1cf2d22540d8ee84baf450dcd2661bd51df4e549..68ae7cbfb774a6ae43d4166e7171cab2f47d7dce 100644 (file)
 [372] = { 3,   TN,             SEN(recvmsg),                   "recvmsg"               },
 [373] = { 2,   TN,             SEN(shutdown),                  "shutdown"              },
 [374] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [372] = { 3,   TN,             SEN(recvmsg),                   "recvmsg"               },
 [373] = { 2,   TN,             SEN(shutdown),                  "shutdown"              },
 [374] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[375 ... 399] = { },
+[375] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[376 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index 4374d8367dae199199453e5750e944eea6f920d7..00ce24e3af2d3228a5ab0166a4b30e26a88c92a3 100644 (file)
 [372] = { 3,   TN,             SEN(recvmsg),                   "recvmsg"               },
 [373] = { 2,   TN,             SEN(shutdown),                  "shutdown"              },
 [374] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [372] = { 3,   TN,             SEN(recvmsg),                   "recvmsg"               },
 [373] = { 2,   TN,             SEN(shutdown),                  "shutdown"              },
 [374] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[375 ... 399] = { },
+[375] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[376 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index d40037175ceb92fe46e3740928b700ecc91ab6d4..4404b95fa147acd0dfeedcdd1a6ab38fee1f50f1 100644 (file)
 [354] = { 2,   TN,             SEN(listen),                    "listen"                },
 [355] = { 5,   TN,             SEN(setsockopt),                "setsockopt"            },
 [356] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [354] = { 2,   TN,             SEN(listen),                    "listen"                },
 [355] = { 5,   TN,             SEN(setsockopt),                "setsockopt"            },
 [356] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[357 ... 399] = { },
+[357] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[358 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index c49a4da84aac1f40493215466dddd2f3d54c672a..29532153c259ebaa2f4292d6af0c4c9cc88d1583 100644 (file)
 [354] = { 2,   TN,             SEN(listen),                    "listen"                },
 [355] = { 5,   TN,             SEN(setsockopt),                "setsockopt"            },
 [356] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [354] = { 2,   TN,             SEN(listen),                    "listen"                },
 [355] = { 5,   TN,             SEN(setsockopt),                "setsockopt"            },
 [356] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[357 ... 399] = { },
+[357] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[358 ... 399] = { },
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
 
 #define SYS_socket_subcall     400
 #include "subcall.h"
index bcc0d383cf9be5691f9a7933a7cd8d5d257b942d..5ef4a667259672d2267d54a316c10df65c1c6f4b 100644 (file)
 [323] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [324] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [325] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [323] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [324] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [325] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
-[326 ... 511] = { },
+[326] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
+[327 ... 511] = { },
 /*
  * x32-specific system call numbers start at 512 to avoid cache impact
  * for native 64-bit operation.
 /*
  * x32-specific system call numbers start at 512 to avoid cache impact
  * for native 64-bit operation.
index 18f00ec57e573063e270d5f1c8c1a6be3457c1a9..52d73bf0ee90d765560c1088cc4569ef81405f24 100644 (file)
 [323] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [324] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [325] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
 [323] = { 1,   TD,             SEN(userfaultfd),               "userfaultfd",          },
 [324] = { 2,   0,              SEN(membarrier),                "membarrier",           },
 [325] = { 3,   TM,             SEN(mlock2),                    "mlock2"                },
+[326] = { 6,   TD,             SEN(copy_file_range),           "copy_file_range"       },
index b2271c457b2fc147c58ab0dff339b8019b73c4e4..74dc3a089803b22cccffe0e8759169dec57c9f76 100644 (file)
@@ -225,8 +225,9 @@ pathtrace_match(struct tcb *tcp)
                        upathmatch(tcp, tcp->u_arg[0]) ||
                        upathmatch(tcp, tcp->u_arg[2]);
 
                        upathmatch(tcp, tcp->u_arg[0]) ||
                        upathmatch(tcp, tcp->u_arg[2]);
 
+       case SEN_copy_file_range:
        case SEN_splice:
        case SEN_splice:
-               /* fd, x, fd, x, x */
+               /* fd, x, fd, x, x, x */
                return fdmatch(tcp, tcp->u_arg[0]) ||
                        fdmatch(tcp, tcp->u_arg[2]);
 
                return fdmatch(tcp, tcp->u_arg[0]) ||
                        fdmatch(tcp, tcp->u_arg[2]);
 
index c5dd3cb7337a347ad1048b5614183d14e2b7b4c1..ce52655af074e510628a24d446c652b4e21894bf 100644 (file)
@@ -15,6 +15,7 @@ bpf
 caps
 clock_nanosleep
 clock_xettime
 caps
 clock_nanosleep
 clock_xettime
+copy_file_range
 epoll_create1
 eventfd
 execve
 epoll_create1
 eventfd
 execve
index 7efbf77afe24457e32fc6d09f68275c0d8bc9ba0..4c7ae8f1bda5591a882d0bcac0096b96aa016692 100644 (file)
@@ -65,6 +65,7 @@ check_PROGRAMS = \
        caps \
        clock_nanosleep \
        clock_xettime \
        caps \
        clock_nanosleep \
        clock_xettime \
+       copy_file_range \
        epoll_create1 \
        eventfd \
        execve \
        epoll_create1 \
        eventfd \
        execve \
@@ -211,6 +212,7 @@ TESTS = \
        caps.test \
        clock_nanosleep.test \
        clock_xettime.test \
        caps.test \
        clock_nanosleep.test \
        clock_xettime.test \
+       copy_file_range.test \
        dumpio.test \
        epoll_create1.test \
        eventfd.test \
        dumpio.test \
        epoll_create1.test \
        eventfd.test \
diff --git a/tests/copy_file_range.c b/tests/copy_file_range.c
new file mode 100644 (file)
index 0000000..e90bf6a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * This file is part of copy_file_range strace test.
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#include "tests.h"
+#include <sys/syscall.h>
+
+#if defined __NR_copy_file_range
+
+# include <assert.h>
+# include <errno.h>
+# include <stdio.h>
+# include <unistd.h>
+
+int
+main(void)
+{
+       const long int fd_in = (long int) 0xdeadbeefffffffff;
+       const long int fd_out = (long int) 0xdeadbeeffffffffe;
+       long long int *const off_in = tail_alloc(sizeof(*off_in));
+       long long int *const off_out = tail_alloc(sizeof(*off_out));
+       *off_in = 0xdeadbef1facefed1;
+       *off_out = 0xdeadbef2facefed2;
+       const size_t len = (size_t) 0xdeadbef3facefed3ULL;
+       const unsigned int flags = 0;
+
+       assert(syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out,
+                      len, flags) == -1);
+       printf("copy_file_range(%d, [%lld], %d, [%lld], %zu, %u) = -1 %s (%m)\n",
+              (int) fd_in, *off_in, (int) fd_out, *off_out, len, flags,
+              errno == ENOSYS ? "ENOSYS" : "EBADF");
+       puts("+++ exited with 0 +++");
+       return 0;
+}
+
+#else
+
+SKIP_MAIN_UNDEFINED("__NR_copy_file_range")
+
+#endif
diff --git a/tests/copy_file_range.test b/tests/copy_file_range.test
new file mode 100755 (executable)
index 0000000..95c34db
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Check copy_file_range syscall decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog > /dev/null
+OUT="$LOG.out"
+run_strace -ecopy_file_range $args > "$OUT"
+match_diff "$LOG" "$OUT"
+rm -f "$OUT"