xref: /freebsd/sys/kern/subr_coverage.c (revision 524553f56d0b89c689754f1e0a51205bbbcf5071)
1*524553f5SAndrew Turner /*-
2*524553f5SAndrew Turner  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*524553f5SAndrew Turner  *
4*524553f5SAndrew Turner  * Copyright (C) 2018 The FreeBSD Foundation. All rights reserved.
5*524553f5SAndrew Turner  * Copyright (C) 2018, 2019 Andrew Turner
6*524553f5SAndrew Turner  *
7*524553f5SAndrew Turner  * This software was developed by Mitchell Horne under sponsorship of
8*524553f5SAndrew Turner  * the FreeBSD Foundation.
9*524553f5SAndrew Turner  *
10*524553f5SAndrew Turner  * This software was developed by SRI International and the University of
11*524553f5SAndrew Turner  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
12*524553f5SAndrew Turner  * ("CTSRD"), as part of the DARPA CRASH research programme.
13*524553f5SAndrew Turner  *
14*524553f5SAndrew Turner  * Redistribution and use in source and binary forms, with or without
15*524553f5SAndrew Turner  * modification, are permitted provided that the following conditions
16*524553f5SAndrew Turner  * are met:
17*524553f5SAndrew Turner  * 1. Redistributions of source code must retain the above copyright
18*524553f5SAndrew Turner  *    notice, this list of conditions and the following disclaimer.
19*524553f5SAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
20*524553f5SAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
21*524553f5SAndrew Turner  *    documentation and/or other materials provided with the distribution.
22*524553f5SAndrew Turner  *
23*524553f5SAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24*524553f5SAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*524553f5SAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*524553f5SAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27*524553f5SAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*524553f5SAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*524553f5SAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*524553f5SAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*524553f5SAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*524553f5SAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*524553f5SAndrew Turner  * SUCH DAMAGE.
34*524553f5SAndrew Turner  *
35*524553f5SAndrew Turner  * $FreeBSD$
36*524553f5SAndrew Turner  */
37*524553f5SAndrew Turner 
38*524553f5SAndrew Turner #include <sys/cdefs.h>
39*524553f5SAndrew Turner __FBSDID("$FreeBSD$");
40*524553f5SAndrew Turner 
41*524553f5SAndrew Turner #include <sys/param.h>
42*524553f5SAndrew Turner #include <sys/coverage.h>
43*524553f5SAndrew Turner 
44*524553f5SAndrew Turner #include <machine/atomic.h>
45*524553f5SAndrew Turner 
46*524553f5SAndrew Turner void __sanitizer_cov_trace_pc(void);
47*524553f5SAndrew Turner void __sanitizer_cov_trace_cmp1(uint8_t, uint8_t);
48*524553f5SAndrew Turner void __sanitizer_cov_trace_cmp2(uint16_t, uint16_t);
49*524553f5SAndrew Turner void __sanitizer_cov_trace_cmp4(uint32_t, uint32_t);
50*524553f5SAndrew Turner void __sanitizer_cov_trace_cmp8(uint64_t, uint64_t);
51*524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp1(uint8_t, uint8_t);
52*524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp2(uint16_t, uint16_t);
53*524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp4(uint32_t, uint32_t);
54*524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp8(uint64_t, uint64_t);
55*524553f5SAndrew Turner void __sanitizer_cov_trace_switch(uint64_t, uint64_t *);
56*524553f5SAndrew Turner 
57*524553f5SAndrew Turner static cov_trace_pc_t cov_trace_pc;
58*524553f5SAndrew Turner static cov_trace_cmp_t cov_trace_cmp;
59*524553f5SAndrew Turner 
60*524553f5SAndrew Turner void
61*524553f5SAndrew Turner cov_register_pc(cov_trace_pc_t trace_pc)
62*524553f5SAndrew Turner {
63*524553f5SAndrew Turner 
64*524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, trace_pc);
65*524553f5SAndrew Turner }
66*524553f5SAndrew Turner 
67*524553f5SAndrew Turner void
68*524553f5SAndrew Turner cov_unregister_pc(void)
69*524553f5SAndrew Turner {
70*524553f5SAndrew Turner 
71*524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, NULL);
72*524553f5SAndrew Turner }
73*524553f5SAndrew Turner 
74*524553f5SAndrew Turner void
75*524553f5SAndrew Turner cov_register_cmp(cov_trace_cmp_t trace_cmp)
76*524553f5SAndrew Turner {
77*524553f5SAndrew Turner 
78*524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, trace_cmp);
79*524553f5SAndrew Turner }
80*524553f5SAndrew Turner 
81*524553f5SAndrew Turner void
82*524553f5SAndrew Turner cov_unregister_cmp(void)
83*524553f5SAndrew Turner {
84*524553f5SAndrew Turner 
85*524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, NULL);
86*524553f5SAndrew Turner }
87*524553f5SAndrew Turner 
88*524553f5SAndrew Turner /*
89*524553f5SAndrew Turner  * Main entry point. A call to this function will be inserted
90*524553f5SAndrew Turner  * at every edge, and if coverage is enabled for the thread
91*524553f5SAndrew Turner  * this function will add the PC to the buffer.
92*524553f5SAndrew Turner  */
93*524553f5SAndrew Turner void
94*524553f5SAndrew Turner __sanitizer_cov_trace_pc(void)
95*524553f5SAndrew Turner {
96*524553f5SAndrew Turner 	cov_trace_pc_t trace_pc;
97*524553f5SAndrew Turner 
98*524553f5SAndrew Turner 	trace_pc = (cov_trace_pc_t)atomic_load_ptr(&cov_trace_pc);
99*524553f5SAndrew Turner 	if (trace_pc != NULL)
100*524553f5SAndrew Turner 		trace_pc((uint64_t)__builtin_return_address(0));
101*524553f5SAndrew Turner }
102*524553f5SAndrew Turner 
103*524553f5SAndrew Turner /*
104*524553f5SAndrew Turner  * Comparison entry points. When the kernel performs a comparison
105*524553f5SAndrew Turner  * operation the compiler inserts a call to one of the following
106*524553f5SAndrew Turner  * functions to record the operation.
107*524553f5SAndrew Turner  */
108*524553f5SAndrew Turner void
109*524553f5SAndrew Turner __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
110*524553f5SAndrew Turner {
111*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
112*524553f5SAndrew Turner 
113*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
114*524553f5SAndrew Turner 	if (trace_cmp != NULL)
115*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0), arg1, arg2,
116*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
117*524553f5SAndrew Turner }
118*524553f5SAndrew Turner 
119*524553f5SAndrew Turner void
120*524553f5SAndrew Turner __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
121*524553f5SAndrew Turner {
122*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
123*524553f5SAndrew Turner 
124*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
125*524553f5SAndrew Turner 	if (trace_cmp != NULL)
126*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1), arg1, arg2,
127*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
128*524553f5SAndrew Turner }
129*524553f5SAndrew Turner 
130*524553f5SAndrew Turner void
131*524553f5SAndrew Turner __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
132*524553f5SAndrew Turner {
133*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
134*524553f5SAndrew Turner 
135*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
136*524553f5SAndrew Turner 	if (trace_cmp != NULL)
137*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2), arg1, arg2,
138*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
139*524553f5SAndrew Turner }
140*524553f5SAndrew Turner 
141*524553f5SAndrew Turner void
142*524553f5SAndrew Turner __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
143*524553f5SAndrew Turner {
144*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
145*524553f5SAndrew Turner 
146*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
147*524553f5SAndrew Turner 	if (trace_cmp != NULL)
148*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3), arg1, arg2,
149*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
150*524553f5SAndrew Turner }
151*524553f5SAndrew Turner 
152*524553f5SAndrew Turner void
153*524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
154*524553f5SAndrew Turner {
155*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
156*524553f5SAndrew Turner 
157*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
158*524553f5SAndrew Turner 	if (trace_cmp != NULL)
159*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0) | COV_CMP_CONST, arg1, arg2,
160*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
161*524553f5SAndrew Turner }
162*524553f5SAndrew Turner 
163*524553f5SAndrew Turner void
164*524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
165*524553f5SAndrew Turner {
166*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
167*524553f5SAndrew Turner 
168*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
169*524553f5SAndrew Turner 	if (trace_cmp != NULL)
170*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1) | COV_CMP_CONST, arg1, arg2,
171*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
172*524553f5SAndrew Turner }
173*524553f5SAndrew Turner 
174*524553f5SAndrew Turner void
175*524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
176*524553f5SAndrew Turner {
177*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
178*524553f5SAndrew Turner 
179*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
180*524553f5SAndrew Turner 	if (trace_cmp != NULL)
181*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2) | COV_CMP_CONST, arg1, arg2,
182*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
183*524553f5SAndrew Turner }
184*524553f5SAndrew Turner 
185*524553f5SAndrew Turner void
186*524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
187*524553f5SAndrew Turner {
188*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
189*524553f5SAndrew Turner 
190*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
191*524553f5SAndrew Turner 	if (trace_cmp != NULL)
192*524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3) | COV_CMP_CONST, arg1, arg2,
193*524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
194*524553f5SAndrew Turner }
195*524553f5SAndrew Turner 
196*524553f5SAndrew Turner /*
197*524553f5SAndrew Turner  * val is the switch operand
198*524553f5SAndrew Turner  * cases[0] is the number of case constants
199*524553f5SAndrew Turner  * cases[1] is the size of val in bits
200*524553f5SAndrew Turner  * cases[2..n] are the case constants
201*524553f5SAndrew Turner  */
202*524553f5SAndrew Turner void
203*524553f5SAndrew Turner __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases)
204*524553f5SAndrew Turner {
205*524553f5SAndrew Turner 	uint64_t i, count, ret, type;
206*524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
207*524553f5SAndrew Turner 
208*524553f5SAndrew Turner 	trace_cmp = (cov_trace_cmp_t)atomic_load_ptr(&cov_trace_cmp);
209*524553f5SAndrew Turner 	if (trace_cmp == NULL)
210*524553f5SAndrew Turner 		return;
211*524553f5SAndrew Turner 
212*524553f5SAndrew Turner 	count = cases[0];
213*524553f5SAndrew Turner 	ret = (uint64_t)__builtin_return_address(0);
214*524553f5SAndrew Turner 
215*524553f5SAndrew Turner 	switch (cases[1]) {
216*524553f5SAndrew Turner 	case 8:
217*524553f5SAndrew Turner 		type = COV_CMP_SIZE(0);
218*524553f5SAndrew Turner 		break;
219*524553f5SAndrew Turner 	case 16:
220*524553f5SAndrew Turner 		type = COV_CMP_SIZE(1);
221*524553f5SAndrew Turner 		break;
222*524553f5SAndrew Turner 	case 32:
223*524553f5SAndrew Turner 		type = COV_CMP_SIZE(2);
224*524553f5SAndrew Turner 		break;
225*524553f5SAndrew Turner 	case 64:
226*524553f5SAndrew Turner 		type = COV_CMP_SIZE(3);
227*524553f5SAndrew Turner 		break;
228*524553f5SAndrew Turner 	default:
229*524553f5SAndrew Turner 		return;
230*524553f5SAndrew Turner 	}
231*524553f5SAndrew Turner 
232*524553f5SAndrew Turner 	val |= COV_CMP_CONST;
233*524553f5SAndrew Turner 
234*524553f5SAndrew Turner 	for (i = 0; i < count; i++)
235*524553f5SAndrew Turner 		if (!trace_cmp(type, val, cases[i + 2], ret))
236*524553f5SAndrew Turner 			return;
237*524553f5SAndrew Turner }
238