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

Zhibin Li haoyouab at gmail.com
Wed Jun 12 16:47:19 UTC 2019


On Tue, Jun 11, 2019 at 01:58:59PM +0300, Dmitry V. Levin wrote:
> 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?
> 

I think so, too. But here's what Patrik said about it:
DRM is a bit tricky in this regard. All userspace applications should go
through libdrm and never access ioctls directly. Some distributions even
remove the drm headers from their kernel headers package to prevent any
misuse.
Will there be a situation that drm headers is removed while libdrm is
absent? In such case they are not available. I'm not so sure about this.

> > +
> > +#define DRM_MAX_NAME_LEN 128
> 
> Where do we need this macro?
> 

My fault. This is for some other functions which are not included in
this patch set. I just forgot to remove it.

> > +
> > +#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?
> 

I'm not sure if there's any. Any suggestions?

> > +
> > +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?
> 

0x50 is the size of struct drm_mode_get_connector. In v3.12-rc7~26^2~2 a
u32 padding had been added into the structure, which made its size 0x50.
That is, in an older version, its size is 0x4c so in this case if we use
ioctl_lookup, the corresponding item in ioctlent0.h will not be found.
It's supposed to be { "DRM_IOCTL_MODE_GETCONNECTOR", 0xc05064a7 }, but
in the case mentioned above, the ioctl code is 0xc04c64a7.
Actually I've discussed a littel bit about this with esyr and I got some
sugguestions from him. Details are in [1].

[1] https://lists.strace.io/pipermail/strace-devel/2019-April/008710.html

> > +				} 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?
> 

Any references to the traditional way? I got this from Patrik's original
patch and I didn't notice this is against the tradition.

> > +
> > +	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?
> 

I took v4.22~55 "evdev: move mpers-specific parsers to a separate file"
as reference. Based on what I've learned about RVAL_* macros, I think
in this case RVAL_DECODED means the decoding procedure has to be
continued. Because in drm_mpers.c RVAL_DECODED is returned when no cases
match the ioctl code.

> > +		}
> > +	}
> > +
> > +	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?
> 

Same above.

> > +
> > +#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?
> 

As mentioned above, the size of struct drm_mode_get_connector in older
versions of headers is 0x4c. In the case of 32 bit aligment, the decoder
will try to fetch a struct of 0x4c while in 64 bit, 0x50 will be
fetched.

As for struct drm_mode_fb_cmd2, I see that in drivers/gpu/drm/drm_ioc32.c
there is a compat struct drm_mode_fb_cmd232 with __attribute__((packed))
flag. Shouldn't it be different 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?
> 

Same above.

> > +
> > +#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?
> 

Explained above. BTW there are comments in evdev.c mentioning variable
length commands so I just referenced that.

> > +
> > +	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.
> 
No, it doesn't. Maybe this can be removed.
> 
> -- 
> ldv



> -- 
> Strace-devel mailing list
> Strace-devel at lists.strace.io
> https://lists.strace.io/mailman/listinfo/strace-devel



More information about the Strace-devel mailing list