/* * xencov: extract test coverage information from Xen. * * Copyright (c) 2013, 2016, Citrix Systems R&D Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; If not, see . */ #include #include #include #include #include #include #include static xc_interface *xch = NULL; int cov_sysctl(int op, struct xen_sysctl *sysctl, struct xc_hypercall_buffer *buf, uint32_t buf_size) { DECLARE_HYPERCALL_BUFFER_ARGUMENT(buf); memset(sysctl, 0, sizeof(*sysctl)); sysctl->cmd = XEN_SYSCTL_coverage_op; sysctl->u.coverage_op.cmd = op; sysctl->u.coverage_op.size = buf_size; set_xen_guest_handle(sysctl->u.coverage_op.buffer, buf); return xc_sysctl(xch, sysctl); } static void cov_read(const char *fn) { struct xen_sysctl sys; uint32_t total_len; DECLARE_HYPERCALL_BUFFER(uint8_t, p); FILE *f; if (cov_sysctl(XEN_SYSCTL_COVERAGE_get_size, &sys, NULL, 0) < 0) err(1, "getting total length"); total_len = sys.u.coverage_op.size; /* Shouldn't exceed a few hundred kilobytes */ if (total_len > 8u * 1024u * 1024u) errx(1, "gcov data too big %u bytes\n", total_len); p = xc_hypercall_buffer_alloc(xch, p, total_len); if (!p) err(1, "allocating buffer"); memset(p, 0, total_len); if (cov_sysctl(XEN_SYSCTL_COVERAGE_read, &sys, HYPERCALL_BUFFER(p), total_len) < 0) err(1, "getting gcov data"); if (!strcmp(fn, "-")) f = stdout; else f = fopen(fn, "w"); if (!f) err(1, "opening output file"); if (fwrite(p, 1, total_len, f) != total_len) err(1, "writing gcov data to file"); if (f != stdout) fclose(f); xc_hypercall_buffer_free(xch, p); } static void cov_reset(void) { struct xen_sysctl sys; if (cov_sysctl(XEN_SYSCTL_COVERAGE_reset, &sys, NULL, 0) < 0) err(1, "resetting gcov information"); } static void usage(int exit_code) { FILE *out = exit_code ? stderr : stdout; fprintf(out, "xencov {reset|read} []\n" "\treset reset information\n" "\tread read information from xen to filename\n" "\tfilename optional filename (default output)\n" ); exit(exit_code); } int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "h")) != -1) { switch (opt) { case 'h': usage(0); break; default: usage(1); } } argv += optind; argc -= optind; if (argc <= 0) usage(1); xch = xc_interface_open(NULL, NULL, 0); if (!xch) err(1, "opening xc interface"); if (strcmp(argv[0], "reset") == 0) cov_reset(); else if (strcmp(argv[0], "read") == 0) cov_read(argc > 1 ? argv[1] : "-"); else usage(1); xc_interface_close(xch); return 0; } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */