1 /******************************************************************************
2  * tools/vmtrace.c
3  *
4  * Demonstrative tool for collecting Intel Processor Trace data from Xen.
5  *  Could be used to externally monitor a given vCPU in given DomU.
6  *
7  * Copyright (C) 2020 by CERT Polska - NASK PIB
8  *
9  * Authors: Michał Leszczyński, michal.leszczynski@cert.pl
10  * Date:    June, 2020
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; under version 2 of the License.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <err.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/mman.h>
31 
32 #include <xenctrl.h>
33 #include <xenforeignmemory.h>
34 
35 #define MSR_RTIT_CTL                        0x00000570
36 #define  RTIT_CTL_OS                        (1 <<  2)
37 #define  RTIT_CTL_USR                       (1 <<  3)
38 #define  RTIT_CTL_BRANCH_EN                 (1 << 13)
39 
40 static xc_interface *xch;
41 static xenforeignmemory_handle *fh;
42 static uint32_t domid, vcpu;
43 static size_t size;
44 static char *buf;
45 
46 static sig_atomic_t interrupted;
close_handler(int signum)47 static void close_handler(int signum)
48 {
49     interrupted = 1;
50 }
51 
get_more_data(void)52 static int get_more_data(void)
53 {
54     static uint64_t last_pos;
55     uint64_t pos;
56 
57     if ( xc_vmtrace_output_position(xch, domid, vcpu, &pos) )
58     {
59         perror("xc_vmtrace_output_position()");
60         return -1;
61     }
62 
63     if ( pos > last_pos )
64         fwrite(buf + last_pos, pos - last_pos, 1, stdout);
65     else if ( pos < last_pos )
66     {
67         /* buffer wrapped */
68         fwrite(buf + last_pos, size - last_pos, 1, stdout);
69         fwrite(buf, pos, 1, stdout);
70     }
71 
72     last_pos = pos;
73     return 0;
74 }
75 
main(int argc,char ** argv)76 int main(int argc, char **argv)
77 {
78     int rc, exit = 1;
79     xenforeignmemory_resource_handle *fres = NULL;
80 
81     struct sigaction act;
82     act.sa_handler = close_handler;
83     act.sa_flags = 0;
84     sigemptyset(&act.sa_mask);
85     sigaction(SIGHUP,  &act, NULL);
86     sigaction(SIGTERM, &act, NULL);
87     sigaction(SIGINT,  &act, NULL);
88     sigaction(SIGALRM, &act, NULL);
89 
90     if ( argc != 3 )
91     {
92         fprintf(stderr, "Usage: %s <domid> <vcpu_id>\n", argv[0]);
93         fprintf(stderr, "It's recommended to redirect thisprogram's output to file\n");
94         fprintf(stderr, "or to pipe it's output to xxd or other program.\n");
95         return 1;
96     }
97 
98     domid = atoi(argv[1]);
99     vcpu  = atoi(argv[2]);
100 
101     xch = xc_interface_open(NULL, NULL, 0);
102     fh = xenforeignmemory_open(NULL, 0);
103 
104     if ( !xch )
105         err(1, "xc_interface_open()");
106     if ( !fh )
107         err(1, "xenforeignmemory_open()");
108 
109     rc = xenforeignmemory_resource_size(
110         fh, domid, XENMEM_resource_vmtrace_buf, vcpu, &size);
111     if ( rc )
112         err(1, "xenforeignmemory_resource_size()");
113 
114     fres = xenforeignmemory_map_resource(
115         fh, domid, XENMEM_resource_vmtrace_buf, vcpu,
116         0, size >> XC_PAGE_SHIFT, (void **)&buf, PROT_READ, 0);
117     if ( !fres )
118         err(1, "xenforeignmemory_map_resource()");
119 
120     if ( xc_vmtrace_set_option(
121              xch, domid, vcpu, MSR_RTIT_CTL,
122              RTIT_CTL_BRANCH_EN | RTIT_CTL_USR | RTIT_CTL_OS) )
123     {
124         perror("xc_vmtrace_set_option()");
125         goto out;
126     }
127 
128     if ( xc_vmtrace_reset_and_enable(xch, domid, vcpu) )
129     {
130         perror("xc_vmtrace_enable()");
131         goto out;
132     }
133 
134     while ( !interrupted )
135     {
136         xc_domaininfo_t dominfo;
137 
138         if ( get_more_data() )
139             goto out;
140 
141         usleep(1000 * 100);
142 
143         if ( xc_domain_getinfo_single(xch, domid, &dominfo) < 0 ||
144              (dominfo.flags & XEN_DOMINF_shutdown) )
145         {
146             if ( get_more_data() )
147                 goto out;
148             break;
149         }
150     }
151 
152     exit = 0;
153 
154  out:
155     if ( xc_vmtrace_disable(xch, domid, vcpu) )
156         perror("xc_vmtrace_disable()");
157 
158     if ( fres && xenforeignmemory_unmap_resource(fh, fres) )
159         perror("xenforeignmemory_unmap_resource()");
160 
161     return exit;
162 }
163 
164 /*
165  * Local variables:
166  * mode: C
167  * c-file-style: "BSD"
168  * c-basic-offset: 4
169  * tab-width: 4
170  * indent-tabs-mode: nil
171  * End:
172  */
173