From: "Dr. David Alan Gilbert" <dgilb...@redhat.com>

 !!! TODO!
   Add some tests (How do I make it immune from kernel changes to flags
       returned?)
   Tests the zeropage and wake code
   don't use my decode_flags64 - I guess I should be using printflags
       but printflags uses struct xlat and they're both unsigned int
       where I'm dealing in uint64_t's; perhaps if I just rework
       printflags/xlat it'll all work ???
 !!!

Decode the ioctl's associated with the userfaultfd fd.
Note that they tend to read from and also returns result in it's data
structure.

* configure.ac: Add test for userfaultfd.h.
* userfaultfd.c: Add ioctl decoder.
* defs.h: declare that decoder.
* ioctl.c: Wire in the new decoder.

Example output:
14279 ioctl(20, UFFDIO_API{api=0xaa,
features.in=0,features.out=0,ioctls=0x8000000000000003(Register|Unregister|API)})
= 0
14279 ioctl(20, UFFDIO_REGISTER{range={start=0x7f72ec200000,
len=0x8fc00000}, mode=0x1(Missing),ioctls=0x1c(Wake|Copy|Zeropage)}) = 0
14308 ioctl(20, UFFDIO_UNREGISTER{start=0x7f72ec200000, len=0x8fc00000})
= 0
14308 ioctl(20, UFFDIO_COPY{dst=0x7f730e076000, src=0x5561e2ad66c0,
len=4096, mode=0, copy=4096}) = 0
---
 configure.ac  |   1 +
 defs.h        |   1 +
 ioctl.c       |   4 ++
 userfaultfd.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 180 insertions(+)

diff --git a/configure.ac b/configure.ac
index 2b29c94..8ad844e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -377,6 +377,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 ac59349..4894fdb 100644
--- a/defs.h
+++ b/defs.h
@@ -649,6 +649,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 f70dc44..1b69e97 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -263,6 +263,10 @@ ioctl_decode(struct tcb *tcp)
        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;
        }
diff --git a/userfaultfd.c b/userfaultfd.c
index 15f825a..accd103 100644
--- a/userfaultfd.c
+++ b/userfaultfd.c
@@ -30,6 +30,180 @@
 
 #include "xlat/uffd_flags.h"
 
