[PATCH v3 2/6] Add GPIO ioctl decoding

Kent Gibson warthog618 at gmail.com
Sat Jan 23 00:04:01 UTC 2021


Decode the GPIO character device ioctls first introduced in Linux v4.8,
as well as those added in subsequent kernel releases up to Linux v5.7.

Signed-off-by: Kent Gibson <warthog618 at gmail.com>
---
 Makefile.am               |   1 +
 configure.ac              |   1 +
 defs.h                    |   1 +
 gpio_ioctl.c              | 230 ++++++++++++++++++++++++++++++++++++++
 ioctl.c                   |   4 +
 types/gpio.h              |  38 +++++++
 xlat/gpio_event_flags.in  |   3 +
 xlat/gpio_handle_flags.in |   8 ++
 xlat/gpio_line_flags.in   |   8 ++
 9 files changed, 294 insertions(+)
 create mode 100644 gpio_ioctl.c
 create mode 100644 types/gpio.h
 create mode 100644 xlat/gpio_event_flags.in
 create mode 100644 xlat/gpio_handle_flags.in
 create mode 100644 xlat/gpio_line_flags.in

diff --git a/Makefile.am b/Makefile.am
index 47d0d05d..ecdd5c32 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -143,6 +143,7 @@ libstrace_a_SOURCES =	\
 	getpagesize.c \
 	getpid.c	\
 	getrandom.c	\
+	gpio_ioctl.c	\
 	hdio.c		\
 	hostname.c	\
 	inotify.c	\
