Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1
0002 /*
0003  * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
0004  */
0005 #include <stdio.h>
0006 #include <stdlib.h>
0007 #include <string.h>
0008 #include <stdint.h>
0009 
0010 #include "event-parse.h"
0011 #include "trace-seq.h"
0012 
0013 #ifdef HAVE_UDIS86
0014 
0015 #include <udis86.h>
0016 
0017 static ud_t ud;
0018 
0019 static void init_disassembler(void)
0020 {
0021     ud_init(&ud);
0022     ud_set_syntax(&ud, UD_SYN_ATT);
0023 }
0024 
0025 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
0026                    int cr0_pe, int eflags_vm,
0027                    int cs_d, int cs_l)
0028 {
0029     int mode;
0030 
0031     if (!cr0_pe)
0032         mode = 16;
0033     else if (eflags_vm)
0034         mode = 16;
0035     else if (cs_l)
0036         mode = 64;
0037     else if (cs_d)
0038         mode = 32;
0039     else
0040         mode = 16;
0041 
0042     ud_set_pc(&ud, rip);
0043     ud_set_mode(&ud, mode);
0044     ud_set_input_buffer(&ud, insn, len);
0045     ud_disassemble(&ud);
0046     return ud_insn_asm(&ud);
0047 }
0048 
0049 #else
0050 
0051 static void init_disassembler(void)
0052 {
0053 }
0054 
0055 static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
0056                    int cr0_pe, int eflags_vm,
0057                    int cs_d, int cs_l)
0058 {
0059     static char out[15*3+1];
0060     int i;
0061 
0062     for (i = 0; i < len; ++i)
0063         sprintf(out + i * 3, "%02x ", insn[i]);
0064     out[len*3-1] = '\0';
0065     return out;
0066 }
0067 
0068 #endif
0069 
0070 
0071 #define VMX_EXIT_REASONS            \
0072     _ER(EXCEPTION_NMI,   0)     \
0073     _ER(EXTERNAL_INTERRUPT,  1)     \
0074     _ER(TRIPLE_FAULT,    2)     \
0075     _ER(PENDING_INTERRUPT,   7)     \
0076     _ER(NMI_WINDOW,      8)     \
0077     _ER(TASK_SWITCH,     9)     \
0078     _ER(CPUID,       10)        \
0079     _ER(HLT,         12)        \
0080     _ER(INVD,        13)        \
0081     _ER(INVLPG,      14)        \
0082     _ER(RDPMC,       15)        \
0083     _ER(RDTSC,       16)        \
0084     _ER(VMCALL,      18)        \
0085     _ER(VMCLEAR,         19)        \
0086     _ER(VMLAUNCH,        20)        \
0087     _ER(VMPTRLD,         21)        \
0088     _ER(VMPTRST,         22)        \
0089     _ER(VMREAD,      23)        \
0090     _ER(VMRESUME,        24)        \
0091     _ER(VMWRITE,         25)        \
0092     _ER(VMOFF,       26)        \
0093     _ER(VMON,        27)        \
0094     _ER(CR_ACCESS,       28)        \
0095     _ER(DR_ACCESS,       29)        \
0096     _ER(IO_INSTRUCTION,  30)        \
0097     _ER(MSR_READ,        31)        \
0098     _ER(MSR_WRITE,       32)        \
0099     _ER(MWAIT_INSTRUCTION,   36)        \
0100     _ER(MONITOR_INSTRUCTION, 39)        \
0101     _ER(PAUSE_INSTRUCTION,   40)        \
0102     _ER(MCE_DURING_VMENTRY,  41)        \
0103     _ER(TPR_BELOW_THRESHOLD, 43)        \
0104     _ER(APIC_ACCESS,     44)        \
0105     _ER(EOI_INDUCED,     45)        \
0106     _ER(EPT_VIOLATION,   48)        \
0107     _ER(EPT_MISCONFIG,   49)        \
0108     _ER(INVEPT,      50)        \
0109     _ER(PREEMPTION_TIMER,    52)        \
0110     _ER(WBINVD,      54)        \
0111     _ER(XSETBV,      55)        \
0112     _ER(APIC_WRITE,      56)        \
0113     _ER(INVPCID,         58)        \
0114     _ER(PML_FULL,        62)        \
0115     _ER(XSAVES,      63)        \
0116     _ER(XRSTORS,         64)
0117 
0118 #define SVM_EXIT_REASONS \
0119     _ER(EXIT_READ_CR0,  0x000)      \
0120     _ER(EXIT_READ_CR3,  0x003)      \
0121     _ER(EXIT_READ_CR4,  0x004)      \
0122     _ER(EXIT_READ_CR8,  0x008)      \
0123     _ER(EXIT_WRITE_CR0, 0x010)      \
0124     _ER(EXIT_WRITE_CR3, 0x013)      \
0125     _ER(EXIT_WRITE_CR4, 0x014)      \
0126     _ER(EXIT_WRITE_CR8, 0x018)      \
0127     _ER(EXIT_READ_DR0,  0x020)      \
0128     _ER(EXIT_READ_DR1,  0x021)      \
0129     _ER(EXIT_READ_DR2,  0x022)      \
0130     _ER(EXIT_READ_DR3,  0x023)      \
0131     _ER(EXIT_READ_DR4,  0x024)      \
0132     _ER(EXIT_READ_DR5,  0x025)      \
0133     _ER(EXIT_READ_DR6,  0x026)      \
0134     _ER(EXIT_READ_DR7,  0x027)      \
0135     _ER(EXIT_WRITE_DR0, 0x030)      \
0136     _ER(EXIT_WRITE_DR1, 0x031)      \
0137     _ER(EXIT_WRITE_DR2, 0x032)      \
0138     _ER(EXIT_WRITE_DR3, 0x033)      \
0139     _ER(EXIT_WRITE_DR4, 0x034)      \
0140     _ER(EXIT_WRITE_DR5, 0x035)      \
0141     _ER(EXIT_WRITE_DR6, 0x036)      \
0142     _ER(EXIT_WRITE_DR7, 0x037)      \
0143     _ER(EXIT_EXCP_DE,   0x040)      \
0144     _ER(EXIT_EXCP_DB,   0x041)      \
0145     _ER(EXIT_EXCP_BP,   0x043)      \
0146     _ER(EXIT_EXCP_OF,   0x044)      \
0147     _ER(EXIT_EXCP_BR,   0x045)      \
0148     _ER(EXIT_EXCP_UD,   0x046)      \
0149     _ER(EXIT_EXCP_NM,   0x047)      \
0150     _ER(EXIT_EXCP_DF,   0x048)      \
0151     _ER(EXIT_EXCP_TS,   0x04a)      \
0152     _ER(EXIT_EXCP_NP,   0x04b)      \
0153     _ER(EXIT_EXCP_SS,   0x04c)      \
0154     _ER(EXIT_EXCP_GP,   0x04d)      \
0155     _ER(EXIT_EXCP_PF,   0x04e)      \
0156     _ER(EXIT_EXCP_MF,   0x050)      \
0157     _ER(EXIT_EXCP_AC,   0x051)      \
0158     _ER(EXIT_EXCP_MC,   0x052)      \
0159     _ER(EXIT_EXCP_XF,   0x053)      \
0160     _ER(EXIT_INTR,      0x060)      \
0161     _ER(EXIT_NMI,       0x061)      \
0162     _ER(EXIT_SMI,       0x062)      \
0163     _ER(EXIT_INIT,      0x063)      \
0164     _ER(EXIT_VINTR,     0x064)      \
0165     _ER(EXIT_CR0_SEL_WRITE, 0x065)      \
0166     _ER(EXIT_IDTR_READ, 0x066)      \
0167     _ER(EXIT_GDTR_READ, 0x067)      \
0168     _ER(EXIT_LDTR_READ, 0x068)      \
0169     _ER(EXIT_TR_READ,   0x069)      \
0170     _ER(EXIT_IDTR_WRITE,    0x06a)      \
0171     _ER(EXIT_GDTR_WRITE,    0x06b)      \
0172     _ER(EXIT_LDTR_WRITE,    0x06c)      \
0173     _ER(EXIT_TR_WRITE,  0x06d)      \
0174     _ER(EXIT_RDTSC,     0x06e)      \
0175     _ER(EXIT_RDPMC,     0x06f)      \
0176     _ER(EXIT_PUSHF,     0x070)      \
0177     _ER(EXIT_POPF,      0x071)      \
0178     _ER(EXIT_CPUID,     0x072)      \
0179     _ER(EXIT_RSM,       0x073)      \
0180     _ER(EXIT_IRET,      0x074)      \
0181     _ER(EXIT_SWINT,     0x075)      \
0182     _ER(EXIT_INVD,      0x076)      \
0183     _ER(EXIT_PAUSE,     0x077)      \
0184     _ER(EXIT_HLT,       0x078)      \
0185     _ER(EXIT_INVLPG,    0x079)      \
0186     _ER(EXIT_INVLPGA,   0x07a)      \
0187     _ER(EXIT_IOIO,      0x07b)      \
0188     _ER(EXIT_MSR,       0x07c)      \
0189     _ER(EXIT_TASK_SWITCH,   0x07d)      \
0190     _ER(EXIT_FERR_FREEZE,   0x07e)      \
0191     _ER(EXIT_SHUTDOWN,  0x07f)      \
0192     _ER(EXIT_VMRUN,     0x080)      \
0193     _ER(EXIT_VMMCALL,   0x081)      \
0194     _ER(EXIT_VMLOAD,    0x082)      \
0195     _ER(EXIT_VMSAVE,    0x083)      \
0196     _ER(EXIT_STGI,      0x084)      \
0197     _ER(EXIT_CLGI,      0x085)      \
0198     _ER(EXIT_SKINIT,    0x086)      \
0199     _ER(EXIT_RDTSCP,    0x087)      \
0200     _ER(EXIT_ICEBP,     0x088)      \
0201     _ER(EXIT_WBINVD,    0x089)      \
0202     _ER(EXIT_MONITOR,   0x08a)      \
0203     _ER(EXIT_MWAIT,     0x08b)      \
0204     _ER(EXIT_MWAIT_COND,    0x08c)      \
0205     _ER(EXIT_XSETBV,    0x08d)      \
0206     _ER(EXIT_NPF,       0x400)      \
0207     _ER(EXIT_AVIC_INCOMPLETE_IPI,       0x401)  \
0208     _ER(EXIT_AVIC_UNACCELERATED_ACCESS, 0x402)  \
0209     _ER(EXIT_ERR,       -1)
0210 
0211 #define _ER(reason, val)    { #reason, val },
0212 struct str_values {
0213     const char  *str;
0214     int     val;
0215 };
0216 
0217 static struct str_values vmx_exit_reasons[] = {
0218     VMX_EXIT_REASONS
0219     { NULL, -1}
0220 };
0221 
0222 static struct str_values svm_exit_reasons[] = {
0223     SVM_EXIT_REASONS
0224     { NULL, -1}
0225 };
0226 
0227 static struct isa_exit_reasons {
0228     unsigned isa;
0229     struct str_values *strings;
0230 } isa_exit_reasons[] = {
0231     { .isa = 1, .strings = vmx_exit_reasons },
0232     { .isa = 2, .strings = svm_exit_reasons },
0233     { }
0234 };
0235 
0236 static const char *find_exit_reason(unsigned isa, int val)
0237 {
0238     struct str_values *strings = NULL;
0239     int i;
0240 
0241     for (i = 0; isa_exit_reasons[i].strings; ++i)
0242         if (isa_exit_reasons[i].isa == isa) {
0243             strings = isa_exit_reasons[i].strings;
0244             break;
0245         }
0246     if (!strings)
0247         return "UNKNOWN-ISA";
0248     for (i = 0; strings[i].str; i++)
0249         if (strings[i].val == val)
0250             break;
0251 
0252     return strings[i].str;
0253 }
0254 
0255 static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
0256                  struct tep_event *event, const char *field)
0257 {
0258     unsigned long long isa;
0259     unsigned long long val;
0260     const char *reason;
0261 
0262     if (tep_get_field_val(s, event, field, record, &val, 1) < 0)
0263         return -1;
0264 
0265     if (tep_get_field_val(s, event, "isa", record, &isa, 0) < 0)
0266         isa = 1;
0267 
0268     reason = find_exit_reason(isa, val);
0269     if (reason)
0270         trace_seq_printf(s, "reason %s", reason);
0271     else
0272         trace_seq_printf(s, "reason UNKNOWN (%llu)", val);
0273     return 0;
0274 }
0275 
0276 static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
0277                 struct tep_event *event, void *context)
0278 {
0279     unsigned long long info1 = 0, info2 = 0;
0280 
0281     if (print_exit_reason(s, record, event, "exit_reason") < 0)
0282         return -1;
0283 
0284     tep_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
0285 
0286     if (tep_get_field_val(s, event, "info1", record, &info1, 0) >= 0
0287         && tep_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
0288         trace_seq_printf(s, " info %llx %llx", info1, info2);
0289 
0290     return 0;
0291 }
0292 
0293 #define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
0294 #define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
0295 #define KVM_EMUL_INSN_F_CS_D   (1 << 2)
0296 #define KVM_EMUL_INSN_F_CS_L   (1 << 3)
0297 
0298 static int kvm_emulate_insn_handler(struct trace_seq *s,
0299                     struct tep_record *record,
0300                     struct tep_event *event, void *context)
0301 {
0302     unsigned long long rip, csbase, len, flags, failed;
0303     int llen;
0304     uint8_t *insn;
0305     const char *disasm;
0306 
0307     if (tep_get_field_val(s, event, "rip", record, &rip, 1) < 0)
0308         return -1;
0309 
0310     if (tep_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
0311         return -1;
0312 
0313     if (tep_get_field_val(s, event, "len", record, &len, 1) < 0)
0314         return -1;
0315 
0316     if (tep_get_field_val(s, event, "flags", record, &flags, 1) < 0)
0317         return -1;
0318 
0319     if (tep_get_field_val(s, event, "failed", record, &failed, 1) < 0)
0320         return -1;
0321 
0322     insn = tep_get_field_raw(s, event, "insn", record, &llen, 1);
0323     if (!insn)
0324         return -1;
0325 
0326     disasm = disassemble(insn, len, rip,
0327                  flags & KVM_EMUL_INSN_F_CR0_PE,
0328                  flags & KVM_EMUL_INSN_F_EFL_VM,
0329                  flags & KVM_EMUL_INSN_F_CS_D,
0330                  flags & KVM_EMUL_INSN_F_CS_L);
0331 
0332     trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
0333              failed ? " FAIL" : "");
0334     return 0;
0335 }
0336 
0337 
0338 static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
0339                         struct tep_event *event, void *context)
0340 {
0341     if (print_exit_reason(s, record, event, "exit_code") < 0)
0342         return -1;
0343 
0344     tep_print_num_field(s, " info1 %llx", event, "exit_info1", record, 1);
0345     tep_print_num_field(s, " info2 %llx", event, "exit_info2", record, 1);
0346     tep_print_num_field(s, " int_info %llx", event, "exit_int_info", record, 1);
0347     tep_print_num_field(s, " int_info_err %llx", event, "exit_int_info_err", record, 1);
0348 
0349     return 0;
0350 }
0351 
0352 static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
0353                      struct tep_event *event, void *context)
0354 {
0355     tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
0356 
0357     return kvm_nested_vmexit_inject_handler(s, record, event, context);
0358 }
0359 
0360 union kvm_mmu_page_role {
0361     unsigned word;
0362     struct {
0363         unsigned level:4;
0364         unsigned cr4_pae:1;
0365         unsigned quadrant:2;
0366         unsigned direct:1;
0367         unsigned access:3;
0368         unsigned invalid:1;
0369         unsigned efer_nx:1;
0370         unsigned cr0_wp:1;
0371         unsigned smep_and_not_wp:1;
0372         unsigned smap_and_not_wp:1;
0373         unsigned pad_for_nice_hex_output:8;
0374         unsigned smm:8;
0375     };
0376 };
0377 
0378 static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
0379                   struct tep_event *event, void *context)
0380 {
0381     unsigned long long val;
0382     static const char *access_str[] = {
0383         "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
0384     };
0385     union kvm_mmu_page_role role;
0386 
0387     if (tep_get_field_val(s, event, "role", record, &val, 1) < 0)
0388         return -1;
0389 
0390     role.word = (int)val;
0391 
0392     /*
0393      * We can only use the structure if file is of the same
0394      * endianness.
0395      */
0396     if (tep_is_file_bigendian(event->tep) ==
0397         tep_is_local_bigendian(event->tep)) {
0398 
0399         trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s",
0400                  role.level,
0401                  role.quadrant,
0402                  role.direct ? " direct" : "",
0403                  access_str[role.access],
0404                  role.invalid ? " invalid" : "",
0405                  role.cr4_pae ? "" : "!",
0406                  role.efer_nx ? "" : "!",
0407                  role.cr0_wp ? "" : "!",
0408                  role.smep_and_not_wp ? " smep" : "",
0409                  role.smap_and_not_wp ? " smap" : "",
0410                  role.smm ? " smm" : "");
0411     } else
0412         trace_seq_printf(s, "WORD: %08x", role.word);
0413 
0414     tep_print_num_field(s, " root %u ",  event,
0415                 "root_count", record, 1);
0416 
0417     if (tep_get_field_val(s, event, "unsync", record, &val, 1) < 0)
0418         return -1;
0419 
0420     trace_seq_printf(s, "%s%c",  val ? "unsync" : "sync", 0);
0421     return 0;
0422 }
0423 
0424 static int kvm_mmu_get_page_handler(struct trace_seq *s,
0425                     struct tep_record *record,
0426                     struct tep_event *event, void *context)
0427 {
0428     unsigned long long val;
0429 
0430     if (tep_get_field_val(s, event, "created", record, &val, 1) < 0)
0431         return -1;
0432 
0433     trace_seq_printf(s, "%s ", val ? "new" : "existing");
0434 
0435     if (tep_get_field_val(s, event, "gfn", record, &val, 1) < 0)
0436         return -1;
0437 
0438     trace_seq_printf(s, "sp gfn %llx ", val);
0439     return kvm_mmu_print_role(s, record, event, context);
0440 }
0441 
0442 #define PT_WRITABLE_SHIFT 1
0443 #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
0444 
0445 static unsigned long long
0446 process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
0447 {
0448     unsigned long pte = args[0];
0449     return pte & PT_WRITABLE_MASK;
0450 }
0451 
0452 int TEP_PLUGIN_LOADER(struct tep_handle *tep)
0453 {
0454     init_disassembler();
0455 
0456     tep_register_event_handler(tep, -1, "kvm", "kvm_exit",
0457                    kvm_exit_handler, NULL);
0458 
0459     tep_register_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
0460                    kvm_emulate_insn_handler, NULL);
0461 
0462     tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
0463                    kvm_nested_vmexit_handler, NULL);
0464 
0465     tep_register_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
0466                    kvm_nested_vmexit_inject_handler, NULL);
0467 
0468     tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
0469                    kvm_mmu_get_page_handler, NULL);
0470 
0471     tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
0472                    kvm_mmu_print_role, NULL);
0473 
0474     tep_register_event_handler(tep, -1,
0475                    "kvmmmu", "kvm_mmu_unsync_page",
0476                    kvm_mmu_print_role, NULL);
0477 
0478     tep_register_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
0479                    kvm_mmu_print_role, NULL);
0480 
0481     tep_register_event_handler(tep, -1, "kvmmmu",
0482             "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
0483             NULL);
0484 
0485     tep_register_print_function(tep,
0486                     process_is_writable_pte,
0487                     TEP_FUNC_ARG_INT,
0488                     "is_writable_pte",
0489                     TEP_FUNC_ARG_LONG,
0490                     TEP_FUNC_ARG_VOID);
0491     return 0;
0492 }
0493 
0494 void TEP_PLUGIN_UNLOADER(struct tep_handle *tep)
0495 {
0496     tep_unregister_event_handler(tep, -1, "kvm", "kvm_exit",
0497                      kvm_exit_handler, NULL);
0498 
0499     tep_unregister_event_handler(tep, -1, "kvm", "kvm_emulate_insn",
0500                      kvm_emulate_insn_handler, NULL);
0501 
0502     tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit",
0503                      kvm_nested_vmexit_handler, NULL);
0504 
0505     tep_unregister_event_handler(tep, -1, "kvm", "kvm_nested_vmexit_inject",
0506                      kvm_nested_vmexit_inject_handler, NULL);
0507 
0508     tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_get_page",
0509                      kvm_mmu_get_page_handler, NULL);
0510 
0511     tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_sync_page",
0512                      kvm_mmu_print_role, NULL);
0513 
0514     tep_unregister_event_handler(tep, -1,
0515                      "kvmmmu", "kvm_mmu_unsync_page",
0516                      kvm_mmu_print_role, NULL);
0517 
0518     tep_unregister_event_handler(tep, -1, "kvmmmu", "kvm_mmu_zap_page",
0519                      kvm_mmu_print_role, NULL);
0520 
0521     tep_unregister_event_handler(tep, -1, "kvmmmu",
0522             "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
0523             NULL);
0524 
0525     tep_unregister_print_function(tep, process_is_writable_pte,
0526                       "is_writable_pte");
0527 }