]> git.saurik.com Git - apple/xnu.git/blob - san/ksancov.h
xnu-6153.121.1.tar.gz
[apple/xnu.git] / san / ksancov.h
1 /*
2 * Copyright (c) 2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #ifndef _KSANCOV_H_
30 #define _KSANCOV_H_
31
32 #include <stdint.h>
33 #include <stdatomic.h>
34 #include <sys/ioccom.h>
35
36 #define KSANCOV_DEVNODE "ksancov"
37 #define KSANCOV_PATH "/dev/" KSANCOV_DEVNODE
38
39 /*
40 * ioctl
41 */
42
43 struct ksancov_buf_desc {
44 uintptr_t ptr; /* ptr to shared buffer [out] */
45 size_t sz; /* size of shared buffer [out] */
46 };
47
48 /* Set mode */
49 #define KSANCOV_IOC_TRACE _IOW('K', 1, size_t) /* number of pcs */
50 #define KSANCOV_IOC_COUNTERS _IO('K', 2)
51
52 /* Establish a shared mapping of the coverage buffer. */
53 #define KSANCOV_IOC_MAP _IOWR('K', 8, struct ksancov_buf_desc)
54
55 /* Establish a shared mapping of the edge address buffer. */
56 #define KSANCOV_IOC_MAP_EDGEMAP _IOWR('K', 9, struct ksancov_buf_desc)
57
58 /* Log the current thread */
59 #define KSANCOV_IOC_START _IOW('K', 10, uintptr_t)
60
61 #define KSANCOV_IOC_NEDGES _IOR('K', 50, size_t)
62
63 #define KSANCOV_IOC_TESTPANIC _IOW('K', 20, uint64_t)
64
65
66 /*
67 * shared kernel-user mapping
68 */
69
70 #define KSANCOV_MAX_EDGES 512UL*1024
71 #define KSANCOV_MAX_HITS UINT8_MAX
72 #define KSANCOV_TRACE_MAGIC (uint32_t)0x5AD17F5BU
73 #define KSANCOV_COUNTERS_MAGIC (uint32_t)0x5AD27F6BU
74 #define KSANCOV_EDGEMAP_MAGIC (uint32_t)0x5AD37F7BU
75
76 struct ksancov_header {
77 uint32_t magic;
78 _Atomic uint32_t enabled;
79 };
80
81 struct ksancov_trace {
82 /* userspace R/O fields */
83 union {
84 struct ksancov_header hdr;
85 struct {
86 uint32_t magic;
87 _Atomic uint32_t enabled;
88 };
89 };
90
91 uintptr_t offset; /* pc entries relative to this */
92 uint32_t maxpcs;
93 _Atomic uint32_t head;
94 uint32_t pcs[];
95 };
96
97 struct ksancov_counters {
98 union {
99 struct ksancov_header hdr;
100 struct {
101 uint32_t magic;
102 _Atomic uint32_t enabled;
103 };
104 };
105
106 uint32_t nedges; /* total number of edges */
107 uint8_t hits[]; /* hits on each edge (8bit saturating) */
108 };
109
110 struct ksancov_edgemap {
111 uint32_t magic;
112 uint32_t nedges;
113 uintptr_t offset; /* edge addrs relative to this */
114 uint32_t addrs[]; /* address of each edge relative to 'offset' */
115 };
116
117 #if XNU_KERNEL_PRIVATE
118 int ksancov_init_dev(void);
119 void **__sanitizer_get_thread_data(thread_t);
120
121 /*
122 * SanitizerCoverage ABI
123 */
124 extern void __sanitizer_cov_trace_pc_guard(uint32_t *guard);
125 extern void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop);
126 extern void __sanitizer_cov_pcs_init(uintptr_t *start, uintptr_t *stop);
127 extern void __sanitizer_cov_trace_pc(void);
128 extern void __sanitizer_cov_trace_pc_indirect(void *callee);
129 #endif
130
131 #ifndef KERNEL
132
133 #include <strings.h>
134 #include <assert.h>
135 #include <unistd.h>
136
137 /*
138 * ksancov userspace API
139 *
140 * Usage:
141 * 1) open the ksancov device
142 * 2) set the coverage mode (trace or edge counters)
143 * 3) map the coverage buffer
144 * 4) start the trace on a thread
145 * 5) flip the enable bit
146 */
147
148 static inline int
149 ksancov_open(void)
150 {
151 return open(KSANCOV_PATH, 0);
152 }
153
154 static inline int
155 ksancov_map(int fd, uintptr_t *buf, size_t *sz)
156 {
157 int ret;
158 struct ksancov_buf_desc mc = {0};
159
160 ret = ioctl(fd, KSANCOV_IOC_MAP, &mc);
161 if (ret == -1) {
162 return errno;
163 }
164
165 *buf = mc.ptr;
166 if (sz) {
167 *sz = mc.sz;
168 }
169
170 struct ksancov_trace *trace = (void *)mc.ptr;
171 assert(trace->magic == KSANCOV_TRACE_MAGIC ||
172 trace->magic == KSANCOV_COUNTERS_MAGIC);
173
174 return 0;
175 }
176
177 static inline int
178 ksancov_map_edgemap(int fd, uintptr_t *buf, size_t *sz)
179 {
180 int ret;
181 struct ksancov_buf_desc mc = {0};
182
183 ret = ioctl(fd, KSANCOV_IOC_MAP_EDGEMAP, &mc);
184 if (ret == -1) {
185 return errno;
186 }
187
188 *buf = mc.ptr;
189 if (sz) {
190 *sz = mc.sz;
191 }
192
193 struct ksancov_trace *trace = (void *)mc.ptr;
194 assert(trace->magic == KSANCOV_EDGEMAP_MAGIC);
195
196 return 0;
197 }
198
199 static inline size_t
200 ksancov_nedges(int fd)
201 {
202 size_t nedges;
203 int ret = ioctl(fd, KSANCOV_IOC_NEDGES, &nedges);
204 if (ret == -1) {
205 return SIZE_MAX;
206 }
207 return nedges;
208 }
209
210 static inline int
211 ksancov_mode_trace(int fd, size_t entries)
212 {
213 int ret;
214 ret = ioctl(fd, KSANCOV_IOC_TRACE, &entries);
215 if (ret == -1) {
216 return errno;
217 }
218 return 0;
219 }
220
221 static inline int
222 ksancov_mode_counters(int fd)
223 {
224 int ret;
225 ret = ioctl(fd, KSANCOV_IOC_COUNTERS);
226 if (ret == -1) {
227 return errno;
228 }
229 return 0;
230 }
231
232 static inline int
233 ksancov_thread_self(int fd)
234 {
235 int ret;
236 uintptr_t th = 0;
237 ret = ioctl(fd, KSANCOV_IOC_START, &th);
238 if (ret == -1) {
239 return errno;
240 }
241 return 0;
242 }
243
244 static inline int
245 ksancov_start(void *buf)
246 {
247 struct ksancov_header *hdr = (struct ksancov_header *)buf;
248 atomic_store_explicit(&hdr->enabled, 1, memory_order_relaxed);
249 return 0;
250 }
251
252 static inline int
253 ksancov_stop(void *buf)
254 {
255 struct ksancov_header *hdr = (struct ksancov_header *)buf;
256 atomic_store_explicit(&hdr->enabled, 0, memory_order_relaxed);
257 return 0;
258 }
259
260 static inline int
261 ksancov_reset(void *buf)
262 {
263 struct ksancov_header *hdr = (struct ksancov_header *)buf;
264 if (hdr->magic == KSANCOV_TRACE_MAGIC) {
265 struct ksancov_trace *trace = (struct ksancov_trace *)buf;
266 atomic_store_explicit(&trace->head, 0, memory_order_relaxed);
267 } else if (hdr->magic == KSANCOV_COUNTERS_MAGIC) {
268 struct ksancov_counters *counters = (struct ksancov_counters *)buf;
269 bzero(counters->hits, counters->nedges);
270 } else {
271 return EINVAL;
272 }
273 return 0;
274 }
275
276 static inline uintptr_t
277 ksancov_edge_addr(struct ksancov_edgemap *addrs, size_t idx)
278 {
279 assert(addrs);
280 if (idx >= addrs->nedges) {
281 return 0;
282 }
283 return addrs->addrs[idx] + addrs->offset;
284 }
285
286 static inline size_t
287 ksancov_trace_max_pcs(struct ksancov_trace *trace)
288 {
289 return trace->maxpcs;
290 }
291
292 static inline uintptr_t
293 ksancov_trace_offset(struct ksancov_trace *trace)
294 {
295 assert(trace);
296 return trace->offset;
297 }
298
299 static inline size_t
300 ksancov_trace_head(struct ksancov_trace *trace)
301 {
302 size_t maxlen = trace->maxpcs;
303 size_t head = atomic_load_explicit(&trace->head, memory_order_acquire);
304 return head < maxlen ? head : maxlen;
305 }
306
307 static inline uintptr_t
308 ksancov_trace_entry(struct ksancov_trace *trace, size_t i)
309 {
310 if (i >= trace->head) {
311 return 0;
312 }
313
314 return trace->pcs[i] + trace->offset;
315 }
316
317 #endif
318
319 #endif /* _KSANCOV_H_ */