xref: /freebsd/sys/kern/subr_coverage.c (revision fdafd315)
1524553f5SAndrew Turner /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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 
36cf4670feSMark Johnston #ifdef SAN_NEEDS_INTERCEPTORS
373ead6023SMark Johnston #define	SAN_RUNTIME
383ead6023SMark Johnston #endif
39fd8f4f3bSAndrew Turner 
40524553f5SAndrew Turner #include <sys/param.h>
41524553f5SAndrew Turner #include <sys/coverage.h>
42524553f5SAndrew Turner 
43524553f5SAndrew Turner #include <machine/atomic.h>
44524553f5SAndrew Turner 
45524553f5SAndrew Turner void __sanitizer_cov_trace_pc(void);
46524553f5SAndrew Turner void __sanitizer_cov_trace_cmp1(uint8_t, uint8_t);
47524553f5SAndrew Turner void __sanitizer_cov_trace_cmp2(uint16_t, uint16_t);
48524553f5SAndrew Turner void __sanitizer_cov_trace_cmp4(uint32_t, uint32_t);
49524553f5SAndrew Turner void __sanitizer_cov_trace_cmp8(uint64_t, uint64_t);
50524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp1(uint8_t, uint8_t);
51524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp2(uint16_t, uint16_t);
52524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp4(uint32_t, uint32_t);
53524553f5SAndrew Turner void __sanitizer_cov_trace_const_cmp8(uint64_t, uint64_t);
54524553f5SAndrew Turner void __sanitizer_cov_trace_switch(uint64_t, uint64_t *);
55524553f5SAndrew Turner 
56524553f5SAndrew Turner static cov_trace_pc_t cov_trace_pc;
57524553f5SAndrew Turner static cov_trace_cmp_t cov_trace_cmp;
58524553f5SAndrew Turner 
59524553f5SAndrew Turner void
cov_register_pc(cov_trace_pc_t trace_pc)60524553f5SAndrew Turner cov_register_pc(cov_trace_pc_t trace_pc)
61524553f5SAndrew Turner {
62524553f5SAndrew Turner 
63524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, trace_pc);
64524553f5SAndrew Turner }
65524553f5SAndrew Turner 
66524553f5SAndrew Turner void
cov_unregister_pc(void)67524553f5SAndrew Turner cov_unregister_pc(void)
68524553f5SAndrew Turner {
69524553f5SAndrew Turner 
70524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_pc, NULL);
71524553f5SAndrew Turner }
72524553f5SAndrew Turner 
73524553f5SAndrew Turner void
cov_register_cmp(cov_trace_cmp_t trace_cmp)74524553f5SAndrew Turner cov_register_cmp(cov_trace_cmp_t trace_cmp)
75524553f5SAndrew Turner {
76524553f5SAndrew Turner 
77524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, trace_cmp);
78524553f5SAndrew Turner }
79524553f5SAndrew Turner 
80524553f5SAndrew Turner void
cov_unregister_cmp(void)81524553f5SAndrew Turner cov_unregister_cmp(void)
82524553f5SAndrew Turner {
83524553f5SAndrew Turner 
84524553f5SAndrew Turner 	atomic_store_ptr(&cov_trace_cmp, NULL);
85524553f5SAndrew Turner }
86524553f5SAndrew Turner 
87524553f5SAndrew Turner /*
88524553f5SAndrew Turner  * Main entry point. A call to this function will be inserted
89524553f5SAndrew Turner  * at every edge, and if coverage is enabled for the thread
90524553f5SAndrew Turner  * this function will add the PC to the buffer.
91524553f5SAndrew Turner  */
92524553f5SAndrew Turner void
__sanitizer_cov_trace_pc(void)93524553f5SAndrew Turner __sanitizer_cov_trace_pc(void)
94524553f5SAndrew Turner {
95524553f5SAndrew Turner 	cov_trace_pc_t trace_pc;
96524553f5SAndrew Turner 
975bc6a91fSMateusz Guzik 	trace_pc = atomic_load_ptr(&cov_trace_pc);
98524553f5SAndrew Turner 	if (trace_pc != NULL)
99524553f5SAndrew Turner 		trace_pc((uint64_t)__builtin_return_address(0));
100524553f5SAndrew Turner }
101524553f5SAndrew Turner 
102524553f5SAndrew Turner /*
103524553f5SAndrew Turner  * Comparison entry points. When the kernel performs a comparison
104524553f5SAndrew Turner  * operation the compiler inserts a call to one of the following
105524553f5SAndrew Turner  * functions to record the operation.
106524553f5SAndrew Turner  */
107524553f5SAndrew Turner void
__sanitizer_cov_trace_cmp1(uint8_t arg1,uint8_t arg2)108524553f5SAndrew Turner __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2)
109524553f5SAndrew Turner {
110524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
111524553f5SAndrew Turner 
1125bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
113524553f5SAndrew Turner 	if (trace_cmp != NULL)
114524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0), arg1, arg2,
115524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
116524553f5SAndrew Turner }
117524553f5SAndrew Turner 
118524553f5SAndrew Turner void
__sanitizer_cov_trace_cmp2(uint16_t arg1,uint16_t arg2)119524553f5SAndrew Turner __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2)
120524553f5SAndrew Turner {
121524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
122524553f5SAndrew Turner 
1235bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
124524553f5SAndrew Turner 	if (trace_cmp != NULL)
125524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1), arg1, arg2,
126524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
127524553f5SAndrew Turner }
128524553f5SAndrew Turner 
129524553f5SAndrew Turner void
__sanitizer_cov_trace_cmp4(uint32_t arg1,uint32_t arg2)130524553f5SAndrew Turner __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2)
131524553f5SAndrew Turner {
132524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
133524553f5SAndrew Turner 
1345bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
135524553f5SAndrew Turner 	if (trace_cmp != NULL)
136524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2), arg1, arg2,
137524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
138524553f5SAndrew Turner }
139524553f5SAndrew Turner 
140524553f5SAndrew Turner void
__sanitizer_cov_trace_cmp8(uint64_t arg1,uint64_t arg2)141524553f5SAndrew Turner __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2)
142524553f5SAndrew Turner {
143524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
144524553f5SAndrew Turner 
1455bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
146524553f5SAndrew Turner 	if (trace_cmp != NULL)
147524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3), arg1, arg2,
148524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
149524553f5SAndrew Turner }
150524553f5SAndrew Turner 
151524553f5SAndrew Turner void
__sanitizer_cov_trace_const_cmp1(uint8_t arg1,uint8_t arg2)152524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2)
153524553f5SAndrew Turner {
154524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
155524553f5SAndrew Turner 
1565bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
157524553f5SAndrew Turner 	if (trace_cmp != NULL)
158524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(0) | COV_CMP_CONST, arg1, arg2,
159524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
160524553f5SAndrew Turner }
161524553f5SAndrew Turner 
162524553f5SAndrew Turner void
__sanitizer_cov_trace_const_cmp2(uint16_t arg1,uint16_t arg2)163524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
164524553f5SAndrew Turner {
165524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
166524553f5SAndrew Turner 
1675bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
168524553f5SAndrew Turner 	if (trace_cmp != NULL)
169524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(1) | COV_CMP_CONST, arg1, arg2,
170524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
171524553f5SAndrew Turner }
172524553f5SAndrew Turner 
173524553f5SAndrew Turner void
__sanitizer_cov_trace_const_cmp4(uint32_t arg1,uint32_t arg2)174524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
175524553f5SAndrew Turner {
176524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
177524553f5SAndrew Turner 
1785bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
179524553f5SAndrew Turner 	if (trace_cmp != NULL)
180524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(2) | COV_CMP_CONST, arg1, arg2,
181524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
182524553f5SAndrew Turner }
183524553f5SAndrew Turner 
184524553f5SAndrew Turner void
__sanitizer_cov_trace_const_cmp8(uint64_t arg1,uint64_t arg2)185524553f5SAndrew Turner __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
186524553f5SAndrew Turner {
187524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
188524553f5SAndrew Turner 
1895bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
190524553f5SAndrew Turner 	if (trace_cmp != NULL)
191524553f5SAndrew Turner 		trace_cmp(COV_CMP_SIZE(3) | COV_CMP_CONST, arg1, arg2,
192524553f5SAndrew Turner 		    (uint64_t)__builtin_return_address(0));
193524553f5SAndrew Turner }
194524553f5SAndrew Turner 
195524553f5SAndrew Turner /*
196524553f5SAndrew Turner  * val is the switch operand
197524553f5SAndrew Turner  * cases[0] is the number of case constants
198524553f5SAndrew Turner  * cases[1] is the size of val in bits
199524553f5SAndrew Turner  * cases[2..n] are the case constants
200524553f5SAndrew Turner  */
201524553f5SAndrew Turner void
__sanitizer_cov_trace_switch(uint64_t val,uint64_t * cases)202524553f5SAndrew Turner __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases)
203524553f5SAndrew Turner {
204524553f5SAndrew Turner 	uint64_t i, count, ret, type;
205524553f5SAndrew Turner 	cov_trace_cmp_t trace_cmp;
206524553f5SAndrew Turner 
2075bc6a91fSMateusz Guzik 	trace_cmp = atomic_load_ptr(&cov_trace_cmp);
208524553f5SAndrew Turner 	if (trace_cmp == NULL)
209524553f5SAndrew Turner 		return;
210524553f5SAndrew Turner 
211524553f5SAndrew Turner 	count = cases[0];
212524553f5SAndrew Turner 	ret = (uint64_t)__builtin_return_address(0);
213524553f5SAndrew Turner 
214524553f5SAndrew Turner 	switch (cases[1]) {
215524553f5SAndrew Turner 	case 8:
216524553f5SAndrew Turner 		type = COV_CMP_SIZE(0);
217524553f5SAndrew Turner 		break;
218524553f5SAndrew Turner 	case 16:
219524553f5SAndrew Turner 		type = COV_CMP_SIZE(1);
220524553f5SAndrew Turner 		break;
221524553f5SAndrew Turner 	case 32:
222524553f5SAndrew Turner 		type = COV_CMP_SIZE(2);
223524553f5SAndrew Turner 		break;
224524553f5SAndrew Turner 	case 64:
225524553f5SAndrew Turner 		type = COV_CMP_SIZE(3);
226524553f5SAndrew Turner 		break;
227524553f5SAndrew Turner 	default:
228524553f5SAndrew Turner 		return;
229524553f5SAndrew Turner 	}
230524553f5SAndrew Turner 
231524553f5SAndrew Turner 	val |= COV_CMP_CONST;
232524553f5SAndrew Turner 
233524553f5SAndrew Turner 	for (i = 0; i < count; i++)
234524553f5SAndrew Turner 		if (!trace_cmp(type, val, cases[i + 2], ret))
235524553f5SAndrew Turner 			return;
236524553f5SAndrew Turner }
237