]> granicus.if.org Git - strace/commitdiff
Decode UFFDIO_* ioctls
authorDr. David Alan Gilbert <dgilbert@redhat.com>
Tue, 10 May 2016 10:49:02 +0000 (11:49 +0100)
committerDmitry V. Levin <ldv@altlinux.org>
Tue, 10 May 2016 10:54:54 +0000 (10:54 +0000)
Decode the ioctls associated with the userfaultfd fd.
Note that they tend to read from and also return result in it's data
structure.

* configure.ac (AC_CHECK_HEADERS): Add linux/userfaultfd.h.
* userfaultfd.c [HAVE_LINUX_USERFAULTFD_H]: Add ioctl decoder.
* defs.h (uffdio_ioctl): New prototype.
* ioctl.c (ioctl_decode) [HAVE_LINUX_USERFAULTFD_H]: Wire in
uffdio_ioctl.
* xlat/uffd_*.in: Create flag xlat for all the IOCTLs.

configure.ac
defs.h
ioctl.c
userfaultfd.c
xlat/uffd_api_flags.in [new file with mode: 0644]
xlat/uffd_copy_flags.in [new file with mode: 0644]
xlat/uffd_register_ioctl_flags.in [new file with mode: 0644]
xlat/uffd_register_mode_flags.in [new file with mode: 0644]
xlat/uffd_zeropage_flags.in [new file with mode: 0644]

