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