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