index dbe52e451290f8bb9e01268fa61a9608a103656a..7c030f890aae34e7f8b784ef50e60fbc8e49ff24 100644 (file)
@@ -375,6 +375,7 @@ AC_CHECK_HEADERS(m4_normalize([
        linux/securebits.h
        linux/sem.h
        linux/shm.h
+       linux/userfaultfd.h
        linux/utsname.h
        mqueue.h
        netinet/sctp.h
diff --git a/defs.h b/defs.h
index 8061047955f10d3cf1e407673e2c76f78a004fc3..a5aff96a0dcb03fc8a2e7a6c7b5ecf0cd255363f 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -668,6 +668,7 @@ extern int scsi_ioctl(struct tcb *, const unsigned int, long);
 extern int sock_ioctl(struct tcb *, const unsigned int, long);
 extern int term_ioctl(struct tcb *, const unsigned int, long);
 extern int ubi_ioctl(struct tcb *, const unsigned int, long);
+extern int uffdio_ioctl(struct tcb *, const unsigned int, long);
 extern int v4l2_ioctl(struct tcb *, const unsigned int, long);
 
 extern int tv_nz(const struct timeval *);
diff --git a/ioctl.c b/ioctl.c
index f70dc44e4c8cefdf82a401fded01a299df753b27..1b69e977e6dee1cc7b6ec7d4f9d6f19e738312d2 100644 (file)
--- a/ioctl.c
+++ b/ioctl.c
@@ -262,6 +262,10 @@ ioctl_decode(struct tcb *tcp)
 #ifdef HAVE_LINUX_INPUT_H
        case 'E':
                return evdev_ioctl(tcp, code, arg);
+#endif
+#ifdef HAVE_LINUX_USERFAULTFD_H
+       case 0xaa:
+               return uffdio_ioctl(tcp, code, arg);
 #endif
        default:
                break;
index 15f825a0345d68a0bdd0c17f91e4740bcb8b7262..27211051989784d3d613df0683f778f77a5af35f 100644 (file)
@@ -36,3 +36,123 @@ SYS_FUNC(userfaultfd)
 
        return RVAL_DECODED | RVAL_FD;
 }
+
+#ifdef HAVE_LINUX_USERFAULTFD_H
+# include <linux/ioctl.h>
+# include <linux/userfaultfd.h>
+
+# include "xlat/uffd_api_flags.h"
+# include "xlat/uffd_copy_flags.h"
+# include "xlat/uffd_register_ioctl_flags.h"
+# include "xlat/uffd_register_mode_flags.h"
+# include "xlat/uffd_zeropage_flags.h"
+
+static void
+tprintf_uffdio_range(const struct uffdio_range *range)
+{
+       tprintf("{start=%#" PRI__x64 ", len=%#" PRI__x64 "}",
+               range->start, range->len);
+}
+
+int
+uffdio_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
+{
+       switch (code) {
+       case UFFDIO_API: {
+               struct uffdio_api ua;
+               if (entering(tcp)) {
+                       tprints(", ");
+                       if (umove_or_printaddr(tcp, arg, &ua))
+                               return RVAL_DECODED | 1;
+                       /* Features is intended to contain some flags, but
+                        * there aren't any defined yet.
+                        */
+                       tprintf("{api=%#" PRI__x64
+                               ", features=%#" PRI__x64,
+                               ua.api, ua.features);
+               } else {
+                       if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
+                               tprintf(", features.out=%#" PRI__x64
+                                       ", ioctls=", ua.features);
+                               printflags64(uffd_api_flags, ua.ioctls,
+                                            "_UFFDIO_???");
+                       }
+                       tprintf("}");
+               }
+               return 1;
+       }
+
+       case UFFDIO_COPY: {
+               struct uffdio_copy uc;
+               if (entering(tcp)) {
+                       tprints(", ");
+                       if (umove_or_printaddr(tcp, arg, &uc))
+                               return RVAL_DECODED | 1;
+                       tprintf("{dst=%#" PRI__x64 ", src=%#" PRI__x64
+                               ", len=%#" PRI__x64 ", mode=",
+                               uc.dst, uc.src, uc.len);
+                       printflags64(uffd_copy_flags, uc.mode,
+                                    "UFFDIO_COPY_???");
+               } else {
+                       if (!syserror(tcp) && !umove(tcp, arg, &uc))
+                               tprintf(", copy=%#" PRI__x64, uc.copy);
+                       tprints("}");
+               }
+               return 1;
+       }
+
+       case UFFDIO_REGISTER: {
+               struct uffdio_register ur;
+               if (entering(tcp)) {
+                       tprints(", ");
+                       if (umove_or_printaddr(tcp, arg, &ur))
+                               return RVAL_DECODED | 1;
+                       tprintf("{range=");
+                       tprintf_uffdio_range(&ur.range);
+                       tprintf(", mode=");
+                       printflags64(uffd_register_mode_flags, ur.mode,
+                                    "UFFDIO_REGISTER_MODE_???");
+               } else {
+                       if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
+                               tprintf(", ioctls=");
+                               printflags64(uffd_register_ioctl_flags,
+                                            ur.ioctls, "UFFDIO_???");
+                       }
+                       tprints("}");
+               }
+               return 1;
+       }
+
+       case UFFDIO_UNREGISTER:
+       case UFFDIO_WAKE: {
+               struct uffdio_range ura;
+               tprints(", ");
+               if (!umove_or_printaddr(tcp, arg, &ura))
+                       tprintf_uffdio_range(&ura);
+               return RVAL_DECODED | 1;
+       }
+
+       case UFFDIO_ZEROPAGE: {
+               struct uffdio_zeropage uz;
+               if (entering(tcp)) {
+                       tprints(", ");
+                       if (umove_or_printaddr(tcp, arg, &uz))
+                               return RVAL_DECODED | 1;
+                       tprintf("{range=");
+                       tprintf_uffdio_range(&uz.range);
+                       tprintf(", mode=");
+                       printflags64(uffd_zeropage_flags, uz.mode,
+                                    "UFFDIO_ZEROPAGE_???");
+               } else {
+                       if (!syserror(tcp) && !umove(tcp, arg, &uz))
+                               tprintf(", zeropage=%#" PRI__x64, uz.zeropage);
+                       tprints("}");
+               }
+               return 1;
+       }
+
+       default:
+               return RVAL_DECODED;
+       }
+}
+#endif /* HAVE_LINUX_USERFAULTFD_H */
diff --git a/xlat/uffd_api_flags.in b/xlat/uffd_api_flags.in
new file mode 100644 (file)
index 0000000..fd21087
--- /dev/null
@@ -0,0 +1,4 @@
+#val_type uint64_t
+1<<_UFFDIO_REGISTER
+1<<_UFFDIO_UNREGISTER
+1<<_UFFDIO_API
diff --git a/xlat/uffd_copy_flags.in b/xlat/uffd_copy_flags.in
new file mode 100644 (file)
index 0000000..02d6b19
--- /dev/null
@@ -0,0 +1,2 @@
+#val_type uint64_t
+UFFDIO_COPY_MODE_DONTWAKE
diff --git a/xlat/uffd_register_ioctl_flags.in b/xlat/uffd_register_ioctl_flags.in
new file mode 100644 (file)
index 0000000..f4e3b94
--- /dev/null
@@ -0,0 +1,4 @@
+#val_type uint64_t
+1<<_UFFDIO_WAKE
+1<<_UFFDIO_COPY
+1<<_UFFDIO_ZEROPAGE
diff --git a/xlat/uffd_register_mode_flags.in b/xlat/uffd_register_mode_flags.in
new file mode 100644 (file)
index 0000000..996b1f3
--- /dev/null
@@ -0,0 +1,3 @@
+#val_type uint64_t
+UFFDIO_REGISTER_MODE_MISSING
+UFFDIO_REGISTER_MODE_WP
diff --git a/xlat/uffd_zeropage_flags.in b/xlat/uffd_zeropage_flags.in
new file mode 100644 (file)
index 0000000..6d48a04
--- /dev/null
@@ -0,0 +1,2 @@
+#val_type uint64_t
+UFFDIO_ZEROPAGE_MODE_DONTWAKE