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 | ||