+#ifdef HAVE_LINUX_USERFAULTFD_H
+#include <linux/ioctl.h>
+#include <linux/userfaultfd.h>
+
+/*
+ * Print value (in hex) followed by a decode using the strings
+ * and masks in masks and names; we stop at a 0 entry in masks.
+ * !!! Need to turn this into printflags - but it's int
+ */
+static void
+decode_flags64(const char *leader, uint64_t value, const uint64_t masks[],
+               const char *names[])
+{
+       unsigned i;
+       bool first = true;
+
+       if (!value) {
+               tprintf("%s%#" PRIx64, leader, value);
+               return;
+       }
+
+       tprintf("%s%#" PRIx64 "(", leader, value);
+
+       for (i = 0; masks[i]; i++) {
+               if (value & masks[i]) {
+                       tprintf(first ? "%s" : "|%s", names[i]);
+                       first = false;
+                       value -= masks[i];
+               }
+       }
+       if (value)
+               tprintf(first ? "%#" PRIx64 : "|%#" PRIx64, value);
+       tprintf(")");
+}
+
+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;
+               const uint64_t api_ioctl_masks[] = {
+                       (uint64_t)1 << _UFFDIO_REGISTER,
+                       (uint64_t)1 << _UFFDIO_UNREGISTER,
+                       (uint64_t)1 << _UFFDIO_API,
+                       0
+                       };
+               const char *api_ioctl_names[] = { "Register", "Unregister",
+                                                 "API" };
+
+               if (entering(tcp)) {
+                       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.in=%#" PRI__x64,
+                               ua.api, ua.features);
+                       return 1;
+               } else {
+                       if (!umove_or_printaddr(tcp, arg, &ua)) {
+                               tprintf(",features.out=%#" PRI__x64,
+                                       ua.features);
+                               decode_flags64(",ioctls=", ua.ioctls,
+                                               api_ioctl_masks, 
api_ioctl_names);
+                       }
+                       tprintf("}");
+                       return 1;
+               }
+       }
+
+       case UFFDIO_COPY: {
+               struct uffdio_copy uc;
+               const uint64_t copy_mode_masks[] = {
+                       UFFDIO_COPY_MODE_DONTWAKE,
+                       0
+                       };
+               const char *copy_mode_names[] = { "Dontwake" };
+               if (entering(tcp)) {
+                       if (umove_or_printaddr(tcp, arg, &uc))
+                               return RVAL_DECODED | 1;
+                       tprintf("{dst=%#" PRI__x64 ", src=%#" PRI__x64
+                               ", len=%" PRI__u64,
+                               uc.dst, uc.src, uc.len);
+                       decode_flags64(", mode=", uc.mode,
+                                       copy_mode_masks, copy_mode_names);
+                       return 1;
+               } else {
+                       if (!umove_or_printaddr(tcp, arg, &uc))
+                               tprintf(", copy=%" PRI__s64, uc.copy);
+                       tprints("}");
+                       return 1;
+               }
+       }
+
+       case UFFDIO_REGISTER: {
+               struct uffdio_register ur;
+               const uint64_t mode_masks[] = {
+                       UFFDIO_REGISTER_MODE_MISSING,
+                       UFFDIO_REGISTER_MODE_WP,
+                       0
+                       };
+               const char *mode_names[] = { "Missing", "WP" };
+               const uint64_t reg_ioctl_masks[] = {
+                       (__u64)1 << _UFFDIO_WAKE,
+                       (__u64)1 << _UFFDIO_COPY,
+                       (__u64)1 << _UFFDIO_ZEROPAGE,
+                       0
+                       };
+               const char *reg_ioctl_names[] = { "Wake", "Copy", "Zeropage" };
+
+               if (entering(tcp)) {
+                       if (umove_or_printaddr(tcp, arg, &ur))
+                               return RVAL_DECODED | 1;
+                       tprintf("{range=");
+                       tprintf_uffdio_range(&ur.range);
+                       decode_flags64(", mode=", ur.mode,
+                                       mode_masks, mode_names);
+                       return 1;
+               } else {
+                       if (!umove_or_printaddr(tcp, arg, &ur))
+                               decode_flags64(",ioctls=", ur.ioctls,
+                               reg_ioctl_masks, reg_ioctl_names);
+                       tprints("}");
+                       return 1;
+               }
+       }
+
+       case UFFDIO_UNREGISTER:
+       case UFFDIO_WAKE: {
+               struct uffdio_range ura;
+               if (entering(tcp)) {
+                       if (umove_or_printaddr(tcp, arg, &ura))
+                               return RVAL_DECODED | 1;
+                       tprintf_uffdio_range(&ura);
+                       return RVAL_DECODED | 1;
+               }
+       }
+       case UFFDIO_ZEROPAGE: {
+               struct uffdio_zeropage uz;
+               const uint64_t zero_mode_masks[] = {
+                       UFFDIO_ZEROPAGE_MODE_DONTWAKE,
+                       0
+                       };
+               const char *zero_mode_names[] = { "Dontwake" };
+               if (entering(tcp)) {
+                       if (umove_or_printaddr(tcp, arg, &uz))
+                               return RVAL_DECODED | 1;
+                       tprintf("{range=");
+                       tprintf_uffdio_range(&uz.range);
+                       decode_flags64(", mode=", uz.mode,
+                                       zero_mode_masks, zero_mode_names);
+                       return 1;
+               } else {
+                       if (!umove_or_printaddr(tcp, arg, &uz))
+                               tprintf(", zeropage=%" PRI__s64, uz.zeropage);
+                       tprints("}");
+                       return 1;
+               }
+       }
+
+       default:
+               return RVAL_DECODED;
+       }
+}
+#endif
+
 SYS_FUNC(userfaultfd)
 {
        printflags(uffd_flags, tcp->u_arg[0], "UFFD_???");
-- 
2.5.5


------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to