]> granicus.if.org Git - strace/blobdiff - userfaultfd.c
mmap_cache: add function to enable mmap_cache
[strace] / userfaultfd.c
index 41224e2f0d9bbabda6d1e284b560a129be38ae18..2fa33c77b464621fded20699cad6cb468e61917b 100644 (file)
@@ -43,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"
@@ -69,96 +70,132 @@ uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
 {
        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.
-                        */
+                               break;
                        PRINT_FIELD_X("{", ua, api);
-                       PRINT_FIELD_X(", ", ua, features);
-               } else {
-                       if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
-                               PRINT_FIELD_X(" => ", ua, features);
-                               PRINT_FIELD_FLAGS64(", ", ua, ioctls,
-                                                   uffd_api_flags,
-                                                   "_UFFDIO_???");
+                       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;
+                               return RVAL_IOCTL_DECODED;
                        PRINT_FIELD_X("{", uc, dst);
                        PRINT_FIELD_X(", ", uc, src);
                        PRINT_FIELD_X(", ", uc, len);
-                       PRINT_FIELD_FLAGS64(", ", uc, mode, uffd_copy_flags,
-                                           "UFFDIO_COPY_???");
-               } else {
-                       if (!syserror(tcp) && !umove(tcp, arg, &uc))
-                               PRINT_FIELD_X(", ", uc, copy);
-                       tprints("}");
+                       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;
+                               return RVAL_IOCTL_DECODED;
                        PRINT_FIELD_UFFDIO_RANGE("{", ur, range);
-                       PRINT_FIELD_FLAGS64(", ", ur, mode,
-                                           uffd_register_mode_flags,
-                                           "UFFDIO_REGISTER_MODE_???");
-               } else {
-                       if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
-                               PRINT_FIELD_FLAGS64(", ", ur, ioctls,
-                                                   uffd_register_ioctl_flags,
-                                                   "UFFDIO_???");
-                       }
-                       tprints("}");
+                       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;
+                               return RVAL_IOCTL_DECODED;
                        PRINT_FIELD_UFFDIO_RANGE("{", uz, range);
-                       PRINT_FIELD_FLAGS64(", ", uz, mode, uffd_zeropage_flags,
-                                           "UFFDIO_ZEROPAGE_???");
-               } else {
-                       if (!syserror(tcp) && !umove(tcp, arg, &uz))
-                               PRINT_FIELD_X(", ", uz, zeropage);
-                       tprints("}");
+                       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 */