Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  * trace/beauty/ioctl.c
0004  *
0005  *  Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
0006  */
0007 
0008 #include "trace/beauty/beauty.h"
0009 #include <linux/kernel.h>
0010 
0011 /*
0012  * FIXME: to support all arches we have to improve this, for
0013  * now, to build on older systems without things like TIOCGEXCL,
0014  * get it directly from our copy.
0015  *
0016  * Right now only x86 is being supported for beautifying ioctl args
0017  * in 'perf trace', see tools/perf/trace/beauty/Build and builtin-trace.c
0018  */
0019 #include <uapi/asm-generic/ioctls.h>
0020 
0021 static size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size)
0022 {
0023     static const char *ioctl_tty_cmd[] = {
0024     [_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
0025     "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY",
0026     "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ",
0027     "TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR",
0028     "FIONREAD", "TIOCLINUX", "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT",
0029     "FIONBIO", "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP",
0030     [_IOC_NR(TIOCSBRK)] = "TIOCSBRK", "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2",
0031     "TCSETSW2", "TCSETSF2", "TIOCGRS48", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
0032     "TIOCGDEV", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG", "TIOCVHANGUP", "TIOCGPKT",
0033     "TIOCGPTLCK", [_IOC_NR(TIOCGEXCL)] = "TIOCGEXCL", "TIOCGPTPEER",
0034     "TIOCGISO7816", "TIOCSISO7816",
0035     [_IOC_NR(FIONCLEX)] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
0036     "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
0037     "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
0038     "TIOCMIWAIT", "TIOCGICOUNT", };
0039     static DEFINE_STRARRAY(ioctl_tty_cmd, "");
0040 
0041     if (nr < strarray__ioctl_tty_cmd.nr_entries && strarray__ioctl_tty_cmd.entries[nr] != NULL)
0042         return scnprintf(bf, size, "%s", strarray__ioctl_tty_cmd.entries[nr]);
0043 
0044     return scnprintf(bf, size, "(%#x, %#x, %#x)", 'T', nr, dir);
0045 }
0046 
0047 static size_t ioctl__scnprintf_drm_cmd(int nr, int dir, char *bf, size_t size)
0048 {
0049 #include "trace/beauty/generated/ioctl/drm_ioctl_array.c"
0050     static DEFINE_STRARRAY(drm_ioctl_cmds, "");
0051 
0052     if (nr < strarray__drm_ioctl_cmds.nr_entries && strarray__drm_ioctl_cmds.entries[nr] != NULL)
0053         return scnprintf(bf, size, "DRM_%s", strarray__drm_ioctl_cmds.entries[nr]);
0054 
0055     return scnprintf(bf, size, "(%#x, %#x, %#x)", 'd', nr, dir);
0056 }
0057 
0058 static size_t ioctl__scnprintf_sndrv_pcm_cmd(int nr, int dir, char *bf, size_t size)
0059 {
0060 #include "trace/beauty/generated/ioctl/sndrv_pcm_ioctl_array.c"
0061     static DEFINE_STRARRAY(sndrv_pcm_ioctl_cmds, "");
0062 
0063     if (nr < strarray__sndrv_pcm_ioctl_cmds.nr_entries && strarray__sndrv_pcm_ioctl_cmds.entries[nr] != NULL)
0064         return scnprintf(bf, size, "SNDRV_PCM_%s", strarray__sndrv_pcm_ioctl_cmds.entries[nr]);
0065 
0066     return scnprintf(bf, size, "(%#x, %#x, %#x)", 'A', nr, dir);
0067 }
0068 
0069 static size_t ioctl__scnprintf_sndrv_ctl_cmd(int nr, int dir, char *bf, size_t size)
0070 {
0071 #include "trace/beauty/generated/ioctl/sndrv_ctl_ioctl_array.c"
0072     static DEFINE_STRARRAY(sndrv_ctl_ioctl_cmds, "");
0073 
0074     if (nr < strarray__sndrv_ctl_ioctl_cmds.nr_entries && strarray__sndrv_ctl_ioctl_cmds.entries[nr] != NULL)
0075         return scnprintf(bf, size, "SNDRV_CTL_%s", strarray__sndrv_ctl_ioctl_cmds.entries[nr]);
0076 
0077     return scnprintf(bf, size, "(%#x, %#x, %#x)", 'U', nr, dir);
0078 }
0079 
0080 static size_t ioctl__scnprintf_kvm_cmd(int nr, int dir, char *bf, size_t size)
0081 {
0082 #include "trace/beauty/generated/ioctl/kvm_ioctl_array.c"
0083     static DEFINE_STRARRAY(kvm_ioctl_cmds, "");
0084 
0085     if (nr < strarray__kvm_ioctl_cmds.nr_entries && strarray__kvm_ioctl_cmds.entries[nr] != NULL)
0086         return scnprintf(bf, size, "KVM_%s", strarray__kvm_ioctl_cmds.entries[nr]);
0087 
0088     return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
0089 }
0090 
0091 static size_t ioctl__scnprintf_vhost_virtio_cmd(int nr, int dir, char *bf, size_t size)
0092 {
0093 #include "trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c"
0094     static DEFINE_STRARRAY(vhost_virtio_ioctl_cmds, "");
0095     static DEFINE_STRARRAY(vhost_virtio_ioctl_read_cmds, "");
0096     struct strarray *s = (dir & _IOC_READ) ? &strarray__vhost_virtio_ioctl_read_cmds : &strarray__vhost_virtio_ioctl_cmds;
0097 
0098     if (nr < s->nr_entries && s->entries[nr] != NULL)
0099         return scnprintf(bf, size, "VHOST_%s", s->entries[nr]);
0100 
0101     return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAF, nr, dir);
0102 }
0103 
0104 static size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size)
0105 {
0106 #include "trace/beauty/generated/ioctl/perf_ioctl_array.c"
0107     static DEFINE_STRARRAY(perf_ioctl_cmds, "");
0108 
0109     if (nr < strarray__perf_ioctl_cmds.nr_entries && strarray__perf_ioctl_cmds.entries[nr] != NULL)
0110         return scnprintf(bf, size, "PERF_%s", strarray__perf_ioctl_cmds.entries[nr]);
0111 
0112     return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir);
0113 }
0114 
0115 static size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size)
0116 {
0117 #include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c"
0118     static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, "");
0119 
0120     if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL)
0121         return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]);
0122 
0123     return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir);
0124 }
0125 
0126 static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix)
0127 {
0128     const char *prefix = "_IOC_";
0129     int dir  = _IOC_DIR(cmd),
0130         type = _IOC_TYPE(cmd),
0131         nr   = _IOC_NR(cmd),
0132         sz   = _IOC_SIZE(cmd);
0133     int printed = 0;
0134     static const struct ioctl_type {
0135         int type;
0136         size_t  (*scnprintf)(int nr, int dir, char *bf, size_t size);
0137     } ioctl_types[] = { /* Must be ordered by type */
0138                   { .type   = '$', .scnprintf = ioctl__scnprintf_perf_cmd, },
0139         ['A' - '$'] = { .type   = 'A', .scnprintf = ioctl__scnprintf_sndrv_pcm_cmd, },
0140         ['T' - '$'] = { .type   = 'T', .scnprintf = ioctl__scnprintf_tty_cmd, },
0141         ['U' - '$'] = { .type   = 'U', .scnprintf = ioctl__scnprintf_sndrv_ctl_cmd, },
0142         ['d' - '$'] = { .type   = 'd', .scnprintf = ioctl__scnprintf_drm_cmd, },
0143         [0xAE - '$'] = { .type  = 0xAE, .scnprintf = ioctl__scnprintf_kvm_cmd, },
0144         [0xAF - '$'] = { .type  = 0xAF, .scnprintf = ioctl__scnprintf_vhost_virtio_cmd, },
0145     };
0146     const int nr_types = ARRAY_SIZE(ioctl_types);
0147 
0148     if (type >= ioctl_types[0].type && type <= ioctl_types[nr_types - 1].type) {
0149         const int index = type - ioctl_types[0].type;
0150 
0151         if (ioctl_types[index].scnprintf != NULL)
0152             return ioctl_types[index].scnprintf(nr, dir, bf, size);
0153     }
0154 
0155     printed += scnprintf(bf + printed, size - printed, "%c", '(');
0156 
0157     if (dir == _IOC_NONE) {
0158         printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "NONE");
0159     } else {
0160         if (dir & _IOC_READ)
0161             printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "READ");
0162         if (dir & _IOC_WRITE) {
0163             printed += scnprintf(bf + printed, size - printed, "%s%s%s", dir & _IOC_READ ? "|" : "",
0164                          show_prefix ? prefix : "",  "WRITE");
0165         }
0166     }
0167 
0168     return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz);
0169 }
0170 
0171 #ifndef USB_DEVICE_MAJOR
0172 #define USB_DEVICE_MAJOR 189
0173 #endif // USB_DEVICE_MAJOR
0174 
0175 size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg)
0176 {
0177     unsigned long cmd = arg->val;
0178     int fd = syscall_arg__val(arg, 0);
0179     struct file *file = thread__files_entry(arg->thread, fd);
0180 
0181     if (file != NULL) {
0182         if (file->dev_maj == USB_DEVICE_MAJOR)
0183             return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size);
0184     }
0185 
0186     return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix);
0187 }