t_kcov.c revision 1.4 1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2018, 2019 Andrew Turner
5 *
6 * This software was developed by SRI International and the University of
7 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8 * ("CTSRD"), as part of the DARPA CRASH research programme.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31 #include <sys/cdefs.h>
32
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/kcov.h>
36 #include <sys/mman.h>
37
38 #include <fcntl.h>
39 #include <pthread.h>
40 #include <semaphore.h>
41
42 #include <atf-c.h>
43
44 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
45
46 static int
47 open_kcov(void)
48 {
49 int fd;
50
51 fd = open("/dev/kcov", O_RDWR);
52 if (fd == -1)
53 atf_tc_skip("Failed to open /dev/kcov");
54
55 return fd;
56 }
57
58 ATF_TC_WITHOUT_HEAD(kcov_bufsize);
59 ATF_TC_BODY(kcov_bufsize, tc)
60 {
61 int fd;
62 kcov_int_t size;
63 fd = open_kcov();
64
65 size = 0;
66 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == -1);
67 size = 2;
68 ATF_CHECK(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
69
70 close(fd);
71 }
72
73 ATF_TC_WITHOUT_HEAD(kcov_mmap);
74 ATF_TC_BODY(kcov_mmap, tc)
75 {
76 void *data;
77 int fd;
78 kcov_int_t size = 2 * PAGE_SIZE / KCOV_ENTRY_SIZE;
79
80 fd = open_kcov();
81
82 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
83 fd, 0) == MAP_FAILED);
84
85 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0);
86
87 ATF_REQUIRE((data = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
88 MAP_SHARED, fd, 0)) != MAP_FAILED);
89
90 munmap(data, 2 * PAGE_SIZE);
91
92 close(fd);
93 }
94
95 /* This shouldn't panic */
96 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap);
97 ATF_TC_BODY(kcov_mmap_no_munmap, tc)
98 {
99 int fd;
100 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
101
102 fd = open_kcov();
103
104 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
105
106 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
107 fd, 0) != MAP_FAILED);
108
109 close(fd);
110 }
111
112 ATF_TC_WITHOUT_HEAD(kcov_mmap_no_munmap_no_close);
113 ATF_TC_BODY(kcov_mmap_no_munmap_no_close, tc)
114 {
115 int fd;
116 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
117
118 fd = open_kcov();
119
120 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
121
122 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
123 fd, 0) != MAP_FAILED);
124 }
125
126 static sem_t sem1, sem2;
127
128 static void *
129 kcov_mmap_enable_thread(void *data)
130 {
131 int fd;
132 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
133
134 fd = open_kcov();
135 *(int *)data = fd;
136
137 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
138 ATF_CHECK(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
139 fd, 0) != MAP_FAILED);
140 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
141
142 sem_post(&sem1);
143 sem_wait(&sem2);
144
145 return NULL;
146 }
147
148 ATF_TC_WITHOUT_HEAD(kcov_mmap_enable_thread_close);
149 ATF_TC_BODY(kcov_mmap_enable_thread_close, tc)
150 {
151 pthread_t thread;
152 int fd;
153
154 sem_init(&sem1, 0, 0);
155 sem_init(&sem2, 0, 0);
156 pthread_create(&thread, NULL,
157 kcov_mmap_enable_thread, &fd);
158 sem_wait(&sem1);
159 close(fd);
160 sem_post(&sem2);
161 pthread_join(thread, NULL);
162 }
163
164 ATF_TC_WITHOUT_HEAD(kcov_enable);
165 ATF_TC_BODY(kcov_enable, tc)
166 {
167 int fd;
168 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
169
170 fd = open_kcov();
171
172 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
173
174 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
175
176 /* We need to enable before disable */
177 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
178
179 /* Check enabling works only with a valid trace method */
180 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
181 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == -1);
182
183 /* Disable should only be called once */
184 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
185 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == -1);
186
187 /* Re-enabling should also work */
188 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
189 ATF_CHECK(ioctl(fd, KCOV_IOC_DISABLE) == 0);
190
191 close(fd);
192 }
193
194 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable);
195 ATF_TC_BODY(kcov_enable_no_disable, tc)
196 {
197 int fd;
198 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
199
200 fd = open_kcov();
201 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
202 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
203 close(fd);
204 }
205
206 ATF_TC_WITHOUT_HEAD(kcov_enable_no_disable_no_close);
207 ATF_TC_BODY(kcov_enable_no_disable_no_close, tc)
208 {
209 int fd;
210 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
211
212 fd = open_kcov();
213 ATF_REQUIRE(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) ==0);
214 ATF_CHECK(ioctl(fd, KCOV_IOC_ENABLE) == 0);
215 }
216
217 static void *
218 common_head(int *fdp)
219 {
220 void *data;
221 int fd;
222 kcov_int_t size = PAGE_SIZE / KCOV_ENTRY_SIZE;
223
224 fd = open_kcov();
225
226 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_SETBUFSIZE, &size) == 0,
227 "Unable to set the kcov buffer size");
228
229 data = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
230 ATF_REQUIRE_MSG(data != MAP_FAILED, "Unable to mmap the kcov buffer");
231
232 *fdp = fd;
233 return data;
234 }
235
236 static void
237 common_tail(int fd, kcov_int_t *data)
238 {
239
240 ATF_REQUIRE_MSG(munmap(__UNVOLATILE(data), PAGE_SIZE) == 0,
241 "Unable to unmap the kcov buffer");
242
243 close(fd);
244 }
245
246 ATF_TC_WITHOUT_HEAD(kcov_basic);
247 ATF_TC_BODY(kcov_basic, tc)
248 {
249 kcov_int_t *buf;
250 int fd;
251
252 buf = common_head(&fd);
253 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
254 "Unable to enable kcov ");
255
256 KCOV_STORE(buf[0], 0);
257
258 sleep(0);
259 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) != 0, "No records found");
260
261 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
262 "Unable to disable kcov");
263
264 common_tail(fd, buf);
265 }
266
267 static void *
268 thread_test_helper(void *ptr)
269 {
270 kcov_int_t *buf = ptr;
271
272 KCOV_STORE(buf[0], 0);
273 sleep(0);
274 ATF_REQUIRE_MSG(KCOV_LOAD(buf[0]) == 0,
275 "Records changed in blocked thread");
276
277 return NULL;
278 }
279
280 ATF_TC_WITHOUT_HEAD(kcov_thread);
281 ATF_TC_BODY(kcov_thread, tc)
282 {
283 pthread_t thread;
284 kcov_int_t *buf;
285 int fd;
286
287 buf = common_head(&fd);
288
289 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_ENABLE) == 0,
290 "Unable to enable kcov ");
291
292 pthread_create(&thread, NULL, thread_test_helper, __UNVOLATILE(buf));
293 pthread_join(thread, NULL);
294
295 ATF_REQUIRE_MSG(ioctl(fd, KCOV_IOC_DISABLE) == 0,
296 "Unable to disable kcov");
297
298 common_tail(fd, buf);
299 }
300
301 ATF_TP_ADD_TCS(tp)
302 {
303
304 ATF_TP_ADD_TC(tp, kcov_bufsize);
305 ATF_TP_ADD_TC(tp, kcov_mmap);
306 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap);
307 ATF_TP_ADD_TC(tp, kcov_mmap_no_munmap_no_close);
308 ATF_TP_ADD_TC(tp, kcov_enable);
309 ATF_TP_ADD_TC(tp, kcov_enable_no_disable);
310 ATF_TP_ADD_TC(tp, kcov_enable_no_disable_no_close);
311 ATF_TP_ADD_TC(tp, kcov_mmap_enable_thread_close);
312 ATF_TP_ADD_TC(tp, kcov_basic);
313 ATF_TP_ADD_TC(tp, kcov_thread);
314 return atf_no_error();
315 }
316