162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * trace/beauty/ioctl.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "trace/beauty/beauty.h" 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * FIXME: to support all arches we have to improve this, for 1362306a36Sopenharmony_ci * now, to build on older systems without things like TIOCGEXCL, 1462306a36Sopenharmony_ci * get it directly from our copy. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Right now only x86 is being supported for beautifying ioctl args 1762306a36Sopenharmony_ci * in 'perf trace', see tools/perf/trace/beauty/Build and builtin-trace.c 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci#include <uapi/asm-generic/ioctls.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci static const char *ioctl_tty_cmd[] = { 2462306a36Sopenharmony_ci [_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW", 2562306a36Sopenharmony_ci "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY", 2662306a36Sopenharmony_ci "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ", 2762306a36Sopenharmony_ci "TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", 2862306a36Sopenharmony_ci "FIONREAD", "TIOCLINUX", "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", 2962306a36Sopenharmony_ci "FIONBIO", "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", 3062306a36Sopenharmony_ci [_IOC_NR(TIOCSBRK)] = "TIOCSBRK", "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", 3162306a36Sopenharmony_ci "TCSETSW2", "TCSETSF2", "TIOCGRS48", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK", 3262306a36Sopenharmony_ci "TIOCGDEV", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG", "TIOCVHANGUP", "TIOCGPKT", 3362306a36Sopenharmony_ci "TIOCGPTLCK", [_IOC_NR(TIOCGEXCL)] = "TIOCGEXCL", "TIOCGPTPEER", 3462306a36Sopenharmony_ci "TIOCGISO7816", "TIOCSISO7816", 3562306a36Sopenharmony_ci [_IOC_NR(FIONCLEX)] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG", 3662306a36Sopenharmony_ci "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS", 3762306a36Sopenharmony_ci "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI", 3862306a36Sopenharmony_ci "TIOCMIWAIT", "TIOCGICOUNT", }; 3962306a36Sopenharmony_ci static DEFINE_STRARRAY(ioctl_tty_cmd, ""); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (nr < strarray__ioctl_tty_cmd.nr_entries && strarray__ioctl_tty_cmd.entries[nr] != NULL) 4262306a36Sopenharmony_ci return scnprintf(bf, size, "%s", strarray__ioctl_tty_cmd.entries[nr]); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 'T', nr, dir); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic size_t ioctl__scnprintf_drm_cmd(int nr, int dir, char *bf, size_t size) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/drm_ioctl_array.c" 5062306a36Sopenharmony_ci static DEFINE_STRARRAY(drm_ioctl_cmds, ""); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (nr < strarray__drm_ioctl_cmds.nr_entries && strarray__drm_ioctl_cmds.entries[nr] != NULL) 5362306a36Sopenharmony_ci return scnprintf(bf, size, "DRM_%s", strarray__drm_ioctl_cmds.entries[nr]); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 'd', nr, dir); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic size_t ioctl__scnprintf_sndrv_pcm_cmd(int nr, int dir, char *bf, size_t size) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/sndrv_pcm_ioctl_array.c" 6162306a36Sopenharmony_ci static DEFINE_STRARRAY(sndrv_pcm_ioctl_cmds, ""); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (nr < strarray__sndrv_pcm_ioctl_cmds.nr_entries && strarray__sndrv_pcm_ioctl_cmds.entries[nr] != NULL) 6462306a36Sopenharmony_ci return scnprintf(bf, size, "SNDRV_PCM_%s", strarray__sndrv_pcm_ioctl_cmds.entries[nr]); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 'A', nr, dir); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic size_t ioctl__scnprintf_sndrv_ctl_cmd(int nr, int dir, char *bf, size_t size) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/sndrv_ctl_ioctl_array.c" 7262306a36Sopenharmony_ci static DEFINE_STRARRAY(sndrv_ctl_ioctl_cmds, ""); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (nr < strarray__sndrv_ctl_ioctl_cmds.nr_entries && strarray__sndrv_ctl_ioctl_cmds.entries[nr] != NULL) 7562306a36Sopenharmony_ci return scnprintf(bf, size, "SNDRV_CTL_%s", strarray__sndrv_ctl_ioctl_cmds.entries[nr]); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 'U', nr, dir); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic size_t ioctl__scnprintf_kvm_cmd(int nr, int dir, char *bf, size_t size) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/kvm_ioctl_array.c" 8362306a36Sopenharmony_ci static DEFINE_STRARRAY(kvm_ioctl_cmds, ""); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (nr < strarray__kvm_ioctl_cmds.nr_entries && strarray__kvm_ioctl_cmds.entries[nr] != NULL) 8662306a36Sopenharmony_ci return scnprintf(bf, size, "KVM_%s", strarray__kvm_ioctl_cmds.entries[nr]); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic size_t ioctl__scnprintf_vhost_virtio_cmd(int nr, int dir, char *bf, size_t size) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c" 9462306a36Sopenharmony_ci static DEFINE_STRARRAY(vhost_virtio_ioctl_cmds, ""); 9562306a36Sopenharmony_ci static DEFINE_STRARRAY(vhost_virtio_ioctl_read_cmds, ""); 9662306a36Sopenharmony_ci struct strarray *s = (dir & _IOC_READ) ? &strarray__vhost_virtio_ioctl_read_cmds : &strarray__vhost_virtio_ioctl_cmds; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (nr < s->nr_entries && s->entries[nr] != NULL) 9962306a36Sopenharmony_ci return scnprintf(bf, size, "VHOST_%s", s->entries[nr]); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAF, nr, dir); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/perf_ioctl_array.c" 10762306a36Sopenharmony_ci static DEFINE_STRARRAY(perf_ioctl_cmds, ""); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (nr < strarray__perf_ioctl_cmds.nr_entries && strarray__perf_ioctl_cmds.entries[nr] != NULL) 11062306a36Sopenharmony_ci return scnprintf(bf, size, "PERF_%s", strarray__perf_ioctl_cmds.entries[nr]); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c" 11862306a36Sopenharmony_ci static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, ""); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL) 12162306a36Sopenharmony_ci return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci const char *prefix = "_IOC_"; 12962306a36Sopenharmony_ci int dir = _IOC_DIR(cmd), 13062306a36Sopenharmony_ci type = _IOC_TYPE(cmd), 13162306a36Sopenharmony_ci nr = _IOC_NR(cmd), 13262306a36Sopenharmony_ci sz = _IOC_SIZE(cmd); 13362306a36Sopenharmony_ci int printed = 0; 13462306a36Sopenharmony_ci static const struct ioctl_type { 13562306a36Sopenharmony_ci int type; 13662306a36Sopenharmony_ci size_t (*scnprintf)(int nr, int dir, char *bf, size_t size); 13762306a36Sopenharmony_ci } ioctl_types[] = { /* Must be ordered by type */ 13862306a36Sopenharmony_ci { .type = '$', .scnprintf = ioctl__scnprintf_perf_cmd, }, 13962306a36Sopenharmony_ci ['A' - '$'] = { .type = 'A', .scnprintf = ioctl__scnprintf_sndrv_pcm_cmd, }, 14062306a36Sopenharmony_ci ['T' - '$'] = { .type = 'T', .scnprintf = ioctl__scnprintf_tty_cmd, }, 14162306a36Sopenharmony_ci ['U' - '$'] = { .type = 'U', .scnprintf = ioctl__scnprintf_sndrv_ctl_cmd, }, 14262306a36Sopenharmony_ci ['d' - '$'] = { .type = 'd', .scnprintf = ioctl__scnprintf_drm_cmd, }, 14362306a36Sopenharmony_ci [0xAE - '$'] = { .type = 0xAE, .scnprintf = ioctl__scnprintf_kvm_cmd, }, 14462306a36Sopenharmony_ci [0xAF - '$'] = { .type = 0xAF, .scnprintf = ioctl__scnprintf_vhost_virtio_cmd, }, 14562306a36Sopenharmony_ci }; 14662306a36Sopenharmony_ci const int nr_types = ARRAY_SIZE(ioctl_types); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (type >= ioctl_types[0].type && type <= ioctl_types[nr_types - 1].type) { 14962306a36Sopenharmony_ci const int index = type - ioctl_types[0].type; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (ioctl_types[index].scnprintf != NULL) 15262306a36Sopenharmony_ci return ioctl_types[index].scnprintf(nr, dir, bf, size); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci printed += scnprintf(bf + printed, size - printed, "%c", '('); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (dir == _IOC_NONE) { 15862306a36Sopenharmony_ci printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "NONE"); 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci if (dir & _IOC_READ) 16162306a36Sopenharmony_ci printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "READ"); 16262306a36Sopenharmony_ci if (dir & _IOC_WRITE) { 16362306a36Sopenharmony_ci printed += scnprintf(bf + printed, size - printed, "%s%s%s", dir & _IOC_READ ? "|" : "", 16462306a36Sopenharmony_ci show_prefix ? prefix : "", "WRITE"); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#ifndef USB_DEVICE_MAJOR 17262306a36Sopenharmony_ci#define USB_DEVICE_MAJOR 189 17362306a36Sopenharmony_ci#endif // USB_DEVICE_MAJOR 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cisize_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci unsigned long cmd = arg->val; 17862306a36Sopenharmony_ci int fd = syscall_arg__val(arg, 0); 17962306a36Sopenharmony_ci struct file *file = thread__files_entry(arg->thread, fd); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (file != NULL) { 18262306a36Sopenharmony_ci if (file->dev_maj == USB_DEVICE_MAJOR) 18362306a36Sopenharmony_ci return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix); 18762306a36Sopenharmony_ci} 188