1*42e22086SApple OSS Distributions /*
2*42e22086SApple OSS Distributions * Copyright (c) 2019 Apple Inc. All rights reserved.
3*42e22086SApple OSS Distributions *
4*42e22086SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*42e22086SApple OSS Distributions *
6*42e22086SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*42e22086SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*42e22086SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*42e22086SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*42e22086SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*42e22086SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*42e22086SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*42e22086SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*42e22086SApple OSS Distributions *
15*42e22086SApple OSS Distributions * Please obtain a copy of the License at
16*42e22086SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*42e22086SApple OSS Distributions *
18*42e22086SApple OSS Distributions * The Original Code and all software distributed under the License are
19*42e22086SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*42e22086SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*42e22086SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*42e22086SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*42e22086SApple OSS Distributions * Please see the License for the specific language governing rights and
24*42e22086SApple OSS Distributions * limitations under the License.
25*42e22086SApple OSS Distributions *
26*42e22086SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*42e22086SApple OSS Distributions */
28*42e22086SApple OSS Distributions
29*42e22086SApple OSS Distributions #include <stdlib.h>
30*42e22086SApple OSS Distributions #include <stdio.h>
31*42e22086SApple OSS Distributions #include <stdint.h>
32*42e22086SApple OSS Distributions #include <stdbool.h>
33*42e22086SApple OSS Distributions #include <stdatomic.h>
34*42e22086SApple OSS Distributions #include <errno.h>
35*42e22086SApple OSS Distributions
36*42e22086SApple OSS Distributions #include <fcntl.h>
37*42e22086SApple OSS Distributions #include <sys/ioctl.h>
38*42e22086SApple OSS Distributions
39*42e22086SApple OSS Distributions #include <getopt.h>
40*42e22086SApple OSS Distributions
41*42e22086SApple OSS Distributions #include "ksancov.h"
42*42e22086SApple OSS Distributions
43*42e22086SApple OSS Distributions static void
usage(void)44*42e22086SApple OSS Distributions usage(void)
45*42e22086SApple OSS Distributions {
46*42e22086SApple OSS Distributions fprintf(stderr,
47*42e22086SApple OSS Distributions "usage: ./ksancov [OPTIONS]\n\n"
48*42e22086SApple OSS Distributions " -t | --trace use trace (PC log) mode [default]\n"
49*42e22086SApple OSS Distributions " -s | --stksize use trace (PC log) with stack size mode\n"
50*42e22086SApple OSS Distributions " -c | --counters use edge counter mode\n"
51*42e22086SApple OSS Distributions " -n | --entries <n> override max entries in trace log\n"
52*42e22086SApple OSS Distributions " -x | --exec <path> instrument execution of binary at <path>\n");
53*42e22086SApple OSS Distributions exit(1);
54*42e22086SApple OSS Distributions }
55*42e22086SApple OSS Distributions
56*42e22086SApple OSS Distributions /*
57*42e22086SApple OSS Distributions * Structure holds all data required for coverage collection.
58*42e22086SApple OSS Distributions */
59*42e22086SApple OSS Distributions typedef struct ksancov_state {
60*42e22086SApple OSS Distributions ksancov_mode_t ks_mode;
61*42e22086SApple OSS Distributions ksancov_edgemap_t *ks_edgemap;
62*42e22086SApple OSS Distributions union {
63*42e22086SApple OSS Distributions ksancov_header_t *ks_header;
64*42e22086SApple OSS Distributions ksancov_trace_t *ks_trace;
65*42e22086SApple OSS Distributions ksancov_counters_t *ks_counters;
66*42e22086SApple OSS Distributions };
67*42e22086SApple OSS Distributions } ksancov_state_t;
68*42e22086SApple OSS Distributions
69*42e22086SApple OSS Distributions /*
70*42e22086SApple OSS Distributions * Configures ksancov device for selected coverage mode.
71*42e22086SApple OSS Distributions */
72*42e22086SApple OSS Distributions static int
ksancov_set_mode(int fd,ksancov_mode_t mode,int max_entries)73*42e22086SApple OSS Distributions ksancov_set_mode(int fd, ksancov_mode_t mode, int max_entries)
74*42e22086SApple OSS Distributions {
75*42e22086SApple OSS Distributions int ret = 0;
76*42e22086SApple OSS Distributions
77*42e22086SApple OSS Distributions switch (mode) {
78*42e22086SApple OSS Distributions case KS_MODE_TRACE:
79*42e22086SApple OSS Distributions ret = ksancov_mode_trace(fd, max_entries);
80*42e22086SApple OSS Distributions break;
81*42e22086SApple OSS Distributions case KS_MODE_STKSIZE:
82*42e22086SApple OSS Distributions ret = ksancov_mode_stksize(fd, max_entries);
83*42e22086SApple OSS Distributions break;
84*42e22086SApple OSS Distributions case KS_MODE_COUNTERS:
85*42e22086SApple OSS Distributions ret = ksancov_mode_counters(fd);
86*42e22086SApple OSS Distributions break;
87*42e22086SApple OSS Distributions default:
88*42e22086SApple OSS Distributions perror("ksancov unsupported mode\n");
89*42e22086SApple OSS Distributions return ENOTSUP;
90*42e22086SApple OSS Distributions }
91*42e22086SApple OSS Distributions
92*42e22086SApple OSS Distributions return ret;
93*42e22086SApple OSS Distributions }
94*42e22086SApple OSS Distributions
95*42e22086SApple OSS Distributions /*
96*42e22086SApple OSS Distributions * Initialize coverage state from provided options. Shared mappings with kernel are established
97*42e22086SApple OSS Distributions * here.
98*42e22086SApple OSS Distributions */
99*42e22086SApple OSS Distributions static int
ksancov_init_state(int fd,ksancov_mode_t mode,int max_entries,ksancov_state_t * state)100*42e22086SApple OSS Distributions ksancov_init_state(int fd, ksancov_mode_t mode, int max_entries, ksancov_state_t *state)
101*42e22086SApple OSS Distributions {
102*42e22086SApple OSS Distributions uintptr_t addr;
103*42e22086SApple OSS Distributions size_t sz;
104*42e22086SApple OSS Distributions int ret = 0;
105*42e22086SApple OSS Distributions
106*42e22086SApple OSS Distributions /* Map edge map into process address space. */
107*42e22086SApple OSS Distributions ret = ksancov_map_edgemap(fd, &addr, NULL);
108*42e22086SApple OSS Distributions if (ret) {
109*42e22086SApple OSS Distributions perror("ksancov map counters\n");
110*42e22086SApple OSS Distributions return ret;
111*42e22086SApple OSS Distributions }
112*42e22086SApple OSS Distributions state->ks_edgemap = (void *)addr;
113*42e22086SApple OSS Distributions fprintf(stderr, "nedges (edgemap) = %u\n", state->ks_edgemap->ke_nedges);
114*42e22086SApple OSS Distributions
115*42e22086SApple OSS Distributions /* Setup selected tracing mode. */
116*42e22086SApple OSS Distributions ret = ksancov_set_mode(fd, mode, max_entries);
117*42e22086SApple OSS Distributions if (ret) {
118*42e22086SApple OSS Distributions perror("ksancov set mode\n");
119*42e22086SApple OSS Distributions return ret;
120*42e22086SApple OSS Distributions }
121*42e22086SApple OSS Distributions
122*42e22086SApple OSS Distributions /* Map buffer for selected mode into process address space. */
123*42e22086SApple OSS Distributions ret = ksancov_map(fd, &addr, &sz);
124*42e22086SApple OSS Distributions if (ret) {
125*42e22086SApple OSS Distributions perror("ksancov map");
126*42e22086SApple OSS Distributions return ret;
127*42e22086SApple OSS Distributions }
128*42e22086SApple OSS Distributions fprintf(stderr, "mapped to 0x%lx + %lu\n", addr, sz);
129*42e22086SApple OSS Distributions
130*42e22086SApple OSS Distributions /* Finalize state members. */
131*42e22086SApple OSS Distributions state->ks_mode = mode;
132*42e22086SApple OSS Distributions state->ks_header = (void *)addr;
133*42e22086SApple OSS Distributions
134*42e22086SApple OSS Distributions if (mode == KS_MODE_COUNTERS) {
135*42e22086SApple OSS Distributions fprintf(stderr, "nedges (counters) = %u\n", state->ks_counters->kc_nedges);
136*42e22086SApple OSS Distributions } else {
137*42e22086SApple OSS Distributions fprintf(stderr, "maxpcs = %lu\n", ksancov_trace_max_ent(state->ks_trace));
138*42e22086SApple OSS Distributions }
139*42e22086SApple OSS Distributions
140*42e22086SApple OSS Distributions return ret;
141*42e22086SApple OSS Distributions }
142*42e22086SApple OSS Distributions
143*42e22086SApple OSS Distributions static int
ksancov_print_state(ksancov_state_t * state)144*42e22086SApple OSS Distributions ksancov_print_state(ksancov_state_t *state)
145*42e22086SApple OSS Distributions {
146*42e22086SApple OSS Distributions if (state->ks_mode == KS_MODE_COUNTERS) {
147*42e22086SApple OSS Distributions for (size_t i = 0; i < state->ks_counters->kc_nedges; i++) {
148*42e22086SApple OSS Distributions size_t hits = state->ks_counters->kc_hits[i];
149*42e22086SApple OSS Distributions if (hits) {
150*42e22086SApple OSS Distributions fprintf(stderr, "0x%lx: %lu hits [idx %lu]\n",
151*42e22086SApple OSS Distributions ksancov_edge_addr(state->ks_edgemap, i), hits, i);
152*42e22086SApple OSS Distributions }
153*42e22086SApple OSS Distributions }
154*42e22086SApple OSS Distributions } else {
155*42e22086SApple OSS Distributions size_t head = ksancov_trace_head(state->ks_trace);
156*42e22086SApple OSS Distributions fprintf(stderr, "head = %lu\n", head);
157*42e22086SApple OSS Distributions
158*42e22086SApple OSS Distributions for (uint32_t i = 0; i < head; i++) {
159*42e22086SApple OSS Distributions if (state->ks_mode == KS_MODE_TRACE) {
160*42e22086SApple OSS Distributions fprintf(stderr, "0x%lx\n", ksancov_trace_entry(state->ks_trace, i));
161*42e22086SApple OSS Distributions } else {
162*42e22086SApple OSS Distributions fprintf(stderr, "0x%lx [size %u]\n", ksancov_stksize_pc(state->ks_trace, i),
163*42e22086SApple OSS Distributions ksancov_stksize_size(state->ks_trace, i));
164*42e22086SApple OSS Distributions }
165*42e22086SApple OSS Distributions }
166*42e22086SApple OSS Distributions }
167*42e22086SApple OSS Distributions
168*42e22086SApple OSS Distributions return 0;
169*42e22086SApple OSS Distributions }
170*42e22086SApple OSS Distributions
171*42e22086SApple OSS Distributions int
main(int argc,char * argv[])172*42e22086SApple OSS Distributions main(int argc, char *argv[])
173*42e22086SApple OSS Distributions {
174*42e22086SApple OSS Distributions ksancov_mode_t ksan_mode = KS_MODE_NONE;
175*42e22086SApple OSS Distributions ksancov_state_t ksan_state;
176*42e22086SApple OSS Distributions
177*42e22086SApple OSS Distributions int ret;
178*42e22086SApple OSS Distributions size_t max_entries = 64UL * 1024;
179*42e22086SApple OSS Distributions char *path = NULL;
180*42e22086SApple OSS Distributions
181*42e22086SApple OSS Distributions static struct option opts[] = {
182*42e22086SApple OSS Distributions { "entries", required_argument, NULL, 'n' },
183*42e22086SApple OSS Distributions { "exec", required_argument, NULL, 'x' },
184*42e22086SApple OSS Distributions
185*42e22086SApple OSS Distributions { "trace", no_argument, NULL, 't' },
186*42e22086SApple OSS Distributions { "counters", no_argument, NULL, 'c' },
187*42e22086SApple OSS Distributions { "stksize", no_argument, NULL, 's' },
188*42e22086SApple OSS Distributions
189*42e22086SApple OSS Distributions { NULL, 0, NULL, 0 }
190*42e22086SApple OSS Distributions };
191*42e22086SApple OSS Distributions
192*42e22086SApple OSS Distributions int ch;
193*42e22086SApple OSS Distributions while ((ch = getopt_long(argc, argv, "tsn:x:c", opts, NULL)) != -1) {
194*42e22086SApple OSS Distributions switch (ch) {
195*42e22086SApple OSS Distributions case 'n':
196*42e22086SApple OSS Distributions max_entries = strtoul(optarg, NULL, 0);
197*42e22086SApple OSS Distributions break;
198*42e22086SApple OSS Distributions case 'x':
199*42e22086SApple OSS Distributions path = optarg;
200*42e22086SApple OSS Distributions break;
201*42e22086SApple OSS Distributions case 't':
202*42e22086SApple OSS Distributions ksan_mode = KS_MODE_TRACE;
203*42e22086SApple OSS Distributions break;
204*42e22086SApple OSS Distributions case 'c':
205*42e22086SApple OSS Distributions ksan_mode = KS_MODE_COUNTERS;
206*42e22086SApple OSS Distributions break;
207*42e22086SApple OSS Distributions case 's':
208*42e22086SApple OSS Distributions ksan_mode = KS_MODE_STKSIZE;
209*42e22086SApple OSS Distributions break;
210*42e22086SApple OSS Distributions default:
211*42e22086SApple OSS Distributions usage();
212*42e22086SApple OSS Distributions }
213*42e22086SApple OSS Distributions }
214*42e22086SApple OSS Distributions
215*42e22086SApple OSS Distributions int fd = ksancov_open();
216*42e22086SApple OSS Distributions if (fd < 0) {
217*42e22086SApple OSS Distributions perror("ksancov_open");
218*42e22086SApple OSS Distributions return errno;
219*42e22086SApple OSS Distributions }
220*42e22086SApple OSS Distributions fprintf(stderr, "opened ksancov on fd %i\n", fd);
221*42e22086SApple OSS Distributions
222*42e22086SApple OSS Distributions /* Initialize ksancov state. */
223*42e22086SApple OSS Distributions ret = ksancov_init_state(fd, ksan_mode, max_entries, &ksan_state);
224*42e22086SApple OSS Distributions if (ret) {
225*42e22086SApple OSS Distributions perror("ksancov init\n");
226*42e22086SApple OSS Distributions return ret;
227*42e22086SApple OSS Distributions }
228*42e22086SApple OSS Distributions
229*42e22086SApple OSS Distributions /* Execute binary (when provided) with enabled coverage collection. Run getppid() otherwise. */
230*42e22086SApple OSS Distributions if (path) {
231*42e22086SApple OSS Distributions int pid = fork();
232*42e22086SApple OSS Distributions if (pid == 0) {
233*42e22086SApple OSS Distributions /* child */
234*42e22086SApple OSS Distributions
235*42e22086SApple OSS Distributions ret = ksancov_thread_self(fd);
236*42e22086SApple OSS Distributions if (ret) {
237*42e22086SApple OSS Distributions perror("ksancov thread");
238*42e22086SApple OSS Distributions return ret;
239*42e22086SApple OSS Distributions }
240*42e22086SApple OSS Distributions
241*42e22086SApple OSS Distributions ksancov_reset(ksan_state.ks_header);
242*42e22086SApple OSS Distributions ksancov_start(ksan_state.ks_header);
243*42e22086SApple OSS Distributions ret = execl(path, path, 0);
244*42e22086SApple OSS Distributions perror("execl");
245*42e22086SApple OSS Distributions
246*42e22086SApple OSS Distributions exit(1);
247*42e22086SApple OSS Distributions } else {
248*42e22086SApple OSS Distributions /* parent */
249*42e22086SApple OSS Distributions waitpid(pid, NULL, 0);
250*42e22086SApple OSS Distributions ksancov_stop(ksan_state.ks_header);
251*42e22086SApple OSS Distributions }
252*42e22086SApple OSS Distributions } else {
253*42e22086SApple OSS Distributions ret = ksancov_thread_self(fd);
254*42e22086SApple OSS Distributions if (ret) {
255*42e22086SApple OSS Distributions perror("ksancov thread");
256*42e22086SApple OSS Distributions return ret;
257*42e22086SApple OSS Distributions }
258*42e22086SApple OSS Distributions
259*42e22086SApple OSS Distributions ksancov_reset(ksan_state.ks_header);
260*42e22086SApple OSS Distributions ksancov_start(ksan_state.ks_header);
261*42e22086SApple OSS Distributions int ppid = getppid();
262*42e22086SApple OSS Distributions ksancov_stop(ksan_state.ks_header);
263*42e22086SApple OSS Distributions fprintf(stderr, "ppid = %i\n", ppid);
264*42e22086SApple OSS Distributions }
265*42e22086SApple OSS Distributions
266*42e22086SApple OSS Distributions /* Print report and cleanup. */
267*42e22086SApple OSS Distributions ksancov_print_state(&ksan_state);
268*42e22086SApple OSS Distributions ret = close(fd);
269*42e22086SApple OSS Distributions fprintf(stderr, "close = %i\n", ret);
270*42e22086SApple OSS Distributions
271*42e22086SApple OSS Distributions return 0;
272*42e22086SApple OSS Distributions }
273