[RFC PATCH v3 3/3] tests: add tests for DRM ioctl decoding

Zhibin Li haoyouab at gmail.com
Sat Jul 27 15:57:45 UTC 2019


* tests/ioctl_drm.c: New file.
* tests/ioctl_drm-success.c: Likewise.
* tests/ioctl_drm-success.tests: New test.
* tests/pure_executables.list : Add ioctl_drm.
* tests/gen_tests.in (ioctl_drm): New entry.
* tests/Makefile.am (check_PROGRAMS): Add ioctl_drm-success.
(DECODER_TESTS): Add ioctl_drm-success.test.
* tests/.gitignore: Add ioctl_drm and ioctl_drm-success.
---
 tests/.gitignore             |    2 +
 tests/Makefile.am            |    2 +
 tests/gen_tests.in           |    1 +
 tests/ioctl_drm-success.c    | 2289 ++++++++++++++++++++++++++++++++++
 tests/ioctl_drm-success.test |   18 +
 tests/ioctl_drm.c            |  192 +++
 tests/pure_executables.list  |    1 +
 7 files changed, 2505 insertions(+)
 create mode 100644 tests/ioctl_drm-success.c
 create mode 100755 tests/ioctl_drm-success.test
 create mode 100644 tests/ioctl_drm.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 7774ceec..b5b464ae 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -160,6 +160,8 @@ ioctl
 ioctl_block
 ioctl_dm
 ioctl_dm-v
+ioctl_drm
+ioctl_drm-success
 ioctl_evdev
 ioctl_evdev-success
 ioctl_evdev-success-v
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 05aede5d..ac44e855 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -99,6 +99,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
 	inject-nf \
 	int_0x80 \
 	ioctl_dm-v \
+	ioctl_drm-success \
 	ioctl_evdev-success \
 	ioctl_evdev-success-v \
 	ioctl_evdev-v \
@@ -243,6 +244,7 @@ DECODER_TESTS = \
 	int_0x80.test \
 	inotify_init-y.test \
 	ioctl.test \
+	ioctl_drm-success.test \
 	ioctl_evdev-success-v.test \
 	ioctl_evdev-success.test \
 	ioctl_perf-success.test \
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index f90910f1..ebb133fc 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -132,6 +132,7 @@ io_uring_setup	-a26 -y
 ioctl_block	+ioctl.test
 ioctl_dm	+ioctl.test -s9
 ioctl_dm-v	+ioctl.test -v -s9
+ioctl_drm	+ioctl.test
 ioctl_evdev	+ioctl.test
 ioctl_evdev-v	+ioctl.test -v
 ioctl_inotify	+ioctl.test
