aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-06-17 20:54:06 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-06-17 20:54:06 -0400
commiteae46f152079cd3603d02258b54504a9aa29f04c (patch)
tree9d698e13a4188e29af94a6375e577a04c57bb996
parente409040d894768d17fb630bdaa99f6ca3a0dd0a2 (diff)
trace-cmd: Add plugin_kvm.so
Added code to handle the kvm events that happened whil doing a trace on a 2.6.34 version of the kernel on my Intel box. This adds a kvm plugin to process some of the kvm events. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile2
-rw-r--r--plugin_kvm.c224
2 files changed, 225 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 662a306..d4067d6 100644
--- a/Makefile
+++ b/Makefile
@@ -265,7 +265,7 @@ TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \
265 trace-output.o trace-record.o 265 trace-output.o trace-record.o
266 266
267PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \ 267PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \
268 plugin_mac80211.o plugin_jbd2.o 268 plugin_mac80211.o plugin_jbd2.o plugin_kvm.o
269 269
270PLUGINS := $(PLUGIN_OBJS:.o=.so) 270PLUGINS := $(PLUGIN_OBJS:.o=.so)
271 271
diff --git a/plugin_kvm.c b/plugin_kvm.c
new file mode 100644
index 0000000..7217e85
--- /dev/null
+++ b/plugin_kvm.c
@@ -0,0 +1,224 @@
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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "parse-events.h"
26
27#define VMX_EXIT_REASONS \
28 _ER(EXCEPTION_NMI, 0) \
29 _ER(EXTERNAL_INTERRUPT, 1) \
30 _ER(TRIPLE_FAULT, 2) \
31 _ER(PENDING_INTERRUPT, 7) \
32 _ER(NMI_WINDOW, 8) \
33 _ER(TASK_SWITCH, 9) \
34 _ER(CPUID, 10) \
35 _ER(HLT, 12) \
36 _ER(INVLPG, 14) \
37 _ER(RDPMC, 15) \
38 _ER(RDTSC, 16) \
39 _ER(VMCALL, 18) \
40 _ER(VMCLEAR, 19) \
41 _ER(VMLAUNCH, 20) \
42 _ER(VMPTRLD, 21) \
43 _ER(VMPTRST, 22) \
44 _ER(VMREAD, 23) \
45 _ER(VMRESUME, 24) \
46 _ER(VMWRITE, 25) \
47 _ER(VMOFF, 26) \
48 _ER(VMON, 27) \
49 _ER(CR_ACCESS, 28) \
50 _ER(DR_ACCESS, 29) \
51 _ER(IO_INSTRUCTION, 30) \
52 _ER(MSR_READ, 31) \
53 _ER(MSR_WRITE, 32) \
54 _ER(MWAIT_INSTRUCTION, 36) \
55 _ER(MONITOR_INSTRUCTION,39) \
56 _ER(PAUSE_INSTRUCTION, 40) \
57 _ER(MCE_DURING_VMENTRY, 41) \
58 _ER(TPR_BELOW_THRESHOLD,43) \
59 _ER(APIC_ACCESS, 44) \
60 _ER(EPT_VIOLATION, 48) \
61 _ER(EPT_MISCONFIG, 49) \
62 _ER(WBINVD, 54)
63
64#define _ER(reason, val) { #reason, val },
65struct str_values {
66 const char *str;
67 int val;
68};
69
70static struct str_values vmx_exit_reasons[] = {
71 VMX_EXIT_REASONS
72 { NULL, -1}
73};
74
75static const char *find_vmx_reason(int val)
76{
77 int i;
78
79 for (i = 0; vmx_exit_reasons[i].val >= 0; i++)
80 if (vmx_exit_reasons[i].val == val)
81 break;
82 if (vmx_exit_reasons[i].str)
83 return vmx_exit_reasons[i].str;
84 return "UNKOWN";
85}
86
87static int kvm_exit_handler(struct trace_seq *s, struct record *record,
88 struct event_format *event, void *context)
89{
90 unsigned long long val;
91
92 if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0)
93 return -1;
94
95 trace_seq_printf(s, "reason %s", find_vmx_reason(val));
96
97 pevent_print_num_field(s, " rip %0xlx", event, "guest_rip", record, 1);
98
99 return 0;
100}
101
102static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct record *record,
103 struct event_format *event, void *context)
104{
105 unsigned long long val;
106
107 pevent_print_num_field(s, " rip %0x016llx", event, "rip", record, 1);
108
109 if (pevent_get_field_val(s, event, "exit_code", record, &val, 1) < 0)
110 return -1;
111
112 trace_seq_printf(s, "reason %s", find_vmx_reason(val));
113
114 pevent_print_num_field(s, " ext_inf1: %0x016llx", event, "exit_info1", record, 1);
115 pevent_print_num_field(s, " ext_inf2: %0x016llx", event, "exit_info2", record, 1);
116 pevent_print_num_field(s, " ext_int: %0x016llx", event, "exit_int_info", record, 1);
117 pevent_print_num_field(s, " ext_int_err: %0x016llx", event, "exit_int_info_err", record, 1);
118
119 return 0;
120}
121
122static int kvm_nested_vmexit_handler(struct trace_seq *s, struct record *record,
123 struct event_format *event, void *context)
124{
125 pevent_print_num_field(s, " rip %0x016llx", event, "rip", record, 1);
126
127 return kvm_nested_vmexit_inject_handler(s, record, event, context);
128}
129
130union kvm_mmu_page_role {
131 unsigned word;
132 struct {
133 unsigned glevels:4;
134 unsigned level:4;
135 unsigned quadrant:2;
136 unsigned pad_for_nice_hex_output:6;
137 unsigned direct:1;
138 unsigned access:3;
139 unsigned invalid:1;
140 unsigned cr4_pge:1;
141 unsigned nxe:1;
142 };
143};
144
145static int kvm_mmu_print_role(struct trace_seq *s, struct record *record,
146 struct event_format *event, void *context)
147{
148 unsigned long long val;
149 static const char *access_str[] =
150 { "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" };
151 union kvm_mmu_page_role role;
152
153 if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
154 return -1;
155
156 role.word = (int)val;
157
158 /*
159 * We can only use the structure if file is of the same
160 * endianess.
161 */
162 if (pevent_is_file_bigendian(event->pevent) ==
163 pevent_is_host_bigendian(event->pevent)) {
164
165 trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe",
166 role.level,
167 role.glevels,
168 role.quadrant,
169 role.direct ? " direct" : "",
170 access_str[role.access],
171 role.invalid ? " invalid" : "",
172 role.cr4_pge ? "" : "!",
173 role.nxe ? "" : "!");
174 } else
175 trace_seq_printf(s, "WORD: %08x", role.word);
176
177 pevent_print_num_field(s, " root %u", event,
178 "root_count", record, 1);
179
180 if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
181 return -1;
182
183 trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
184
185 return 0;
186}
187static int kvm_mmu_get_page_handler(struct trace_seq *s, struct record *record,
188 struct event_format *event, void *context)
189{
190 unsigned long long val;
191
192 if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
193 return -1;
194
195 trace_seq_printf(s, "sp gfn %llx ", val);
196
197 return kvm_mmu_print_role(s, record, event, context);
198}
199
200int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
201{
202 pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
203 kvm_exit_handler, NULL);
204
205 pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
206 kvm_nested_vmexit_handler, NULL);
207
208 pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
209 kvm_nested_vmexit_inject_handler, NULL);
210
211 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
212 kvm_mmu_get_page_handler, NULL);
213
214 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
215 kvm_mmu_print_role, NULL);
216
217 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_unsync_page",
218 kvm_mmu_print_role, NULL);
219
220 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
221 kvm_mmu_print_role, NULL);
222
223 return 0;
224}