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
  27#ifdef HAVE_UDIS86
  28
  29#include <udis86.h>
  30
  31static ud_t ud;
  32
  33static void init_disassembler(void)
  34{
  35        ud_init(&ud);
  36        ud_set_syntax(&ud, UD_SYN_ATT);
  37}
  38
  39static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
  40                               int cr0_pe, int eflags_vm,
  41                               int cs_d, int cs_l)
  42{
  43        int mode;
  44
  45        if (!cr0_pe)
  46                mode = 16;
  47        else if (eflags_vm)
  48                mode = 16;
  49        else if (cs_l)
  50                mode = 64;
  51        else if (cs_d)
  52                mode = 32;
  53        else
  54                mode = 16;
  55
  56        ud_set_pc(&ud, rip);
  57        ud_set_mode(&ud, mode);
  58        ud_set_input_buffer(&ud, insn, len);
  59        ud_disassemble(&ud);
  60        return ud_insn_asm(&ud);
  61}
  62
  63#else
  64
  65static void init_disassembler(void)
  66{
  67}
  68
  69static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
  70                               int cr0_pe, int eflags_vm,
  71                               int cs_d, int cs_l)
  72{
  73        static char out[15*3+1];
  74        int i;
  75
  76        for (i = 0; i < len; ++i)
  77                sprintf(out + i * 3, "%02x ", insn[i]);
  78        out[len*3-1] = '\0';
  79        return out;
  80}
  81
  82#endif
  83
  84
  85#define VMX_EXIT_REASONS                        \
  86        _ER(EXCEPTION_NMI,       0)             \
  87        _ER(EXTERNAL_INTERRUPT,  1)             \
  88        _ER(TRIPLE_FAULT,        2)             \
  89        _ER(PENDING_INTERRUPT,   7)             \
  90        _ER(NMI_WINDOW,          8)             \
  91        _ER(TASK_SWITCH,         9)             \
  92        _ER(CPUID,               10)            \
  93        _ER(HLT,                 12)            \
  94        _ER(INVD,                13)            \
  95        _ER(INVLPG,              14)            \
  96        _ER(RDPMC,               15)            \
  97        _ER(RDTSC,               16)            \
  98        _ER(VMCALL,              18)            \
  99        _ER(VMCLEAR,             19)            \
 100        _ER(VMLAUNCH,            20)            \
 101        _ER(VMPTRLD,             21)            \
 102        _ER(VMPTRST,             22)            \
 103        _ER(VMREAD,              23)            \
 104        _ER(VMRESUME,            24)            \
 105        _ER(VMWRITE,             25)            \
 106        _ER(VMOFF,               26)            \
 107        _ER(VMON,                27)            \
 108        _ER(CR_ACCESS,           28)            \
 109        _ER(DR_ACCESS,           29)            \
 110        _ER(IO_INSTRUCTION,      30)            \
 111        _ER(MSR_READ,            31)            \
 112        _ER(MSR_WRITE,           32)            \
 113        _ER(MWAIT_INSTRUCTION,   36)            \
 114        _ER(MONITOR_INSTRUCTION, 39)            \
 115        _ER(PAUSE_INSTRUCTION,   40)            \
 116        _ER(MCE_DURING_VMENTRY,  41)            \
 117        _ER(TPR_BELOW_THRESHOLD, 43)            \
 118        _ER(APIC_ACCESS,         44)            \
 119        _ER(EOI_INDUCED,         45)            \
 120        _ER(EPT_VIOLATION,       48)            \
 121        _ER(EPT_MISCONFIG,       49)            \
 122        _ER(INVEPT,              50)            \
 123        _ER(PREEMPTION_TIMER,    52)            \
 124        _ER(WBINVD,              54)            \
 125        _ER(XSETBV,              55)            \
 126        _ER(APIC_WRITE,          56)            \
 127        _ER(INVPCID,             58)            \
 128        _ER(PML_FULL,            62)            \
 129        _ER(XSAVES,              63)            \
 130        _ER(XRSTORS,             64)
 131
 132#define SVM_EXIT_REASONS \
 133        _ER(EXIT_READ_CR0,      0x000)          \
 134        _ER(EXIT_READ_CR3,      0x003)          \
 135        _ER(EXIT_READ_CR4,      0x004)          \
 136        _ER(EXIT_READ_CR8,      0x008)          \
 137        _ER(EXIT_WRITE_CR0,     0x010)          \
 138        _ER(EXIT_WRITE_CR3,     0x013)          \
 139        _ER(EXIT_WRITE_CR4,     0x014)          \
 140        _ER(EXIT_WRITE_CR8,     0x018)          \
 141        _ER(EXIT_READ_DR0,      0x020)          \
 142        _ER(EXIT_READ_DR1,      0x021)          \
 143        _ER(EXIT_READ_DR2,      0x022)          \
 144        _ER(EXIT_READ_DR3,      0x023)          \
 145        _ER(EXIT_READ_DR4,      0x024)          \
 146        _ER(EXIT_READ_DR5,      0x025)          \
 147        _ER(EXIT_READ_DR6,      0x026)          \
 148        _ER(EXIT_READ_DR7,      0x027)          \
 149        _ER(EXIT_WRITE_DR0,     0x030)          \
 150        _ER(EXIT_WRITE_DR1,     0x031)          \
 151        _ER(EXIT_WRITE_DR2,     0x032)          \
 152        _ER(EXIT_WRITE_DR3,     0x033)          \
 153        _ER(EXIT_WRITE_DR4,     0x034)          \
 154        _ER(EXIT_WRITE_DR5,     0x035)          \
 155        _ER(EXIT_WRITE_DR6,     0x036)          \
 156        _ER(EXIT_WRITE_DR7,     0x037)          \
 157        _ER(EXIT_EXCP_BASE,     0x040)          \
 158        _ER(EXIT_INTR,          0x060)          \
 159        _ER(EXIT_NMI,           0x061)          \
 160        _ER(EXIT_SMI,           0x062)          \
 161        _ER(EXIT_INIT,          0x063)          \
 162        _ER(EXIT_VINTR,         0x064)          \
 163        _ER(EXIT_CR0_SEL_WRITE, 0x065)          \
 164        _ER(EXIT_IDTR_READ,     0x066)          \
 165        _ER(EXIT_GDTR_READ,     0x067)          \
 166        _ER(EXIT_LDTR_READ,     0x068)          \
 167        _ER(EXIT_TR_READ,       0x069)          \
 168        _ER(EXIT_IDTR_WRITE,    0x06a)          \
 169        _ER(EXIT_GDTR_WRITE,    0x06b)          \
 170        _ER(EXIT_LDTR_WRITE,    0x06c)          \
 171        _ER(EXIT_TR_WRITE,      0x06d)          \
 172        _ER(EXIT_RDTSC,         0x06e)          \
 173        _ER(EXIT_RDPMC,         0x06f)          \
 174        _ER(EXIT_PUSHF,         0x070)          \
 175        _ER(EXIT_POPF,          0x071)          \
 176        _ER(EXIT_CPUID,         0x072)          \
 177        _ER(EXIT_RSM,           0x073)          \
 178        _ER(EXIT_IRET,          0x074)          \
 179        _ER(EXIT_SWINT,         0x075)          \
 180        _ER(EXIT_INVD,          0x076)          \
 181        _ER(EXIT_PAUSE,         0x077)          \
 182        _ER(EXIT_HLT,           0x078)          \
 183        _ER(EXIT_INVLPG,        0x079)          \
 184        _ER(EXIT_INVLPGA,       0x07a)          \
 185        _ER(EXIT_IOIO,          0x07b)          \
 186        _ER(EXIT_MSR,           0x07c)          \
 187        _ER(EXIT_TASK_SWITCH,   0x07d)          \
 188        _ER(EXIT_FERR_FREEZE,   0x07e)          \
 189        _ER(EXIT_SHUTDOWN,      0x07f)          \
 190        _ER(EXIT_VMRUN,         0x080)          \
 191        _ER(EXIT_VMMCALL,       0x081)          \
 192        _ER(EXIT_VMLOAD,        0x082)          \
 193        _ER(EXIT_VMSAVE,        0x083)          \
 194        _ER(EXIT_STGI,          0x084)          \
 195        _ER(EXIT_CLGI,          0x085)          \
 196        _ER(EXIT_SKINIT,        0x086)          \
 197        _ER(EXIT_RDTSCP,        0x087)          \
 198        _ER(EXIT_ICEBP,         0x088)          \
 199        _ER(EXIT_WBINVD,        0x089)          \
 200        _ER(EXIT_MONITOR,       0x08a)          \
 201        _ER(EXIT_MWAIT,         0x08b)          \
 202        _ER(EXIT_MWAIT_COND,    0x08c)          \
 203        _ER(EXIT_NPF,           0x400)          \
 204        _ER(EXIT_ERR,           -1)
 205
 206#define _ER(reason, val)        { #reason, val },
 207struct str_values {
 208        const char      *str;
 209        int             val;
 210};
 211
 212static struct str_values vmx_exit_reasons[] = {
 213        VMX_EXIT_REASONS
 214        { NULL, -1}
 215};
 216
 217static struct str_values svm_exit_reasons[] = {
 218        SVM_EXIT_REASONS
 219        { NULL, -1}
 220};
 221
 222static struct isa_exit_reasons {
 223        unsigned isa;
 224        struct str_values *strings;
 225} isa_exit_reasons[] = {
 226        { .isa = 1, .strings = vmx_exit_reasons },
 227        { .isa = 2, .strings = svm_exit_reasons },
 228        { }
 229};
 230
 231static const char *find_exit_reason(unsigned isa, int val)
 232{
 233        struct str_values *strings = NULL;
 234        int i;
 235
 236        for (i = 0; isa_exit_reasons[i].strings; ++i)
 237                if (isa_exit_reasons[i].isa == isa) {
 238                        strings = isa_exit_reasons[i].strings;
 239                        break;
 240                }
 241        if (!strings)
 242                return "UNKNOWN-ISA";
 243        for (i = 0; strings[i].val >= 0; i++)
 244                if (strings[i].val == val)
 245                        break;
 246
 247        return strings[i].str;
 248}
 249
 250static int print_exit_reason(struct trace_seq *s, struct pevent_record *record,
 251                             struct event_format *event, const char *field)
 252{
 253        unsigned long long isa;
 254        unsigned long long val;
 255        const char *reason;
 256
 257        if (pevent_get_field_val(s, event, field, record, &val, 1) < 0)
 258                return -1;
 259
 260        if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
 261                isa = 1;
 262
 263        reason = find_exit_reason(isa, val);
 264        if (reason)
 265                trace_seq_printf(s, "reason %s", reason);
 266        else
 267                trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
 268        return 0;
 269}
 270
 271static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
 272                            struct event_format *event, void *context)
 273{
 274        unsigned long long info1 = 0, info2 = 0;
 275
 276        if (print_exit_reason(s, record, event, "exit_reason") < 0)
 277                return -1;
 278
 279        pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
 280
 281        if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
 282            && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
 283                trace_seq_printf(s, " info %llx %llx", info1, info2);
 284
 285        return 0;
 286}
 287
 288#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
 289#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
 290#define KVM_EMUL_INSN_F_CS_D   (1 << 2)
 291#define KVM_EMUL_INSN_F_CS_L   (1 << 3)
 292
 293static int kvm_emulate_insn_handler(struct trace_seq *s,
 294                                    struct pevent_record *record,
 295                                    struct event_format *event, void *context)
 296{
 297        unsigned long long rip, csbase, len, flags, failed;
 298        int llen;
 299        uint8_t *insn;
 300        const char *disasm;
 301
 302        if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
 303                return -1;
 304
 305        if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
 306                return -1;
 307
 308        if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
 309                return -1;
 310
 311        if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
 312                return -1;
 313
 314        if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
 315                return -1;
 316
 317        insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
 318        if (!insn)
 319                return -1;
 320
 321        disasm = disassemble(insn, len, rip,
 322                             flags & KVM_EMUL_INSN_F_CR0_PE,
 323                             flags & KVM_EMUL_INSN_F_EFL_VM,
 324                             flags & KVM_EMUL_INSN_F_CS_D,
 325                             flags & KVM_EMUL_INSN_F_CS_L);
 326
 327        trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
 328                         failed ? " FAIL" : "");
 329        return 0;
 330}
 331
 332
 333static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct pevent_record *record,
 334                                            struct event_format *event, void *context)
 335{
 336        if (print_exit_reason(s, record, event, "exit_code") < 0)
 337                return -1;
 338
 339        pevent_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
 340        pevent_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
 341        pevent_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
 342        pevent_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
 343
 344        return 0;
 345}
 346
 347static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record *record,
 348                                     struct event_format *event, void *context)
 349{
 350        pevent_print_num_field(s, "rip %llx ", event, "rip", record, 1);
 351
 352        return kvm_nested_vmexit_inject_handler(s, record, event, context);
 353}
 354
 355union kvm_mmu_page_role {
 356        unsigned word;
 357        struct {
 358                unsigned level:4;
 359                unsigned cr4_pae:1;
 360                unsigned quadrant:2;
 361                unsigned direct:1;
 362                unsigned access:3;
 363                unsigned invalid:1;
 364                unsigned nxe:1;
 365                unsigned cr0_wp:1;
 366                unsigned smep_and_not_wp:1;
 367                unsigned smap_and_not_wp:1;
 368                unsigned pad_for_nice_hex_output:8;
 369                unsigned smm:8;
 370        };
 371};
 372
 373static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
 374                              struct event_format *event, void *context)
 375{
 376        unsigned long long val;
 377        static const char *access_str[] = {
 378                "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
 379        };
 380        union kvm_mmu_page_role role;
 381
 382        if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
 383                return -1;
 384
 385        role.word = (int)val;
 386
 387        /*
 388         * We can only use the structure if file is of the same
 389         * endianess.
 390         */
 391        if (pevent_is_file_bigendian(event->pevent) ==
 392            pevent_is_host_bigendian(event->pevent)) {
 393
 394                trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
 395                                 role.level,
 396                                 role.quadrant,
 397                                 role.direct ? " direct" : "",
 398                                 access_str[role.access],
 399                                 role.invalid ? " invalid" : "",
 400                                 role.cr4_pae ? "" : "!",
 401                                 role.nxe ? "" : "!",
 402                                 role.cr0_wp ? "" : "!",
 403                                 role.smep_and_not_wp ? " smep" : "",
 404                                 role.smap_and_not_wp ? " smap" : "",
 405                                 role.smm ? " smm" : "");
 406        } else
 407                trace_seq_printf(s, "WORD: %08x", role.word);
 408
 409        pevent_print_num_field(s, " root %u ",  event,
 410                               "root_count", record, 1);
 411
 412        if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
 413                return -1;
 414
 415        trace_seq_printf(s, "%s%c",  val ? "unsync" : "sync", 0);
 416        return 0;
 417}
 418
 419static int kvm_mmu_get_page_handler(struct trace_seq *s,
 420                                    struct pevent_record *record,
 421                                    struct event_format *event, void *context)
 422{
 423        unsigned long long val;
 424
 425        if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
 426                return -1;
 427
 428        trace_seq_printf(s, "%s ", val ? "new" : "existing");
 429
 430        if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
 431                return -1;
 432
 433        trace_seq_printf(s, "sp gfn %llx ", val);
 434        return kvm_mmu_print_role(s, record, event, context);
 435}
 436
 437#define PT_WRITABLE_SHIFT 1
 438#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
 439
 440static unsigned long long
 441process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
 442{
 443        unsigned long pte = args[0];
 444        return pte & PT_WRITABLE_MASK;
 445}
 446
 447int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
 448{
 449        init_disassembler();
 450
 451        pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
 452                                      kvm_exit_handler, NULL);
 453
 454        pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
 455                                      kvm_emulate_insn_handler, NULL);
 456
 457        pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
 458                                      kvm_nested_vmexit_handler, NULL);
 459
 460        pevent_register_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
 461                                      kvm_nested_vmexit_inject_handler, NULL);
 462
 463        pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
 464                                      kvm_mmu_get_page_handler, NULL);
 465
 466        pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
 467                                      kvm_mmu_print_role, NULL);
 468
 469        pevent_register_event_handler(pevent, -1,
 470                                      "kvmmmu", "kvm_mmu_unsync_page",
 471                                      kvm_mmu_print_role, NULL);
 472
 473        pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
 474                                      kvm_mmu_print_role, NULL);
 475
 476        pevent_register_event_handler(pevent, -1, "kvmmmu",
 477                        "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
 478                        NULL);
 479
 480        pevent_register_print_function(pevent,
 481                                       process_is_writable_pte,
 482                                       PEVENT_FUNC_ARG_INT,
 483                                       "is_writable_pte",
 484                                       PEVENT_FUNC_ARG_LONG,
 485                                       PEVENT_FUNC_ARG_VOID);
 486        return 0;
 487}
 488
 489void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
 490{
 491        pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
 492                                        kvm_exit_handler, NULL);
 493
 494        pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
 495                                        kvm_emulate_insn_handler, NULL);
 496
 497        pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit",
 498                                        kvm_nested_vmexit_handler, NULL);
 499
 500        pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_nested_vmexit_inject",
 501                                        kvm_nested_vmexit_inject_handler, NULL);
 502
 503        pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
 504                                        kvm_mmu_get_page_handler, NULL);
 505
 506        pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
 507                                        kvm_mmu_print_role, NULL);
 508
 509        pevent_unregister_event_handler(pevent, -1,
 510                                        "kvmmmu", "kvm_mmu_unsync_page",
 511                                        kvm_mmu_print_role, NULL);
 512
 513        pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
 514                                        kvm_mmu_print_role, NULL);
 515
 516        pevent_unregister_event_handler(pevent, -1, "kvmmmu",
 517                        "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
 518                        NULL);
 519
 520        pevent_unregister_print_function(pevent, process_is_writable_pte,
 521                                         "is_writable_pte");
 522}
 523