xref: /freebsd/sys/kern/subr_coverage.c (revision 3ead6023)
1524553f5SAndrew Turner /*-
2524553f5SAndrew Turner  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3524553f5SAndrew Turner  *
4524553f5SAndrew Turner  * Copyright (C) 2018 The FreeBSD Foundation. All rights reserved.
5524553f5SAndrew Turner  * Copyright (C) 2018, 2019 Andrew Turner
6524553f5SAndrew Turner  *
7524553f5SAndrew Turner  * This software was developed by Mitchell Horne under sponsorship of
8524553f5SAndrew Turner  * the FreeBSD Foundation.
9524553f5SAndrew Turner  *
10524553f5SAndrew Turner  * This software was developed by SRI International and the University of
11524553f5SAndrew Turner  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
12524553f5SAndrew Turner  * ("CTSRD"), as part of the DARPA CRASH research programme.
13524553f5SAndrew Turner  *
14524553f5SAndrew Turner  * Redistribution and use in source and binary forms, with or without
15524553f5SAndrew Turner  * modification, are permitted provided that the following conditions
16524553f5SAndrew Turner  * are met:
17524553f5SAndrew Turner  * 1. Redistributions of source code must retain the above copyright
18524553f5SAndrew Turner  *    notice, this list of conditions and the following disclaimer.
19524553f5SAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
20524553f5SAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
21524553f5SAndrew Turner  *    documentation and/or other materials provided with the distribution.
22524553f5SAndrew Turner  *
23524553f5SAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24524553f5SAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25524553f5SAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26524553f5SAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27524553f5SAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28524553f5SAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29524553f5SAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30524553f5SAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31524553f5SAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32524553f5SAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33524553f5SAndrew Turner  * SUCH DAMAGE.
34524553f5SAndrew Turner  *
35524553f5SAndrew Turner  * $FreeBSD$
36524553f5SAndrew Turner  */
37524553f5SAndrew Turner 
383ead6023SMark Johnston #ifdef KCSAN
393ead6023SMark Johnston #define	SAN_RUNTIME
403ead6023SMark Johnston #endif
41fd8f4f3bSAndrew Turner 
42524553f5SAndrew Turner #include <sys/cdefs.h>
43524553f5SAndrew Turner __FBSDID("$FreeBSD$");
44524553f5SAndrew Turner 
45524553f5SAndrew Turner #include <sys/param.h>
46524553f5SAndrew Turner #include <sys/coverage.h>
47524553f5SAndrew Turner 
48524553f5SAndrew Turner #include <machine/atomic.h>
49524553f5SAndrew Turner 
50524553f5SAndrew Turner void __sanitizer_cov_trace_pc(void);
51524553f5SAndrew Turner void __sanitizer_cov_trace_cmp1(uint8_t, uint8_t);
52524553f5SAndrew Turner void __sanitizer_cov_trace_cmp2(uint16_t, uint16_t);
53524553f5SAndrew Turner void __sanitizer_cov_trace_cmp4(uint32_t, uint32_t);
54524553f5SAndrew Turner void __sanitizer_cov_trace_cmp8(uint64_t, uint64_t);
55524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp1(uint8_t, uint8_t);
56524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp2(uint16_t, uint16_t);
57524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp4(uint32_t, uint32_t);
58524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp8(uint64_t, uint64_t);
59524553f5SAndrew Turner void __sanitizer_cov_trace_switch(uint64_t, uint64_t *);
60524553f5SAndrew Turner 
61524553f5SAndrew Turner static cov_trace_pc_t cov_trace_pc;
62524553f5SAndrew Turner static cov_trace_cmp_t cov_trace_cmp;
63524553f5SAndrew Turner 
64524553f5SAndrew Turner void
65524553f5SAndrew Turner cov_register_pc(cov_trace_pc_t trace_pc)
66524553f5SAndrew Turner {
67524553f5SAndrew Turner 
68524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, trace_pc);
69524553f5SAndrew Turner }
70524553f5SAndrew Turner 
71524553f5SAndrew Turner void
72524553f5SAndrew Turner cov_unregister_pc(void)
73524553f5SAndrew Turner {
74524553f5SAndrew Turner 
75524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, NULL);
76524553f5SAndrew Turner }
77524553f5SAndrew Turner 
78524553f5SAndrew Turner void
79524553f5SAndrew Turner cov_register_cmp(cov_trace_cmp_t trace_cmp)
80524553f5SAndrew Turner {
81524553f5SAndrew Turner 
82524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, trace_cmp);
83524553f5SAndrew Turner }
84524553f5SAndrew Turner 
85524553f5SAndrew Turner void
86524553f5SAndrew Turner cov_unregister_cmp(void)
87524553f5SAndrew Turner {
88524553f5SAndrew Turner 
89524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, NULL);
90524553f5SAndrew Turner }
91524553f5SAndrew Turner 
92524553f5SAndrew Turner /*
93524553f5SAndrew Turner  * Main entry point. A call to this function will be inserted
94524553f5SAndrew Turner  * at every edge, and if coverage is enabled for the thread
95524553f5SAndrew Turner  * this function will add the PC to the buffer.
96524553f5SAndrew Turner  */
97524553f5SAndrew Turner void
98524553f5SAndrew Turner __sanitizer_cov_trace_pc(void)
99524553f5SAndrew Turner {
100524553f5SAndrew Turner 	cov_trace_pc_t trace_pc;
101524553f5SAndrew Turner 
1025bc6a91fSMateusz Guzik 	trace_pc = atomic_load_ptr(&cov_trace_pc);
103524553f5SAndrew Turner 	if (trace_pc != NULL)
104524553f5SAndrew Turner 		trace_pc((uint64_t)__builtin_return_address(0));
105524553f5SAndrew Turner }
106524553f5SAndrew Turner 
107524553f5SAndrew Turner /*
108524553f5SAndrew Turner  * Comparison entry points. When the kernel performs a comparison
109524553f5SAndrew Turner  * operation the compiler inserts a call to one of the following
110524553f5SAndrew Turner  * functions to record the operation.
111524553f5SAndrew Turner  */
112524553f5SAndrew Turner void
113524553f5SAndrew Turner __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
114524553f5SAndrew Turner {
115524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
116524553f5SAndrew Turner 
1175bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
118524553f5SAndrew Turner 	if (trace_cmp != NULL)
119524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0), arg1, arg2,
120524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
121524553f5SAndrew Turner }
122524553f5SAndrew Turner 
123524553f5SAndrew Turner void
124524553f5SAndrew Turner __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
125524553f5SAndrew Turner {
126524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
127524553f5SAndrew Turner 
1285bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
129524553f5SAndrew Turner 	if (trace_cmp != NULL)
130524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1), arg1, arg2,
131524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
132524553f5SAndrew Turner }
133524553f5SAndrew Turner 
134524553f5SAndrew Turner void
135524553f5SAndrew Turner __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
136524553f5SAndrew Turner {
137524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
138524553f5SAndrew Turner 
1395bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
140524553f5SAndrew Turner 	if (trace_cmp != NULL)
141524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2), arg1, arg2,
142524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
143524553f5SAndrew Turner }
144524553f5SAndrew Turner 
145524553f5SAndrew Turner void
146524553f5SAndrew Turner __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
147524553f5SAndrew Turner {
148524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
149524553f5SAndrew Turner 
1505bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
151524553f5SAndrew Turner 	if (trace_cmp != NULL)
152524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3), arg1, arg2,
153524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
154524553f5SAndrew Turner }
155524553f5SAndrew Turner 
156524553f5SAndrew Turner void
157524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
158524553f5SAndrew Turner {
159524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
160524553f5SAndrew Turner 
1615bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
162524553f5SAndrew Turner 	if (trace_cmp != NULL)
163524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0) | COV_CMP_CONST, arg1, arg2,
164524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
165524553f5SAndrew Turner }
166524553f5SAndrew Turner 
167524553f5SAndrew Turner void
168524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
169524553f5SAndrew Turner {
170524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
171524553f5SAndrew Turner 
1725bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
173524553f5SAndrew Turner 	if (trace_cmp != NULL)
174524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1) | COV_CMP_CONST, arg1, arg2,
175524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
176524553f5SAndrew Turner }
177524553f5SAndrew Turner 
178524553f5SAndrew Turner void
179524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
180524553f5SAndrew Turner {
181524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
182524553f5SAndrew Turner 
1835bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
184524553f5SAndrew Turner 	if (trace_cmp != NULL)
185524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2) | COV_CMP_CONST, arg1, arg2,
186524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
187524553f5SAndrew Turner }
188524553f5SAndrew Turner 
189524553f5SAndrew Turner void
190524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
191524553f5SAndrew Turner {
192524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
193524553f5SAndrew Turner 
1945bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
195524553f5SAndrew Turner 	if (trace_cmp != NULL)
196524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3) | COV_CMP_CONST, arg1, arg2,
197524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
198524553f5SAndrew Turner }
199524553f5SAndrew Turner 
200524553f5SAndrew Turner /*
201524553f5SAndrew Turner  * val is the switch operand
202524553f5SAndrew Turner  * cases[0] is the number of case constants
203524553f5SAndrew Turner  * cases[1] is the size of val in bits
204524553f5SAndrew Turner  * cases[2..n] are the case constants
205524553f5SAndrew Turner  */
206524553f5SAndrew Turner void
207524553f5SAndrew Turner __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases)
208524553f5SAndrew Turner {
209524553f5SAndrew Turner 	uint64_t i, count, ret, type;
210524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
211524553f5SAndrew Turner 
2125bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
213524553f5SAndrew Turner 	if (trace_cmp == NULL)
214524553f5SAndrew Turner 		return;
215524553f5SAndrew Turner 
216524553f5SAndrew Turner 	count = cases[0];
217524553f5SAndrew Turner 	ret = (uint64_t)__builtin_return_address(0);
218524553f5SAndrew Turner 
219524553f5SAndrew Turner 	switch (cases[1]) {
220524553f5SAndrew Turner 	case 8:
221524553f5SAndrew Turner 		type = COV_CMP_SIZE(0);
222524553f5SAndrew Turner 		break;
223524553f5SAndrew Turner 	case 16:
224524553f5SAndrew Turner 		type = COV_CMP_SIZE(1);
225524553f5SAndrew Turner 		break;
226524553f5SAndrew Turner 	case 32:
227524553f5SAndrew Turner 		type = COV_CMP_SIZE(2);
228524553f5SAndrew Turner 		break;
229524553f5SAndrew Turner 	case 64:
230524553f5SAndrew Turner 		type = COV_CMP_SIZE(3);
231524553f5SAndrew Turner 		break;
232524553f5SAndrew Turner 	default:
233524553f5SAndrew Turner 		return;
234524553f5SAndrew Turner 	}
235524553f5SAndrew Turner 
236524553f5SAndrew Turner 	val |= COV_CMP_CONST;
237524553f5SAndrew Turner 
238524553f5SAndrew Turner 	for (i = 0; i < count; i++)
239524553f5SAndrew Turner 		if (!trace_cmp(type, val, cases[i + 2], ret))
240524553f5SAndrew Turner 			return;
241524553f5SAndrew Turner }
242