xref: /xnu-12377.1.9/san/tools/ksancov.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1*f6217f89SApple OSS Distributions /*
2*f6217f89SApple OSS Distributions  * Copyright (c) 2019 Apple Inc. All rights reserved.
3*f6217f89SApple OSS Distributions  *
4*f6217f89SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*f6217f89SApple OSS Distributions  *
6*f6217f89SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*f6217f89SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*f6217f89SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*f6217f89SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*f6217f89SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*f6217f89SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*f6217f89SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*f6217f89SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*f6217f89SApple OSS Distributions  *
15*f6217f89SApple OSS Distributions  * Please obtain a copy of the License at
16*f6217f89SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*f6217f89SApple OSS Distributions  *
18*f6217f89SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*f6217f89SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*f6217f89SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*f6217f89SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*f6217f89SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*f6217f89SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*f6217f89SApple OSS Distributions  * limitations under the License.
25*f6217f89SApple OSS Distributions  *
26*f6217f89SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*f6217f89SApple OSS Distributions  */
28*f6217f89SApple OSS Distributions 
29*f6217f89SApple OSS Distributions #include <stdlib.h>
30*f6217f89SApple OSS Distributions #include <stdio.h>
31*f6217f89SApple OSS Distributions #include <stdint.h>
32*f6217f89SApple OSS Distributions #include <stdbool.h>
33*f6217f89SApple OSS Distributions #include <stdatomic.h>
34*f6217f89SApple OSS Distributions #include <errno.h>
35*f6217f89SApple OSS Distributions 
36*f6217f89SApple OSS Distributions #include <fcntl.h>
37*f6217f89SApple OSS Distributions #include <sys/ioctl.h>
38*f6217f89SApple OSS Distributions 
39*f6217f89SApple OSS Distributions #include <getopt.h>
40*f6217f89SApple OSS Distributions #include <unistd.h>
41*f6217f89SApple OSS Distributions 
42*f6217f89SApple OSS Distributions #include "ksancov.h"
43*f6217f89SApple OSS Distributions 
44*f6217f89SApple OSS Distributions static void
usage(void)45*f6217f89SApple OSS Distributions usage(void)
46*f6217f89SApple OSS Distributions {
47*f6217f89SApple OSS Distributions 	fprintf(stderr,
48*f6217f89SApple OSS Distributions 	    "usage: ./ksancov [OPTIONS]\n\n"
49*f6217f89SApple OSS Distributions 	    "  -t | --trace        use trace (PC log) mode [default]\n"
50*f6217f89SApple OSS Distributions 	    "  -s | --stksize      use trace (PC log) with stack size mode\n"
51*f6217f89SApple OSS Distributions 	    "  -c | --counters     use edge counter mode\n"
52*f6217f89SApple OSS Distributions 	    "  -p | --cmptrace     use trace (CMP log) mode\n"
53*f6217f89SApple OSS Distributions 	    "  -n | --entries <n>  override max entries in trace log\n"
54*f6217f89SApple OSS Distributions 	    "  -x | --exec <path>  instrument execution of binary at <path>\n"
55*f6217f89SApple OSS Distributions 	    "  -b | --bundle <b>   bundle for on-demand tracing\n");
56*f6217f89SApple OSS Distributions 	exit(1);
57*f6217f89SApple OSS Distributions }
58*f6217f89SApple OSS Distributions 
59*f6217f89SApple OSS Distributions /*
60*f6217f89SApple OSS Distributions  * Structure holds all data required for coverage collection.
61*f6217f89SApple OSS Distributions  */
62*f6217f89SApple OSS Distributions typedef struct ksancov_state {
63*f6217f89SApple OSS Distributions 	ksancov_mode_t       ks_mode;
64*f6217f89SApple OSS Distributions 	ksancov_edgemap_t    *ks_edgemap;
65*f6217f89SApple OSS Distributions 	union {
66*f6217f89SApple OSS Distributions 		ksancov_header_t       *ks_header;
67*f6217f89SApple OSS Distributions 		ksancov_trace_t        *ks_trace;
68*f6217f89SApple OSS Distributions 		ksancov_counters_t     *ks_counters;
69*f6217f89SApple OSS Distributions 	};
70*f6217f89SApple OSS Distributions 	ksancov_cmps_mode_t  ks_cmps_mode;
71*f6217f89SApple OSS Distributions 	union {
72*f6217f89SApple OSS Distributions 		ksancov_header_t       *ks_cmps_header;
73*f6217f89SApple OSS Distributions 		ksancov_trace_t        *ks_cmps_trace;
74*f6217f89SApple OSS Distributions 	};
75*f6217f89SApple OSS Distributions } ksancov_state_t;
76*f6217f89SApple OSS Distributions 
77*f6217f89SApple OSS Distributions /*
78*f6217f89SApple OSS Distributions  * Configures ksancov device for selected coverage mode.
79*f6217f89SApple OSS Distributions  */
80*f6217f89SApple OSS Distributions static int
ksancov_set_mode(int fd,ksancov_mode_t mode,int max_entries)81*f6217f89SApple OSS Distributions ksancov_set_mode(int fd, ksancov_mode_t mode, int max_entries)
82*f6217f89SApple OSS Distributions {
83*f6217f89SApple OSS Distributions 	int ret = 0;
84*f6217f89SApple OSS Distributions 
85*f6217f89SApple OSS Distributions 	switch (mode) {
86*f6217f89SApple OSS Distributions 	case KS_MODE_TRACE:
87*f6217f89SApple OSS Distributions 		ret = ksancov_mode_trace(fd, max_entries);
88*f6217f89SApple OSS Distributions 		break;
89*f6217f89SApple OSS Distributions 	case KS_MODE_STKSIZE:
90*f6217f89SApple OSS Distributions 		ret = ksancov_mode_stksize(fd, max_entries);
91*f6217f89SApple OSS Distributions 		break;
92*f6217f89SApple OSS Distributions 	case KS_MODE_COUNTERS:
93*f6217f89SApple OSS Distributions 		ret = ksancov_mode_counters(fd);
94*f6217f89SApple OSS Distributions 		break;
95*f6217f89SApple OSS Distributions 	default:
96*f6217f89SApple OSS Distributions 		perror("ksancov unsupported mode\n");
97*f6217f89SApple OSS Distributions 		return ENOTSUP;
98*f6217f89SApple OSS Distributions 	}
99*f6217f89SApple OSS Distributions 
100*f6217f89SApple OSS Distributions 	return ret;
101*f6217f89SApple OSS Distributions }
102*f6217f89SApple OSS Distributions 
103*f6217f89SApple OSS Distributions /*
104*f6217f89SApple OSS Distributions  * Configures ksancov device for selected comparison mode.
105*f6217f89SApple OSS Distributions  */
106*f6217f89SApple OSS Distributions static int
ksancov_cmps_set_mode(int fd,ksancov_cmps_mode_t mode,int max_entries)107*f6217f89SApple OSS Distributions ksancov_cmps_set_mode(int fd, ksancov_cmps_mode_t mode, int max_entries)
108*f6217f89SApple OSS Distributions {
109*f6217f89SApple OSS Distributions 	int ret = 0;
110*f6217f89SApple OSS Distributions 
111*f6217f89SApple OSS Distributions 	switch (mode) {
112*f6217f89SApple OSS Distributions 	case KS_CMPS_MODE_TRACE:
113*f6217f89SApple OSS Distributions 		ret = ksancov_cmps_mode_trace(fd, max_entries, false);
114*f6217f89SApple OSS Distributions 		break;
115*f6217f89SApple OSS Distributions 	case KS_CMPS_MODE_TRACE_FUNC:
116*f6217f89SApple OSS Distributions 		ret = ksancov_cmps_mode_trace(fd, max_entries, true);
117*f6217f89SApple OSS Distributions 		break;
118*f6217f89SApple OSS Distributions 	default:
119*f6217f89SApple OSS Distributions 		perror("ksancov unsupported cmps mode\n");
120*f6217f89SApple OSS Distributions 		return ENOTSUP;
121*f6217f89SApple OSS Distributions 	}
122*f6217f89SApple OSS Distributions 
123*f6217f89SApple OSS Distributions 	return ret;
124*f6217f89SApple OSS Distributions }
125*f6217f89SApple OSS Distributions 
126*f6217f89SApple OSS Distributions /*
127*f6217f89SApple OSS Distributions  * Initialize coverage state from provided options. Shared mappings with kernel are established
128*f6217f89SApple OSS Distributions  * here.
129*f6217f89SApple OSS Distributions  */
130*f6217f89SApple OSS Distributions static int
ksancov_init_state(int fd,ksancov_mode_t mode,ksancov_cmps_mode_t cmps_mode,int max_entries,ksancov_state_t * state)131*f6217f89SApple OSS Distributions ksancov_init_state(int fd, ksancov_mode_t mode, ksancov_cmps_mode_t cmps_mode, int max_entries, ksancov_state_t *state)
132*f6217f89SApple OSS Distributions {
133*f6217f89SApple OSS Distributions 	uintptr_t addr;
134*f6217f89SApple OSS Distributions 	size_t sz;
135*f6217f89SApple OSS Distributions 	int ret = 0;
136*f6217f89SApple OSS Distributions 
137*f6217f89SApple OSS Distributions 	/* Map edge map into process address space. */
138*f6217f89SApple OSS Distributions 	ret = ksancov_map_edgemap(fd, &addr, NULL);
139*f6217f89SApple OSS Distributions 	if (ret) {
140*f6217f89SApple OSS Distributions 		perror("ksancov map counters\n");
141*f6217f89SApple OSS Distributions 		return ret;
142*f6217f89SApple OSS Distributions 	}
143*f6217f89SApple OSS Distributions 	state->ks_edgemap = (void *)addr;
144*f6217f89SApple OSS Distributions 	fprintf(stderr, "nedges (edgemap) = %u\n", state->ks_edgemap->ke_nedges);
145*f6217f89SApple OSS Distributions 
146*f6217f89SApple OSS Distributions 	/* Setup selected tracing mode. */
147*f6217f89SApple OSS Distributions 	ret = ksancov_set_mode(fd, mode, max_entries);
148*f6217f89SApple OSS Distributions 	if (ret) {
149*f6217f89SApple OSS Distributions 		perror("ksancov set mode\n");
150*f6217f89SApple OSS Distributions 		return ret;
151*f6217f89SApple OSS Distributions 	}
152*f6217f89SApple OSS Distributions 
153*f6217f89SApple OSS Distributions 	/* Map buffer for selected mode into process address space. */
154*f6217f89SApple OSS Distributions 	ret = ksancov_map(fd, &addr, &sz);
155*f6217f89SApple OSS Distributions 	if (ret) {
156*f6217f89SApple OSS Distributions 		perror("ksancov map");
157*f6217f89SApple OSS Distributions 		return ret;
158*f6217f89SApple OSS Distributions 	}
159*f6217f89SApple OSS Distributions 	fprintf(stderr, "mapped to 0x%lx + %lu\n", addr, sz);
160*f6217f89SApple OSS Distributions 
161*f6217f89SApple OSS Distributions 	/* Finalize state members. */
162*f6217f89SApple OSS Distributions 	state->ks_mode = mode;
163*f6217f89SApple OSS Distributions 	state->ks_header = (void *)addr;
164*f6217f89SApple OSS Distributions 
165*f6217f89SApple OSS Distributions 	if (mode == KS_MODE_COUNTERS) {
166*f6217f89SApple OSS Distributions 		fprintf(stderr, "nedges (counters) = %u\n", state->ks_counters->kc_nedges);
167*f6217f89SApple OSS Distributions 	} else {
168*f6217f89SApple OSS Distributions 		fprintf(stderr, "maxpcs = %lu\n", ksancov_trace_max_ent(state->ks_trace));
169*f6217f89SApple OSS Distributions 	}
170*f6217f89SApple OSS Distributions 
171*f6217f89SApple OSS Distributions 	if (cmps_mode == KS_CMPS_MODE_NONE) {
172*f6217f89SApple OSS Distributions 		state->ks_cmps_mode = cmps_mode;
173*f6217f89SApple OSS Distributions 		state->ks_cmps_header = NULL;
174*f6217f89SApple OSS Distributions 		return ret;
175*f6217f89SApple OSS Distributions 	}
176*f6217f89SApple OSS Distributions 
177*f6217f89SApple OSS Distributions 	/* Setup selected comparison tracing mode. */
178*f6217f89SApple OSS Distributions 	ret = ksancov_cmps_set_mode(fd, cmps_mode, max_entries);
179*f6217f89SApple OSS Distributions 	if (ret) {
180*f6217f89SApple OSS Distributions 		perror("ksancov cmps set mode\n");
181*f6217f89SApple OSS Distributions 		return ret;
182*f6217f89SApple OSS Distributions 	}
183*f6217f89SApple OSS Distributions 
184*f6217f89SApple OSS Distributions 	/* Map buffer for selected mode into process address space. */
185*f6217f89SApple OSS Distributions 	ret = ksancov_cmps_map(fd, &addr, &sz);
186*f6217f89SApple OSS Distributions 	if (ret) {
187*f6217f89SApple OSS Distributions 		perror("ksancov cmps map");
188*f6217f89SApple OSS Distributions 		return ret;
189*f6217f89SApple OSS Distributions 	}
190*f6217f89SApple OSS Distributions 	fprintf(stderr, "cmps mapped to 0x%lx + %lu\n", addr, sz);
191*f6217f89SApple OSS Distributions 
192*f6217f89SApple OSS Distributions 	/* Finalize state members. */
193*f6217f89SApple OSS Distributions 	state->ks_cmps_mode = cmps_mode;
194*f6217f89SApple OSS Distributions 	state->ks_cmps_header = (void *)addr;
195*f6217f89SApple OSS Distributions 
196*f6217f89SApple OSS Distributions 	fprintf(stderr, "maxcmps = %lu\n", ksancov_trace_max_ent(state->ks_cmps_trace));
197*f6217f89SApple OSS Distributions 
198*f6217f89SApple OSS Distributions 	return ret;
199*f6217f89SApple OSS Distributions }
200*f6217f89SApple OSS Distributions 
201*f6217f89SApple OSS Distributions static int
ksancov_print_state(ksancov_state_t * state)202*f6217f89SApple OSS Distributions ksancov_print_state(ksancov_state_t *state)
203*f6217f89SApple OSS Distributions {
204*f6217f89SApple OSS Distributions 	if (state->ks_mode == KS_MODE_COUNTERS) {
205*f6217f89SApple OSS Distributions 		for (size_t i = 0; i < state->ks_counters->kc_nedges; i++) {
206*f6217f89SApple OSS Distributions 			size_t hits = state->ks_counters->kc_hits[i];
207*f6217f89SApple OSS Distributions 			if (hits) {
208*f6217f89SApple OSS Distributions 				fprintf(stderr, "0x%lx: %lu hits [idx %lu]\n",
209*f6217f89SApple OSS Distributions 				    ksancov_edge_addr(state->ks_edgemap, i), hits, i);
210*f6217f89SApple OSS Distributions 			}
211*f6217f89SApple OSS Distributions 		}
212*f6217f89SApple OSS Distributions 	} else {
213*f6217f89SApple OSS Distributions 		size_t head = ksancov_trace_head(state->ks_trace);
214*f6217f89SApple OSS Distributions 		fprintf(stderr, "head = %lu\n", head);
215*f6217f89SApple OSS Distributions 
216*f6217f89SApple OSS Distributions 		for (uint32_t i = 0; i < head; i++) {
217*f6217f89SApple OSS Distributions 			if (state->ks_mode == KS_MODE_TRACE) {
218*f6217f89SApple OSS Distributions 				fprintf(stderr, "0x%lx\n", ksancov_trace_entry(state->ks_trace, i));
219*f6217f89SApple OSS Distributions 			} else {
220*f6217f89SApple OSS Distributions 				fprintf(stderr, "0x%lx [size %u]\n", ksancov_stksize_pc(state->ks_trace, i),
221*f6217f89SApple OSS Distributions 				    ksancov_stksize_size(state->ks_trace, i));
222*f6217f89SApple OSS Distributions 			}
223*f6217f89SApple OSS Distributions 		}
224*f6217f89SApple OSS Distributions 	}
225*f6217f89SApple OSS Distributions 
226*f6217f89SApple OSS Distributions 	if (state->ks_cmps_mode == KS_CMPS_MODE_TRACE || state->ks_cmps_mode == KS_CMPS_MODE_TRACE_FUNC) {
227*f6217f89SApple OSS Distributions 		static const char *type_map[KCOV_CMP_SIZE8 + 1] = {
228*f6217f89SApple OSS Distributions 			"8 bits", NULL, "16 bits", NULL, "32 bits",
229*f6217f89SApple OSS Distributions 			NULL, "64 bits"
230*f6217f89SApple OSS Distributions 		};
231*f6217f89SApple OSS Distributions 
232*f6217f89SApple OSS Distributions 		size_t head = ksancov_trace_head(state->ks_cmps_trace);
233*f6217f89SApple OSS Distributions 		fprintf(stderr, "cmps head = %lu\n", head);
234*f6217f89SApple OSS Distributions 
235*f6217f89SApple OSS Distributions 		for (uint32_t i = 0; i < head;) {
236*f6217f89SApple OSS Distributions 			ksancov_cmps_trace_ent_t *entry = ksancov_cmps_trace_entry(state->ks_cmps_trace, i);
237*f6217f89SApple OSS Distributions 			if (KCOV_CMP_IS_FUNC(entry->type)) {
238*f6217f89SApple OSS Distributions 				size_t space = ksancov_cmps_trace_func_space(entry->len1_func, entry->len2_func);
239*f6217f89SApple OSS Distributions 				i += space / sizeof(ksancov_cmps_trace_ent_t);
240*f6217f89SApple OSS Distributions 				fprintf(stderr, "0x%llx [func %u %u] '%s' '%s'\n", entry->pc, entry->len1_func, entry->len2_func,
241*f6217f89SApple OSS Distributions 				    ksancov_cmps_trace_func_arg1(entry),
242*f6217f89SApple OSS Distributions 				    ksancov_cmps_trace_func_arg2(entry));
243*f6217f89SApple OSS Distributions 			} else {
244*f6217f89SApple OSS Distributions 				uint64_t type = entry->type & KCOV_CMP_SIZE_MASK;
245*f6217f89SApple OSS Distributions 				fprintf(stderr, "0x%llx [%s] 0x%llx 0x%llx\n", entry->pc, type_map[type], entry->args[0], entry->args[1]);
246*f6217f89SApple OSS Distributions 				++i;
247*f6217f89SApple OSS Distributions 			}
248*f6217f89SApple OSS Distributions 		}
249*f6217f89SApple OSS Distributions 	}
250*f6217f89SApple OSS Distributions 
251*f6217f89SApple OSS Distributions 	return 0;
252*f6217f89SApple OSS Distributions }
253*f6217f89SApple OSS Distributions 
254*f6217f89SApple OSS Distributions static int
ksancov_on_demand_set_enabled(int fd,const char * bundle,bool enabled)255*f6217f89SApple OSS Distributions ksancov_on_demand_set_enabled(int fd, const char *bundle, bool enabled)
256*f6217f89SApple OSS Distributions {
257*f6217f89SApple OSS Distributions 	int ret = 0;
258*f6217f89SApple OSS Distributions 	const uint64_t gate = enabled ? 1 : 0;
259*f6217f89SApple OSS Distributions 	if (bundle) {
260*f6217f89SApple OSS Distributions 		fprintf(stderr, "setting on-demand gate for '%s': %llu\n", bundle, gate);
261*f6217f89SApple OSS Distributions 		ret = ksancov_on_demand_set_gate(fd, bundle, gate);
262*f6217f89SApple OSS Distributions 		if (ret) {
263*f6217f89SApple OSS Distributions 			perror("ksancov on demand");
264*f6217f89SApple OSS Distributions 		}
265*f6217f89SApple OSS Distributions 	}
266*f6217f89SApple OSS Distributions 	return ret;
267*f6217f89SApple OSS Distributions }
268*f6217f89SApple OSS Distributions 
269*f6217f89SApple OSS Distributions int
main(int argc,char * argv[])270*f6217f89SApple OSS Distributions main(int argc, char *argv[])
271*f6217f89SApple OSS Distributions {
272*f6217f89SApple OSS Distributions 	ksancov_mode_t ksan_mode = KS_MODE_NONE;
273*f6217f89SApple OSS Distributions 	ksancov_cmps_mode_t ksan_cmps_mode = KS_CMPS_MODE_NONE;
274*f6217f89SApple OSS Distributions 	ksancov_state_t ksan_state = {0};
275*f6217f89SApple OSS Distributions 
276*f6217f89SApple OSS Distributions 	int ret;
277*f6217f89SApple OSS Distributions 	size_t max_entries = 64UL * 1024;
278*f6217f89SApple OSS Distributions 	char *path = NULL;
279*f6217f89SApple OSS Distributions 	char *od_bundle = NULL;
280*f6217f89SApple OSS Distributions 
281*f6217f89SApple OSS Distributions 	static struct option opts[] = {
282*f6217f89SApple OSS Distributions 		{ "entries", required_argument, NULL, 'n' },
283*f6217f89SApple OSS Distributions 		{ "exec", required_argument, NULL, 'x' },
284*f6217f89SApple OSS Distributions 
285*f6217f89SApple OSS Distributions 		{ "trace", no_argument, NULL, 't' },
286*f6217f89SApple OSS Distributions 		{ "counters", no_argument, NULL, 'c' },
287*f6217f89SApple OSS Distributions 		{ "stksize", no_argument, NULL, 's' },
288*f6217f89SApple OSS Distributions 		{ "cmptrace", no_argument, NULL, 'p' },
289*f6217f89SApple OSS Distributions 
290*f6217f89SApple OSS Distributions 		{ "bundle", required_argument, NULL, 'b' },
291*f6217f89SApple OSS Distributions 
292*f6217f89SApple OSS Distributions 		{ NULL, 0, NULL, 0 }
293*f6217f89SApple OSS Distributions 	};
294*f6217f89SApple OSS Distributions 
295*f6217f89SApple OSS Distributions 	int ch;
296*f6217f89SApple OSS Distributions 	while ((ch = getopt_long(argc, argv, "tsn:x:cpb:", opts, NULL)) != -1) {
297*f6217f89SApple OSS Distributions 		switch (ch) {
298*f6217f89SApple OSS Distributions 		case 'n':
299*f6217f89SApple OSS Distributions 			max_entries = strtoul(optarg, NULL, 0);
300*f6217f89SApple OSS Distributions 			break;
301*f6217f89SApple OSS Distributions 		case 'x':
302*f6217f89SApple OSS Distributions 			path = optarg;
303*f6217f89SApple OSS Distributions 			break;
304*f6217f89SApple OSS Distributions 		case 't':
305*f6217f89SApple OSS Distributions 			ksan_mode = KS_MODE_TRACE;
306*f6217f89SApple OSS Distributions 			break;
307*f6217f89SApple OSS Distributions 		case 'c':
308*f6217f89SApple OSS Distributions 			ksan_mode = KS_MODE_COUNTERS;
309*f6217f89SApple OSS Distributions 			break;
310*f6217f89SApple OSS Distributions 		case 's':
311*f6217f89SApple OSS Distributions 			ksan_mode = KS_MODE_STKSIZE;
312*f6217f89SApple OSS Distributions 			break;
313*f6217f89SApple OSS Distributions 		case 'p':
314*f6217f89SApple OSS Distributions 			ksan_cmps_mode = KS_CMPS_MODE_TRACE_FUNC;
315*f6217f89SApple OSS Distributions 			break;
316*f6217f89SApple OSS Distributions 		case 'b':
317*f6217f89SApple OSS Distributions 			od_bundle = optarg;
318*f6217f89SApple OSS Distributions 			break;
319*f6217f89SApple OSS Distributions 		default:
320*f6217f89SApple OSS Distributions 			usage();
321*f6217f89SApple OSS Distributions 		}
322*f6217f89SApple OSS Distributions 	}
323*f6217f89SApple OSS Distributions 
324*f6217f89SApple OSS Distributions 	int fd = ksancov_open();
325*f6217f89SApple OSS Distributions 	if (fd < 0) {
326*f6217f89SApple OSS Distributions 		perror("ksancov_open");
327*f6217f89SApple OSS Distributions 		return errno;
328*f6217f89SApple OSS Distributions 	}
329*f6217f89SApple OSS Distributions 	fprintf(stderr, "opened ksancov on fd %i\n", fd);
330*f6217f89SApple OSS Distributions 
331*f6217f89SApple OSS Distributions 	/* Initialize ksancov state. */
332*f6217f89SApple OSS Distributions 	ret = ksancov_init_state(fd, ksan_mode, ksan_cmps_mode, max_entries, &ksan_state);
333*f6217f89SApple OSS Distributions 	if (ret) {
334*f6217f89SApple OSS Distributions 		perror("ksancov init\n");
335*f6217f89SApple OSS Distributions 		return ret;
336*f6217f89SApple OSS Distributions 	}
337*f6217f89SApple OSS Distributions 
338*f6217f89SApple OSS Distributions 	/* Execute binary (when provided) with enabled coverage collection. Run getppid() otherwise. */
339*f6217f89SApple OSS Distributions 	if (path) {
340*f6217f89SApple OSS Distributions 		int pid = fork();
341*f6217f89SApple OSS Distributions 		if (pid == 0) {
342*f6217f89SApple OSS Distributions 			/* child */
343*f6217f89SApple OSS Distributions 
344*f6217f89SApple OSS Distributions 			ret = ksancov_thread_self(fd);
345*f6217f89SApple OSS Distributions 			if (ret) {
346*f6217f89SApple OSS Distributions 				perror("ksancov thread");
347*f6217f89SApple OSS Distributions 				return ret;
348*f6217f89SApple OSS Distributions 			}
349*f6217f89SApple OSS Distributions 
350*f6217f89SApple OSS Distributions 			ksancov_on_demand_set_enabled(fd, od_bundle, true);
351*f6217f89SApple OSS Distributions 			ksancov_reset(ksan_state.ks_header);
352*f6217f89SApple OSS Distributions 			ksancov_start(ksan_state.ks_header);
353*f6217f89SApple OSS Distributions 			if (ksan_state.ks_cmps_header) {
354*f6217f89SApple OSS Distributions 				ksancov_reset(ksan_state.ks_cmps_header);
355*f6217f89SApple OSS Distributions 				ksancov_start(ksan_state.ks_cmps_header);
356*f6217f89SApple OSS Distributions 			}
357*f6217f89SApple OSS Distributions 			ret = execl(path, path, 0);
358*f6217f89SApple OSS Distributions 			perror("execl");
359*f6217f89SApple OSS Distributions 			ksancov_on_demand_set_enabled(fd, od_bundle, false);
360*f6217f89SApple OSS Distributions 
361*f6217f89SApple OSS Distributions 			exit(1);
362*f6217f89SApple OSS Distributions 		} else {
363*f6217f89SApple OSS Distributions 			/* parent */
364*f6217f89SApple OSS Distributions 			waitpid(pid, NULL, 0);
365*f6217f89SApple OSS Distributions 			ksancov_stop(ksan_state.ks_header);
366*f6217f89SApple OSS Distributions 			if (ksan_state.ks_cmps_header) {
367*f6217f89SApple OSS Distributions 				ksancov_stop(ksan_state.ks_cmps_header);
368*f6217f89SApple OSS Distributions 			}
369*f6217f89SApple OSS Distributions 			ksancov_on_demand_set_enabled(fd, od_bundle, false);
370*f6217f89SApple OSS Distributions 		}
371*f6217f89SApple OSS Distributions 	} else {
372*f6217f89SApple OSS Distributions 		ret = ksancov_thread_self(fd);
373*f6217f89SApple OSS Distributions 		if (ret) {
374*f6217f89SApple OSS Distributions 			perror("ksancov thread");
375*f6217f89SApple OSS Distributions 			return ret;
376*f6217f89SApple OSS Distributions 		}
377*f6217f89SApple OSS Distributions 
378*f6217f89SApple OSS Distributions 		ksancov_on_demand_set_enabled(fd, od_bundle, true);
379*f6217f89SApple OSS Distributions 		ksancov_reset(ksan_state.ks_header);
380*f6217f89SApple OSS Distributions 		ksancov_start(ksan_state.ks_header);
381*f6217f89SApple OSS Distributions 		if (ksan_state.ks_cmps_header) {
382*f6217f89SApple OSS Distributions 			ksancov_reset(ksan_state.ks_cmps_header);
383*f6217f89SApple OSS Distributions 			ksancov_start(ksan_state.ks_cmps_header);
384*f6217f89SApple OSS Distributions 		}
385*f6217f89SApple OSS Distributions 		int ppid = getppid();
386*f6217f89SApple OSS Distributions 		ksancov_stop(ksan_state.ks_header);
387*f6217f89SApple OSS Distributions 		if (ksan_state.ks_cmps_header) {
388*f6217f89SApple OSS Distributions 			ksancov_stop(ksan_state.ks_cmps_header);
389*f6217f89SApple OSS Distributions 		}
390*f6217f89SApple OSS Distributions 		ksancov_on_demand_set_enabled(fd, od_bundle, false);
391*f6217f89SApple OSS Distributions 		fprintf(stderr, "ppid = %i\n", ppid);
392*f6217f89SApple OSS Distributions 	}
393*f6217f89SApple OSS Distributions 
394*f6217f89SApple OSS Distributions 	/* Print report and cleanup. */
395*f6217f89SApple OSS Distributions 	ksancov_print_state(&ksan_state);
396*f6217f89SApple OSS Distributions 	ret = close(fd);
397*f6217f89SApple OSS Distributions 	fprintf(stderr, "close = %i\n", ret);
398*f6217f89SApple OSS Distributions 
399*f6217f89SApple OSS Distributions 	return 0;
400*f6217f89SApple OSS Distributions }
401