[RFC v2] Decode UFFDIO_* ioctls
Dr. David Alan Gilbert (git)
dgilbert at redhat.com
Fri Apr 22 18:02:08 UTC 2016
From: "Dr. David Alan Gilbert" <dgilbert at 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
More information about the Strace-devel
mailing list