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