From: Dmitry V. Levin Date: Sat, 13 Feb 2016 03:45:32 +0000 (+0000) Subject: Implement copy_file_range syscall decoding X-Git-Tag: v4.12~551 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c1f99f569a7d6362822f9e9ed5c2c3cf82fb72b6;p=strace Implement copy_file_range syscall decoding * 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. --- diff --git a/Makefile.am b/Makefile.am index 944a1f5e..e15c2d91 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,6 +82,7 @@ strace_SOURCES = \ chdir.c \ chmod.c \ clone.c \ + copy_file_range.c \ count.c \ defs.h \ desc.c \ diff --git a/NEWS b/NEWS index 0fae1ea1..c5193829 100644 --- 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. + * Implemented decoding of copy_file_range syscall. * 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 index 00000000..8e711d1e --- /dev/null +++ b/copy_file_range.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 Dmitry V. Levin + * 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; +} diff --git a/linux/32/syscallent.h b/linux/32/syscallent.h index 6aaa0255..03874ac8 100644 --- a/linux/32/syscallent.h +++ b/linux/32/syscallent.h @@ -275,6 +275,7 @@ [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 diff --git a/linux/64/syscallent.h b/linux/64/syscallent.h index 64cc86f8..fc78605f 100644 --- a/linux/64/syscallent.h +++ b/linux/64/syscallent.h @@ -268,3 +268,4 @@ [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" }, diff --git a/linux/arm/syscallent.h b/linux/arm/syscallent.h index 2433df8f..a94bedc7 100644 --- a/linux/arm/syscallent.h +++ b/linux/arm/syscallent.h @@ -415,7 +415,8 @@ [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 diff --git a/linux/i386/syscallent.h b/linux/i386/syscallent.h index ee8d23ba..f91fe1db 100644 --- a/linux/i386/syscallent.h +++ b/linux/i386/syscallent.h @@ -402,7 +402,8 @@ [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" diff --git a/linux/ia64/syscallent.h b/linux/ia64/syscallent.h index 6f75f1ca..911e21f3 100644 --- a/linux/ia64/syscallent.h +++ b/linux/ia64/syscallent.h @@ -363,3 +363,4 @@ [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" }, diff --git a/linux/m68k/syscallent.h b/linux/m68k/syscallent.h index 20288412..23d507dd 100644 --- a/linux/m68k/syscallent.h +++ b/linux/m68k/syscallent.h @@ -401,7 +401,8 @@ [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" diff --git a/linux/powerpc/syscallent.h b/linux/powerpc/syscallent.h index afbd602b..8a79c9f0 100644 --- a/linux/powerpc/syscallent.h +++ b/linux/powerpc/syscallent.h @@ -405,7 +405,8 @@ [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" diff --git a/linux/powerpc64/syscallent.h b/linux/powerpc64/syscallent.h index 486b3aea..685ee232 100644 --- a/linux/powerpc64/syscallent.h +++ b/linux/powerpc64/syscallent.h @@ -400,7 +400,8 @@ [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" diff --git a/linux/s390/syscallent.h b/linux/s390/syscallent.h index 1cf2d225..68ae7cbf 100644 --- a/linux/s390/syscallent.h +++ b/linux/s390/syscallent.h @@ -403,7 +403,8 @@ [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" diff --git a/linux/s390x/syscallent.h b/linux/s390x/syscallent.h index 4374d836..00ce24e3 100644 --- a/linux/s390x/syscallent.h +++ b/linux/s390x/syscallent.h @@ -387,7 +387,8 @@ [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" diff --git a/linux/sparc/syscallent.h b/linux/sparc/syscallent.h index d4003717..4404b95f 100644 --- a/linux/sparc/syscallent.h +++ b/linux/sparc/syscallent.h @@ -355,7 +355,8 @@ [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" diff --git a/linux/sparc64/syscallent.h b/linux/sparc64/syscallent.h index c49a4da8..29532153 100644 --- a/linux/sparc64/syscallent.h +++ b/linux/sparc64/syscallent.h @@ -353,7 +353,8 @@ [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" diff --git a/linux/x32/syscallent.h b/linux/x32/syscallent.h index bcc0d383..5ef4a667 100644 --- a/linux/x32/syscallent.h +++ b/linux/x32/syscallent.h @@ -324,7 +324,8 @@ [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. diff --git a/linux/x86_64/syscallent.h b/linux/x86_64/syscallent.h index 18f00ec5..52d73bf0 100644 --- a/linux/x86_64/syscallent.h +++ b/linux/x86_64/syscallent.h @@ -324,3 +324,4 @@ [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" }, diff --git a/pathtrace.c b/pathtrace.c index b2271c45..74dc3a08 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -225,8 +225,9 @@ pathtrace_match(struct tcb *tcp) upathmatch(tcp, tcp->u_arg[0]) || upathmatch(tcp, tcp->u_arg[2]); + case SEN_copy_file_range: 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]); diff --git a/tests/.gitignore b/tests/.gitignore index c5dd3cb7..ce52655a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -15,6 +15,7 @@ bpf caps clock_nanosleep clock_xettime +copy_file_range epoll_create1 eventfd execve diff --git a/tests/Makefile.am b/tests/Makefile.am index 7efbf77a..4c7ae8f1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,6 +65,7 @@ check_PROGRAMS = \ caps \ clock_nanosleep \ clock_xettime \ + copy_file_range \ epoll_create1 \ eventfd \ execve \ @@ -211,6 +212,7 @@ TESTS = \ caps.test \ clock_nanosleep.test \ clock_xettime.test \ + copy_file_range.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 index 00000000..e90bf6a1 --- /dev/null +++ b/tests/copy_file_range.c @@ -0,0 +1,65 @@ +/* + * This file is part of copy_file_range strace test. + * + * Copyright (c) 2016 Dmitry V. Levin + * 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 + +#if defined __NR_copy_file_range + +# include +# include +# include +# include + +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 index 00000000..95c34dbf --- /dev/null +++ b/tests/copy_file_range.test @@ -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"