diff --git a/configure.ac b/configure.ac
index c199f02d..55597ad1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -414,6 +414,7 @@ AC_CHECK_HEADERS(m4_normalize([
 	linux/dm-ioctl.h
 	linux/dqblk_xfs.h
 	linux/falloc.h
+	linux/gpio.h
 	linux/hiddev.h
 	linux/ip_vs.h
 	linux/ipc.h
diff --git a/defs.h b/defs.h
index cc7b4505..dae851aa 100644
--- a/defs.h
+++ b/defs.h
@@ -1223,6 +1223,7 @@ DECL_IOCTL(evdev);
 DECL_IOCTL(fs_0x94);
 DECL_IOCTL(fs_f);
 DECL_IOCTL(fs_x);
+DECL_IOCTL(gpio);
 DECL_IOCTL(inotify);
 DECL_IOCTL(kvm);
 DECL_IOCTL(nbd);
diff --git a/gpio_ioctl.c b/gpio_ioctl.c
new file mode 100644
index 00000000..cc7de942
--- /dev/null
+++ b/gpio_ioctl.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+#include "print_fields.h"
+
+#if HAVE_LINUX_GPIO_H
+
+#include "types/gpio.h"
+
+static int
+print_gpiochip_info(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpiochip_info info;
+
+	if (entering(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr(tcp, arg, &info))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_CSTRING("{", info, name);
+	PRINT_FIELD_CSTRING(", ", info, label);
+	PRINT_FIELD_U(", ", info, lines);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+#include "xlat/gpio_line_flags.h"
+
+static int
+print_gpioline_info(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpioline_info info;
+
+	if (entering(tcp))
+		tprints(", ");
+	else if (syserror(tcp))
+		return RVAL_IOCTL_DECODED;
+	else
+		tprints(" => ");
+
+	if (umove_or_printaddr(tcp, arg, &info))
+		return RVAL_IOCTL_DECODED;
+
+	if (entering(tcp)) {
+		PRINT_FIELD_U("{", info, line_offset);
+		tprints("}");
+		return 0;
+	}
+
+	/* exiting */
+	PRINT_FIELD_FLAGS("{", info, flags, gpio_line_flags, "GPIOLINE_FLAG_???");
+	PRINT_FIELD_CSTRING(", ", info, name);
+	PRINT_FIELD_CSTRING(", ", info, consumer);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpioline_info_unwatch(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	uint32_t offset;
+
+	tprints(", ");
+	if (!umove_or_printaddr(tcp, arg, &offset))
+		tprintf("{offset=%u}", offset);
+
+	return RVAL_IOCTL_DECODED;
+}
+
+#include "xlat/gpio_handle_flags.h"
+
+static int
+print_gpiohandle_request(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpiohandle_request hr;
+
+	if (entering(tcp))
+		tprints(", ");
+	else if (syserror(tcp))
+		return RVAL_IOCTL_DECODED;
+	else
+		tprints(" => ");
+
+	if (umove_or_printaddr(tcp, arg, &hr))
+		return RVAL_IOCTL_DECODED;
+
+	if (!entering(tcp)) {
+		/* exiting */
+		PRINT_FIELD_FD("{", hr, fd, tcp);
+		tprints("}");
+		return RVAL_IOCTL_DECODED;
+	}
+
+	/* entering */
+	PRINT_FIELD_U("{", hr, lines);
+	if (hr.lines > GPIOHANDLES_MAX)
+		hr.lines = GPIOHANDLES_MAX;
+	PRINT_FIELD_ARRAY_UPTO(", ", hr, lineoffsets, hr.lines, tcp,
+			       print_uint32_array_member);
+	PRINT_FIELD_FLAGS(", ", hr, flags, gpio_handle_flags,
+			  "GPIOHANDLE_REQUEST_???");
+	PRINT_FIELD_ARRAY_UPTO(", ", hr, default_values, hr.lines, tcp,
+			       print_uint8_array_member);
+	PRINT_FIELD_CSTRING(", ", hr, consumer_label);
+	tprints("}");
+	return 0;
+}
+
+#include "xlat/gpio_event_flags.h"
+
+static int
+print_gpioevent_request(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpioevent_request er;
+
+	if (entering(tcp))
+		tprints(", ");
+	else if (syserror(tcp))
+		return RVAL_IOCTL_DECODED;
+	else
+		tprints(" => ");
+
+	if (umove_or_printaddr(tcp, arg, &er))
+		return RVAL_IOCTL_DECODED;
+
+	if (!entering(tcp)) {
+		/* exiting */
+		PRINT_FIELD_FD("{", er, fd, tcp);
+		tprints("}");
+		return RVAL_IOCTL_DECODED;
+	}
+
+	/* entering */
+	PRINT_FIELD_U("{", er, lineoffset);
+	PRINT_FIELD_FLAGS(", ", er, handleflags, gpio_handle_flags,
+			  "GPIOHANDLE_REQUEST_???");
+	PRINT_FIELD_FLAGS(", ", er, eventflags, gpio_event_flags,
+			  "GPIOEVENT_REQUEST_???");
+	PRINT_FIELD_CSTRING(", ", er, consumer_label);
+	tprints("}");
+	return 0;
+}
+
+static void
+print_gpiohandle_data(struct tcb *const tcp, const struct gpiohandle_data *vals)
+{
+	PRINT_FIELD_ARRAY("{", *vals, values, tcp, print_uint8_array_member);
+	tprints("}");
+}
+
+static int
+print_gpiohandle_get_values(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpiohandle_data vals;
+
+	if (entering(tcp))
+		return 0;
+
+	/* exiting */
+	tprints(", ");
+	if (!umove_or_printaddr(tcp, arg, &vals))
+		print_gpiohandle_data(tcp, &vals);
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpiohandle_set_values(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct gpiohandle_data vals;
+
+	tprints(", ");
+	if (!umove_or_printaddr(tcp, arg, &vals))
+		print_gpiohandle_data(tcp, &vals);
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static int
+print_gpiohandle_set_config(struct tcb *const tcp, const kernel_ulong_t arg)
+{
+	struct_gpiohandle_config hc;
+
+	tprints(", ");
+	if (umove_or_printaddr(tcp, arg, &hc))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_FLAGS("{", hc, flags, gpio_handle_flags, "GPIOHANDLE_REQUEST_???");
+	PRINT_FIELD_ARRAY(", ", hc, default_values, tcp, print_uint8_array_member);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+int
+gpio_ioctl(struct tcb *const tcp, const unsigned int code,
+	   const kernel_ulong_t arg)
+{
+	switch (code) {
+	case GPIO_GET_CHIPINFO_IOCTL:
+		return print_gpiochip_info(tcp, arg);
+	case GPIO_GET_LINEINFO_UNWATCH_IOCTL:
+		return print_gpioline_info_unwatch(tcp, arg);
+	case GPIO_GET_LINEINFO_IOCTL:
+	case GPIO_GET_LINEINFO_WATCH_IOCTL:
+		return print_gpioline_info(tcp, arg);
+	case GPIO_GET_LINEHANDLE_IOCTL:
+		return print_gpiohandle_request(tcp, arg);
+	case GPIO_GET_LINEEVENT_IOCTL:
+		return print_gpioevent_request(tcp, arg);
+	case GPIOHANDLE_GET_LINE_VALUES_IOCTL:
+		return print_gpiohandle_get_values(tcp, arg);
+	case GPIOHANDLE_SET_LINE_VALUES_IOCTL:
+		return print_gpiohandle_set_values(tcp, arg);
+	case GPIOHANDLE_SET_CONFIG_IOCTL:
+		return print_gpiohandle_set_config(tcp, arg);
+	}
+	return RVAL_DECODED;
+}
+
+#endif /* HAVE_LINUX_GPIO_H */
diff --git a/ioctl.c b/ioctl.c
index d61b2150..6b8256a3 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -360,6 +360,10 @@ ioctl_decode(struct tcb *tcp)
 #ifdef HAVE_LINUX_KVM_H
 	case 0xae:
 		return kvm_ioctl(tcp, code, arg);
+#endif
+#ifdef HAVE_LINUX_GPIO_H
+	case 0xb4:
+		return gpio_ioctl(tcp, code, arg);
 #endif
 	case 0xb7:
 		return nsfs_ioctl(tcp, code, arg);
diff --git a/types/gpio.h b/types/gpio.h
new file mode 100644
index 00000000..47fa00da
--- /dev/null
+++ b/types/gpio.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_TYPES_GPIO_H
+# define STRACE_TYPES_GPIO_H
+
+# include <inttypes.h>
+# include <linux/ioctl.h>
+# ifdef HAVE_LINUX_GPIO_H
+#  include <linux/gpio.h>
+# endif
+
+# ifndef GPIOHANDLES_MAX
+#  define GPIOHANDLES_MAX 64
+# endif
+
+/* added in Linux v5.5 */
+# ifndef GPIOHANDLE_SET_CONFIG_IOCTL
+#  define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0A, struct_gpiohandle_config)
+# endif
+
+/* added in Linux v5.7 */
+# ifndef GPIO_GET_LINEINFO_WATCH_IOCTL
+#  define GPIO_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x0B, struct gpioline_info)
+#  define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0C, uint32_t)
+# endif
+
+typedef struct {
+	uint32_t flags;
+	uint8_t default_values[GPIOHANDLES_MAX];
+	uint32_t padding[4];
+} struct_gpiohandle_config;
+
+#endif /* STRACE_TYPES_GPIO_H */
diff --git a/xlat/gpio_event_flags.in b/xlat/gpio_event_flags.in
new file mode 100644
index 00000000..c355b10b
--- /dev/null
+++ b/xlat/gpio_event_flags.in
@@ -0,0 +1,3 @@
+GPIOEVENT_REQUEST_BOTH_EDGES	0x00000003
+GPIOEVENT_REQUEST_RISING_EDGE	0x00000001
+GPIOEVENT_REQUEST_FALLING_EDGE	0x00000002
diff --git a/xlat/gpio_handle_flags.in b/xlat/gpio_handle_flags.in
new file mode 100644
index 00000000..0c75034e
--- /dev/null
+++ b/xlat/gpio_handle_flags.in
@@ -0,0 +1,8 @@
+GPIOHANDLE_REQUEST_INPUT	0x00000001
+GPIOHANDLE_REQUEST_OUTPUT	0x00000002
+GPIOHANDLE_REQUEST_ACTIVE_LOW	0x00000004
+GPIOHANDLE_REQUEST_OPEN_DRAIN	0x00000008
+GPIOHANDLE_REQUEST_OPEN_SOURCE	0x00000010
+GPIOHANDLE_REQUEST_BIAS_PULL_UP	0x00000020
+GPIOHANDLE_REQUEST_BIAS_PULL_DOWN	0x00000040
+GPIOHANDLE_REQUEST_BIAS_DISABLE	0x00000080
diff --git a/xlat/gpio_line_flags.in b/xlat/gpio_line_flags.in
new file mode 100644
index 00000000..a7d505e2
--- /dev/null
+++ b/xlat/gpio_line_flags.in
@@ -0,0 +1,8 @@
+GPIOLINE_FLAG_KERNEL		0x00000001
+GPIOLINE_FLAG_IS_OUT		0x00000002
+GPIOLINE_FLAG_ACTIVE_LOW	0x00000004
+GPIOLINE_FLAG_OPEN_DRAIN	0x00000008
+GPIOLINE_FLAG_OPEN_SOURCE	0x00000010
+GPIOLINE_FLAG_BIAS_PULL_UP	0x00000020
+GPIOLINE_FLAG_BIAS_PULL_DOWN	0x00000040
+GPIOLINE_FLAG_BIAS_DISABLE	0x00000080
-- 
2.30.0



More information about the Strace-devel mailing list