1 /*
2 * xencov: extract test coverage information from Xen.
3 *
4 * Copyright (c) 2013, 2016, Citrix Systems R&D Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <err.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <xenctrl.h>
26
27 static xc_interface *xch = NULL;
28
cov_sysctl(int op,struct xen_sysctl * sysctl,struct xc_hypercall_buffer * buf,uint32_t buf_size)29 int cov_sysctl(int op, struct xen_sysctl *sysctl,
30 struct xc_hypercall_buffer *buf, uint32_t buf_size)
31 {
32 DECLARE_HYPERCALL_BUFFER_ARGUMENT(buf);
33
34 memset(sysctl, 0, sizeof(*sysctl));
35 sysctl->cmd = XEN_SYSCTL_coverage_op;
36
37 sysctl->u.coverage_op.cmd = op;
38 sysctl->u.coverage_op.size = buf_size;
39 set_xen_guest_handle(sysctl->u.coverage_op.buffer, buf);
40
41 return xc_sysctl(xch, sysctl);
42 }
43
cov_read(const char * fn)44 static void cov_read(const char *fn)
45 {
46 struct xen_sysctl sys;
47 uint32_t total_len;
48 DECLARE_HYPERCALL_BUFFER(uint8_t, p);
49 FILE *f;
50
51 if (cov_sysctl(XEN_SYSCTL_COVERAGE_get_size, &sys, NULL, 0) < 0)
52 err(1, "getting total length");
53 total_len = sys.u.coverage_op.size;
54
55 /* Shouldn't exceed a few hundred kilobytes */
56 if (total_len > 8u * 1024u * 1024u)
57 errx(1, "gcov data too big %u bytes\n", total_len);
58
59 p = xc_hypercall_buffer_alloc(xch, p, total_len);
60 if (!p)
61 err(1, "allocating buffer");
62
63 memset(p, 0, total_len);
64 if (cov_sysctl(XEN_SYSCTL_COVERAGE_read, &sys, HYPERCALL_BUFFER(p),
65 total_len) < 0)
66 err(1, "getting gcov data");
67
68 if (!strcmp(fn, "-"))
69 f = stdout;
70 else
71 f = fopen(fn, "w");
72
73 if (!f)
74 err(1, "opening output file");
75
76 if (fwrite(p, 1, total_len, f) != total_len)
77 err(1, "writing gcov data to file");
78
79 if (f != stdout)
80 fclose(f);
81
82 xc_hypercall_buffer_free(xch, p);
83 }
84
cov_reset(void)85 static void cov_reset(void)
86 {
87 struct xen_sysctl sys;
88
89 if (cov_sysctl(XEN_SYSCTL_COVERAGE_reset, &sys, NULL, 0) < 0)
90 err(1, "resetting gcov information");
91 }
92
usage(int exit_code)93 static void usage(int exit_code)
94 {
95 FILE *out = exit_code ? stderr : stdout;
96
97 fprintf(out, "xencov {reset|read} [<filename>]\n"
98 "\treset reset information\n"
99 "\tread read information from xen to filename\n"
100 "\tfilename optional filename (default output)\n"
101 );
102 exit(exit_code);
103 }
104
main(int argc,char ** argv)105 int main(int argc, char **argv)
106 {
107 int opt;
108
109 while ((opt = getopt(argc, argv, "h")) != -1) {
110 switch (opt) {
111 case 'h':
112 usage(0);
113 break;
114 default:
115 usage(1);
116 }
117 }
118
119 argv += optind;
120 argc -= optind;
121 if (argc <= 0)
122 usage(1);
123
124 xch = xc_interface_open(NULL, NULL, 0);
125 if (!xch)
126 err(1, "opening xc interface");
127
128 if (strcmp(argv[0], "reset") == 0)
129 cov_reset();
130 else if (strcmp(argv[0], "read") == 0)
131 cov_read(argc > 1 ? argv[1] : "-");
132 else
133 usage(1);
134
135 xc_interface_close(xch);
136
137 return 0;
138 }
139
140 /*
141 * Local variables:
142 * mode: C
143 * c-file-style: "BSD"
144 * c-basic-offset: 4
145 * tab-width: 4
146 * indent-tabs-mode: nil
147 * End:
148 */
149