/****************************************************************************** * tools/vmtrace.c * * Demonstrative tool for collecting Intel Processor Trace data from Xen. * Could be used to externally monitor a given vCPU in given DomU. * * Copyright (C) 2020 by CERT Polska - NASK PIB * * Authors: Michał Leszczyński, michal.leszczynski@cert.pl * Date: June, 2020 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 2 of the License. * * This program is distributed in the hope that 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 #include #define MSR_RTIT_CTL 0x00000570 #define RTIT_CTL_OS (1 << 2) #define RTIT_CTL_USR (1 << 3) #define RTIT_CTL_BRANCH_EN (1 << 13) static xc_interface *xch; static xenforeignmemory_handle *fh; static uint32_t domid, vcpu; static size_t size; static char *buf; static sig_atomic_t interrupted; static void close_handler(int signum) { interrupted = 1; } static int get_more_data(void) { static uint64_t last_pos; uint64_t pos; if ( xc_vmtrace_output_position(xch, domid, vcpu, &pos) ) { perror("xc_vmtrace_output_position()"); return -1; } if ( pos > last_pos ) fwrite(buf + last_pos, pos - last_pos, 1, stdout); else if ( pos < last_pos ) { /* buffer wrapped */ fwrite(buf + last_pos, size - last_pos, 1, stdout); fwrite(buf, pos, 1, stdout); } last_pos = pos; return 0; } int main(int argc, char **argv) { int rc, exit = 1; xenforeignmemory_resource_handle *fres = NULL; struct sigaction act; act.sa_handler = close_handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGHUP, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGALRM, &act, NULL); if ( argc != 3 ) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "It's recommended to redirect thisprogram's output to file\n"); fprintf(stderr, "or to pipe it's output to xxd or other program.\n"); return 1; } domid = atoi(argv[1]); vcpu = atoi(argv[2]); xch = xc_interface_open(NULL, NULL, 0); fh = xenforeignmemory_open(NULL, 0); if ( !xch ) err(1, "xc_interface_open()"); if ( !fh ) err(1, "xenforeignmemory_open()"); rc = xenforeignmemory_resource_size( fh, domid, XENMEM_resource_vmtrace_buf, vcpu, &size); if ( rc ) err(1, "xenforeignmemory_resource_size()"); fres = xenforeignmemory_map_resource( fh, domid, XENMEM_resource_vmtrace_buf, vcpu, 0, size >> XC_PAGE_SHIFT, (void **)&buf, PROT_READ, 0); if ( !fres ) err(1, "xenforeignmemory_map_resource()"); if ( xc_vmtrace_set_option( xch, domid, vcpu, MSR_RTIT_CTL, RTIT_CTL_BRANCH_EN | RTIT_CTL_USR | RTIT_CTL_OS) ) { perror("xc_vmtrace_set_option()"); goto out; } if ( xc_vmtrace_reset_and_enable(xch, domid, vcpu) ) { perror("xc_vmtrace_enable()"); goto out; } while ( !interrupted ) { xc_domaininfo_t dominfo; if ( get_more_data() ) goto out; usleep(1000 * 100); if ( xc_domain_getinfo_single(xch, domid, &dominfo) < 0 || (dominfo.flags & XEN_DOMINF_shutdown) ) { if ( get_more_data() ) goto out; break; } } exit = 0; out: if ( xc_vmtrace_disable(xch, domid, vcpu) ) perror("xc_vmtrace_disable()"); if ( fres && xenforeignmemory_unmap_resource(fh, fres) ) perror("xenforeignmemory_unmap_resource()"); return exit; } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */