1 /*
2 * Check decoding of COUNTER_* commands of ioctl syscall.
3 *
4 * Copyright (c) 2022 Eugene Syromyatnikov <evgsyr@gmail.com>.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12
13 #include <errno.h>
14 #include <inttypes.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include <linux/ioctl.h>
21 #include <linux/counter.h>
22
23
24 /* A hack for handling different types of _IOC() on various platforms */
25 #if XLAT_RAW
26 # define XLAT_ARGS_U(a_) (unsigned int) (a_)
27 #elif XLAT_VERBOSE
28 # define XLAT_ARGS_U(a_) (unsigned int) (a_), #a_
29 #else
30 # define XLAT_ARGS_U(a_) #a_
31 #endif
32
33 static const char *errstr;
34
35 static long
36 sys_ioctl(kernel_long_t fd, kernel_ulong_t cmd, kernel_ulong_t arg)
37 {
38 const long rc = syscall(__NR_ioctl, fd, cmd, arg);
39 errstr = sprintrc(rc);
40 return rc;
41 }
42
43 int
44 main(void)
45 {
46 static const struct {
47 uint32_t val;
48 const char *str;
49 } dirs[] = {
50 { ARG_STR(_IOC_NONE) },
51 { ARG_STR(_IOC_READ) },
52 { ARG_STR(_IOC_WRITE) },
53 { ARG_STR(_IOC_READ|_IOC_WRITE) },
54 };
55 static const kernel_ulong_t magic =
56 (kernel_ulong_t) 0xdeadbeefbadc0dedULL;
57
58 /* Unknown counter ioctl */
59 for (size_t i = 0; i < ARRAY_SIZE(dirs); i++) {
60 for (unsigned int j = 0; j < 32; j += 1) {
61 sys_ioctl(-1, _IOC(dirs[i].val, '>', 3, j), magic);
62 printf("ioctl(-1, "
63 XLAT_KNOWN(%#x, "_IOC(%s, 0x3e, 0x3, %#x)")
64 ", %#lx) = %s\n",
65 #if XLAT_RAW || XLAT_VERBOSE
66 (unsigned int) _IOC(dirs[i].val, '>', 3, j),
67 #endif
68 #if !XLAT_RAW
69 dirs[i].str, j,
70 #endif
71 (unsigned long) magic, errstr);
72 }
73 }
74
75 /* COUNTER_ADD_WATCH_IOCTL */
76 static const struct {
77 struct counter_watch val;;
78 const char *str;
79 } watches[] = {
80 { { { 0 } },
81 "{component={type=" XLAT_KNOWN(0, "COUNTER_COMPONENT_NONE")
82 ", scope=" XLAT_KNOWN(0, "COUNTER_SCOPE_DEVICE")
83 ", parent=0, id=0}"
84 ", event=" XLAT_KNOWN(0, "COUNTER_EVENT_OVERFLOW")
85 ", channel=0}" },
86 { { { COUNTER_COMPONENT_EXTENSION, COUNTER_SCOPE_COUNT,
87 23, 42 }, COUNTER_EVENT_CAPTURE, 69 },
88 "{component="
89 "{type=" XLAT_KNOWN(0x5, "COUNTER_COMPONENT_EXTENSION")
90 ", scope=" XLAT_KNOWN(0x2, "COUNTER_SCOPE_COUNT")
91 ", parent=23, id=42}"
92 ", event=" XLAT_KNOWN(0x6, "COUNTER_EVENT_CAPTURE")
93 ", channel=69}" },
94 { { { COUNTER_COMPONENT_EXTENSION + 1, COUNTER_SCOPE_COUNT + 1,
95 142, 160 }, COUNTER_EVENT_CAPTURE + 1, 173 },
96 "{component={type=" XLAT_UNKNOWN(0x6, "COUNTER_COMPONENT_???")
97 ", scope=" XLAT_UNKNOWN(0x3, "COUNTER_SCOPE_???")
98 ", parent=142, id=160}"
99 ", event=" XLAT_UNKNOWN(0x7, "COUNTER_EVENT_???")
100 ", channel=173}" },
101 };
102 TAIL_ALLOC_OBJECT_CONST_PTR(struct counter_watch, watch);
103
104 sys_ioctl(-1, COUNTER_ADD_WATCH_IOCTL, 0);
105 printf("ioctl(-1, " XLAT_FMT ", NULL) = %s\n",
106 XLAT_ARGS_U(COUNTER_ADD_WATCH_IOCTL), errstr);
107
108 sys_ioctl(-1, COUNTER_ADD_WATCH_IOCTL, (uintptr_t) watch + 1);
109 printf("ioctl(-1, " XLAT_FMT ", %p) = %s\n",
110 XLAT_ARGS_U(COUNTER_ADD_WATCH_IOCTL),
111 (char *) watch + 1, errstr);
112
113 for (size_t i = 0; i < ARRAY_SIZE(watches); i++) {
114 memcpy(watch, &watches[i].val, sizeof(watches[i].val));
115 sys_ioctl(-1, COUNTER_ADD_WATCH_IOCTL, (uintptr_t) watch);
116 printf("ioctl(-1, " XLAT_FMT ", %s) = %s\n",
117 XLAT_ARGS_U(COUNTER_ADD_WATCH_IOCTL),
118 watches[i].str, errstr);
119 }
120
121 /* COUNTER_ENABLE_EVENTS_IOCTL */
122 sys_ioctl(-1, COUNTER_ENABLE_EVENTS_IOCTL, magic);
123 printf("ioctl(-1, " XLAT_FMT ") = %s\n",
124 XLAT_ARGS_U(COUNTER_ENABLE_EVENTS_IOCTL), errstr);
125
126 /* COUNTER_DISABLE_EVENTS_IOCTL */
127 sys_ioctl(-1, COUNTER_DISABLE_EVENTS_IOCTL, magic);
128 printf("ioctl(-1, " XLAT_FMT ") = %s\n",
129 XLAT_ARGS_U(COUNTER_DISABLE_EVENTS_IOCTL), errstr);
130
131 puts("+++ exited with 0 +++");
132 return 0;
133 }