• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3  *
4  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation;
8  * version 2.1 of the License (not later!)
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not,  see <http://www.gnu.org/licenses>
17  *
18  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 
25 #include "event-parse.h"
26 #include "trace-seq.h"
27 
28 #ifdef HAVE_UDIS86
29 
30 #include <udis86.h>
31 
32 static ud_t ud;
33 
init_disassembler(void)34 static void init_disassembler(void)
35 {
36 	ud_init(&ud);
37 	ud_set_syntax(&ud, UD_SYN_ATT);
38 }
39 
disassemble(unsigned char * insn,int len,uint64_t rip,int cr0_pe,int eflags_vm,int cs_d,int cs_l)40 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
41 			       int cr0_pe, int eflags_vm,
42 			       int cs_d, int cs_l)
43 {
44 	int mode;
45 
46 	if (!cr0_pe)
47 		mode = 16;
48 	else if (eflags_vm)
49 		mode = 16;
50 	else if (cs_l)
51 		mode = 64;
52 	else if (cs_d)
53 		mode = 32;
54 	else
55 		mode = 16;
56 
57 	ud_set_pc(&ud, rip);
58 	ud_set_mode(&ud, mode);
59 	ud_set_input_buffer(&ud, insn, len);
60 	ud_disassemble(&ud);
61 	return ud_insn_asm(&ud);
62 }
63 
64 #else
65 
init_disassembler(void)66 static void init_disassembler(void)
67 {
68 }
69 
disassemble(unsigned char * insn,int len,uint64_t rip,int cr0_pe,int eflags_vm,int cs_d,int cs_l)70 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
71 			       int cr0_pe, int eflags_vm,
72 			       int cs_d, int cs_l)
73 {
74 	static char out[15*3+1];
75 	int i;
76 
77 	for (i = 0; i < len; ++i)
78 		sprintf(out + i * 3, "%02x ", insn[i]);
79 	out[len*3-1] = '\0';
80 	return out;
81 }
82 
83 #endif
84 
85 
86 #define VMX_EXIT_REASONS			\
87 	_ER(EXCEPTION_NMI,	 0)		\
88 	_ER(EXTERNAL_INTERRUPT,	 1)		\
89 	_ER(TRIPLE_FAULT,	 2)		\
90 	_ER(PENDING_INTERRUPT,	 7)		\
91 	_ER(NMI_WINDOW,		 8)		\
92 	_ER(TASK_SWITCH,	 9)		\
93 	_ER(CPUID,		 10)		\
94 	_ER(HLT,		 12)		\
95 	_ER(INVD,		 13)		\
96 	_ER(INVLPG,		 14)		\
97 	_ER(RDPMC,		 15)		\
98 	_ER(RDTSC,		 16)		\
99 	_ER(VMCALL,		 18)		\
100 	_ER(VMCLEAR,		 19)		\
101 	_ER(VMLAUNCH,		 20)		\
102 	_ER(VMPTRLD,		 21)		\
103 	_ER(VMPTRST,		 22)		\
104 	_ER(VMREAD,		 23)		\
105 	_ER(VMRESUME,		 24)		\
106 	_ER(VMWRITE,		 25)		\
107 	_ER(VMOFF,		 26)		\
108 	_ER(VMON,		 27)		\
109 	_ER(CR_ACCESS,		 28)		\
110 	_ER(DR_ACCESS,		 29)		\
111 	_ER(IO_INSTRUCTION,	 30)		\
112 	_ER(MSR_READ,		 31)		\
113 	_ER(MSR_WRITE,		 32)		\
114 	_ER(MWAIT_INSTRUCTION,	 36)		\
115 	_ER(MONITOR_INSTRUCTION, 39)		\
116 	_ER(PAUSE_INSTRUCTION,	 40)		\
117 	_ER(MCE_DURING_VMENTRY,	 41)		\
118 	_ER(TPR_BELOW_THRESHOLD, 43)		\
119 	_ER(APIC_ACCESS,	 44)		\
120 	_ER(EOI_INDUCED,	 45)		\
121 	_ER(EPT_VIOLATION,	 48)		\
122 	_ER(EPT_MISCONFIG,	 49)		\
123 	_ER(INVEPT,		 50)		\
124 	_ER(PREEMPTION_TIMER,	 52)		\
125 	_ER(WBINVD,		 54)		\
126 	_ER(XSETBV,		 55)		\
127 	_ER(APIC_WRITE,		 56)		\
128 	_ER(INVPCID,		 58)		\
129 	_ER(PML_FULL,		 62)		\
130 	_ER(XSAVES,		 63)		\
131 	_ER(XRSTORS,		 64)
132 
133 #define SVM_EXIT_REASONS \
134 	_ER(EXIT_READ_CR0,	0x000)		\
135 	_ER(EXIT_READ_CR3,	0x003)		\
136 	_ER(EXIT_READ_CR4,	0x004)		\
137 	_ER(EXIT_READ_CR8,	0x008)		\
138 	_ER(EXIT_WRITE_CR0,	0x010)		\
139 	_ER(EXIT_WRITE_CR3,	0x013)		\
140 	_ER(EXIT_WRITE_CR4,	0x014)		\
141 	_ER(EXIT_WRITE_CR8,	0x018)		\
142 	_ER(EXIT_READ_DR0,	0x020)		\
143 	_ER(EXIT_READ_DR1,	0x021)		\
144 	_ER(EXIT_READ_DR2,	0x022)		\
145 	_ER(EXIT_READ_DR3,	0x023)		\
146 	_ER(EXIT_READ_DR4,	0x024)		\
147 	_ER(EXIT_READ_DR5,	0x025)		\
148 	_ER(EXIT_READ_DR6,	0x026)		\
149 	_ER(EXIT_READ_DR7,	0x027)		\
150 	_ER(EXIT_WRITE_DR0,	0x030)		\
151 	_ER(EXIT_WRITE_DR1,	0x031)		\
152 	_ER(EXIT_WRITE_DR2,	0x032)		\
153 	_ER(EXIT_WRITE_DR3,	0x033)		\
154 	_ER(EXIT_WRITE_DR4,	0x034)		\
155 	_ER(EXIT_WRITE_DR5,	0x035)		\
156 	_ER(EXIT_WRITE_DR6,	0x036)		\
157 	_ER(EXIT_WRITE_DR7,	0x037)		\
158 	_ER(EXIT_EXCP_BASE,     0x040)		\
159 	_ER(EXIT_INTR,		0x060)		\
160 	_ER(EXIT_NMI,		0x061)		\
161 	_ER(EXIT_SMI,		0x062)		\
162 	_ER(EXIT_INIT,		0x063)		\
163 	_ER(EXIT_VINTR,		0x064)		\
164 	_ER(EXIT_CR0_SEL_WRITE,	0x065)		\
165 	_ER(EXIT_IDTR_READ,	0x066)		\
166 	_ER(EXIT_GDTR_READ,	0x067)		\
167 	_ER(EXIT_LDTR_READ,	0x068)		\
168 	_ER(EXIT_TR_READ,	0x069)		\
169 	_ER(EXIT_IDTR_WRITE,	0x06a)		\
170 	_ER(EXIT_GDTR_WRITE,	0x06b)		\
171 	_ER(EXIT_LDTR_WRITE,	0x06c)		\
172 	_ER(EXIT_TR_WRITE,	0x06d)		\
173 	_ER(EXIT_RDTSC,		0x06e)		\
174 	_ER(EXIT_RDPMC,		0x06f)		\
175 	_ER(EXIT_PUSHF,		0x070)		\
176 	_ER(EXIT_POPF,		0x071)		\
177 	_ER(EXIT_CPUID,		0x072)		\
178 	_ER(EXIT_RSM,		0x073)		\
179 	_ER(EXIT_IRET,		0x074)		\
180 	_ER(EXIT_SWINT,		0x075)		\
181 	_ER(EXIT_INVD,		0x076)		\
182 	_ER(EXIT_PAUSE,		0x077)		\
183 	_ER(EXIT_HLT,		0x078)		\
184 	_ER(EXIT_INVLPG,	0x079)		\
185 	_ER(EXIT_INVLPGA,	0x07a)		\
186 	_ER(EXIT_IOIO,		0x07b)		\
187 	_ER(EXIT_MSR,		0x07c)		\
188 	_ER(EXIT_TASK_SWITCH,	0x07d)		\
189 	_ER(EXIT_FERR_FREEZE,	0x07e)		\
190 	_ER(EXIT_SHUTDOWN,	0x07f)		\
191 	_ER(EXIT_VMRUN,		0x080)		\
192 	_ER(EXIT_VMMCALL,	0x081)		\
193 	_ER(EXIT_VMLOAD,	0x082)		\
194 	_ER(EXIT_VMSAVE,	0x083)		\
195 	_ER(EXIT_STGI,		0x084)		\
196 	_ER(EXIT_CLGI,		0x085)		\
197 	_ER(EXIT_SKINIT,	0x086)		\
198 	_ER(EXIT_RDTSCP,	0x087)		\
199 	_ER(EXIT_ICEBP,		0x088)		\
200 	_ER(EXIT_WBINVD,	0x089)		\
201 	_ER(EXIT_MONITOR,	0x08a)		\
202 	_ER(EXIT_MWAIT,		0x08b)		\
203 	_ER(EXIT_MWAIT_COND,	0x08c)		\
204 	_ER(EXIT_NPF,		0x400)		\
205 	_ER(EXIT_ERR,		-1)
206 
207 #define _ER(reason, val)	{ #reason, val },
208 struct str_values {
209 	const char	*str;
210 	int		val;
211 };
212 
213 static struct str_values vmx_exit_reasons[] = {
214 	VMX_EXIT_REASONS
215 	{ NULL, -1}
216 };
217 
218 static struct str_values svm_exit_reasons[] = {
219 	SVM_EXIT_REASONS
220 	{ NULL, -1}
221 };
222 
223 static struct isa_exit_reasons {
224 	unsigned isa;
225 	struct str_values *strings;
226 } isa_exit_reasons[] = {
227 	{ .isa = 1, .strings = vmx_exit_reasons },
228 	{ .isa = 2, .strings = svm_exit_reasons },
229 	{ }
230 };
231 
find_exit_reason(unsigned isa,int val)232 static const char *find_exit_reason(unsigned isa, int val)
233 {
234 	struct str_values *strings = NULL;
235 	int i;
236 
237 	for (i = 0; isa_exit_reasons[i].strings; ++i)
238 		if (isa_exit_reasons[i].isa == isa) {
239 			strings = isa_exit_reasons[i].strings;
240 			break;
241 		}
242 	if (!strings)
243 		return "UNKNOWN-ISA";
244 	for (i = 0; strings[i].val >= 0; i++)
245 		if (strings[i].val == val)
246 			break;
247 
248 	return strings[i].str;
249 }
250 
print_exit_reason(struct trace_seq * s,struct tep_record * record,struct tep_event * event,const char * field)251 static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
252 			     struct tep_event *event, const char *field)
253 {
254 	unsigned long long isa;
255 	unsigned long long val;
256 	const char *reason;
257 
258 	if (tep_get_field_val(s, event, field, record, &val, 1) < 0)
259 		return -1;
260 
261 	if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0)
262 		isa = 1;
263 
264 	reason = find_exit_reason(isa, val);
265 	if (reason)
266 		trace_seq_printf(s, "reason %s", reason);
267 	else
268 		trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
269 	return 0;
270 }
271 
kvm_exit_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)272 static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
273 			    struct tep_event *event, void *context)
274 {
275 	unsigned long long info1 = 0, info2 = 0;
276 
277 	if (print_exit_reason(s, record, event, "exit_reason") < 0)
278 		return -1;
279 
280 	tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
281 
282 	if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
283 	    && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
284 		trace_seq_printf(s, " info %llx %llx", info1, info2);
285 
286 	return 0;
287 }
288 
289 #define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
290 #define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
291 #define KVM_EMUL_INSN_F_CS_D   (1 << 2)
292 #define KVM_EMUL_INSN_F_CS_L   (1 << 3)
293 
kvm_emulate_insn_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)294 static int kvm_emulate_insn_handler(struct trace_seq *s,
295 				    struct tep_record *record,
296 				    struct tep_event *event, void *context)
297 {
298 	unsigned long long rip, csbase, len, flags, failed;
299 	int llen;
300 	uint8_t *insn;
301 	const char *disasm;
302 
303 	if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
304 		return -1;
305 
306 	if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
307 		return -1;
308 
309 	if (tep_get_field_val(s, event, "len", record, &len, 1) < 0)
310 		return -1;
311 
312 	if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0)
313 		return -1;
314 
315 	if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0)
316 		return -1;
317 
318 	insn = tep_get_field_raw(s, event, "insn", record, &llen, 1);
319 	if (!insn)
320 		return -1;
321 
322 	disasm = disassemble(insn, len, rip,
323 			     flags & KVM_EMUL_INSN_F_CR0_PE,
324 			     flags & KVM_EMUL_INSN_F_EFL_VM,
325 			     flags & KVM_EMUL_INSN_F_CS_D,
326 			     flags & KVM_EMUL_INSN_F_CS_L);
327 
328 	trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
329 			 failed ? " FAIL" : "");
330 	return 0;
331 }
332 
333 
kvm_nested_vmexit_inject_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)334 static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
335 					    struct tep_event *event, void *context)
336 {
337 	if (print_exit_reason(s, record, event, "exit_code") < 0)
338 		return -1;
339 
340 	tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
341 	tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
342 	tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
343 	tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
344 
345 	return 0;
346 }
347 
kvm_nested_vmexit_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)348 static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
349 				     struct tep_event *event, void *context)
350 {
351 	tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
352 
353 	return kvm_nested_vmexit_inject_handler(s, record, event, context);
354 }
355 
356 union kvm_mmu_page_role {
357 	unsigned word;
358 	struct {
359 		unsigned level:4;
360 		unsigned cr4_pae:1;
361 		unsigned quadrant:2;
362 		unsigned direct:1;
363 		unsigned access:3;
364 		unsigned invalid:1;
365 		unsigned nxe:1;
366 		unsigned cr0_wp:1;
367 		unsigned smep_and_not_wp:1;
368 		unsigned smap_and_not_wp:1;
369 		unsigned pad_for_nice_hex_output:8;
370 		unsigned smm:8;
371 	};
372 };
373 
kvm_mmu_print_role(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)374 static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
375 			      struct tep_event *event, void *context)
376 {
377 	unsigned long long val;
378 	static const char *access_str[] = {
379 		"---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
380 	};
381 	union kvm_mmu_page_role role;
382 
383 	if (tep_get_field_val(s, event, "role", record, &val, 1) < 0)
384 		return -1;
385 
386 	role.word = (int)val;
387 
388 	/*
389 	 * We can only use the structure if file is of the same
390 	 * endianness.
391 	 */
392 	if (tep_is_file_bigendian(event->tep) ==
393 	    tep_is_local_bigendian(event->tep)) {
394 
395 		trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
396 				 role.level,
397 				 role.quadrant,
398 				 role.direct ? " direct" : "",
399 				 access_str[role.access],
400 				 role.invalid ? " invalid" : "",
401 				 role.cr4_pae ? "" : "!",
402 				 role.nxe ? "" : "!",
403 				 role.cr0_wp ? "" : "!",
404 				 role.smep_and_not_wp ? " smep" : "",
405 				 role.smap_and_not_wp ? " smap" : "",
406 				 role.smm ? " smm" : "");
407 	} else
408 		trace_seq_printf(s, "WORD: %08x", role.word);
409 
410 	tep_print_num_field(s, " root %u ",  event,
411 			    "root_count", record, 1);
412 
413 	if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0)
414 		return -1;
415 
416 	trace_seq_printf(s, "%s%c",  val ? "unsync" : "sync", 0);
417 	return 0;
418 }
419 
kvm_mmu_get_page_handler(struct trace_seq * s,struct tep_record * record,struct tep_event * event,void * context)420 static int kvm_mmu_get_page_handler(struct trace_seq *s,
421 				    struct tep_record *record,
422 				    struct tep_event *event, void *context)
423 {
424 	unsigned long long val;
425 
426 	if (tep_get_field_val(s, event, "created", record, &val, 1) < 0)
427 		return -1;
428 
429 	trace_seq_printf(s, "%s ", val ? "new" : "existing");
430 
431 	if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0)
432 		return -1;
433 
434 	trace_seq_printf(s, "sp gfn %llx ", val);
435 	return kvm_mmu_print_role(s, record, event, context);
436 }
437 
438 #define PT_WRITABLE_SHIFT 1
439 #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
440 
441 static unsigned long long
process_is_writable_pte(struct trace_seq * s,unsigned long long * args)442 process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
443 {
444 	unsigned long pte = args[0];
445 	return pte & PT_WRITABLE_MASK;
446 }
447 
TEP_PLUGIN_LOADER(struct tep_handle * tep)448 int TEP_PLUGIN_LOADER(struct tep_handle *tep)
449 {
450 	init_disassembler();
451 
452 	tep_register_event_handler(tep, -1, "kvm", "kvm_exit",
453 				   kvm_exit_handler, NULL);
454 
455 	tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
456 				   kvm_emulate_insn_handler, NULL);
457 
458 	tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
459 				   kvm_nested_vmexit_handler, NULL);
460 
461 	tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
462 				   kvm_nested_vmexit_inject_handler, NULL);
463 
464 	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
465 				   kvm_mmu_get_page_handler, NULL);
466 
467 	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
468 				   kvm_mmu_print_role, NULL);
469 
470 	tep_register_event_handler(tep, -1,
471 				   "kvmmmu", "kvm_mmu_unsync_page",
472 				   kvm_mmu_print_role, NULL);
473 
474 	tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
475 				   kvm_mmu_print_role, NULL);
476 
477 	tep_register_event_handler(tep, -1, "kvmmmu",
478 			"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
479 			NULL);
480 
481 	tep_register_print_function(tep,
482 				    process_is_writable_pte,
483 				    TEP_FUNC_ARG_INT,
484 				    "is_writable_pte",
485 				    TEP_FUNC_ARG_LONG,
486 				    TEP_FUNC_ARG_VOID);
487 	return 0;
488 }
489 
TEP_PLUGIN_UNLOADER(struct tep_handle * tep)490 void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
491 {
492 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit",
493 				     kvm_exit_handler, NULL);
494 
495 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
496 				     kvm_emulate_insn_handler, NULL);
497 
498 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
499 				     kvm_nested_vmexit_handler, NULL);
500 
501 	tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
502 				     kvm_nested_vmexit_inject_handler, NULL);
503 
504 	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
505 				     kvm_mmu_get_page_handler, NULL);
506 
507 	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
508 				     kvm_mmu_print_role, NULL);
509 
510 	tep_unregister_event_handler(tep, -1,
511 				     "kvmmmu", "kvm_mmu_unsync_page",
512 				     kvm_mmu_print_role, NULL);
513 
514 	tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
515 				     kvm_mmu_print_role, NULL);
516 
517 	tep_unregister_event_handler(tep, -1, "kvmmmu",
518 			"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
519 			NULL);
520 
521 	tep_unregister_print_function(tep, process_is_writable_pte,
522 				      "is_writable_pte");
523 }
524