blob: e19eb6ea361d72a740153dc7ea7d7a9f44f54e04 [file] [log] [blame]
David Brazdil0f672f62019-12-10 10:32:29 +00001// SPDX-License-Identifier: LGPL-2.1
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00002/*
3 * trace/beauty/ioctl.c
4 *
5 * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00006 */
7
8#include "trace/beauty/beauty.h"
9#include <linux/kernel.h>
10
11/*
12 * FIXME: to support all arches we have to improve this, for
13 * now, to build on older systems without things like TIOCGEXCL,
14 * get it directly from our copy.
15 *
16 * Right now only x86 is being supported for beautifying ioctl args
17 * in 'perf trace', see tools/perf/trace/beauty/Build and builtin-trace.c
18 */
19#include <uapi/asm-generic/ioctls.h>
20
21static size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size)
22{
23 static const char *ioctl_tty_cmd[] = {
David Brazdil0f672f62019-12-10 10:32:29 +000024 [_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000025 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY",
26 "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ",
27 "TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR",
28 "FIONREAD", "TIOCLINUX", "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT",
29 "FIONBIO", "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP",
30 [_IOC_NR(TIOCSBRK)] = "TIOCSBRK", "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2",
31 "TCSETSW2", "TCSETSF2", "TIOCGRS48", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
32 "TIOCGDEV", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG", "TIOCVHANGUP", "TIOCGPKT",
33 "TIOCGPTLCK", [_IOC_NR(TIOCGEXCL)] = "TIOCGEXCL", "TIOCGPTPEER",
David Brazdil0f672f62019-12-10 10:32:29 +000034 "TIOCGISO7816", "TIOCSISO7816",
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000035 [_IOC_NR(FIONCLEX)] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
36 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
37 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
38 "TIOCMIWAIT", "TIOCGICOUNT", };
David Brazdil0f672f62019-12-10 10:32:29 +000039 static DEFINE_STRARRAY(ioctl_tty_cmd, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000040
41 if (nr < strarray__ioctl_tty_cmd.nr_entries && strarray__ioctl_tty_cmd.entries[nr] != NULL)
42 return scnprintf(bf, size, "%s", strarray__ioctl_tty_cmd.entries[nr]);
43
44 return scnprintf(bf, size, "(%#x, %#x, %#x)", 'T', nr, dir);
45}
46
47static size_t ioctl__scnprintf_drm_cmd(int nr, int dir, char *bf, size_t size)
48{
49#include "trace/beauty/generated/ioctl/drm_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +000050 static DEFINE_STRARRAY(drm_ioctl_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000051
52 if (nr < strarray__drm_ioctl_cmds.nr_entries && strarray__drm_ioctl_cmds.entries[nr] != NULL)
53 return scnprintf(bf, size, "DRM_%s", strarray__drm_ioctl_cmds.entries[nr]);
54
55 return scnprintf(bf, size, "(%#x, %#x, %#x)", 'd', nr, dir);
56}
57
58static size_t ioctl__scnprintf_sndrv_pcm_cmd(int nr, int dir, char *bf, size_t size)
59{
60#include "trace/beauty/generated/ioctl/sndrv_pcm_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +000061 static DEFINE_STRARRAY(sndrv_pcm_ioctl_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000062
63 if (nr < strarray__sndrv_pcm_ioctl_cmds.nr_entries && strarray__sndrv_pcm_ioctl_cmds.entries[nr] != NULL)
64 return scnprintf(bf, size, "SNDRV_PCM_%s", strarray__sndrv_pcm_ioctl_cmds.entries[nr]);
65
66 return scnprintf(bf, size, "(%#x, %#x, %#x)", 'A', nr, dir);
67}
68
69static size_t ioctl__scnprintf_sndrv_ctl_cmd(int nr, int dir, char *bf, size_t size)
70{
71#include "trace/beauty/generated/ioctl/sndrv_ctl_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +000072 static DEFINE_STRARRAY(sndrv_ctl_ioctl_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000073
74 if (nr < strarray__sndrv_ctl_ioctl_cmds.nr_entries && strarray__sndrv_ctl_ioctl_cmds.entries[nr] != NULL)
75 return scnprintf(bf, size, "SNDRV_CTL_%s", strarray__sndrv_ctl_ioctl_cmds.entries[nr]);
76
77 return scnprintf(bf, size, "(%#x, %#x, %#x)", 'U', nr, dir);
78}
79
80static size_t ioctl__scnprintf_kvm_cmd(int nr, int dir, char *bf, size_t size)
81{
82#include "trace/beauty/generated/ioctl/kvm_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +000083 static DEFINE_STRARRAY(kvm_ioctl_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000084
85 if (nr < strarray__kvm_ioctl_cmds.nr_entries && strarray__kvm_ioctl_cmds.entries[nr] != NULL)
86 return scnprintf(bf, size, "KVM_%s", strarray__kvm_ioctl_cmds.entries[nr]);
87
88 return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
89}
90
91static size_t ioctl__scnprintf_vhost_virtio_cmd(int nr, int dir, char *bf, size_t size)
92{
93#include "trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +000094 static DEFINE_STRARRAY(vhost_virtio_ioctl_cmds, "");
95 static DEFINE_STRARRAY(vhost_virtio_ioctl_read_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +000096 struct strarray *s = (dir & _IOC_READ) ? &strarray__vhost_virtio_ioctl_read_cmds : &strarray__vhost_virtio_ioctl_cmds;
97
98 if (nr < s->nr_entries && s->entries[nr] != NULL)
99 return scnprintf(bf, size, "VHOST_%s", s->entries[nr]);
100
101 return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAF, nr, dir);
102}
103
104static size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size)
105{
106#include "trace/beauty/generated/ioctl/perf_ioctl_array.c"
David Brazdil0f672f62019-12-10 10:32:29 +0000107 static DEFINE_STRARRAY(perf_ioctl_cmds, "");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000108
109 if (nr < strarray__perf_ioctl_cmds.nr_entries && strarray__perf_ioctl_cmds.entries[nr] != NULL)
110 return scnprintf(bf, size, "PERF_%s", strarray__perf_ioctl_cmds.entries[nr]);
111
112 return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
113}
114
David Brazdil0f672f62019-12-10 10:32:29 +0000115static size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size)
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000116{
David Brazdil0f672f62019-12-10 10:32:29 +0000117#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c"
118 static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, "");
119
120 if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL)
121 return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]);
122
123 return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir);
124}
125
126static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
127{
128 const char *prefix = "_IOC_";
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000129 int dir = _IOC_DIR(cmd),
130 type = _IOC_TYPE(cmd),
131 nr = _IOC_NR(cmd),
132 sz = _IOC_SIZE(cmd);
133 int printed = 0;
134 static const struct ioctl_type {
135 int type;
136 size_t (*scnprintf)(int nr, int dir, char *bf, size_t size);
137 } ioctl_types[] = { /* Must be ordered by type */
138 { .type = '$', .scnprintf = ioctl__scnprintf_perf_cmd, },
139 ['A' - '$'] = { .type = 'A', .scnprintf = ioctl__scnprintf_sndrv_pcm_cmd, },
140 ['T' - '$'] = { .type = 'T', .scnprintf = ioctl__scnprintf_tty_cmd, },
141 ['U' - '$'] = { .type = 'U', .scnprintf = ioctl__scnprintf_sndrv_ctl_cmd, },
142 ['d' - '$'] = { .type = 'd', .scnprintf = ioctl__scnprintf_drm_cmd, },
143 [0xAE - '$'] = { .type = 0xAE, .scnprintf = ioctl__scnprintf_kvm_cmd, },
144 [0xAF - '$'] = { .type = 0xAF, .scnprintf = ioctl__scnprintf_vhost_virtio_cmd, },
145 };
146 const int nr_types = ARRAY_SIZE(ioctl_types);
147
148 if (type >= ioctl_types[0].type && type <= ioctl_types[nr_types - 1].type) {
149 const int index = type - ioctl_types[0].type;
150
151 if (ioctl_types[index].scnprintf != NULL)
152 return ioctl_types[index].scnprintf(nr, dir, bf, size);
153 }
154
155 printed += scnprintf(bf + printed, size - printed, "%c", '(');
156
157 if (dir == _IOC_NONE) {
David Brazdil0f672f62019-12-10 10:32:29 +0000158 printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "NONE");
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000159 } else {
160 if (dir & _IOC_READ)
David Brazdil0f672f62019-12-10 10:32:29 +0000161 printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "READ");
162 if (dir & _IOC_WRITE) {
163 printed += scnprintf(bf + printed, size - printed, "%s%s%s", dir & _IOC_READ ? "|" : "",
164 show_prefix ? prefix : "", "WRITE");
165 }
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000166 }
167
168 return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
169}
170
David Brazdil0f672f62019-12-10 10:32:29 +0000171#ifndef USB_DEVICE_MAJOR
172#define USB_DEVICE_MAJOR 189
173#endif // USB_DEVICE_MAJOR
174
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000175size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
176{
177 unsigned long cmd = arg->val;
David Brazdil0f672f62019-12-10 10:32:29 +0000178 int fd = syscall_arg__val(arg, 0);
179 struct file *file = thread__files_entry(arg->thread, fd);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000180
David Brazdil0f672f62019-12-10 10:32:29 +0000181 if (file != NULL) {
182 if (file->dev_maj == USB_DEVICE_MAJOR)
183 return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size);
184 }
185
186 return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
Andrew Scullb4b6d4a2019-01-02 15:54:55 +0000187}