[RFC PATCH v1 2/3] drm: implement decoding of DRM ioctls

Dmitry V. Levin ldv at altlinux.org
Tue Jun 11 10:58:59 UTC 2019


On Mon, Jun 03, 2019 at 09:24:34PM +0800, Zhibin Li wrote:
> * drm_mpers.c: New file. all mpersified drm ioctls are here.
> (drm_version, drm_get_unique, drm_wait_vblank, drm_mode_get_connector,
> drm_mode_add_fb2): New functions.
> (drm_ioctl_mpers): Use them.
> * drm.c: New file.
> (drm_decode_number, drm_set_version, drm_get_magic, drm_mode_get_resources,
> drm_mode_print_modeinfo, drm_mode_get_crtc, drm_mode_set_crtc,
> drm_mode_cursor, drm_mode_cursor2, drm_mode_get_gamma, drm_mode_set_gamma,
> drm_mode_get_encoder, drm_mode_get_property, drm_mode_set_property,
> drm_mode_get_prop_blob, drm_mode_add_fb, drm_mode_get_fb, drm_mode_rm_fb,
> drm_mode_page_flip, drm_mode_dirty_fb, drm_mode_create_dumb,
> drm_mode_map_dumb, drm_mode_destroy_dumb, drm_gem_close): New functions.
> (drm_ioctl): Use them and use drm_ioctl_mpers.
> * defs.h (drm_ioctl, drm_decode_number): New prototype.
> * ioctl.c (ioctl_decode): Call drm_ioctl for ioctl type 'd'.
> (ioctl_decode_command_number): Call drm_decode_number for ioctl type 'd'.
> * Makefile.am: Add drm.c and drm_mpers.c
> * configure.ac: Check whether struct drm_mode_fb_cmd2.modifier is defined
> in <drm.h> or <drm/drm.h>.
> 
> Co-authored-by: Patrik Jakobsson <patrik.r.jakobsson at gmail.com>
> ---
>  Makefile.am  |   2 +
>  configure.ac |   8 +-
>  defs.h       |   2 +
>  drm.c        | 629 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  drm_mpers.c  | 201 ++++++++++++++++
>  ioctl.c      |   8 +
>  6 files changed, 848 insertions(+), 2 deletions(-)
>  create mode 100644 drm.c
>  create mode 100644 drm_mpers.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index a8ace321..78694f30 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -101,6 +101,8 @@ strace_SOURCES =	\
>  	dirent.c	\
>  	dirent64.c	\
>  	dm.c		\
> +	drm.c		\
> +	drm_mpers.c	\
>  	dyxlat.c	\
>  	empty.h		\
>  	epoll.c		\
> diff --git a/configure.ac b/configure.ac
> index 6397231d..cfa95ac2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -897,8 +897,12 @@ st_STACKTRACE
>  
>  PKG_CHECK_MODULES([LIBDRM], [libdrm],
>  		  [CPPFLAGS="$CPPFLAGS $LIBDRM_CFLAGS"
> -		   AC_CHECK_HEADERS([drm.h])],
> -		  [AC_CHECK_HEADERS([drm/drm.h])])
> +		   AC_CHECK_HEADERS([drm.h], [
> +			AC_CHECK_MEMBERS([struct drm_mode_fb_cmd2.modifier],,, [#include <drm.h>])
> +		   ])],
> +		  [AC_CHECK_HEADERS([drm/drm.h], [
> +			AC_CHECK_MEMBERS([struct drm_mode_fb_cmd2.modifier],,, [#include <drm/drm.h>])
> +		  ])])
>  
>  if test "$arch" = mips && test "$no_create" != yes; then
>  	mkdir -p linux/mips
> diff --git a/defs.h b/defs.h
> index 512ad51f..ff364ddf 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -982,6 +982,7 @@ name ## _ioctl(struct tcb *, unsigned int request, kernel_ulong_t arg)	\
>  /* End of DECL_IOCTL definition. */
>  
>  DECL_IOCTL(dm);
> +DECL_IOCTL(drm);
>  DECL_IOCTL(evdev);
>  DECL_IOCTL(file);
>  DECL_IOCTL(fs_x);
> @@ -999,6 +1000,7 @@ DECL_IOCTL(uffdio);
>  
>  extern int decode_sg_io_v4(struct tcb *, const kernel_ulong_t arg);
>  extern void print_evdev_ff_type(const kernel_ulong_t val);
> +extern int drm_decode_number(struct tcb *, const unsigned int code);
>  
>  struct nlmsghdr;
>  
> diff --git a/drm.c b/drm.c
> new file mode 100644
> index 00000000..832a0859
> --- /dev/null
> +++ b/drm.c
> @@ -0,0 +1,629 @@
> +/*
> + * Copyright (c) 2019 Patrik Jakobsson <pjakobsson at suse.de>
> + *
> + * SPDX-License-Identifier: LGPL-2.1-or-later
> + */
> +
> +#include "defs.h"
> +#include "print_fields.h"
> +
> +#include <sys/param.h>
> +#include <stdint.h>
> +
> +#ifdef HAVE_DRM_H
> +# include <drm.h>
> +#else
> +# include <drm/drm.h>
> +#endif

This means that either <drm.h> or <drm/drm.h> is always available.
Can we assume this?

> +
> +#define DRM_MAX_NAME_LEN 128

Where do we need this macro?

> +
> +#define PRINT_IOWR(nr, size, str) \
> +	tprintf("DRM_IOWR(%#x, %#x) /* %s */", nr, size, str)

What's the benefit of making it a macro instead of a function?

> +
> +int
> +drm_decode_number(struct tcb *const tcp, const unsigned int code)
> +{
> +	const unsigned int nr = _IOC_NR(code);
> +
> +	if (_IOC_DIR(code) == (_IOC_READ | _IOC_WRITE)) {
> +		switch (nr) {
> +			case 0xa7:
> +				if (_IOC_SIZE(code) != 0x50) {
> +					PRINT_IOWR(nr, _IOC_SIZE(code),
> +						   "DRM_IOCTL_MODE_GETCONNECTOR");
> +					return IOCTL_NUMBER_STOP_LOOKUP;

What is 0x50?  Why do we skip lookup for this particular value?

> +				} else {
> +					return 0;
> +				}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +drm_set_version(struct tcb *const tcp, long arg)
> +{
> +	struct drm_set_version ver;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &ver))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_D("write:{", 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);
> +		tprints("}");
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &ver)) {
> +		PRINT_FIELD_D(", read:{", 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);
> +		tprints("}");
> +	}

Why does this differ from our traditional way of printing read-write
structures?

> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_get_magic(struct tcb *const tcp, long arg)
> +{
> +	struct drm_auth auth;
> +
> +	if (exiting(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &auth))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_U("{", auth, magic);
> +		tprints("}");
> +
> +		return RVAL_IOCTL_DECODED;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +drm_mode_get_resources(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_card_res res;
> +
> +	if (exiting(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &res))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_PTR("{", res, fb_id_ptr);
> +		PRINT_FIELD_PTR(", ", res, crtc_id_ptr);
> +		PRINT_FIELD_PTR(", ", res, connector_id_ptr);
> +		PRINT_FIELD_PTR(", ", 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);
> +		tprints("}");
> +
> +		return RVAL_IOCTL_DECODED;
> +	}
> +
> +	return 0;
> +}
> +
> +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);
> +	PRINT_FIELD_X(", ", *info, flags);
> +	PRINT_FIELD_U(", ", *info, type);
> +	PRINT_FIELD_CSTRING(", ", *info, name);
> +}
> +
> +static int
> +drm_mode_get_crtc(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_crtc crtc;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &crtc))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", crtc, crtc_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &crtc)) {
> +		PRINT_FIELD_PTR(", ", 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);
> +		tprints("mode={");
> +
> +		drm_mode_print_modeinfo(&crtc.mode);
> +		tprints("}");
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_set_crtc(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_crtc crtc;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &crtc))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_PTR("{", crtc, set_connectors_ptr);
> +		PRINT_FIELD_U(", ", crtc, count_connectors);
> +		PRINT_FIELD_U(", ", crtc, crtc_id);
> +		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);
> +		tprints("mode={");
> +
> +		drm_mode_print_modeinfo(&crtc.mode);
> +		tprints("}}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_cursor(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_cursor cursor;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &cursor))
> +			return RVAL_IOCTL_DECODED;
> +
> +		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);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_cursor2(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_cursor2 cursor;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &cursor))
> +			return RVAL_IOCTL_DECODED;
> +
> +		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);
> +		PRINT_FIELD_D(", ", cursor, hot_x);
> +		PRINT_FIELD_D(", ", cursor, hot_y);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_gamma(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_crtc_lut lut;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &lut))
> +			return RVAL_IOCTL_DECODED;
> +
> +		/* We don't print the entire table, just the pointers */
> +		PRINT_FIELD_U("{", lut, crtc_id);
> +		PRINT_FIELD_U(", ", lut, gamma_size);
> +		PRINT_FIELD_PTR(", ", lut, red);
> +		PRINT_FIELD_PTR(", ", lut, green);
> +		PRINT_FIELD_PTR(", ", lut, blue);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_set_gamma(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_crtc_lut lut;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &lut))
> +			return RVAL_IOCTL_DECODED;
> +
> +		/* We don't print the entire table, just the rgb pointers */
> +		PRINT_FIELD_U("{", lut, crtc_id);
> +		PRINT_FIELD_U(", ", lut, gamma_size);
> +		PRINT_FIELD_PTR(", ", lut, red);
> +		PRINT_FIELD_PTR(", ", lut, green);
> +		PRINT_FIELD_PTR(", ", lut, blue);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_encoder(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_get_encoder enc;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &enc))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", enc, encoder_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &enc)) {
> +		/* TODO: Print name of encoder type */
> +		PRINT_FIELD_U(", ", enc, encoder_type);
> +		PRINT_FIELD_U(", ", enc, crtc_id);
> +		PRINT_FIELD_X(", ", enc, possible_crtcs);
> +		PRINT_FIELD_X(", ", enc, possible_clones);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_property(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_get_property prop;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &prop))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", prop, prop_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &prop)) {
> +		PRINT_FIELD_PTR(", ", prop, values_ptr);
> +		PRINT_FIELD_PTR(", ", 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);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_set_property(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_connector_set_property prop;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &prop)) {
> +		PRINT_FIELD_U("{", prop, value);
> +		PRINT_FIELD_U(", ", prop, prop_id);
> +		PRINT_FIELD_U(", ", prop, connector_id);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_prop_blob(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_get_blob blob;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &blob))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", blob, blob_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &blob)) {
> +		PRINT_FIELD_U(", ", blob, length);
> +		PRINT_FIELD_U(", ", blob, data);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_add_fb(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_fb_cmd cmd;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &cmd))
> +			return RVAL_IOCTL_DECODED;
> +		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);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove_or_printaddr(tcp, arg, &cmd)) {
> +		PRINT_FIELD_U(", ", cmd, fb_id);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_fb(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_fb_cmd cmd;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &cmd))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", cmd, fb_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &cmd)) {
> +		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);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_rm_fb(struct tcb *const tcp, long arg)
> +{
> +	unsigned int handle;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &handle))
> +		tprintf("%u", handle);
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_page_flip(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_crtc_page_flip flip;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &flip)) {
> +		PRINT_FIELD_U("{", flip, crtc_id);
> +		PRINT_FIELD_U(", ", flip, fb_id);
> +		PRINT_FIELD_X(", ", flip, flags);
> +		PRINT_FIELD_X(", ", flip, user_data);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_dirty_fb(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_fb_dirty_cmd cmd;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &cmd)) {
> +		PRINT_FIELD_U("{", cmd, fb_id);
> +		PRINT_FIELD_X(", ", cmd, flags);
> +		PRINT_FIELD_X(", ", cmd, color);
> +		PRINT_FIELD_U(", ", cmd, num_clips);
> +		PRINT_FIELD_PTR(", ", cmd, clips_ptr);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_create_dumb(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_create_dumb dumb;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &dumb))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", dumb, width);
> +		PRINT_FIELD_U(", ", dumb, height);
> +		PRINT_FIELD_U(", ", dumb, bpp);
> +		PRINT_FIELD_X(", ", dumb, flags);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &dumb)) {
> +		PRINT_FIELD_U(", ", dumb, handle);
> +		PRINT_FIELD_U(", ", dumb, pitch);
> +		PRINT_FIELD_U(", ", dumb, size);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_map_dumb(struct tcb *const tcp, long arg)
> +{
> +	struct drm_mode_map_dumb dumb;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &dumb))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", dumb, handle);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &dumb)) {
> +		PRINT_FIELD_U(", ", dumb, offset);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_destroy_dumb(struct tcb *const tcp, const unsigned int long arg)
> +{
> +	struct drm_mode_destroy_dumb dumb;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &dumb)) {
> +		PRINT_FIELD_U("{", dumb, handle);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_gem_close(struct tcb *const tcp, const unsigned int long arg)
> +{
> +	struct drm_gem_close close;
> +
> +	tprints(", ");
> +	if (!umove_or_printaddr(tcp, arg, &close)) {
> +		PRINT_FIELD_U("{", close, handle);
> +		tprints("}");
> +	}
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +int
> +drm_ioctl(struct tcb *const tcp, const unsigned int code,
> +	  const kernel_ulong_t arg)
> +{
> +	switch (code) {
> +	case DRM_IOCTL_SET_VERSION:
> +		return drm_set_version(tcp, arg);
> +	case DRM_IOCTL_GET_MAGIC:
> +		return drm_get_magic(tcp, arg);
> +	case DRM_IOCTL_MODE_GETRESOURCES:
> +		return drm_mode_get_resources(tcp, arg);
> +	case DRM_IOCTL_MODE_GETCRTC:
> +		return drm_mode_get_crtc(tcp, arg);
> +	case DRM_IOCTL_MODE_SETCRTC:
> +		return drm_mode_set_crtc(tcp, arg);
> +	case DRM_IOCTL_MODE_CURSOR:
> +		return drm_mode_cursor(tcp, arg);
> +	case DRM_IOCTL_MODE_CURSOR2:
> +		return drm_mode_cursor2(tcp, arg);
> +	case DRM_IOCTL_MODE_GETGAMMA:
> +		return drm_mode_get_gamma(tcp, arg);
> +	case DRM_IOCTL_MODE_SETGAMMA:
> +		return drm_mode_set_gamma(tcp, arg);
> +	case DRM_IOCTL_MODE_GETENCODER:
> +		return drm_mode_get_encoder(tcp, arg);
> +	case DRM_IOCTL_MODE_GETPROPERTY:
> +		return drm_mode_get_property(tcp, arg);
> +	case DRM_IOCTL_MODE_SETPROPERTY:
> +		return drm_mode_set_property(tcp, arg);
> +	case DRM_IOCTL_MODE_GETPROPBLOB:
> +		return drm_mode_get_prop_blob(tcp, arg);
> +	case DRM_IOCTL_MODE_GETFB:
> +		return drm_mode_get_fb(tcp, arg);
> +	case DRM_IOCTL_MODE_ADDFB:
> +		return drm_mode_add_fb(tcp, arg);
> +	case DRM_IOCTL_MODE_RMFB:
> +		return drm_mode_rm_fb(tcp, arg);
> +	case DRM_IOCTL_MODE_PAGE_FLIP:
> +		return drm_mode_page_flip(tcp, arg);
> +	case DRM_IOCTL_MODE_DIRTYFB:
> +		return drm_mode_dirty_fb(tcp, arg);
> +	case DRM_IOCTL_MODE_CREATE_DUMB:
> +		return drm_mode_create_dumb(tcp, arg);
> +	case DRM_IOCTL_MODE_MAP_DUMB:
> +		return drm_mode_map_dumb(tcp, arg);
> +	case DRM_IOCTL_MODE_DESTROY_DUMB:
> +		return drm_mode_destroy_dumb(tcp, arg);
> +	case DRM_IOCTL_GEM_CLOSE:
> +		return drm_gem_close(tcp, arg);
> +	default: {
> +			int rc = drm_ioctl_mpers(tcp, code, arg);
> +			if (rc != RVAL_DECODED)
> +				return rc;

Why RVAL_DECODED is filtered here?

> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/drm_mpers.c b/drm_mpers.c
> new file mode 100644
> index 00000000..44d85090
> --- /dev/null
> +++ b/drm_mpers.c
> @@ -0,0 +1,201 @@
> +#include "defs.h"
> +#include "print_fields.h"
> +
> +#include <sys/param.h>
> +#include <stdint.h>
> +
> +#ifdef HAVE_DRM_H
> +# include <drm.h>
> +#else
> +# include <drm/drm.h>
> +#endif

This means that either <drm.h> or <drm/drm.h> is always available.
Can we assume this?

> +
> +#include DEF_MPERS_TYPE(struct_drm_version)
> +#include DEF_MPERS_TYPE(struct_drm_unique)
> +#include DEF_MPERS_TYPE(union_drm_wait_vblank)
> +#include DEF_MPERS_TYPE(struct_drm_mode_get_connector)
> +#include DEF_MPERS_TYPE(struct_drm_mode_fb_cmd2)

Interesting.  Are the last two structures really differ between
personalities?

> +typedef struct drm_version struct_drm_version;
> +typedef struct drm_unique struct_drm_unique;
> +typedef union drm_wait_vblank union_drm_wait_vblank;
> +typedef struct drm_mode_get_connector struct_drm_mode_get_connector;
> +typedef struct drm_mode_fb_cmd2 struct_drm_mode_fb_cmd2;
> +
> +#define DRM_MAX_NAME_LEN 128

Where do we need this macro?

> +
> +#include MPERS_DEFS
> +
> +static int
> +drm_version(struct tcb *const tcp, const kernel_ulong_t arg)
> +{
> +	struct_drm_version ver;
> +
> +	if (exiting(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &ver))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_D("{", ver, version_major);
> +		PRINT_FIELD_D(", ", ver, version_minor);
> +		PRINT_FIELD_D(", ", ver, version_patchlevel);
> +		PRINT_FIELD_U(", ", ver, name_len);
> +		tprints(", name=");
> +		printstrn(tcp, ptr_to_kulong(ver.name), ver.name_len);
> +		PRINT_FIELD_U(", ", ver, date_len);
> +		tprints(", date=");
> +		printstrn(tcp, ptr_to_kulong(ver.date), ver.date_len);
> +		PRINT_FIELD_U(", ", ver, desc_len);
> +		tprints(", desc=");
> +		printstrn(tcp, ptr_to_kulong(ver.desc), ver.desc_len);
> +		tprints("}");
> +
> +		return RVAL_IOCTL_DECODED;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +drm_get_unique(struct tcb *const tcp, const kernel_ulong_t arg)
> +{
> +	struct_drm_unique unique;
> +
> +	if (exiting(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &unique))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_U("{", unique, unique_len);
> +		tprints(", unique=");
> +		printstrn(tcp, ptr_to_kulong(unique.unique), unique.unique_len);
> +		tprints("}");
> +
> +		return RVAL_IOCTL_DECODED;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +drm_wait_vblank(struct tcb *const tcp, const kernel_ulong_t arg)
> +{
> +	union_drm_wait_vblank vblank;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &vblank))
> +			return RVAL_IOCTL_DECODED;
> +
> +		PRINT_FIELD_U("{request={", vblank.request, type);
> +		PRINT_FIELD_U(", ", vblank.request, sequence);
> +		PRINT_FIELD_U(", ", vblank.request, signal);
> +		tprints("}");
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &vblank)) {
> +		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);
> +		tprints("}");
> +	}
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_get_connector(struct tcb *const tcp, const kernel_ulong_t arg)
> +{
> +	struct_drm_mode_get_connector con;
> +
> +	/* We could be very verbose here but keep is simple for now */
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &con))
> +			return RVAL_IOCTL_DECODED;
> +		PRINT_FIELD_U("{", con, connector_id);
> +
> +		return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &con)) {
> +		PRINT_FIELD_PTR(", ", con, encoders_ptr);
> +		PRINT_FIELD_PTR(", ", con, modes_ptr);
> +		PRINT_FIELD_PTR(", ", con, props_ptr);
> +		PRINT_FIELD_PTR(", ", con, prop_values_ptr);
> +		PRINT_FIELD_U(", ", con, count_modes);
> +		PRINT_FIELD_U(", ", con, count_props);
> +		PRINT_FIELD_U(", ", con, count_encoders);
> +		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);
> +	}
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +static int
> +drm_mode_add_fb2(struct tcb *const tcp, const kernel_ulong_t arg)
> +{
> +	struct_drm_mode_fb_cmd2 cmd;
> +
> +	if (entering(tcp)) {
> +		tprints(", ");
> +		if (umove_or_printaddr(tcp, arg, &cmd))
> +			return RVAL_IOCTL_DECODED;
> +		tprintf("{width=%u, height=%u, pixel_format=%#x, flags=%u, "
> +			"handles={%u, %u, %u, %u}, "
> +			"pitches={%u, %u, %u, %u}, "
> +			"offsets={%u, %u, %u, %u}",
> +			cmd.width, cmd.height, cmd.pixel_format, cmd.flags,
> +			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
> +		tprintf(", 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
> +
> +			return 0;
> +	}
> +
> +	if (!syserror(tcp) && !umove(tcp, arg, &cmd))
> +		PRINT_FIELD_U(", ", cmd, fb_id);
> +
> +	tprints("}");
> +
> +	return RVAL_IOCTL_DECODED;
> +}
> +
> +MPERS_PRINTER_DECL(int, drm_ioctl_mpers, struct tcb *const tcp,
> +		   const unsigned int code, const kernel_ulong_t arg)
> +{
> +	switch (code) {
> +	case DRM_IOCTL_VERSION:
> +		return drm_version(tcp, arg);
> +	case DRM_IOCTL_GET_UNIQUE:
> +		return drm_get_unique(tcp, arg);
> +	case DRM_IOCTL_WAIT_VBLANK:
> +		return drm_wait_vblank(tcp, arg);
> +	case DRM_IOCTL_MODE_ADDFB2:
> +		return drm_mode_add_fb2(tcp, arg);
> +	}
> +	/* variable length, so we can't use switch(code) to identify DRM_IOCTL_MODE_GETCONNECTOR */
> +	if (_IOC_NR(code) == _IOC_NR(DRM_IOCTL_MODE_GETCONNECTOR)) {
> +		return drm_mode_get_connector(tcp, arg);
> +	}

What do you mean by variable length?

> +
> +	return RVAL_DECODED;
> +}
> diff --git a/ioctl.c b/ioctl.c
> index d3205b22..be31b33d 100644
> --- a/ioctl.c
> +++ b/ioctl.c
> @@ -197,6 +197,10 @@ ioctl_decode_command_number(struct tcb *tcp)
>  				return 1;
>  			}
>  			return 0;
> +#if defined(HAVE_DRM_H) || defined(HAVE_DRM_DRM_H)
> +		case 'd':
> +			return drm_decode_number(tcp, code);
> +#endif
>  		default:
>  			return 0;
>  	}
> @@ -266,6 +270,10 @@ ioctl_decode(struct tcb *tcp)
>  		return fs_x_ioctl(tcp, code, arg);
>  	case 0x22:
>  		return scsi_ioctl(tcp, code, arg);
> +#if defined(HAVE_DRM_H) || defined(HAVE_DRM_DRM_H)
> +	case 'd':
> +		return drm_ioctl(tcp, code, arg);
> +#endif
>  	case 'L':
>  		return loop_ioctl(tcp, code, arg);
>  #ifdef HAVE_STRUCT_MTD_WRITE_REQ

Note that unlike drm.c this doesn't assume that either <drm.h>
or <drm/drm.h> is always available.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20190611/b9438ff4/attachment.bin>


More information about the Strace-devel mailing list