[PATCH 2/4] Add GPIO ioctl decoding

Kent Gibson warthog618 at gmail.com
Tue Dec 22 22:07:46 UTC 2020


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 +
 gpio_ioctl.c              | 252 ++++++++++++++++++++++++++++++++++++++
 ioctl.c                   |   4 +
 xlat/gpio_event_flags.in  |   3 +
 xlat/gpio_handle_flags.in |   8 ++
 xlat/gpio_line_flags.in   |   8 ++
 7 files changed, 277 insertions(+)
 create mode 100644 gpio_ioctl.c
 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 723460f2..f8280e01 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -138,6 +138,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 bb5b7ca6..00174747 100644
--- a/configure.ac
+++ b/configure.ac
@@ -416,6 +416,7 @@ AC_CHECK_HEADERS(m4_normalize([
 	linux/falloc.h
 	linux/fib_rules.h
 	linux/fiemap.h
+	linux/gpio.h
 	linux/hiddev.h
 	linux/ip_vs.h
 	linux/ipc.h
diff --git a/gpio_ioctl.c b/gpio_ioctl.c
new file mode 100644
index 00000000..228b4cf4
--- /dev/null
+++ b/gpio_ioctl.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2020 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#if HAVE_LINUX_GPIO_H
+
+#include <linux/gpio.h>
+
+#include MPERS_DEFS
+
+#include "print_fields.h"
+
+#ifndef GPIOHANDLES_MAX
+#define GPIOHANDLES_MAX 64
+#endif
+
+#ifndef GPIOHANDLE_SET_CONFIG_IOCTL
+/* added in Linux v5.5 */
+#define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0A, struct gpiohandle_config)
+struct gpiohandle_config {
+	__u32 flags;
+	__u8 default_values[GPIOHANDLES_MAX];
+	__u32 padding[4];
+};
+#endif
+
+#ifndef GPIO_GET_LINEINFO_WATCH_IOCTL
+/* added in Linux v5.7 */
+#define GPIO_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x0B, struct gpioline_info)
+#define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0C, __u32)
+#endif
+
+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))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &info))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_U("{", info, line_offset);
+	if (!tcp->u_rval) {
+		tprints(", flags=");
+		printflags(gpio_line_flags, info.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)
+{
+	__u32 offset;
+
+	if (entering(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &offset))
+		return RVAL_IOCTL_DECODED;
+
+	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))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &hr))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_U("{", hr, lines);
+	tprints(", lineoffsets=");
+	if (hr.lines > GPIOHANDLES_MAX)
+		hr.lines = GPIOHANDLES_MAX;
+	print_local_array_ex(tcp, hr.lineoffsets, hr.lines,
+			sizeof(hr.lineoffsets[0]), print_uint32_array_member,
+			NULL, 0, NULL, NULL);
+	PRINT_FIELD_FLAGS(", ", hr, flags, gpio_handle_flags,
+			  "GPIOHANDLE_FLAG_???");
+	tprints(", default_values=");
+	print_local_array_ex(tcp, hr.default_values, hr.lines,
+			sizeof(hr.default_values[0]), print_uint8_array_member,
+			NULL, 0, NULL, NULL);
+	PRINT_FIELD_CSTRING(", ", hr, consumer_label);
+	if (!tcp->u_rval)
+		PRINT_FIELD_FD(", ", hr, fd, tcp);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+#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))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &er))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_U("{", er, lineoffset);
+	PRINT_FIELD_FLAGS(", ", er, handleflags, gpio_handle_flags,
+			  "GPIOHANDLE_FLAG_???");
+	PRINT_FIELD_FLAGS(", ", er, eventflags, gpio_event_flags,
+			  "GPIOEVENT_FLAG_???");
+	PRINT_FIELD_CSTRING(", ", er, consumer_label);
+	if (!tcp->u_rval)
+		PRINT_FIELD_FD(", ", er, fd, tcp);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+static void
+print_handle_data(struct tcb *const tcp, struct gpiohandle_data *vals)
+{
+	tprints("{values=");
+	print_local_array(tcp, vals->values, 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;
+
+	tprints(", ");
+	if (umove_or_printaddr(tcp, arg, &vals))
+		return RVAL_IOCTL_DECODED;
+
+	print_handle_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;
+
+	if (exiting(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &vals))
+		return RVAL_IOCTL_DECODED;
+
+	print_handle_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;
+
+	if (exiting(tcp))
+		return 0;
+
+	tprints(", ");
+	if (umove_or_printaddr_ignore_syserror(tcp, arg, &hc))
+		return RVAL_IOCTL_DECODED;
+
+	PRINT_FIELD_FLAGS("{", hc, flags, gpio_handle_flags,
+			  "GPIOHANDLE_FLAG_???");
+	tprints(", default_values=");
+	print_local_array(tcp, hc.default_values, print_uint8_array_member);
+	tprints("}");
+
+	return RVAL_IOCTL_DECODED;
+}
+
+MPERS_PRINTER_DECL(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);
+	default:
+		return RVAL_DECODED;
+	}
+}
+
+#endif
diff --git a/ioctl.c b/ioctl.c
index 1e3ec910..fa4aed27 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -347,6 +347,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/xlat/gpio_event_flags.in b/xlat/gpio_event_flags.in
new file mode 100644
index 00000000..9b87f50d
--- /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..2b027647
--- /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..fd4b7004
--- /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.29.2



More information about the Strace-devel mailing list