]> granicus.if.org Git - strace/blobdiff - userfaultfd.c
mmap_cache: add function to enable mmap_cache
[strace] / userfaultfd.c
index aeeb3eabc663defccd5cda3081195630268b795f..2fa33c77b464621fded20699cad6cb468e61917b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
+ * Copyright (c) 2015-2017 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,6 +27,7 @@
  */
 
 #include "defs.h"
+#include "print_fields.h"
 #include <fcntl.h>
 
 #include "xlat/uffd_flags.h"
@@ -41,6 +43,7 @@ SYS_FUNC(userfaultfd)
 # include <linux/ioctl.h>
 # include <linux/userfaultfd.h>
 
+# include "xlat/uffd_api_features.h"
 # include "xlat/uffd_api_flags.h"
 # include "xlat/uffd_copy_flags.h"
 # include "xlat/uffd_register_ioctl_flags.h"
@@ -50,110 +53,149 @@ SYS_FUNC(userfaultfd)
 static void
 tprintf_uffdio_range(const struct uffdio_range *range)
 {
-       tprintf("{start=%#" PRI__x64 ", len=%#" PRI__x64 "}",
-               range->start, range->len);
+       PRINT_FIELD_X("{", *range, start);
+       PRINT_FIELD_X(", ", *range, len);
+       tprints("}");
 }
 
+#define PRINT_FIELD_UFFDIO_RANGE(prefix_, where_, field_)              \
+       do {                                                            \
+               STRACE_PRINTF("%s%s=", (prefix_), #field_);             \
+               tprintf_uffdio_range(&(where_).field_);                 \
+       } while (0)
+
 int
 uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
             const kernel_ulong_t arg)
 {
        switch (code) {
        case UFFDIO_API: {
+               uint64_t *entering_features;
                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_???");
+                               break;
+                       PRINT_FIELD_X("{", ua, api);
+                       PRINT_FIELD_FLAGS(", ", ua, features, uffd_api_features,
+                                         "UFFD_FEATURE_???");
+                       entering_features = malloc(sizeof(*entering_features));
+                       if (entering_features) {
+                               *entering_features = ua.features;
+                               set_tcb_priv_data(tcp, entering_features, free);
+                       }
+
+                       return 0;
+               }
+
+               if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
+                       entering_features = get_tcb_priv_data(tcp);
+
+                       if (!entering_features
+                           || *entering_features != ua.features) {
+                               PRINT_FIELD_FLAGS(" => ", ua, features,
+                                                 uffd_api_features,
+                                                 "UFFD_FEATURE_???");
                        }
-                       tprints("}");
+
+                       PRINT_FIELD_FLAGS(", ", ua, ioctls, uffd_api_flags,
+                                         "_UFFDIO_???");
                }
-               return 1;
+
+               tprints("}");
+
+               break;
        }
 
        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 RVAL_IOCTL_DECODED;
+                       PRINT_FIELD_X("{", uc, dst);
+                       PRINT_FIELD_X(", ", uc, src);
+                       PRINT_FIELD_X(", ", uc, len);
+                       PRINT_FIELD_FLAGS(", ", uc, mode, uffd_copy_flags,
+                                         "UFFDIO_COPY_???");
+
+                       return 0;
                }
-               return 1;
+
+               if (!syserror(tcp) && !umove(tcp, arg, &uc))
+                       PRINT_FIELD_X(", ", uc, copy);
+
+               tprints("}");
+
+               break;
        }
 
        case UFFDIO_REGISTER: {
                struct uffdio_register ur;
+
                if (entering(tcp)) {
                        tprints(", ");
                        if (umove_or_printaddr(tcp, arg, &ur))
-                               return RVAL_DECODED | 1;
-                       tprints("{range=");
-                       tprintf_uffdio_range(&ur.range);
-                       tprints(", mode=");
-                       printflags64(uffd_register_mode_flags, ur.mode,
-                                    "UFFDIO_REGISTER_MODE_???");
-               } else {
-                       if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
-                               tprints(", ioctls=");
-                               printflags64(uffd_register_ioctl_flags,
-                                            ur.ioctls, "UFFDIO_???");
-                       }
-                       tprints("}");
+                               return RVAL_IOCTL_DECODED;
+                       PRINT_FIELD_UFFDIO_RANGE("{", ur, range);
+                       PRINT_FIELD_FLAGS(", ", ur, mode,
+                                         uffd_register_mode_flags,
+                                         "UFFDIO_REGISTER_MODE_???");
+
+                       return 0;
+               }
+
+               if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
+                       PRINT_FIELD_FLAGS(", ", ur, ioctls,
+                                         uffd_register_ioctl_flags,
+                                         "UFFDIO_???");
                }
-               return 1;
+
+               tprints("}");
+
+               break;
        }
 
        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;
+
+               break;
        }
 
        case UFFDIO_ZEROPAGE: {
                struct uffdio_zeropage uz;
+
                if (entering(tcp)) {
                        tprints(", ");
                        if (umove_or_printaddr(tcp, arg, &uz))
-                               return RVAL_DECODED | 1;
-                       tprints("{range=");
-                       tprintf_uffdio_range(&uz.range);
-                       tprints(", 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 RVAL_IOCTL_DECODED;
+                       PRINT_FIELD_UFFDIO_RANGE("{", uz, range);
+                       PRINT_FIELD_FLAGS(", ", uz, mode, uffd_zeropage_flags,
+                                         "UFFDIO_ZEROPAGE_???");
+
+                       return 0;
                }
-               return 1;
+
+               if (!syserror(tcp) && !umove(tcp, arg, &uz))
+                       PRINT_FIELD_X(", ", uz, zeropage);
+
+               tprints("}");
+
+               break;
        }
 
        default:
                return RVAL_DECODED;
        }
+
+       return RVAL_IOCTL_DECODED;
 }
 #endif /* HAVE_LINUX_USERFAULTFD_H */