diff options
author | Avi Kivity <avi@redhat.com> | 2010-09-19 10:33:57 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-09-23 18:28:25 -0400 |
commit | 84d78973993710e0964aa801d5dcf1b5c4690216 (patch) | |
tree | 410a804a6937b18162f8870c817c223ba77159ef | |
parent | af41ffe13947069a95dad4738da0159ebd0fe84c (diff) |
plugin_kvm: Disassemble instructions for kvm_emulate_insn
Override kvm_emulate_insn formatting to use a disassembler to format
the emulated instruction. If a disassembler (udis86) is not available,
fall back to showing the instruction bytes in hex.
Signed-off-by: Avi Kivity <avi@redhat.com>
LKML-Reference: <1284906837-2431-1-git-send-email-avi@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | plugin_kvm.c | 111 |
2 files changed, 121 insertions, 1 deletions
@@ -74,6 +74,14 @@ ifeq ($(shell sh -c "python-config --includes > /dev/null 2>&1 && echo y"), y) | |||
74 | PYTHON_PY_INSTALL := event-viewer.install tracecmd.install tracecmdgui.install | 74 | PYTHON_PY_INSTALL := event-viewer.install tracecmd.install tracecmdgui.install |
75 | endif | 75 | endif |
76 | 76 | ||
77 | # $(call test-build, snippet, ret) -> ret if snippet compiles | ||
78 | # -> empty otherwise | ||
79 | test-build = $(if $(shell $(CC) -o /dev/null -c -x c - > /dev/null 2>&1 \ | ||
80 | <<<'$1' && echo y), $2) | ||
81 | |||
82 | # have udis86 disassembler library? | ||
83 | udis86-flags := $(call test-build,\#include <udis86.h>,-DHAVE_UDIS86 -ludis86) | ||
84 | |||
77 | ifeq ("$(origin O)", "command line") | 85 | ifeq ("$(origin O)", "command line") |
78 | BUILD_OUTPUT := $(O) | 86 | BUILD_OUTPUT := $(O) |
79 | endif | 87 | endif |
@@ -188,6 +196,7 @@ CFLAGS ?= -g -Wall | |||
188 | 196 | ||
189 | # Append required CFLAGS | 197 | # Append required CFLAGS |
190 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) | 198 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) |
199 | override CFLAGS += $(udis86-flags) | ||
191 | 200 | ||
192 | ifeq ($(VERBOSE),1) | 201 | ifeq ($(VERBOSE),1) |
193 | Q = | 202 | Q = |
@@ -228,7 +237,7 @@ do_compile_plugin_obj = \ | |||
228 | 237 | ||
229 | do_plugin_build = \ | 238 | do_plugin_build = \ |
230 | ($(print_plugin_build) \ | 239 | ($(print_plugin_build) \ |
231 | $(CC) -shared -nostartfiles -o $@ $<) | 240 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) |
232 | 241 | ||
233 | do_build_static_lib = \ | 242 | do_build_static_lib = \ |
234 | ($(print_static_lib_build) \ | 243 | ($(print_static_lib_build) \ |
diff --git a/plugin_kvm.c b/plugin_kvm.c index 7217e85..00cac5a 100644 --- a/plugin_kvm.c +++ b/plugin_kvm.c | |||
@@ -21,9 +21,68 @@ | |||
21 | #include <stdio.h> | 21 | #include <stdio.h> |
22 | #include <stdlib.h> | 22 | #include <stdlib.h> |
23 | #include <string.h> | 23 | #include <string.h> |
24 | #include <stdint.h> | ||
24 | 25 | ||
25 | #include "parse-events.h" | 26 | #include "parse-events.h" |
26 | 27 | ||
28 | #ifdef HAVE_UDIS86 | ||
29 | |||
30 | #include <udis86.h> | ||
31 | |||
32 | static ud_t ud; | ||
33 | |||
34 | static void init_disassembler(void) | ||
35 | { | ||
36 | ud_init(&ud); | ||
37 | ud_set_syntax(&ud, UD_SYN_ATT); | ||
38 | } | ||
39 | |||
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 | |||
66 | static void init_disassembler(void) | ||
67 | { | ||
68 | } | ||
69 | |||
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 | |||
27 | #define VMX_EXIT_REASONS \ | 86 | #define VMX_EXIT_REASONS \ |
28 | _ER(EXCEPTION_NMI, 0) \ | 87 | _ER(EXCEPTION_NMI, 0) \ |
29 | _ER(EXTERNAL_INTERRUPT, 1) \ | 88 | _ER(EXTERNAL_INTERRUPT, 1) \ |
@@ -99,6 +158,53 @@ static int kvm_exit_handler(struct trace_seq *s, struct record *record, | |||
99 | return 0; | 158 | return 0; |
100 | } | 159 | } |
101 | 160 | ||
161 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||
162 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||
163 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | ||
164 | #define KVM_EMUL_INSN_F_CS_L (1 << 3) | ||
165 | |||
166 | static int kvm_emulate_insn_handler(struct trace_seq *s, struct record *record, | ||
167 | struct event_format *event, void *context) | ||
168 | { | ||
169 | unsigned long long rip, csbase, len, flags, failed; | ||
170 | int llen; | ||
171 | uint8_t *insn; | ||
172 | const char *disasm; | ||
173 | |||
174 | if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) | ||
175 | return -1; | ||
176 | |||
177 | if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) | ||
178 | return -1; | ||
179 | |||
180 | if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) | ||
181 | return -1; | ||
182 | |||
183 | if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) | ||
184 | return -1; | ||
185 | |||
186 | if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) | ||
187 | return -1; | ||
188 | |||
189 | insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); | ||
190 | if (!insn) | ||
191 | return -1; | ||
192 | |||
193 | disasm = disassemble(insn, len, rip, | ||
194 | flags & KVM_EMUL_INSN_F_CR0_PE, | ||
195 | flags & KVM_EMUL_INSN_F_EFL_VM, | ||
196 | flags & KVM_EMUL_INSN_F_CS_D, | ||
197 | flags & KVM_EMUL_INSN_F_CS_L); | ||
198 | |||
199 | trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, | ||
200 | failed ? " FAIL" : ""); | ||
201 | |||
202 | pevent_print_num_field(s, " rip %0xlx", event, "guest_rip", record, 1); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | |||
102 | static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct record *record, | 208 | static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct record *record, |
103 | struct event_format *event, void *context) | 209 | struct event_format *event, void *context) |
104 | { | 210 | { |
@@ -199,9 +305,14 @@ static int kvm_mmu_get_page_handler(struct trace_seq *s, struct record *record, | |||
199 | 305 | ||
200 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | 306 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) |
201 | { | 307 | { |
308 | init_disassembler(); | ||
309 | |||
202 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", | 310 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", |
203 | kvm_exit_handler, NULL); | 311 | kvm_exit_handler, NULL); |
204 | 312 | ||
313 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
314 | kvm_emulate_insn_handler, NULL); | ||
315 | |||
205 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", | 316 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit", |
206 | kvm_nested_vmexit_handler, NULL); | 317 | kvm_nested_vmexit_handler, NULL); |
207 | 318 | ||