diff --git a/tests/ioctl_drm-success.c b/tests/ioctl_drm-success.c
new file mode 100644
index 00000000..a03c501f
--- /dev/null
+++ b/tests/ioctl_drm-success.c
@@ -0,0 +1,2289 @@
+#include "tests.h"
+
+#if defined(HAVE_DRM_H) || defined(HAVE_DRM_DRM_H)
+
+# include <errno.h>
+# include <inttypes.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/ioctl.h>
+# include "print_fields.h"
+
+# ifdef HAVE_DRM_H
+#  include <drm.h>
+# else
+#  include <drm/drm.h>
+# endif
+
+# include "xlat.h"
+
+static const unsigned int magic = 0xdeadbeef;
+static const unsigned long lmagic = (unsigned long) 0xdeadbeefbadc0dedULL;
+static const char *errstr;
+
+struct drm_check {
+	unsigned long cmd;
+	const char *cmd_str;
+	void *arg_ptr;
+	void (*print_arg)(long rc, void *ptr, void *arg);
+};
+
+struct drm_mode_rm_fb_wrap {
+	unsigned int fb_id;
+};
+
+static long
+invoke_test_syscall(unsigned long cmd, void *p)
+{
+	long rc = ioctl(-1, cmd, p);
+	errstr = sprintrc(rc);
+	static char inj_errstr[4096];
+
+	snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
+	errstr = inj_errstr;
+	return rc;
+}
+
+static void
+test_drm(struct drm_check *check, void *arg)
+{
+
+	long rc = invoke_test_syscall(check->cmd, check->arg_ptr);
+	printf("ioctl(-1, %s, ", check->cmd_str);
+	if (check->print_arg)
+		check->print_arg(rc, check->arg_ptr, arg);
+	else
+		printf("%p", check->arg_ptr);
+	printf(") = %s\n", errstr);
+}
+
+static void
+print_drm_version(long rc, void *ptr, void *arg)
+{
+	struct drm_version *ver = ptr;
+
+	if (rc < 0) {
+		printf("%p", ver);
+		return;
+	}
+	PRINT_FIELD_U("{", *ver, name_len);
+	PRINT_FIELD_U(", ", *ver, date_len);
+	PRINT_FIELD_U(", ", *ver, desc_len);
+	PRINT_FIELD_D("} => {", *ver, version_major);
+	PRINT_FIELD_D(", ", *ver, version_minor);
+	PRINT_FIELD_D(", ", *ver, version_patchlevel);
+	PRINT_FIELD_U(", ", *ver, name_len);
+	printf(", name=\"%s\"", ver->name);
+	PRINT_FIELD_U(", ", *ver, date_len);
+	printf(", date=\"%s\"", ver->date);
+	PRINT_FIELD_U(", ", *ver, desc_len);
+	printf(", desc=\"%s\"", ver->desc);
+	printf("}");
+}
+
+static void
+print_drm_get_unique(long rc, void *ptr, void *arg)
+{
+	struct drm_unique *unique = ptr;
+
+	if (rc < 0) {
+		printf("%p", unique);
+		return;
+	}
+	PRINT_FIELD_U("{", *unique, unique_len);
+	PRINT_FIELD_U("} => {", *unique, unique_len);
+	printf(", unique=\"%s\"", unique->unique);
+	printf("}");
+}
+
+static void
+print_drm_get_magic(long rc, void *ptr, void *arg)
+{
+	struct drm_auth *auth = ptr;
+
+	if (rc < 0) {
+		printf("%p", auth);
+		return;
+	}
+	PRINT_FIELD_U("{", *auth, magic);
+	printf("}");
+}
+
+static void
+print_drm_irq_busid(long rc, void *ptr, void *arg)
+{
+	struct drm_irq_busid *busid = ptr;
+
+	if (rc < 0) {
+		printf("%p", busid);
+		return;
+	}
+	PRINT_FIELD_D("{", *busid, busnum);
+	PRINT_FIELD_D(", ", *busid, devnum);
+	PRINT_FIELD_D(", ", *busid, funcnum);
+	PRINT_FIELD_D(", ", *busid, irq);
+	printf("}");
+}
+
+
+# include "xlat/drm_map_type.h"
+# include "xlat/drm_map_flags.h"
+
+static void
+print_drm_get_map(long rc, void *ptr, void *arg)
+{
+	struct drm_map *map = ptr;
+
+	if (rc < 0) {
+		printf("%p", map);
+		return;
+	}
+	PRINT_FIELD_X("{", *map, offset);
+	PRINT_FIELD_X("} => {", *map, offset);
+	PRINT_FIELD_U(", ", *map, size);
+	printf(", type=");
+	printxval(drm_map_type, map->type, "_DRM_???");
+	printf(", flags=");
+	printxval(drm_map_flags, map->flags, "_DRM_???");
+	printf(", handle=%p", map->handle);
+	PRINT_FIELD_D(", ", *map, mtrr);
+	printf("}");
+}
+
+static void
+print_drm_get_client(long rc, void *ptr, void *arg)
+{
+	struct drm_client *client = ptr;
+
+	if (rc < 0) {
+		printf("%p", client);
+		return;
+	}
+	PRINT_FIELD_D("{", *client, idx);
+	PRINT_FIELD_D(", ", *client, auth);
+	PRINT_FIELD_U(", ", *client, pid);
+	PRINT_FIELD_U(", ", *client, uid);
+	PRINT_FIELD_U(", ", *client, magic);
+	PRINT_FIELD_U(", ", *client, iocs);
+	printf("}");
+}
+
+# include "xlat/drm_stat_type.h"
+
+static void
+print_drm_get_stats(long rc, void *ptr, void *arg)
+{
+	struct drm_stats *stats = ptr;
+
+	if (rc < 0) {
+		printf("%p", stats);
+		return;
+	}
+	PRINT_FIELD_U("{", *stats, count);
+	printf(", data=[");
+	for (unsigned int i = 0; i < 15; i++) {
+		printf("%s%lu", i > 0 ? ", {value=" : "{value=", (unsigned long) stats->data[i].value);
+		printf(", type=");
+		printxval(drm_stat_type, stats->data[i].type, "_DRM_STAT_???");
+		printf("}");
+	}
+	printf("]}");
+}
+
+static void
+print_drm_set_version(long rc, void *ptr, void *arg)
+{
+	struct drm_set_version *ver = ptr;
+
+	if (rc < 0) {
+		printf("%p", ver);
+		return;
+	}
+	PRINT_FIELD_D("{", *ver, drm_di_major);
+	PRINT_FIELD_D(", ", *ver, drm_di_minor);
+	PRINT_FIELD_D(", ", *ver, drm_dd_major);
+	PRINT_FIELD_D(", ", *ver, drm_dd_minor);
+	PRINT_FIELD_D("} => {", *ver, drm_di_major);
+	PRINT_FIELD_D(", ", *ver, drm_di_minor);
+	PRINT_FIELD_D(", ", *ver, drm_dd_major);
+	PRINT_FIELD_D(", ", *ver, drm_dd_minor);
+	printf("}");
+
+}
+
+# include "xlat/drm_modeset_cmd.h"
+
+static void
+print_drm_modeset_ctl(long rc, void *ptr, void *arg)
+{
+	struct drm_modeset_ctl *ctl = ptr;
+
+	if (rc < 0) {
+		printf("%p", ctl);
+		return;
+	}
+	PRINT_FIELD_U("{", *ctl, crtc);
+	printxval(drm_modeset_cmd, ctl->cmd, "_DRM_???");
+	printf("}");
+}
+
+static void
+print_drm_gem_close(long rc, void *ptr, void *arg)
+{
+	struct drm_gem_close *close = ptr;
+
+	if (rc < 0) {
+		printf("%p", close);
+		return;
+	}
+	PRINT_FIELD_U("{", *close, handle);
+	printf("}");
+}
+
+static void
+print_drm_gem_flink(long rc, void *ptr, void *arg)
+{
+	struct drm_gem_flink *flink = ptr;
+
+	if (rc < 0) {
+		printf("%p", flink);
+		return;
+	}
+	PRINT_FIELD_U("{", *flink, handle);
+	PRINT_FIELD_U(", ", *flink, name);
+	printf("}");
+}
+
+static void
+print_drm_gem_open(long rc, void *ptr, void *arg)
+{
+	struct drm_gem_open *open = ptr;
+
+	if (rc < 0) {
+		printf("%p", open);
+		return;
+	}
+	PRINT_FIELD_U("{", *open, name);
+	PRINT_FIELD_U(", ", *open, handle);
+	PRINT_FIELD_U(", ", *open, size);
+	printf("}");
+}
+
+# include "xlat/drm_capability.h"
+
+static void
+print_drm_get_cap(long rc, void *ptr, void *arg)
+{
+	struct drm_get_cap *cap = ptr;
+
+	if (rc < 0) {
+		printf("%p", cap);
+		return;
+	}
+	printf("{capability=");
+	printxval(drm_capability, cap->capability, "DRM_CAP_???");
+	PRINT_FIELD_U(", ", *cap, value);
+	printf("}");
+}
+
+# include "xlat/drm_client_capability.h"
+
+static void
+print_drm_set_client_cap(long rc, void *ptr, void *arg)
+{
+	struct drm_set_client_cap *cap = ptr;
+
+	if (rc < 0) {
+		printf("%p", cap);
+		return;
+	}
+	printf("{capability=");
+	printxval(drm_client_capability, cap->capability, "DRM_CLIENT_CAP_???");
+	PRINT_FIELD_U(", ", *cap, value);
+	printf("}");
+}
+
+static void
+print_drm_auth_magic(long rc, void *ptr, void *arg)
+{
+	struct drm_auth *auth = ptr;
+
+	if (rc < 0) {
+		printf("%p", auth);
+		return;
+	}
+	PRINT_FIELD_U("{", *auth, magic);
+	printf("}");
+}
+
+static void
+print_drm_block(long rc, void *ptr, void *arg)
+{
+	struct drm_block *block = ptr;
+
+	printf("%p", block);
+}
+
+static void
+print_drm_unblock(long rc, void *ptr, void *arg)
+{
+	struct drm_block *block = ptr;
+
+	printf("%p", block);
+}
+
+# include "xlat/drm_control_func.h"
+
+static void
+print_drm_control(long rc, void *ptr, void *arg)
+{
+	struct drm_control *control = ptr;
+
+	if (rc < 0) {
+		printf("%p", control);
+		return;
+	}
+	printf("{func=");
+	printxval(drm_control_func, control->func, "DRM_???");
+	PRINT_FIELD_D(", ", *control, irq);
+	printf("}");
+}
+
+static void
+print_drm_add_map(long rc, void *ptr, void *arg)
+{
+	struct drm_map *map = ptr;
+
+	if (rc < 0) {
+		printf("%p", map);
+		return;
+	}
+	PRINT_FIELD_X("{", *map, offset);
+	PRINT_FIELD_U(", ", *map, size);
+	printf(", type=");
+	printxval(drm_map_type, map->type, "_DRM_???");
+	printf(", flags");
+	printxval(drm_map_flags, map->flags, "_DRM_???");
+	printf("}");
+}
+
+# include "xlat/drm_buf_desc_flags.h"
+
+static void
+print_drm_add_bufs(long rc, void *ptr, void *arg)
+{
+	struct drm_buf_desc *desc = ptr;
+
+	if (rc < 0) {
+		printf("%p", desc);
+		return;
+	}
+	PRINT_FIELD_D("{", *desc, count);
+	PRINT_FIELD_D(", ", *desc, size);
+	printf(", flags=");
+	printxval(drm_buf_desc_flags, desc->flags, "_DRM_???");
+	PRINT_FIELD_X(", ", *desc, agp_start);
+	PRINT_FIELD_D("} => {", *desc, count);
+	PRINT_FIELD_D(", ", *desc, size);
+	printf("}");
+}
+
+static void
+print_drm_mark_bufs(long rc, void *ptr, void *arg)
+{
+	struct drm_buf_desc *desc = ptr;
+
+	if (rc < 0) {
+		printf("%p", desc);
+		return;
+	}
+	PRINT_FIELD_D("{", *desc, size);
+	PRINT_FIELD_D(", ", *desc, low_mark);
+	PRINT_FIELD_D(", ", *desc, high_mark);
+	printf("}");
+}
+
+static void
+print_drm_info_bufs(long rc, void *ptr, void *arg)
+{
+	struct drm_buf_info *info = ptr;
+
+	if (rc < 0) {
+		printf("%p", info);
+		return;
+	}
+	printf("{list=%p", info->list);
+	PRINT_FIELD_D(", ", *info, count);
+	PRINT_FIELD_D("} => {", *info, count);
+	printf("}");
+}
+
+static void
+print_drm_map_bufs(long rc, void *ptr, void *arg)
+{
+	struct drm_buf_map *map = ptr;
+
+	if (rc < 0) {
+		printf("%p", map);
+		return;
+	}
+	PRINT_FIELD_D("{", *map, count);
+	printf(", virtual=%p", map->virtual);
+	printf(", list=%p", map->list);
+	printf("}");
+}
+
+static void
+print_drm_free_bufs(long rc, void *ptr, void *arg)
+{
+	struct drm_buf_free *free = ptr;
+
+	if (rc < 0) {
+		printf("%p", free);
+		return;
+	}
+	PRINT_FIELD_D("{", *free, count);
+	printf(", list=%p", free->list);
+	printf("}");
+}
+
+static void
+print_drm_rm_map(long rc, void *ptr, void *arg)
+{
+	struct drm_map *map = ptr;
+
+	if (rc < 0) {
+		printf("%p", map);
+		return;
+	}
+	printf("{handle=%p}", map->handle);
+}
+
+static void
+print_drm_sarea_ctx(long rc, void *ptr, void *arg)
+{
+	struct drm_ctx_priv_map *map = ptr;
+
+	if (rc < 0) {
+		printf("%p", map);
+		return;
+	}
+	PRINT_FIELD_U("{", *map, ctx_id);
+	printf(", handle=%p}", map->handle);
+}
+
+
+static void
+print_drm_ctx(long rc, void *ptr, void *arg)
+{
+	struct drm_ctx *ctx = ptr;
+
+	if (rc < 0) {
+		printf("%p", ctx);
+		return;
+	}
+	PRINT_FIELD_U("{", *ctx, handle);
+	printf("}");
+}
+
+# include "xlat/drm_ctx_flags.h"
+
+static void
+print_drm_get_ctx(long rc, void *ptr, void *arg)
+{
+	struct drm_ctx *ctx = ptr;
+
+	if (rc < 0) {
+		printf("%p", ctx);
+		return;
+	}
+	printf("{flags=");
+	printxval(drm_ctx_flags, ctx->flags, "_DRM_CONTEXT_???");
+	printf("}");
+}
+
+static void
+print_drm_res_ctx(long rc, void *ptr, void *arg)
+{
+	struct drm_ctx_res *res = ptr;
+
+	if (rc < 0) {
+		printf("%p", res);
+		return;
+	}
+	PRINT_FIELD_D("{", *res, count);
+	PRINT_FIELD_D("} => {", *res, count);
+	printf(", contexts=%p", res->contexts);
+	printf("}");
+}
+
+# include "xlat/drm_lock_flags.h"
+
+static void
+print_drm_lock(long rc, void *ptr, void *arg)
+{
+	struct drm_lock *lock = ptr;
+
+	if (rc < 0) {
+		printf("%p", lock);
+		return;
+	}
+	PRINT_FIELD_D("{", *lock, context);
+	printf(", flags=");
+	printxval(drm_lock_flags, lock->flags, "_DRM_LOCK_???");
+	printf("}");
+}
+
+static void
+print_drm_prime_handle_to_fd(long rc, void *ptr, void *arg)
+{
+	struct drm_prime_handle *handle = ptr;
+
+	if (rc < 0) {
+		printf("%p", handle);
+		return;
+	}
+	PRINT_FIELD_U("{", *handle, handle);
+	PRINT_FIELD_X(", ", *handle, flags);
+	PRINT_FIELD_U(", ", *handle, fd);
+	printf("}");
+}
+
+static void
+print_drm_prime_fd_to_handle(long rc, void *ptr, void *arg)
+{
+	struct drm_prime_handle *handle = ptr;
+
+	if (rc < 0) {
+		printf("%p", handle);
+		return;
+	}
+	PRINT_FIELD_U("{", *handle, fd);
+	PRINT_FIELD_U(", ", *handle, handle);
+	printf("}");
+}
+
+static void
+print_drm_agp_enable(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_mode *mode = ptr;
+
+	if (rc < 0) {
+		printf("%p", mode);
+		return;
+	}
+	PRINT_FIELD_U("{", *mode, mode);
+	printf("}");
+}
+
+static void
+print_drm_agp_info(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_info *info = ptr;
+
+	if (rc < 0) {
+		printf("%p", info);
+		return;
+	}
+	PRINT_FIELD_D("{", *info, agp_version_major);
+	PRINT_FIELD_D(", ", *info, agp_version_minor);
+	PRINT_FIELD_U(", ", *info, mode);
+	PRINT_FIELD_U(", ", *info, aperture_base);
+	PRINT_FIELD_U(", ", *info, aperture_size);
+	PRINT_FIELD_U(", ", *info, memory_allowed);
+	PRINT_FIELD_U(", ", *info, memory_used);
+	PRINT_FIELD_U(", ", *info, id_vendor);
+	PRINT_FIELD_U(", ", *info, id_device);
+	printf("}");
+}
+
+static void
+print_drm_agp_alloc(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_buffer *buffer = ptr;
+
+	if (rc < 0) {
+		printf("%p", buffer);
+		return;
+	}
+	PRINT_FIELD_U("{", *buffer, size);
+	PRINT_FIELD_U(", ", *buffer, type);
+	PRINT_FIELD_U(", ", *buffer, handle);
+	PRINT_FIELD_U(", ", *buffer, physical);
+	printf("}");
+}
+
+static void
+print_drm_agp_free(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_buffer *buffer = ptr;
+
+	if (rc < 0) {
+		printf("%p", buffer);
+		return;
+	}
+	PRINT_FIELD_U("{", *buffer, handle);
+	printf("}");
+}
+
+static void
+print_drm_agp_bind(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_binding *binding = ptr;
+
+	if (rc < 0) {
+		printf("%p", binding);
+		return;
+	}
+	PRINT_FIELD_U("{", *binding, handle);
+	PRINT_FIELD_X(", ", *binding, offset);
+	printf("}");
+}
+
+static void
+print_drm_agp_unbind(long rc, void *ptr, void *arg)
+{
+	struct drm_agp_binding *binding = ptr;
+
+	if (rc < 0) {
+		printf("%p", binding);
+		return;
+	}
+	PRINT_FIELD_U("{", *binding, handle);
+	printf("}");
+}
+
+static void
+print_drm_sg_alloc(long rc, void *ptr, void *arg)
+{
+	struct drm_scatter_gather *sg = ptr;
+
+	if (rc < 0) {
+		printf("%p", sg);
+		return;
+	}
+	PRINT_FIELD_U("{", *sg, size);
+	PRINT_FIELD_U(", ", *sg, handle);
+	printf("}");
+}
+
+static void
+print_drm_sg_free(long rc, void *ptr, void *arg)
+{
+	struct drm_scatter_gather *sg = ptr;
+
+	if (rc < 0) {
+		printf("%p", sg);
+		return;
+	}
+	PRINT_FIELD_U("{", *sg, handle);
+	printf("}");
+}
+
+# include "xlat/drm_vblank_seq_type.h"
+
+static void
+print_drm_wait_vblank(long rc, void *ptr, void *arg)
+{
+	union drm_wait_vblank *vblank = ptr;
+
+	if (rc < 0) {
+		printf("%p", vblank);
+		return;
+	}
+	printf("{request={type=");
+	printxval(drm_vblank_seq_type, vblank->request.type, "_DRM_VBLANK_???");
+	PRINT_FIELD_U(", ", vblank->request, sequence);
+	PRINT_FIELD_U(", ", vblank->request, signal);
+	printf("}");
+
+
+	PRINT_FIELD_U(", reply={", vblank->reply, type);
+	PRINT_FIELD_U(", ", vblank->reply, sequence);
+	PRINT_FIELD_U(", ", vblank->reply, tval_sec);
+	PRINT_FIELD_U(", ", vblank->reply, tval_usec);
+	printf("}}");
+}
+
+# ifdef DRM_IOCTL_CRTC_GET_SEQUENCE
+static void
+print_drm_crtc_get_sequence(long rc, void *ptr, void *arg)
+{
+	struct drm_crtc_get_sequence *seq = ptr;
+
+	if (rc < 0) {
+		printf("%p", seq);
+		return;
+	}
+	PRINT_FIELD_U("{", *seq, crtc_id);
+	PRINT_FIELD_U(", ", *seq, active);
+	PRINT_FIELD_U(", ", *seq, sequence);
+	PRINT_FIELD_D(", ", *seq, sequence_ns);
+	printf("}");
+}
+# endif
+
+# include "xlat/drm_crtc_sequence_flags.h"
+
+# ifdef DRM_IOCTL_CRTC_QUEUE_SEQUENCE
+static void
+print_drm_crtc_queue_sequence(long rc, void *ptr, void *arg)
+{
+	struct drm_crtc_queue_sequence *seq = ptr;
+
+	if (rc < 0) {
+		printf("%p", seq);
+		return;
+	}
+	PRINT_FIELD_U("{", *seq, crtc_id);
+	printf(", flags=");
+	printxval(drm_crtc_sequence_flags, seq->flags, "DRM_CRTC_SEQUENCE_???");
+	PRINT_FIELD_U(", ", *seq, user_data);
+	PRINT_FIELD_U(", ", *seq, sequence);
+	PRINT_FIELD_U("} => {", *seq, sequence);
+	printf("}");
+}
+# endif
+
+static void
+print_drm_mode_get_resources(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_card_res *res = ptr;
+
+	if (rc < 0) {
+		printf("%p", res);
+		return;
+	}
+	printf("{fb_id_ptr=%#llx, ", (unsigned long long) res->fb_id_ptr);
+	printf("crtc_id_ptr=%#llx, ", (unsigned long long) res->crtc_id_ptr);
+	printf("connector_id_ptr=%#llx, ", (unsigned long long) res->connector_id_ptr);
+	printf("encoder_id_ptr=%#llx", (unsigned long long) res->encoder_id_ptr);
+	PRINT_FIELD_U(", ", *res, count_fbs);
+	PRINT_FIELD_U(", ", *res, count_crtcs);
+	PRINT_FIELD_U(", ", *res, count_connectors);
+	PRINT_FIELD_U(", ", *res, count_encoders);
+	PRINT_FIELD_U(", ", *res, min_width);
+	PRINT_FIELD_U(", ", *res, max_width);
+	PRINT_FIELD_U(", ", *res, min_height);
+	PRINT_FIELD_U(", ", *res, max_height);
+	printf("}");
+}
+
+# include "xlat/drm_mode_type.h"
+# include "xlat/drm_mode_flags.h"
+
+static void
+drm_mode_print_modeinfo(struct drm_mode_modeinfo *info)
+{
+	PRINT_FIELD_U("", *info, clock);
+	PRINT_FIELD_U(", ", *info, hdisplay);
+	PRINT_FIELD_U(", ", *info, hsync_start);
+	PRINT_FIELD_U(", ", *info, hsync_end);
+	PRINT_FIELD_U(", ", *info, htotal);
+	PRINT_FIELD_U(", ", *info, hskew);
+	PRINT_FIELD_U(", ", *info, vdisplay);
+	PRINT_FIELD_U(", ", *info, vsync_start);
+	PRINT_FIELD_U(", ", *info, vsync_end);
+	PRINT_FIELD_U(", ", *info, vtotal);
+	PRINT_FIELD_U(", ", *info, vscan);
+	PRINT_FIELD_U(", ", *info, vrefresh);
+	printf(", flags=");
+	printxval(drm_mode_flags, info->flags, "DRM_MODE_FLAG_PIC_???");
+	printf(", type=");
+	printxval(drm_mode_type, info->type, "DRM_MODE_TYPE_???");
+	printf(", name=\"%s\"", info->name);
+}
+
+static void
+print_drm_mode_crtc(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_crtc *crtc = ptr;
+
+	if (rc < 0) {
+		printf("%p", crtc);
+		return;
+	}
+	PRINT_FIELD_U("{", *crtc, crtc_id);
+	printf(", set_connectors_ptr=%#llx", (unsigned long long) crtc->set_connectors_ptr);
+	PRINT_FIELD_U(", ", *crtc, count_connectors);
+	PRINT_FIELD_U(", ", *crtc, fb_id);
+	PRINT_FIELD_U(", ", *crtc, x);
+	PRINT_FIELD_U(", ", *crtc, y);
+	PRINT_FIELD_U(", ", *crtc, gamma_size);
+	PRINT_FIELD_U(", ", *crtc, mode_valid);
+	printf(", mode={");
+	drm_mode_print_modeinfo(&crtc->mode);
+	printf("}}");
+}
+
+static void
+print_drm_mode_cursor(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_cursor *cursor = ptr;
+
+	if (rc < 0) {
+		printf("%p", cursor);
+		return;
+	}
+	PRINT_FIELD_X("{", *cursor, flags);
+	PRINT_FIELD_U(", ", *cursor, crtc_id);
+	PRINT_FIELD_D(", ", *cursor, x);
+	PRINT_FIELD_D(", ", *cursor, y);
+	PRINT_FIELD_U(", ", *cursor, width);
+	PRINT_FIELD_U(", ", *cursor, height);
+	PRINT_FIELD_U(", ", *cursor, handle);
+	printf("}");
+}
+
+static void
+print_drm_mode_get_gamma(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_crtc_lut *lut = ptr;
+
+	if (rc < 0) {
+		printf("%p", lut);
+		return;
+	}
+	PRINT_FIELD_U("{", *lut, crtc_id);
+	PRINT_FIELD_U(", ", *lut, gamma_size);
+	printf(", red=%#llx", (unsigned long long) lut->red);
+	printf(", green=%#llx", (unsigned long long) lut->green);
+	printf(", blue=%#llx", (unsigned long long) lut->blue);
+	printf("}");
+}
+
+static void
+print_drm_mode_set_gamma(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_crtc_lut *lut = ptr;
+
+	if (rc < 0) {
+		printf("%p", lut);
+		return;
+	}
+	PRINT_FIELD_U("{", *lut, crtc_id);
+	PRINT_FIELD_U(", ", *lut, gamma_size);
+	printf(", red=%#llx", (unsigned long long) lut->red);
+	printf(", green=%#llx", (unsigned long long) lut->green);
+	printf(", blue=%#llx", (unsigned long long) lut->blue);
+	printf("}");
+}
+
+# include "xlat/drm_mode_encoder_type.h"
+
+static void
+print_drm_mode_get_encoder(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_encoder *enc = ptr;
+
+	if (rc < 0) {
+		printf("%p", enc);
+		return;
+	}
+	PRINT_FIELD_U("{", *enc, encoder_id);
+	PRINT_FIELD_U("} => {", *enc, encoder_id);
+	printf(", encoder_type=");
+	printxval(drm_mode_encoder_type, enc->encoder_type, "DRM_MODE_ENCODER_???");
+	PRINT_FIELD_U(", ", *enc, crtc_id);
+	PRINT_FIELD_X(", ", *enc, possible_crtcs);
+	PRINT_FIELD_X(", ", *enc, possible_clones);
+	printf("}");
+}
+
+static void
+print_drm_mode_get_connector(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_connector *con = ptr;
+
+	if (rc < 0) {
+		printf("%p", con);
+		return;
+	}
+	PRINT_FIELD_U("{", *con, connector_id);
+	PRINT_FIELD_U(", ", *con, count_encoders);
+	PRINT_FIELD_U("} => {", *con, connector_id);
+	PRINT_FIELD_U(", ", *con, count_encoders);
+	printf(", encoders_ptr=%#llx", (unsigned long long) con->encoders_ptr);
+	printf(", modes_ptr=%#llx", (unsigned long long) con->modes_ptr);
+	printf(", props_ptr=%#llx", (unsigned long long) con->props_ptr);
+	printf(", prop_values_ptr=%#llx", (unsigned long long) con->prop_values_ptr);
+	PRINT_FIELD_U(", ", *con, count_modes);
+	PRINT_FIELD_U(", ", *con, count_props);
+	PRINT_FIELD_U(", ", *con, encoder_id);
+	PRINT_FIELD_U(", ", *con, connector_type);
+	PRINT_FIELD_U(", ", *con, connector_type_id);
+	PRINT_FIELD_U(", ", *con, connection);
+	PRINT_FIELD_U(", ", *con, mm_width);
+	PRINT_FIELD_U(", ", *con, mm_height);
+	PRINT_FIELD_U(", ", *con, subpixel);
+	printf("}");
+}
+
+static void
+print_drm_mode_get_property(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_property *prop = ptr;
+
+	if (rc < 0) {
+		printf("%p", prop);
+		return;
+	}
+	PRINT_FIELD_U("{", *prop, prop_id);
+	printf(", values_ptr=%#llx", prop->values_ptr);
+	printf(", enum_blob_ptr=%#llx", prop->enum_blob_ptr);
+	PRINT_FIELD_X(", ", *prop, flags);
+	PRINT_FIELD_CSTRING(", ", *prop, name);
+	PRINT_FIELD_U(", ", *prop, count_values);
+	PRINT_FIELD_U(", ", *prop, count_enum_blobs);
+	printf("}");
+}
+
+static void
+print_drm_mode_set_property(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_connector_set_property *prop = ptr;
+
+	if (rc < 0) {
+		printf("%p", prop);
+		return;
+	}
+	PRINT_FIELD_U("{", *prop, value);
+	PRINT_FIELD_U(", ", *prop, prop_id);
+	PRINT_FIELD_U(", ", *prop, connector_id);
+	printf("}");
+}
+
+static void
+print_drm_mode_get_prop_blob(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_blob *blob = ptr;
+
+	if (rc < 0) {
+		printf("%p", blob);
+		return;
+	}
+	PRINT_FIELD_U("{", *blob, blob_id);
+	PRINT_FIELD_U(", ", *blob, length);
+	PRINT_FIELD_U(", ", *blob, data);
+	printf("}");
+}
+
+static void
+print_drm_mode_get_fb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_fb_cmd *cmd = ptr;
+
+	if (rc < 0) {
+		printf("%p", cmd);
+		return;
+	}
+	PRINT_FIELD_U("{", *cmd, fb_id);
+	PRINT_FIELD_U(", ", *cmd, width);
+	PRINT_FIELD_U(", ", *cmd, height);
+	PRINT_FIELD_U(", ", *cmd, pitch);
+	PRINT_FIELD_U(", ", *cmd, bpp);
+	PRINT_FIELD_U(", ", *cmd, depth);
+	PRINT_FIELD_U(", ", *cmd, handle);
+	printf("}");
+
+}
+
+static void
+print_drm_mode_add_fb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_fb_cmd *cmd = ptr;
+
+	if (rc < 0) {
+		printf("%p", cmd);
+		return;
+	}
+	PRINT_FIELD_U("{", *cmd, width);
+	PRINT_FIELD_U(", ", *cmd, height);
+	PRINT_FIELD_U(", ", *cmd, pitch);
+	PRINT_FIELD_U(", ", *cmd, bpp);
+	PRINT_FIELD_U(", ", *cmd, depth);
+	PRINT_FIELD_U(", ", *cmd, handle);
+	PRINT_FIELD_U(", ", *cmd, fb_id);
+	printf("}");
+}
+
+static void
+print_drm_mode_rm_fb(long rc, void *ptr, void *arg)
+{
+	//TODO unsigned int *handle = ptr;
+	struct drm_mode_rm_fb_wrap *wrap = ptr;
+
+	if (rc < 0) {
+		printf("%p", wrap);
+		return;
+	}
+	printf("%u", wrap->fb_id);
+}
+
+# include "xlat/drm_mode_page_flip_flags.h"
+
+static void
+print_drm_mode_page_flip(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_crtc_page_flip *flip = ptr;
+
+	if (rc < 0) {
+		printf("%p", flip);
+		return;
+	}
+	PRINT_FIELD_U("{", *flip, crtc_id);
+	PRINT_FIELD_U(", ", *flip, fb_id);
+	printf(", flags=");
+	printxval(drm_mode_page_flip_flags, flip->flags, "DRM_MODE_PAGE_FLIP_???");
+	PRINT_FIELD_X(", ", *flip, user_data);
+	printf("}");
+}
+
+static void
+print_drm_mode_dirty_fb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_fb_dirty_cmd *cmd = ptr;
+
+	if (rc < 0) {
+		printf("%p", cmd);
+		return;
+	}
+	PRINT_FIELD_U("{", *cmd, fb_id);
+	PRINT_FIELD_X(", ", *cmd, flags);
+	PRINT_FIELD_X(", ", *cmd, color);
+	PRINT_FIELD_U(", ", *cmd, num_clips);
+	printf(", clips_ptr=%#llx", cmd->clips_ptr);
+	printf("}");
+}
+
+static void
+print_drm_mode_create_dumb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_create_dumb *dumb = ptr;
+
+	if (rc < 0) {
+		printf("%p", dumb);
+		return;
+	}
+	PRINT_FIELD_U("{", *dumb, width);
+	PRINT_FIELD_U(", ", *dumb, height);
+	PRINT_FIELD_U(", ", *dumb, bpp);
+	PRINT_FIELD_X(", ", *dumb, flags);
+	PRINT_FIELD_U(", ", *dumb, handle);
+	PRINT_FIELD_U(", ", *dumb, pitch);
+	PRINT_FIELD_U(", ", *dumb, size);
+	printf("}");
+}
+
+static void
+print_drm_mode_map_dumb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_map_dumb *dumb = ptr;
+
+	if (rc < 0) {
+		printf("%p", dumb);
+		return;
+	}
+	PRINT_FIELD_U("{", *dumb, handle);
+	PRINT_FIELD_U(", ", *dumb, offset);
+	printf("}");
+}
+
+static void
+print_drm_mode_destroy_dumb(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_destroy_dumb *dumb = ptr;
+
+	if (rc < 0) {
+		printf("%p", dumb);
+		return;
+	}
+	PRINT_FIELD_U("{", *dumb, handle);
+	printf("}");
+}
+
+static void
+print_drm_mode_getplaneresources(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_plane_res *res = ptr;
+
+	if (rc < 0) {
+		printf("%p", res);
+		return;
+	}
+	printf("{plane_id_ptr=%#llx", (unsigned long long) res->plane_id_ptr);
+	PRINT_FIELD_U(", ", *res, count_planes);
+	PRINT_FIELD_U("} => {", *res, count_planes);
+	printf("}");
+}
+
+static void
+print_drm_mode_getplane(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_plane *plane = ptr;
+
+	if (rc < 0) {
+		printf("%p", plane);
+		return;
+	}
+	PRINT_FIELD_U("{", *plane, plane_id);
+	printf(", format_type_ptr=%#llx", plane->format_type_ptr);
+	printf("} => {format_type_ptr=%#llx", plane->format_type_ptr);
+	PRINT_FIELD_U(", ", *plane, crtc_id);
+	PRINT_FIELD_U(", ", *plane, fb_id);
+	PRINT_FIELD_U(", ", *plane, possible_crtcs);
+	PRINT_FIELD_U(", ", *plane, gamma_size);
+	PRINT_FIELD_U(", ", *plane, count_format_types);
+	printf("}");
+}
+
+static void
+print_drm_mode_setplane(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_set_plane *plane = ptr;
+
+	if (rc < 0) {
+		printf("%p", plane);
+		return;
+	}
+	PRINT_FIELD_U("{", *plane, plane_id);
+	PRINT_FIELD_U(", ", *plane, crtc_id);
+	PRINT_FIELD_U(", ", *plane, fb_id);
+	PRINT_FIELD_X(", ", *plane, flags);
+	PRINT_FIELD_D(", ", *plane, crtc_x);
+	PRINT_FIELD_D(", ", *plane, crtc_y);
+	PRINT_FIELD_D(", ", *plane, crtc_w);
+	PRINT_FIELD_D(", ", *plane, crtc_h);
+	PRINT_FIELD_D(", ", *plane, src_x);
+	PRINT_FIELD_D(", ", *plane, src_y);
+	PRINT_FIELD_D(", ", *plane, src_h);
+	PRINT_FIELD_D(", ", *plane, src_w);
+	printf("}");
+}
+
+static void
+print_drm_mode_add_fb2(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_fb_cmd2 *cmd = ptr;
+
+	if (rc < 0) {
+		printf("%p", cmd);
+		return;
+	}
+	PRINT_FIELD_U("{", *cmd, width);
+	PRINT_FIELD_U(", ", *cmd, height);
+	PRINT_FIELD_X(", ", *cmd, pixel_format);
+	PRINT_FIELD_U(", ", *cmd, flags);
+	printf(", handles=[%u, %u, %u, %u], "
+	       "pitches=[%u, %u, %u, %u], "
+	       "offsets=[%u, %u, %u, %u]",
+	       cmd->handles[0], cmd->handles[1], cmd->handles[2],
+	       cmd->handles[3], cmd->pitches[0], cmd->pitches[1],
+	       cmd->pitches[2], cmd->pitches[3], cmd->offsets[0],
+	       cmd->offsets[1], cmd->offsets[2], cmd->offsets[3]);
+#ifdef HAVE_STRUCT_DRM_MODE_FB_CMD2_MODIFIER
+	printf(", modifiers=[%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "]",
+	       (uint64_t) cmd->modifier[0], (uint64_t) cmd->modifier[1],
+	       (uint64_t) cmd->modifier[2], (uint64_t) cmd->modifier[3]);
+#endif
+	PRINT_FIELD_U(", ", *cmd, fb_id);
+	printf("}");
+}
+
+static void
+print_drm_mode_obj_getproperties(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_obj_get_properties *props = ptr;
+
+	if (rc < 0) {
+		printf("%p", props);
+		return;
+	}
+	printf("{props_ptr=%#llx", props->props_ptr);
+	printf(", prop_values_ptr=%#llx", props->prop_values_ptr);
+	PRINT_FIELD_U(", ", *props, obj_id);
+	PRINT_FIELD_U(", ", *props, obj_type);
+	PRINT_FIELD_U(", ", *props, count_props);
+	printf("}");
+}
+
+static void
+print_drm_mode_obj_setproperty(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_obj_set_property *prop = ptr;
+
+	if (rc < 0) {
+		printf("%p", prop);
+		return;
+	}
+	PRINT_FIELD_U("{", *prop, value);
+	PRINT_FIELD_U(", ", *prop, prop_id);
+	PRINT_FIELD_U(", ", *prop, obj_id);
+	PRINT_FIELD_U(", ", *prop, obj_type);
+	printf("}");
+}
+
+static void
+print_drm_mode_cursor2(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_cursor2 *cursor2 = ptr;
+
+	if (rc < 0) {
+		printf("%p", cursor2);
+		return;
+	}
+	PRINT_FIELD_X("{", *cursor2, flags);
+	PRINT_FIELD_U(", ", *cursor2, crtc_id);
+	PRINT_FIELD_D(", ", *cursor2, x);
+	PRINT_FIELD_D(", ", *cursor2, y);
+	PRINT_FIELD_U(", ", *cursor2, width);
+	PRINT_FIELD_U(", ", *cursor2, height);
+	PRINT_FIELD_U(", ", *cursor2, handle);
+	PRINT_FIELD_D(", ", *cursor2, hot_x);
+	PRINT_FIELD_D(", ", *cursor2, hot_y);
+	printf("}");
+}
+
+static void
+print_drm_mode_atomic(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_atomic *atomic = ptr;
+
+	if (rc < 0) {
+		printf("%p", atomic);
+		return;
+	}
+	PRINT_FIELD_X("{", *atomic, flags);
+	PRINT_FIELD_U(", ", *atomic, count_objs);
+	printf(", objs_ptr=%#llx", atomic->objs_ptr);
+	printf(", count_props_ptr=%#llx", atomic->count_props_ptr);
+	printf(", props_ptr=%#llx", atomic->props_ptr);
+	printf(", prop_values_ptr=%#llx", atomic->prop_values_ptr);
+	PRINT_FIELD_U(", ", *atomic, reserved);
+	PRINT_FIELD_U(", ", *atomic, user_data);
+	printf("}");
+}
+
+static void
+print_drm_mode_createpropblob(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_create_blob *blob = ptr;
+
+	if (rc < 0) {
+		printf("%p", blob);
+		return;
+	}
+	printf("{data=%#llx", blob->data);
+	PRINT_FIELD_U(", ", *blob, length);
+	PRINT_FIELD_U(", ", *blob, blob_id);
+	printf("}");
+}
+
+static void
+print_drm_destroypropblob(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_destroy_blob *blob = ptr;
+
+	if (rc < 0) {
+		printf("%p", blob);
+		return;
+	}
+	PRINT_FIELD_U("{", *blob, blob_id);
+	printf("}");
+}
+
+# ifdef DRM_IOCTL_SYNCOBJ_CREATE
+
+# include "xlat/drm_syncobj_flags.h"
+
+static void
+print_drm_syncobj_create(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_create *create = ptr;
+
+	if (rc < 0) {
+		printf("%p", create);
+		return;
+	}
+	printf("{flags=");
+	printxval(drm_syncobj_flags, create->flags, "DRM_SYNCOJB_???");
+	PRINT_FIELD_U(", ", *create, handle);
+	printf("}");
+}
+
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_DESTROY
+static void
+print_drm_syncobj_destroy(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_destroy *destroy = ptr;
+
+	if (rc < 0) {
+		printf("%p", destroy);
+		return;
+	}
+	PRINT_FIELD_U("{", *destroy, handle);
+	PRINT_FIELD_U(", ", *destroy, pad);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
+static void
+print_drm_syncobj_handle_to_fd(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_handle *handle = ptr;
+
+	if (rc < 0) {
+		printf("%p", handle);
+		return;
+	}
+	PRINT_FIELD_U("{", *handle, handle);
+	PRINT_FIELD_X(", ", *handle, flags);
+	PRINT_FIELD_U(", ", *handle, pad);
+	PRINT_FIELD_D(", ", *handle, fd);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
+static void
+print_drm_syncobj_fd_to_handle(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_handle *handle = ptr;
+
+	if (rc < 0) {
+		printf("%p", handle);
+		return;
+	}
+	PRINT_FIELD_D("{", *handle, fd);
+	PRINT_FIELD_X(", ", *handle, flags);
+	PRINT_FIELD_U(", ", *handle, pad);
+	PRINT_FIELD_U(", ", *handle, handle);
+	printf("}");
+
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_WAIT
+static void
+print_drm_syncobj_wait(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_wait *wait = ptr;
+
+	if (rc < 0) {
+		printf("%p", wait);
+		return;
+	}
+	printf("{handles=%#llx", wait->handles);
+	PRINT_FIELD_D(", ", *wait, timeout_nsec);
+	PRINT_FIELD_U(", ", *wait, count_handles);
+	PRINT_FIELD_X(", ", *wait, flags);
+	PRINT_FIELD_U(", ", *wait, first_signaled);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_RESET
+static void
+print_drm_syncobj_reset_or_signal(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_array *array = ptr;
+
+	if (rc < 0) {
+		printf("%p", array);
+		return;
+	}
+	printf("{handles=%#llx", array->handles);
+	PRINT_FIELD_U(", ", *array, count_handles);
+	PRINT_FIELD_U(", ", *array, pad);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_MODE_CREATE_LEASE
+static void
+print_drm_mode_create_lease(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_create_lease *lease= ptr;
+
+	if (rc < 0) {
+		printf("%p", lease);
+		return;
+	}
+	printf("{object_ids=%#llx", lease->object_ids);
+	PRINT_FIELD_U(", ", *lease, object_count);
+	PRINT_FIELD_X(", ", *lease, flags);
+	PRINT_FIELD_U(", ", *lease, lessee_id);
+	PRINT_FIELD_U(", ", *lease, fd);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_MODE_LIST_LESSEES
+static void
+print_drm_mode_list_lessees(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_list_lessees *lessees = ptr;
+
+	if (rc < 0) {
+		printf("%p", lessees);
+		return;
+	}
+	PRINT_FIELD_U("{", *lessees, pad);
+	printf(", lessees_ptr=%#llx", (unsigned long long) lessees->lessees_ptr);
+	PRINT_FIELD_U(", ", *lessees, count_lessees);
+	PRINT_FIELD_U("} => {", *lessees, count_lessees);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_MODE_GET_LEASE
+static void
+print_drm_mode_get_lease(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_get_lease *lease = ptr;
+
+	if (rc < 0) {
+		printf("%p", lease);
+		return;
+	}
+	PRINT_FIELD_U("{", *lease, pad);
+	printf(", objects_ptr=%#llx", lease->objects_ptr);
+	PRINT_FIELD_U(", ", *lease, count_objects);
+	PRINT_FIELD_U("} => {", *lease, count_objects);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_MODE_REVOKE_LEASE
+static void
+print_drm_mode_revoke_lease(long rc, void *ptr, void *arg)
+{
+	struct drm_mode_revoke_lease *lease = ptr;
+
+	if (rc < 0) {
+		printf("%p", lease);
+		return;
+	}
+	PRINT_FIELD_U("{", *lease, lessee_id);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
+
+# include "xlat/drm_syncobj_wait_flags.h"
+
+static void
+print_drm_syncobj_timeline_wait(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_timeline_wait *wait = ptr;
+
+	if (rc < 0) {
+		printf("%p", wait);
+		return;
+	}
+	printf("{handles=%#llx", (unsigned long long) wait->handles);
+	PRINT_FIELD_D(", ", *wait, timeout_nsec);
+	PRINT_FIELD_U(", ", *wait, count_handles);
+	printf(", flags=");
+	printxval(drm_syncobj_wait_flags, wait->flags, "DRM_SYNCOBJ_WAIT_FLAGS_???");
+	PRINT_FIELD_U(", ", *wait, first_signaled);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+static void
+print_drm_syncobj_query_or_timeline_signal(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_timeline_array *array = ptr;
+
+	if (rc < 0) {
+		printf("%p", array);
+		return;
+	}
+	printf("{handles=%#llx", (unsigned long long) array->handles);
+	printf(", points=%#llx", (unsigned long long) array->points);
+	PRINT_FIELD_U(", ", *array, count_handles);
+	PRINT_FIELD_U(", ", *array, pad);
+	printf("}");
+}
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_TRANSFER
+static void
+print_drm_syncobj_transfer(long rc, void *ptr, void *arg)
+{
+	struct drm_syncobj_transfer *transfer = ptr;
+
+	if (rc < 0) {
+		printf("%p", transfer);
+		return;
+	}
+	PRINT_FIELD_U("{", *transfer, src_handle);
+	PRINT_FIELD_U(", ", *transfer, dst_handle);
+	PRINT_FIELD_U(", ", *transfer, src_point);
+	PRINT_FIELD_U(", ", *transfer, dst_point);
+	printf(", flags=");
+	printxval(drm_syncobj_wait_flags, transfer->flags, "DRM_SYNCOBJ_WAIT_FLAGS_???");
+	PRINT_FIELD_U(", ", *transfer, pad);
+	printf("}");
+}
+# endif
+
+int
+main(int argc, char **argv)
+{
+	unsigned long num_skip;
+	long inject_retval;
+	bool locked = false;
+
+	if (argc == 1)
+		return 0;
+
+	if (argc < 3)
+		error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
+
+	num_skip = strtoul(argv[1], NULL, 0);
+	inject_retval = strtol(argv[2], NULL, 0);
+
+	if (inject_retval < 0)
+		error_msg_and_fail("Expected non-negative INJECT_RETVAL, "
+				   "but got %ld", inject_retval);
+
+	for (unsigned int i = 0; i < num_skip; i++) {
+		long rc = ioctl(-1, DRM_IOCTL_VERSION, NULL);
+		printf("ioctl(-1, DRM_IOCTL_VERSION, NULL) = %s%s\n",
+		       sprintrc(rc),
+		       rc == inject_retval ? " (INJECTED)" : "");
+
+		if (rc != inject_retval)
+			continue;
+
+		locked = true;
+		break;
+	}
+
+	if (!locked)
+		error_msg_and_fail("Hasn't locked on ioctl(-1"
+				   ", DRM_IOCTL_VERSION, NULL) returning %lu",
+				   inject_retval);
+
+	/* drm_version */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_version, ver);
+	char bogus_name[4096] = "bogus_name";
+	char bogus_date[4096] = "bogus_date";
+	char bogus_desc[4096] = "bogus_desc";
+	ver->version_major = (int) magic;
+	ver->version_minor = (int) magic;
+	ver->version_patchlevel = (int) magic;
+	ver->name_len = strlen(bogus_name);
+	ver->name = bogus_name;
+	ver->date_len = strlen(bogus_date);
+	ver->date = bogus_date;
+	ver->desc_len = strlen(bogus_desc);
+	ver->desc = bogus_desc;
+
+	/* drm_unique */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_unique, unique);
+	char bogus_unique[4096] = "bogus_unique";
+	unique->unique_len = strlen(bogus_unique);
+	unique->unique = bogus_unique;
+
+	/* drm_auth */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_auth, auth);
+	auth->magic = magic;
+
+	/* drm_irq_busid */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_irq_busid, busid);
+	busid->busnum = (int) magic;
+	busid->devnum = (int) magic;
+	busid->funcnum = (int) magic;
+	busid->irq = (int) magic;
+
+	/* drm_map */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_map, map);
+	map->offset = lmagic;
+	map->size = lmagic;
+	map->type = _DRM_FRAME_BUFFER;
+	map->flags = _DRM_RESTRICTED;
+	map->handle = (void *) lmagic;
+	map->mtrr = magic;
+
+	/* drm_client */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_client, client);
+	client->idx = magic;
+	client->auth = magic;
+	client->pid = magic;
+	client->uid = magic;
+
+	/* drm_stats */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_stats, stats);
+	stats->count = magic;
+	for (unsigned int i = 0; i < 15; i++) {
+		stats->data[i].value = lmagic;
+		stats->data[i].type = _DRM_STAT_LOCK;
+	}
+
+	/* drm_set_version */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_set_version, set_ver);
+	set_ver->drm_di_major = (int) magic;
+	set_ver->drm_di_minor = (int) magic;
+	set_ver->drm_dd_major = (int) magic;
+	set_ver->drm_dd_minor = (int) magic;
+
+	/* drm_modeset_ctl */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_modeset_ctl, ctl);
+	ctl->crtc = magic;
+	ctl->cmd = _DRM_PRE_MODESET;
+
+	/* drm_gem_close */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_gem_close, close);
+	close->handle = magic;
+
+	/* drm_gem_flink */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_gem_flink, flink);
+	flink->handle = magic;
+	flink->name = magic;
+
+	/* drm_gen_open */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_gem_open, open);
+	open->name = magic;
+	open->handle = magic;
+	open->size = lmagic;
+
+	/* drm_get_cap */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_get_cap, cap);
+	cap->capability = DRM_CAP_DUMB_BUFFER;
+	cap->value = lmagic;
+
+	/* drm_set_client_cap */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_set_client_cap, cli_cap);
+	cli_cap->capability = DRM_CLIENT_CAP_STEREO_3D;
+	cli_cap->value = lmagic;
+
+	/* drm_block */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_block, block);
+	block->unused = (int) magic;
+
+	/* drm_control */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_control, control);
+	control->func = DRM_ADD_COMMAND;
+	control->irq = (int) magic;
+
+	/* drm_buf_desc */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_buf_desc, desc);
+	desc->count = (int) magic;
+	desc->size = (int) magic;
+	desc->low_mark = (int) magic;
+	desc->high_mark = (int) magic;
+	desc->flags = _DRM_PAGE_ALIGN;
+	desc->agp_start = lmagic;
+
+	/* drm_buf_info */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_buf_info, info);
+	info->count = (int) magic;
+	info->list = (struct drm_buf_desc *) lmagic;
+
+	/* drm_buf_map */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_buf_map, buf_map);
+	buf_map->count = (int) magic;
+	buf_map->virtual = (void *) lmagic;
+	buf_map->list = (struct drm_buf_pub *) lmagic;
+
+	/* drm_buf_free */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_buf_free, buf_free);
+	buf_free->count = (int) magic;
+	buf_free->list = (int *) lmagic;
+
+	/* drm_ctx_priv_map */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_ctx_priv_map, priv_map);
+	priv_map->ctx_id = magic;
+	priv_map->handle = (void *) lmagic;
+
+	/* drm_ctx */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_ctx, ctx);
+	ctx->handle = magic;
+	ctx->flags = _DRM_CONTEXT_PRESERVED;
+
+	/* drm_ctx_res */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_ctx_res, ctx_res);
+	ctx_res->count = (int) magic;
+	ctx_res->contexts = (struct drm_ctx *) lmagic;
+
+	/* drm_draw */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_draw, draw);
+	draw->handle = magic;
+
+	/* drm_lock */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_lock, lock);
+	lock->context = (int) magic;
+	lock->flags = _DRM_LOCK_READY;
+
+	/* drm_prime_handle */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_prime_handle, prime_handle);
+	prime_handle->handle = magic;
+	prime_handle->flags = magic;
+	prime_handle->fd = (int) magic;
+
+	/* drm_agp_mode */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_agp_mode, agp_mode);
+	agp_mode->mode = lmagic;
+
+	/* drm_agp_info */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_agp_info, agp_info);
+	agp_info->agp_version_major = (int) magic;
+	agp_info->agp_version_minor = (int) magic;
+	agp_info->mode = lmagic;
+	agp_info->aperture_base = lmagic;
+	agp_info->aperture_size = lmagic;
+	agp_info->memory_allowed = lmagic;
+	agp_info->memory_used = lmagic;
+	agp_info->id_vendor = (unsigned short) magic;
+	agp_info->id_device = (unsigned short) magic;
+
+	/* drm_agp_buffer */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_agp_buffer, agp_buffer);
+	agp_buffer->size = lmagic;
+	agp_buffer->handle = lmagic;
+	agp_buffer->type = lmagic;
+	agp_buffer->physical = lmagic;
+
+	/* drm_agp_binding */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_agp_binding, agp_binding);
+	agp_binding->handle = lmagic;
+	agp_binding->offset = lmagic;
+
+	/* drm_scatter_gather */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_scatter_gather, sg);
+	sg->size = lmagic;
+	sg->handle = lmagic;
+
+	/* drm_wait_vblank */
+	TAIL_ALLOC_OBJECT_CONST_PTR(union drm_wait_vblank, vblank);
+	vblank->request.type = _DRM_VBLANK_ABSOLUTE;
+	vblank->request.sequence = magic;
+	vblank->request.signal = lmagic;
+	vblank->reply.tval_usec = (long) lmagic;
+
+# ifdef DRM_IOCTL_CRTC_GET_SEQUENCE
+	/* drm_crtc_get_sequence */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_crtc_get_sequence, get_seq);
+	get_seq->crtc_id = magic;
+	get_seq->active = magic;
+	get_seq->sequence = lmagic;
+	get_seq->sequence_ns = (long) lmagic;
+# endif
+
+# ifdef DRM_IOCTL_CRTC_QUEUE_SEQUENCE
+	/* drm_crtc_queue_sequence */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_crtc_queue_sequence, queue_seq);
+	queue_seq->crtc_id = magic;
+	queue_seq->flags = DRM_CRTC_SEQUENCE_RELATIVE;
+	queue_seq->sequence = lmagic;
+	queue_seq->user_data = lmagic;
+# endif
+
+	/* drm_update_draw */
+
+	/* drm_mode_card_res */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_card_res, card_res);
+	card_res->fb_id_ptr = lmagic;
+	card_res->crtc_id_ptr = lmagic;
+	card_res->connector_id_ptr = lmagic;
+	card_res->encoder_id_ptr = lmagic;
+	card_res->count_fbs = magic;
+	card_res->count_crtcs = magic;
+	card_res->count_connectors = magic;
+	card_res->count_encoders = magic;
+	card_res->min_width = magic;
+	card_res->max_width = magic;
+	card_res->min_height = magic;
+	card_res->max_height = magic;
+
+	/* drm_mode_crtc */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_crtc, crtc);
+	char bogus_mode_name[DRM_DISPLAY_MODE_LEN] = "bogus_mode_name";
+	crtc->crtc_id = magic;
+	crtc->set_connectors_ptr = lmagic;
+	crtc->count_connectors = magic;
+	crtc->fb_id = magic;
+	crtc->x = magic;
+	crtc->y = magic;
+	crtc->gamma_size = magic;
+	crtc->mode_valid = magic;
+	snprintf(crtc->mode.name, sizeof(bogus_mode_name), "%s", bogus_mode_name);
+
+	/* drm_mode_cursor */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_cursor, cursor);
+	cursor->flags = magic;
+	cursor->crtc_id = magic;
+	cursor->x = (int) magic;
+	cursor->y = (int) magic;
+	cursor->width = magic;
+	cursor->height = magic;
+	cursor->handle = magic;
+
+	/* drm_mode_crtc_lut */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_crtc_lut, lut);
+	lut->crtc_id = magic;
+	lut->gamma_size = magic;
+	lut->red = lmagic;
+	lut->green = lmagic;
+	lut->blue = lmagic;
+
+	/* drm_mode_get_encoder */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_encoder, enc);
+	enc->encoder_id = magic;
+	enc->encoder_type = DRM_MODE_ENCODER_NONE;
+	enc->crtc_id = magic;
+	enc->possible_crtcs = magic;
+	enc->possible_clones = magic;
+
+	/* drm_mode_get_connector */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_connector, con);
+	char con_str[4096];
+	snprintf(con_str, sizeof(con_str), "DRM_IOWR(0xa7, %#lx) /* DRM_IOCTL_MODE_GETCONNECTOR */",
+		 (long unsigned int) _IOC_SIZE(DRM_IOCTL_MODE_GETCONNECTOR));
+	con->connector_id = magic;
+	con->encoders_ptr = lmagic;
+	con->modes_ptr = lmagic;
+	con->props_ptr = lmagic;
+	con->prop_values_ptr = lmagic;
+	con->count_modes = magic;
+	con->count_props = magic;
+	con->count_encoders = magic;
+	con->encoder_id = magic;
+	con->connector_type = magic;
+	con->connector_type_id = magic;
+	con->connection = magic;
+	con->mm_width = magic;
+	con->mm_height = magic;
+	con->subpixel = magic;
+
+	/* drm_mode_mode_cmd */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_mode_cmd, mode_cmd);
+	mode_cmd->connector_id = magic;
+	snprintf(mode_cmd->mode.name, sizeof(bogus_mode_name), "%s", bogus_mode_name);
+
+	/* drm_mode_get_property */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_property, prop);
+	char bogus_property_name[DRM_PROP_NAME_LEN] = "bogus_property_name";
+	prop->prop_id = magic;
+	prop->values_ptr = lmagic;
+	prop->enum_blob_ptr = lmagic;
+	prop->flags = magic;
+	snprintf(prop->name, sizeof(bogus_property_name), "%s", bogus_property_name);
+
+	/* drm_mode_connector_set_property */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_connector_set_property, set_prop);
+	set_prop->value = lmagic;
+	set_prop->prop_id = magic;
+	set_prop->connector_id = magic;
+
+	/* drm_mode_get_blob */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_blob, blob);
+	blob->blob_id = magic;
+	blob->length = magic;
+	blob->data = lmagic;
+
+	/* drm_mode_fb_cmd */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_fb_cmd, cmd);
+	cmd->width = magic;
+	cmd->height = magic;
+	cmd->pitch = magic;
+	cmd->bpp = magic;
+	cmd->depth = magic;
+	cmd->handle = magic;
+	cmd->fb_id = magic;
+
+	/* drm_mode_crtc_page_flip */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_crtc_page_flip, flip);
+	flip->crtc_id = magic;
+	flip->fb_id = magic;
+	flip->flags = DRM_MODE_PAGE_FLIP_EVENT;
+	flip->user_data = lmagic;
+
+	/* drm_mode_fb_dirty_cmd */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_fb_dirty_cmd, dirty_cmd);
+	dirty_cmd->fb_id = magic;
+	dirty_cmd->flags = magic;
+	dirty_cmd->color = magic;
+	dirty_cmd->num_clips = magic;
+	dirty_cmd->clips_ptr = lmagic;
+
+	/* struct drm_mode_create_dumb */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_create_dumb, dumb);
+	dumb->width = magic;
+	dumb->height = magic;
+	dumb->bpp = magic;
+	dumb->flags = magic;
+	dumb->handle = magic;
+	dumb->pitch = magic;
+	dumb->size = lmagic;
+
+	/* struct drm_mode_map_dumb */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_map_dumb, map_dumb);
+	map_dumb->handle = magic;
+	map_dumb->offset = magic;
+
+	/* struct drm_mode_destroy_dumb */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_destroy_dumb, destroy_dumb);
+	destroy_dumb->handle = magic;
+
+	/* drm_mode_get_plane_res */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_plane_res, plane_res);
+	plane_res->plane_id_ptr = lmagic;
+	plane_res->count_planes = magic;
+
+	/* drm_mode_get_plane */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_plane, get_plane);
+	get_plane->plane_id = magic;
+	get_plane->crtc_id = magic;
+	get_plane->fb_id = magic;
+	get_plane->possible_crtcs = magic;
+	get_plane->gamma_size = magic;
+	get_plane->count_format_types = magic;
+	get_plane->format_type_ptr = lmagic;
+
+	/* drm_mode_set_plane */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_set_plane, set_plane);
+	set_plane->plane_id = magic;
+	set_plane->crtc_id = magic;
+	set_plane->fb_id = magic;
+	set_plane->flags = magic;
+	set_plane->crtc_x = magic;
+	set_plane->crtc_y = magic;
+	set_plane->crtc_w = magic;
+	set_plane->crtc_h = magic;
+	set_plane->src_x = magic;
+	set_plane->src_y = magic;
+	set_plane->src_h = magic;
+	set_plane->src_w = magic;
+
+	/* wrap up DRM_IOCTL_MODE_RMFB */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_rm_fb_wrap, wrap);
+	wrap->fb_id = 3;
+
+	/* drm_mode_fb_cmd2 */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_fb_cmd2, cmd2);
+	cmd2->width = 1;
+	cmd2->height = 1;
+	cmd2->pixel_format = 0x1;
+	cmd2->flags = 1;
+	for (unsigned int i = 0; i < 4; i++) {
+		cmd2->handles[i] = 1;
+		cmd2->pitches[i] = 1;
+		cmd2->offsets[i] = 1;
+#ifdef HAVE_STRUCT_DRM_MODE_FB_CMD2_MODIFIER
+		cmd2->modifier[i] = 1;
+#endif
+	}
+	cmd2->fb_id = 1;
+
+	/* drm_mode_obj_get_properties */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_obj_get_properties, obj_get_prop);
+	obj_get_prop->props_ptr = lmagic;
+	obj_get_prop->prop_values_ptr = lmagic;
+	obj_get_prop->count_props = magic;
+	obj_get_prop->obj_id = magic;
+	obj_get_prop->obj_type = magic;
+
+	/* drm_mode_obj_set_property */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_obj_set_property, obj_set_prop);
+	obj_set_prop->value = lmagic;
+	obj_set_prop->prop_id = magic;
+	obj_set_prop->obj_id = magic;
+	obj_set_prop->obj_type = magic;
+
+	/* drm_mode_cursor2 */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_cursor2, cursor2);
+	cursor2->flags = magic;
+	cursor2->crtc_id = magic;
+	cursor2->x = (int) magic;
+	cursor2->y = (int) magic;
+	cursor2->width = magic;
+	cursor2->height = magic;
+	cursor2->handle = magic;
+	cursor2->hot_x = (int) magic;
+	cursor2->hot_y = (int) magic;
+
+	/* drm_mode_atomic */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_atomic, atomic);
+	atomic->flags = magic;
+	atomic->count_objs = magic;
+	atomic->objs_ptr = lmagic;
+	atomic->count_props_ptr = lmagic;
+	atomic->props_ptr = lmagic;
+	atomic->prop_values_ptr = lmagic;
+	atomic->reserved = lmagic;
+	atomic->user_data = lmagic;
+
+	/* drm_mode_create_blob */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_create_blob, create_blob);
+	create_blob->data = lmagic;
+	create_blob->length = magic;
+	create_blob->blob_id = magic;
+
+	/* drm_mode_destroy_blob */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_destroy_blob, destroy_blob);
+	destroy_blob->blob_id = magic;
+
+# ifdef DRM_IOCTL_SYNCOBJ_CREATE
+	/* drm_syncobj_create */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_create, sync_create);
+	sync_create->handle = magic;
+	sync_create->flags = DRM_SYNCOBJ_CREATE_SIGNALED;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_DESTROY
+	/* drm_syncobj_destroy */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_destroy, sync_destroy);
+	sync_destroy->handle = magic;
+	sync_destroy->pad = magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
+	/* drm_syncobj_handle */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_handle, sync_handle);
+	sync_handle->handle = magic;
+	sync_handle->flags = magic;
+	sync_handle->fd = 123;
+	sync_handle->pad= magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_WAIT
+	/* drm_syncobj_wait */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_wait, sync_wait);
+	sync_wait->handles = lmagic;
+	sync_wait->timeout_nsec = (long) lmagic;
+	sync_wait->count_handles = magic;
+	sync_wait->flags = magic;
+	sync_wait->first_signaled = magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_RESET
+	/* drm_syncobj_array */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_array, sync_array);
+	sync_array->handles = lmagic;
+	sync_array->count_handles = magic;
+	sync_array->pad = magic;
+# endif
+
+# ifdef DRM_IOCTL_MODE_CREATE_LEASE
+	/* drm_mode_create_lease */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_create_lease, create_lease);
+	create_lease->object_ids = lmagic;
+	create_lease->object_count = magic;
+	create_lease->flags = magic;
+	create_lease->lessee_id = magic;
+	create_lease->fd = magic;
+# endif
+
+# ifdef DRM_IOCTL_MODE_LIST_LESSEES
+	/* drm_mode_list_lessees */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_list_lessees, list_lessees);
+	list_lessees->count_lessees = magic;
+	list_lessees->pad = magic;
+	list_lessees->lessees_ptr = lmagic;
+# endif
+
+# ifdef DRM_IOCTL_MODE_GET_LEASE
+	/* drm_mode_get_lease */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_get_lease, get_lease);
+	get_lease->count_objects = magic;
+	get_lease->pad = magic;
+	get_lease->objects_ptr = magic;
+# endif
+
+# ifdef DRM_IOCTL_MODE_REVOKE_LEASE
+	/* drm_mode_revoke_lease */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_mode_revoke_lease, revoke_lease);
+	revoke_lease->lessee_id = magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
+	/* drm_syncobj_timeline_wait */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_timeline_wait, timeline_wait);
+	timeline_wait->handles = lmagic;
+	timeline_wait->points = lmagic;
+	timeline_wait->timeout_nsec = (long) lmagic;
+	timeline_wait->count_handles = magic;
+	timeline_wait->flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
+	timeline_wait->first_signaled = magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+	/* drm_syncobj_timeline_array */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_timeline_array, timeline_array);
+	timeline_array->handles = lmagic;
+	timeline_array->points = lmagic;
+	timeline_array->count_handles = magic;
+	timeline_array->pad = magic;
+# endif
+
+# ifdef DRM_IOCTL_SYNCOBJ_TRANSFER
+	/* drm_syncobj_transfer */
+	TAIL_ALLOC_OBJECT_CONST_PTR(struct drm_syncobj_transfer, sync_transfer);
+	sync_transfer->src_handle = magic;
+	sync_transfer->dst_handle = magic;
+	sync_transfer->src_point = lmagic;
+	sync_transfer->dst_point = lmagic;
+	sync_transfer->flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
+	sync_transfer->pad = magic;
+# endif
+
+	struct drm_check a[] = {
+		{ ARG_STR(DRM_IOCTL_VERSION), ver, print_drm_version },
+		{ ARG_STR(DRM_IOCTL_GET_UNIQUE), unique, print_drm_get_unique },
+		{ ARG_STR(DRM_IOCTL_GET_MAGIC), auth, print_drm_get_magic },
+		{ ARG_STR(DRM_IOCTL_IRQ_BUSID), busid, print_drm_irq_busid },
+		{ ARG_STR(DRM_IOCTL_GET_MAP), map, print_drm_get_map },
+		{ ARG_STR(DRM_IOCTL_GET_CLIENT), client, print_drm_get_client },
+		{ ARG_STR(DRM_IOCTL_GET_STATS), stats, print_drm_get_stats },
+		{ ARG_STR(DRM_IOCTL_SET_VERSION), set_ver, print_drm_set_version },
+		{ ARG_STR(DRM_IOCTL_MODESET_CTL), ctl, print_drm_modeset_ctl },
+		{ ARG_STR(DRM_IOCTL_GEM_CLOSE), close, print_drm_gem_close },
+		{ ARG_STR(DRM_IOCTL_GEM_FLINK), flink, print_drm_gem_flink },
+		{ ARG_STR(DRM_IOCTL_GEM_OPEN), open, print_drm_gem_open },
+		{ ARG_STR(DRM_IOCTL_GET_CAP), cap, print_drm_get_cap },
+		{ ARG_STR(DRM_IOCTL_SET_CLIENT_CAP), cli_cap, print_drm_set_client_cap },
+		{ ARG_STR(DRM_IOCTL_AUTH_MAGIC), auth, print_drm_auth_magic },
+		{ ARG_STR(DRM_IOCTL_BLOCK), block, print_drm_block },
+		{ ARG_STR(DRM_IOCTL_UNBLOCK), block, print_drm_unblock },
+		{ ARG_STR(DRM_IOCTL_CONTROL), control, print_drm_control },
+		{ ARG_STR(DRM_IOCTL_ADD_MAP), map, print_drm_add_map },
+		{ ARG_STR(DRM_IOCTL_ADD_BUFS), desc, print_drm_add_bufs },
+		{ ARG_STR(DRM_IOCTL_MARK_BUFS), desc, print_drm_mark_bufs },
+		{ ARG_STR(DRM_IOCTL_INFO_BUFS), info, print_drm_info_bufs },
+		{ ARG_STR(DRM_IOCTL_MAP_BUFS), buf_map, print_drm_map_bufs },
+		{ ARG_STR(DRM_IOCTL_FREE_BUFS), buf_free, print_drm_free_bufs },
+		{ ARG_STR(DRM_IOCTL_RM_MAP), map, print_drm_rm_map },
+		{ ARG_STR(DRM_IOCTL_SET_SAREA_CTX), priv_map, print_drm_sarea_ctx },
+		{ ARG_STR(DRM_IOCTL_GET_SAREA_CTX), priv_map, print_drm_sarea_ctx },
+		{ ARG_STR(DRM_IOCTL_ADD_CTX), ctx, print_drm_ctx },
+		{ ARG_STR(DRM_IOCTL_RM_CTX), ctx, print_drm_ctx },
+		{ ARG_STR(DRM_IOCTL_GET_CTX), ctx, print_drm_get_ctx },
+		{ ARG_STR(DRM_IOCTL_SWITCH_CTX), ctx, print_drm_ctx },
+		{ ARG_STR(DRM_IOCTL_NEW_CTX), ctx, print_drm_ctx },
+		{ ARG_STR(DRM_IOCTL_RES_CTX), ctx_res, print_drm_res_ctx },
+		{ ARG_STR(DRM_IOCTL_LOCK), lock, print_drm_lock },
+		{ ARG_STR(DRM_IOCTL_UNLOCK), lock, print_drm_lock },
+		{ ARG_STR(DRM_IOCTL_PRIME_HANDLE_TO_FD), prime_handle, print_drm_prime_handle_to_fd },
+		{ ARG_STR(DRM_IOCTL_PRIME_FD_TO_HANDLE), prime_handle, print_drm_prime_fd_to_handle },
+		{ ARG_STR(DRM_IOCTL_AGP_ENABLE), agp_mode, print_drm_agp_enable },
+		{ ARG_STR(DRM_IOCTL_AGP_INFO), agp_info, print_drm_agp_info },
+		{ ARG_STR(DRM_IOCTL_AGP_ALLOC), agp_buffer, print_drm_agp_alloc },
+		{ ARG_STR(DRM_IOCTL_AGP_FREE), agp_buffer, print_drm_agp_free },
+		{ ARG_STR(DRM_IOCTL_AGP_BIND), agp_binding, print_drm_agp_bind },
+		{ ARG_STR(DRM_IOCTL_AGP_UNBIND), agp_binding, print_drm_agp_unbind },
+		{ ARG_STR(DRM_IOCTL_SG_ALLOC), sg, print_drm_sg_alloc },
+		{ ARG_STR(DRM_IOCTL_SG_FREE), sg, print_drm_sg_free },
+		{ ARG_STR(DRM_IOCTL_WAIT_VBLANK), vblank, print_drm_wait_vblank },
+# ifdef DRM_IOCTL_CRTC_GET_SEQUENCE
+		{ ARG_STR(DRM_IOCTL_CRTC_GET_SEQUENCE), get_seq, print_drm_crtc_get_sequence },
+# endif
+# ifdef DRM_IOCTL_CRTC_QUEUE_SEQUENCE
+		{ ARG_STR(DRM_IOCTL_CRTC_QUEUE_SEQUENCE), queue_seq, print_drm_crtc_queue_sequence },
+# endif
+		{ ARG_STR(DRM_IOCTL_MODE_GETRESOURCES), card_res, print_drm_mode_get_resources },
+		{ ARG_STR(DRM_IOCTL_MODE_GETCRTC), crtc, print_drm_mode_crtc },
+		{ ARG_STR(DRM_IOCTL_MODE_SETCRTC), crtc, print_drm_mode_crtc },
+		{ ARG_STR(DRM_IOCTL_MODE_CURSOR), cursor, print_drm_mode_cursor },
+		{ ARG_STR(DRM_IOCTL_MODE_GETGAMMA), lut, print_drm_mode_get_gamma },
+		{ ARG_STR(DRM_IOCTL_MODE_SETGAMMA), lut, print_drm_mode_set_gamma },
+		{ ARG_STR(DRM_IOCTL_MODE_GETENCODER), enc, print_drm_mode_get_encoder },
+		{ ARG_STR(DRM_IOCTL_MODE_GETPROPERTY), prop, print_drm_mode_get_property },
+		{ ARG_STR(DRM_IOCTL_MODE_SETPROPERTY), set_prop, print_drm_mode_set_property },
+		{ ARG_STR(DRM_IOCTL_MODE_GETPROPBLOB), blob, print_drm_mode_get_prop_blob },
+		{ ARG_STR(DRM_IOCTL_MODE_GETFB), cmd, print_drm_mode_get_fb },
+		{ ARG_STR(DRM_IOCTL_MODE_ADDFB), cmd, print_drm_mode_add_fb },
+		{ ARG_STR(DRM_IOCTL_MODE_RMFB), wrap, print_drm_mode_rm_fb },
+		{ ARG_STR(DRM_IOCTL_MODE_PAGE_FLIP), flip, print_drm_mode_page_flip },
+		{ ARG_STR(DRM_IOCTL_MODE_DIRTYFB), dirty_cmd, print_drm_mode_dirty_fb },
+		{ ARG_STR(DRM_IOCTL_MODE_CREATE_DUMB), dumb, print_drm_mode_create_dumb },
+		{ ARG_STR(DRM_IOCTL_MODE_MAP_DUMB), map_dumb, print_drm_mode_map_dumb },
+		{ ARG_STR(DRM_IOCTL_MODE_DESTROY_DUMB), destroy_dumb, print_drm_mode_destroy_dumb },
+		{ ARG_STR(DRM_IOCTL_MODE_GETPLANERESOURCES), plane_res, print_drm_mode_getplaneresources },
+		{ ARG_STR(DRM_IOCTL_MODE_GETPLANE), get_plane, print_drm_mode_getplane },
+		{ ARG_STR(DRM_IOCTL_MODE_SETPLANE), set_plane, print_drm_mode_setplane },
+		{ ARG_STR(DRM_IOCTL_MODE_ADDFB2), cmd2, print_drm_mode_add_fb2 },
+		{ ARG_STR(DRM_IOCTL_MODE_OBJ_GETPROPERTIES), obj_get_prop, print_drm_mode_obj_getproperties},
+		{ ARG_STR(DRM_IOCTL_MODE_OBJ_SETPROPERTY), obj_set_prop, print_drm_mode_obj_setproperty },
+		{ ARG_STR(DRM_IOCTL_MODE_CURSOR2), cursor2, print_drm_mode_cursor2 },
+		{ ARG_STR(DRM_IOCTL_MODE_ATOMIC), atomic, print_drm_mode_atomic },
+		{ ARG_STR(DRM_IOCTL_MODE_CREATEPROPBLOB), create_blob, print_drm_mode_createpropblob},
+		{ ARG_STR(DRM_IOCTL_MODE_DESTROYPROPBLOB), destroy_blob, print_drm_destroypropblob },
+# ifdef DRM_IOCTL_SYNCOBJ_CREATE
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_CREATE), sync_create, print_drm_syncobj_create },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_DESTROY
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_DESTROY), sync_destroy, print_drm_syncobj_destroy },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD), sync_handle, print_drm_syncobj_handle_to_fd },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE), sync_handle, print_drm_syncobj_fd_to_handle },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_WAIT
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_WAIT), sync_wait, print_drm_syncobj_wait },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_RESET
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_RESET), sync_array, print_drm_syncobj_reset_or_signal },
+# endif
+# ifdef DRM_IOCTL_MODE_CREATE_LEASE
+		{ ARG_STR(DRM_IOCTL_MODE_CREATE_LEASE), create_lease, print_drm_mode_create_lease },
+# endif
+# ifdef DRM_IOCTL_MODE_LIST_LESSEES
+		{ ARG_STR(DRM_IOCTL_MODE_LIST_LESSEES), list_lessees, print_drm_mode_list_lessees },
+# endif
+# ifdef DRM_IOCTL_MODE_GET_LEASE
+		{ ARG_STR(DRM_IOCTL_MODE_GET_LEASE), get_lease, print_drm_mode_get_lease },
+# endif
+# ifdef DRM_IOCTL_MODE_REVOKE_LEASE
+		{ ARG_STR(DRM_IOCTL_MODE_REVOKE_LEASE), revoke_lease, print_drm_mode_revoke_lease },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT), timeline_wait, print_drm_syncobj_timeline_wait },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_QUERY), timeline_array, print_drm_syncobj_query_or_timeline_signal },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_TRANSFER
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_TRANSFER), sync_transfer, print_drm_syncobj_transfer },
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+		{ ARG_STR(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL), timeline_array, print_drm_syncobj_query_or_timeline_signal },
+# endif
+	};
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) {
+		test_drm(&a[i], NULL);
+	}
+
+	struct drm_check b = {
+		.cmd = DRM_IOCTL_MODE_GETCONNECTOR,
+		.arg_ptr = con,
+		.print_arg = print_drm_mode_get_connector,
+	};
+
+	if (_IOC_SIZE(DRM_IOCTL_MODE_GETCONNECTOR) == 0x50) {
+		b.cmd_str = "DRM_IOCTL_MODE_GETCONNECTOR";
+	} else {
+		b.cmd_str = con_str;
+	}
+	test_drm(&b, NULL);
+
+	puts("+++ exited with 0 +++");
+	return 0;
+}
+#else
+
+SKIP_MAIN_UNDEFINED("HAVE_DRM_H && HAVE_DRM_DRM_H");
+
+#endif
diff --git a/tests/ioctl_drm-success.test b/tests/ioctl_drm-success.test
new file mode 100755
index 00000000..3dd076d5
--- /dev/null
+++ b/tests/ioctl_drm-success.test
@@ -0,0 +1,18 @@
+#!/bin/sh -efu
+#
+# Copyright (c) 2018 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+. "${srcdir=.}/scno_tampering.sh"
+
+: ${IOCTL_INJECT_START=256}
+: ${IOCTL_INJECT_RETVAL=42}
+
+run_prog
+run_strace -a16 -e trace=ioctl \
+	-e inject=ioctl:retval="${IOCTL_INJECT_RETVAL}":when="${IOCTL_INJECT_START}+" \
+	../ioctl_drm-success "${IOCTL_INJECT_START}" "${IOCTL_INJECT_RETVAL}"> "$EXP"
+grep -v '^ioctl([012][,<]' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
diff --git a/tests/ioctl_drm.c b/tests/ioctl_drm.c
new file mode 100644
index 00000000..8588853b
--- /dev/null
+++ b/tests/ioctl_drm.c
@@ -0,0 +1,192 @@
+#include "tests.h"
+
+#if defined(HAVE_DRM_H) || defined(HAVE_DRM_DRM_H)
+
+# include <errno.h>
+# include <inttypes.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/ioctl.h>
+
+# ifdef HAVE_DRM_H
+#  include <drm.h>
+# else
+#  include <drm/drm.h>
+# endif
+
+# define TEST_NULL_ARG_EX(cmd, str)					\
+	do {								\
+		ioctl(-1, cmd, 0);					\
+		printf("ioctl(-1, %s, NULL) = -1 EBADF (%m)\n", str);	\
+	} while(0)
+
+# define TEST_NULL_ARG(cmd) TEST_NULL_ARG_EX(cmd, #cmd)
+
+static const unsigned long lmagic = (unsigned long) 0xdeadbeefbadc0dedULL;
+
+int
+main(void)
+{
+	TEST_NULL_ARG(DRM_IOCTL_VERSION);
+	TEST_NULL_ARG(DRM_IOCTL_GET_UNIQUE);
+	TEST_NULL_ARG(DRM_IOCTL_GET_MAGIC);
+	TEST_NULL_ARG(DRM_IOCTL_IRQ_BUSID);
+	TEST_NULL_ARG(DRM_IOCTL_GET_MAP);
+	TEST_NULL_ARG(DRM_IOCTL_GET_CLIENT);
+	TEST_NULL_ARG(DRM_IOCTL_GET_STATS);
+	TEST_NULL_ARG(DRM_IOCTL_SET_VERSION);
+	TEST_NULL_ARG(DRM_IOCTL_MODESET_CTL);
+	TEST_NULL_ARG(DRM_IOCTL_GEM_CLOSE);
+	TEST_NULL_ARG(DRM_IOCTL_GEM_FLINK);
+	TEST_NULL_ARG(DRM_IOCTL_GEM_OPEN);
+	TEST_NULL_ARG(DRM_IOCTL_GET_CAP);
+	TEST_NULL_ARG(DRM_IOCTL_SET_CLIENT_CAP);
+	TEST_NULL_ARG(DRM_IOCTL_AUTH_MAGIC);
+	TEST_NULL_ARG(DRM_IOCTL_BLOCK);
+	TEST_NULL_ARG(DRM_IOCTL_UNBLOCK);
+	TEST_NULL_ARG(DRM_IOCTL_CONTROL);
+	TEST_NULL_ARG(DRM_IOCTL_ADD_MAP);
+	TEST_NULL_ARG(DRM_IOCTL_ADD_BUFS);
+	TEST_NULL_ARG(DRM_IOCTL_MARK_BUFS);
+	TEST_NULL_ARG(DRM_IOCTL_INFO_BUFS);
+	TEST_NULL_ARG(DRM_IOCTL_MAP_BUFS);
+	TEST_NULL_ARG(DRM_IOCTL_FREE_BUFS);
+	TEST_NULL_ARG(DRM_IOCTL_RM_MAP);
+	TEST_NULL_ARG(DRM_IOCTL_SET_SAREA_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_GET_SAREA_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_ADD_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_RM_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_MOD_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_GET_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_SWITCH_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_NEW_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_RES_CTX);
+	TEST_NULL_ARG(DRM_IOCTL_ADD_DRAW);
+	TEST_NULL_ARG(DRM_IOCTL_RM_DRAW);
+	TEST_NULL_ARG(DRM_IOCTL_LOCK);
+	TEST_NULL_ARG(DRM_IOCTL_UNLOCK);
+	TEST_NULL_ARG(DRM_IOCTL_FINISH);
+	TEST_NULL_ARG(DRM_IOCTL_PRIME_HANDLE_TO_FD);
+	TEST_NULL_ARG(DRM_IOCTL_PRIME_FD_TO_HANDLE);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_ENABLE);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_INFO);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_ALLOC);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_FREE);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_BIND);
+	TEST_NULL_ARG(DRM_IOCTL_AGP_UNBIND);
+	TEST_NULL_ARG(DRM_IOCTL_SG_ALLOC);
+	TEST_NULL_ARG(DRM_IOCTL_SG_FREE);
+	TEST_NULL_ARG(DRM_IOCTL_WAIT_VBLANK);
+# ifdef DRM_IOCTL_CRTC_GET_SEQUENCE
+	TEST_NULL_ARG(DRM_IOCTL_CRTC_GET_SEQUENCE);
+# endif
+# ifdef DRM_IOCTL_CRTC_QUEUE_SEQUENCE
+	TEST_NULL_ARG(DRM_IOCTL_CRTC_QUEUE_SEQUENCE);
+# endif
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETRESOURCES);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETCRTC);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_SETCRTC);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_CURSOR);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETGAMMA);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_SETGAMMA);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETENCODER);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_ATTACHMODE);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_DETACHMODE);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETPROPERTY);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_SETPROPERTY);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETPROPBLOB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETFB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_ADDFB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_RMFB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_PAGE_FLIP);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_DIRTYFB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_CREATE_DUMB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_MAP_DUMB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_DESTROY_DUMB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETPLANERESOURCES);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GETPLANE);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_SETPLANE);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_ADDFB2);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_OBJ_GETPROPERTIES);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_OBJ_SETPROPERTY);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_CURSOR2);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_ATOMIC);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_CREATEPROPBLOB);
+	TEST_NULL_ARG(DRM_IOCTL_MODE_DESTROYPROPBLOB);
+# ifdef DRM_IOCTL_SYNCOBJ_CREATE
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_CREATE);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_DESTROY
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_DESTROY);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_WAIT
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_WAIT);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_RESET
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_RESET);
+# endif
+# ifdef DRM_IOCTL_MODE_CREATE_LEASE
+	TEST_NULL_ARG(DRM_IOCTL_MODE_CREATE_LEASE);
+# endif
+# ifdef DRM_IOCTL_MODE_LIST_LESSEES
+	TEST_NULL_ARG(DRM_IOCTL_MODE_LIST_LESSEES);
+# endif
+# ifdef DRM_IOCTL_MODE_GET_LEASE
+	TEST_NULL_ARG(DRM_IOCTL_MODE_GET_LEASE);
+# endif
+# ifdef DRM_IOCTL_MODE_REVOKE_LEASE
+	TEST_NULL_ARG(DRM_IOCTL_MODE_REVOKE_LEASE);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_QUERY);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_TRANSFER
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_TRANSFER);
+# endif
+# ifdef DRM_IOCTL_SYNCOBJ_QUERY
+	TEST_NULL_ARG(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL);
+# endif
+
+	if (_IOC_SIZE(DRM_IOCTL_MODE_GETCONNECTOR) == 0x50) {
+		TEST_NULL_ARG(DRM_IOCTL_MODE_GETCONNECTOR);
+	} else {
+		ioctl(-1, DRM_IOCTL_MODE_GETCONNECTOR, 0);
+		printf("ioctl(-1, DRM_IOWR(%#lx, %#lx) /* DRM_IOCTL_MODE_GETCONNECTOR */, NULL) = -1 EBADF (%m)\n",
+		       (long unsigned int)  _IOC_NR(DRM_IOCTL_MODE_GETCONNECTOR),
+		       (long unsigned int) _IOC_SIZE(DRM_IOCTL_MODE_GETCONNECTOR));
+	}
+
+	ioctl(-1, _IOC(_IOC_READ, 0x45, 0x1, 0xff), lmagic);
+	printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n",
+	       "_IOC(_IOC_READ, 0x45, 0x1, 0xff)", lmagic);
+
+	ioctl(-1, _IOC(_IOC_WRITE, 0x45, 0x1, 0xff), lmagic);
+	printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n",
+	       "_IOC(_IOC_WRITE, 0x45, 0x1, 0xff)", lmagic);
+
+	ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff), lmagic);
+	printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n",
+	       "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff)", lmagic);
+
+	ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0), lmagic);
+	printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n",
+	       "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0)", lmagic);
+
+	puts("+++ exited with 0 +++");
+	return 0;
+}
+#else
+
+SKIP_MAIN_UNDEFINED("HAVE_DRM_H");
+
+#endif
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index 3224999e..01f5faec 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -136,6 +136,7 @@ io_uring_setup
 ioctl
 ioctl_block
 ioctl_dm
+ioctl_drm
 ioctl_evdev
 ioctl_inotify
 ioctl_kvm_run
-- 
2.20.1



More information about the Strace-devel mailing list