[PATCH v2 2/6] Add GPIO ioctl decoding
Kent Gibson
warthog618 at gmail.com
Mon Jan 11 15:09:08 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 | 259 ++++++++++++++++++++++++++++++++++++++
ioctl.c | 4 +
xlat/gpio_event_flags.in | 3 +
xlat/gpio_handle_flags.in | 8 ++
xlat/gpio_line_flags.in | 8 ++
8 files changed, 285 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 c0199f65..5fbee7b5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -139,6 +139,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 a736e70b..5de50f04 100644
--- a/configure.ac
+++ b/configure.ac
@@ -415,6 +415,7 @@ AC_CHECK_HEADERS(m4_normalize([
linux/dqblk_xfs.h
linux/falloc.h
linux/fib_rules.h
+ linux/gpio.h
linux/hiddev.h
linux/ip_vs.h
linux/ipc.h
diff --git a/defs.h b/defs.h
index 8a12f751..2cfb550a 100644
--- a/defs.h
+++ b/defs.h
@@ -1216,6 +1216,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..7bd5dfc8
--- /dev/null
+++ b/gpio_ioctl.c
@@ -0,0 +1,259 @@
+/*
+ * 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 <linux/gpio.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 {
+ uint32_t flags;
+ uint8_t default_values[GPIOHANDLES_MAX];
+ uint32_t 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, uint32_t)
+#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))
+ 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)
+{
+ tprintf(", {offset=%u}", (uint32_t)arg);
+
+ 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)) {
+ 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_REQUEST_???");
+ 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);
+ tprints("}");
+ return 0;
+ }
+
+ /* exiting */
+ 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))
+ 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)) {
+ 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;
+ }
+
+ /* exiting */
+ 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)) {
+ tprints(", ");
+ return 0;
+ }
+ /* exiting */
+ if (syserror(tcp)) {
+ printaddr(arg);
+ return RVAL_IOCTL_DECODED;
+ }
+ 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;
+
+ 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_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_???");
+ tprints(", default_values=");
+ print_local_array(tcp, hc.default_values, 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 f3f6f0ab..944834df 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -345,6 +345,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..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