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