18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * trace/beauty/ioctl.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "trace/beauty/beauty.h"
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * FIXME: to support all arches we have to improve this, for
138c2ecf20Sopenharmony_ci * now, to build on older systems without things like TIOCGEXCL,
148c2ecf20Sopenharmony_ci * get it directly from our copy.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Right now only x86 is being supported for beautifying ioctl args
178c2ecf20Sopenharmony_ci * in 'perf trace', see tools/perf/trace/beauty/Build and builtin-trace.c
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci#include <uapi/asm-generic/ioctls.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	static const char *ioctl_tty_cmd[] = {
248c2ecf20Sopenharmony_ci	[_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
258c2ecf20Sopenharmony_ci	"TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY",
268c2ecf20Sopenharmony_ci	"TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ",
278c2ecf20Sopenharmony_ci	"TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR",
288c2ecf20Sopenharmony_ci	"FIONREAD", "TIOCLINUX", "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT",
298c2ecf20Sopenharmony_ci	"FIONBIO", "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP",
308c2ecf20Sopenharmony_ci	[_IOC_NR(TIOCSBRK)] = "TIOCSBRK", "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2",
318c2ecf20Sopenharmony_ci	"TCSETSW2", "TCSETSF2", "TIOCGRS48", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
328c2ecf20Sopenharmony_ci	"TIOCGDEV", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG", "TIOCVHANGUP", "TIOCGPKT",
338c2ecf20Sopenharmony_ci	"TIOCGPTLCK", [_IOC_NR(TIOCGEXCL)] = "TIOCGEXCL", "TIOCGPTPEER",
348c2ecf20Sopenharmony_ci	"TIOCGISO7816", "TIOCSISO7816",
358c2ecf20Sopenharmony_ci	[_IOC_NR(FIONCLEX)] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
368c2ecf20Sopenharmony_ci	"TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
378c2ecf20Sopenharmony_ci	"TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
388c2ecf20Sopenharmony_ci	"TIOCMIWAIT", "TIOCGICOUNT", };
398c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(ioctl_tty_cmd, "");
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (nr < strarray__ioctl_tty_cmd.nr_entries && strarray__ioctl_tty_cmd.entries[nr] != NULL)
428c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "%s", strarray__ioctl_tty_cmd.entries[nr]);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 'T', nr, dir);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_drm_cmd(int nr, int dir, char *bf, size_t size)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/drm_ioctl_array.c"
508c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(drm_ioctl_cmds, "");
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (nr < strarray__drm_ioctl_cmds.nr_entries && strarray__drm_ioctl_cmds.entries[nr] != NULL)
538c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "DRM_%s", strarray__drm_ioctl_cmds.entries[nr]);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 'd', nr, dir);
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_sndrv_pcm_cmd(int nr, int dir, char *bf, size_t size)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/sndrv_pcm_ioctl_array.c"
618c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(sndrv_pcm_ioctl_cmds, "");
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (nr < strarray__sndrv_pcm_ioctl_cmds.nr_entries && strarray__sndrv_pcm_ioctl_cmds.entries[nr] != NULL)
648c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "SNDRV_PCM_%s", strarray__sndrv_pcm_ioctl_cmds.entries[nr]);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 'A', nr, dir);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_sndrv_ctl_cmd(int nr, int dir, char *bf, size_t size)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/sndrv_ctl_ioctl_array.c"
728c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(sndrv_ctl_ioctl_cmds, "");
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (nr < strarray__sndrv_ctl_ioctl_cmds.nr_entries && strarray__sndrv_ctl_ioctl_cmds.entries[nr] != NULL)
758c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "SNDRV_CTL_%s", strarray__sndrv_ctl_ioctl_cmds.entries[nr]);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 'U', nr, dir);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_kvm_cmd(int nr, int dir, char *bf, size_t size)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/kvm_ioctl_array.c"
838c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(kvm_ioctl_cmds, "");
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (nr < strarray__kvm_ioctl_cmds.nr_entries && strarray__kvm_ioctl_cmds.entries[nr] != NULL)
868c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "KVM_%s", strarray__kvm_ioctl_cmds.entries[nr]);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_vhost_virtio_cmd(int nr, int dir, char *bf, size_t size)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c"
948c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(vhost_virtio_ioctl_cmds, "");
958c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(vhost_virtio_ioctl_read_cmds, "");
968c2ecf20Sopenharmony_ci	struct strarray *s = (dir & _IOC_READ) ? &strarray__vhost_virtio_ioctl_read_cmds : &strarray__vhost_virtio_ioctl_cmds;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (nr < s->nr_entries && s->entries[nr] != NULL)
998c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "VHOST_%s", s->entries[nr]);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAF, nr, dir);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/perf_ioctl_array.c"
1078c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(perf_ioctl_cmds, "");
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (nr < strarray__perf_ioctl_cmds.nr_entries && strarray__perf_ioctl_cmds.entries[nr] != NULL)
1108c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "PERF_%s", strarray__perf_ioctl_cmds.entries[nr]);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c"
1188c2ecf20Sopenharmony_ci	static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, "");
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL)
1218c2ecf20Sopenharmony_ci		return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	const char *prefix = "_IOC_";
1298c2ecf20Sopenharmony_ci	int dir	 = _IOC_DIR(cmd),
1308c2ecf20Sopenharmony_ci	    type = _IOC_TYPE(cmd),
1318c2ecf20Sopenharmony_ci	    nr	 = _IOC_NR(cmd),
1328c2ecf20Sopenharmony_ci	    sz	 = _IOC_SIZE(cmd);
1338c2ecf20Sopenharmony_ci	int printed = 0;
1348c2ecf20Sopenharmony_ci	static const struct ioctl_type {
1358c2ecf20Sopenharmony_ci		int	type;
1368c2ecf20Sopenharmony_ci		size_t	(*scnprintf)(int nr, int dir, char *bf, size_t size);
1378c2ecf20Sopenharmony_ci	} ioctl_types[] = { /* Must be ordered by type */
1388c2ecf20Sopenharmony_ci			      { .type	= '$', .scnprintf = ioctl__scnprintf_perf_cmd, },
1398c2ecf20Sopenharmony_ci		['A' - '$'] = { .type	= 'A', .scnprintf = ioctl__scnprintf_sndrv_pcm_cmd, },
1408c2ecf20Sopenharmony_ci		['T' - '$'] = { .type	= 'T', .scnprintf = ioctl__scnprintf_tty_cmd, },
1418c2ecf20Sopenharmony_ci		['U' - '$'] = { .type	= 'U', .scnprintf = ioctl__scnprintf_sndrv_ctl_cmd, },
1428c2ecf20Sopenharmony_ci		['d' - '$'] = { .type	= 'd', .scnprintf = ioctl__scnprintf_drm_cmd, },
1438c2ecf20Sopenharmony_ci		[0xAE - '$'] = { .type	= 0xAE, .scnprintf = ioctl__scnprintf_kvm_cmd, },
1448c2ecf20Sopenharmony_ci		[0xAF - '$'] = { .type	= 0xAF, .scnprintf = ioctl__scnprintf_vhost_virtio_cmd, },
1458c2ecf20Sopenharmony_ci	};
1468c2ecf20Sopenharmony_ci	const int nr_types = ARRAY_SIZE(ioctl_types);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (type >= ioctl_types[0].type && type <= ioctl_types[nr_types - 1].type) {
1498c2ecf20Sopenharmony_ci		const int index = type - ioctl_types[0].type;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		if (ioctl_types[index].scnprintf != NULL)
1528c2ecf20Sopenharmony_ci			return ioctl_types[index].scnprintf(nr, dir, bf, size);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	printed += scnprintf(bf + printed, size - printed, "%c", '(');
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (dir == _IOC_NONE) {
1588c2ecf20Sopenharmony_ci		printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "NONE");
1598c2ecf20Sopenharmony_ci	} else {
1608c2ecf20Sopenharmony_ci		if (dir & _IOC_READ)
1618c2ecf20Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "READ");
1628c2ecf20Sopenharmony_ci		if (dir & _IOC_WRITE) {
1638c2ecf20Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed, "%s%s%s", dir & _IOC_READ ? "|" : "",
1648c2ecf20Sopenharmony_ci					     show_prefix ? prefix : "",  "WRITE");
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci#ifndef USB_DEVICE_MAJOR
1728c2ecf20Sopenharmony_ci#define USB_DEVICE_MAJOR 189
1738c2ecf20Sopenharmony_ci#endif // USB_DEVICE_MAJOR
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cisize_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	unsigned long cmd = arg->val;
1788c2ecf20Sopenharmony_ci	int fd = syscall_arg__val(arg, 0);
1798c2ecf20Sopenharmony_ci	struct file *file = thread__files_entry(arg->thread, fd);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (file != NULL) {
1828c2ecf20Sopenharmony_ci		if (file->dev_maj == USB_DEVICE_MAJOR)
1838c2ecf20Sopenharmony_ci			return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size);
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
1878c2ecf20Sopenharmony_ci}
188