linux/tools/lib/traceevent/plugin_kvm.c
<<
>>
Prefs
   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
  32static ud_t ud;
  33
  34static void init_disassembler(void)
  35{
  36        ud_init(&ud);
  37        ud_set_syntax(&ud, UD_SYN_ATT);
  38}
  39
  40static 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
  66static void init_disassembler(void)
  67{
  68}
  69
  70static 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 },
 208struct str_values {
 209        const char      *str;
 210        int             val;
 211};
 212
 213static struct str_values vmx_exit_reasons[] = {
 214        VMX_EXIT_REASONS
 215        { NULL, -1}
 216};
 217
 218static struct str_values svm_exit_reasons[] = {
 219        SVM_EXIT_REASONS
 220        { NULL, -1}
 221};
 222
 223static 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
 232static 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
 251static 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
 272static 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
 294static 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
 334static 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
 348static 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
 356union 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
 374static 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_file_bigendian(event->pevent) ==
 393            tep_is_host_bigendian(event->pevent)) {
 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
 420static 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
 441static unsigned long long
 442process_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
 448int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
 449{
 450        init_disassembler();
 451
 452        tep_register_event_handler(pevent, -1, "kvm", "kvm_exit",
 453                                   kvm_exit_handler, NULL);
 454
 455        tep_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
 456                                   kvm_emulate_insn_handler, NULL);
 457
 458        tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
 459                                   kvm_nested_vmexit_handler, NULL);
 460
 461        tep_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
 462                                   kvm_nested_vmexit_inject_handler, NULL);
 463
 464        tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
 465                                   kvm_mmu_get_page_handler, NULL);
 466
 467        tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
 468                                   kvm_mmu_print_role, NULL);
 469
 470        tep_register_event_handler(pevent, -1,
 471                                   "kvmmmu", "kvm_mmu_unsync_page",
 472                                   kvm_mmu_print_role, NULL);
 473
 474        tep_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
 475                                   kvm_mmu_print_role, NULL);
 476
 477        tep_register_event_handler(pevent, -1, "kvmmmu",
 478                        "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
 479                        NULL);
 480
 481        tep_register_print_function(pevent,
 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
 490void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
 491{
 492        tep_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
 493                                     kvm_exit_handler, NULL);
 494
 495        tep_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
 496                                     kvm_emulate_insn_handler, NULL);
 497
 498        tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
 499                                     kvm_nested_vmexit_handler, NULL);
 500
 501        tep_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
 502                                     kvm_nested_vmexit_inject_handler, NULL);
 503
 504        tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
 505                                     kvm_mmu_get_page_handler, NULL);
 506
 507        tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
 508                                     kvm_mmu_print_role, NULL);
 509
 510        tep_unregister_event_handler(pevent, -1,
 511                                     "kvmmmu", "kvm_mmu_unsync_page",
 512                                     kvm_mmu_print_role, NULL);
 513
 514        tep_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
 515                                     kvm_mmu_print_role, NULL);
 516
 517        tep_unregister_event_handler(pevent, -1, "kvmmmu",
 518                        "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
 519                        NULL);
 520
 521        tep_unregister_print_function(pevent, process_is_writable_pte,
 522                                      "is_writable_pte");
 523}
 524