/*
* 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
*/
#include "defs.h"
+#include "print_fields.h"
#include <fcntl.h>
#include "xlat/uffd_flags.h"
# 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"
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 */