root/tools/lib/traceevent/plugins/plugin_kvm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_disassembler
  2. disassemble
  3. init_disassembler
  4. disassemble
  5. find_exit_reason
  6. print_exit_reason
  7. kvm_exit_handler
  8. kvm_emulate_insn_handler
  9. kvm_nested_vmexit_inject_handler
  10. kvm_nested_vmexit_handler
  11. kvm_mmu_print_role
  12. kvm_mmu_get_page_handler
  13. process_is_writable_pte
  14. TEP_PLUGIN_LOADER
  15. TEP_PLUGIN_UNLOADER

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

/* [<][>][^][v][top][bottom][index][help] */