[PATCH v4 2/6] Add GPIO ioctl decoding
Kent Gibson
warthog618 at gmail.com
Sat Jan 23 01:56:41 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 | 226 ++++++++++++++++++++++++++++++++++++++
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, 290 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..1098699b
--- /dev/null
+++ b/gpio_ioctl.c
@@ -0,0 +1,226 @@
+/*
+ * 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 (exiting(tcp)) {
+ PRINT_FIELD_FD("{", hr, fd, tcp);
+ tprints("}");
+ return RVAL_IOCTL_DECODED;
+ }
+
+ /* entering */
+ PRINT_FIELD_U("{", hr, lines);
+ 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 (exiting(tcp)) {
+ 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