Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/types.h>
0003 #include <string.h>
0004 
0005 #include "debug.h"
0006 #include "tests/tests.h"
0007 #include "arch-tests.h"
0008 #include "../../../../arch/x86/include/asm/insn.h"
0009 
0010 #include "intel-pt-decoder/intel-pt-insn-decoder.h"
0011 
0012 struct test_data {
0013     u8 data[MAX_INSN_SIZE];
0014     int expected_length;
0015     int expected_rel;
0016     const char *expected_op_str;
0017     const char *expected_branch_str;
0018     const char *asm_rep;
0019 };
0020 
0021 struct test_data test_data_32[] = {
0022 #include "insn-x86-dat-32.c"
0023     {{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee             \trdpkru"},
0024     {{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef             \twrpkru"},
0025     {{0}, 0, 0, NULL, NULL, NULL},
0026 };
0027 
0028 struct test_data test_data_64[] = {
0029 #include "insn-x86-dat-64.c"
0030     {{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee             \trdpkru"},
0031     {{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef             \twrpkru"},
0032     {{0}, 0, 0, NULL, NULL, NULL},
0033 };
0034 
0035 static int get_op(const char *op_str)
0036 {
0037     struct val_data {
0038         const char *name;
0039         int val;
0040     } vals[] = {
0041         {"other",   INTEL_PT_OP_OTHER},
0042         {"call",    INTEL_PT_OP_CALL},
0043         {"ret",     INTEL_PT_OP_RET},
0044         {"jcc",     INTEL_PT_OP_JCC},
0045         {"jmp",     INTEL_PT_OP_JMP},
0046         {"loop",    INTEL_PT_OP_LOOP},
0047         {"iret",    INTEL_PT_OP_IRET},
0048         {"int",     INTEL_PT_OP_INT},
0049         {"syscall", INTEL_PT_OP_SYSCALL},
0050         {"sysret",  INTEL_PT_OP_SYSRET},
0051         {"vmentry",  INTEL_PT_OP_VMENTRY},
0052         {NULL, 0},
0053     };
0054     struct val_data *val;
0055 
0056     if (!op_str || !strlen(op_str))
0057         return 0;
0058 
0059     for (val = vals; val->name; val++) {
0060         if (!strcmp(val->name, op_str))
0061             return val->val;
0062     }
0063 
0064     pr_debug("Failed to get op\n");
0065 
0066     return -1;
0067 }
0068 
0069 static int get_branch(const char *branch_str)
0070 {
0071     struct val_data {
0072         const char *name;
0073         int val;
0074     } vals[] = {
0075         {"no_branch",     INTEL_PT_BR_NO_BRANCH},
0076         {"indirect",      INTEL_PT_BR_INDIRECT},
0077         {"conditional",   INTEL_PT_BR_CONDITIONAL},
0078         {"unconditional", INTEL_PT_BR_UNCONDITIONAL},
0079         {NULL, 0},
0080     };
0081     struct val_data *val;
0082 
0083     if (!branch_str || !strlen(branch_str))
0084         return 0;
0085 
0086     for (val = vals; val->name; val++) {
0087         if (!strcmp(val->name, branch_str))
0088             return val->val;
0089     }
0090 
0091     pr_debug("Failed to get branch\n");
0092 
0093     return -1;
0094 }
0095 
0096 static int test_data_item(struct test_data *dat, int x86_64)
0097 {
0098     struct intel_pt_insn intel_pt_insn;
0099     int op, branch, ret;
0100     struct insn insn;
0101 
0102     ret = insn_decode(&insn, dat->data, MAX_INSN_SIZE,
0103               x86_64 ? INSN_MODE_64 : INSN_MODE_32);
0104     if (ret < 0) {
0105         pr_debug("Failed to decode: %s\n", dat->asm_rep);
0106         return -1;
0107     }
0108 
0109     if (insn.length != dat->expected_length) {
0110         pr_debug("Failed to decode length (%d vs expected %d): %s\n",
0111              insn.length, dat->expected_length, dat->asm_rep);
0112         return -1;
0113     }
0114 
0115     op = get_op(dat->expected_op_str);
0116     branch = get_branch(dat->expected_branch_str);
0117 
0118     if (intel_pt_get_insn(dat->data, MAX_INSN_SIZE, x86_64, &intel_pt_insn)) {
0119         pr_debug("Intel PT failed to decode: %s\n", dat->asm_rep);
0120         return -1;
0121     }
0122 
0123     if ((int)intel_pt_insn.op != op) {
0124         pr_debug("Failed to decode 'op' value (%d vs expected %d): %s\n",
0125              intel_pt_insn.op, op, dat->asm_rep);
0126         return -1;
0127     }
0128 
0129     if ((int)intel_pt_insn.branch != branch) {
0130         pr_debug("Failed to decode 'branch' value (%d vs expected %d): %s\n",
0131              intel_pt_insn.branch, branch, dat->asm_rep);
0132         return -1;
0133     }
0134 
0135     if (intel_pt_insn.rel != dat->expected_rel) {
0136         pr_debug("Failed to decode 'rel' value (%#x vs expected %#x): %s\n",
0137              intel_pt_insn.rel, dat->expected_rel, dat->asm_rep);
0138         return -1;
0139     }
0140 
0141     pr_debug("Decoded ok: %s\n", dat->asm_rep);
0142 
0143     return 0;
0144 }
0145 
0146 static int test_data_set(struct test_data *dat_set, int x86_64)
0147 {
0148     struct test_data *dat;
0149     int ret = 0;
0150 
0151     for (dat = dat_set; dat->expected_length; dat++) {
0152         if (test_data_item(dat, x86_64))
0153             ret = -1;
0154     }
0155 
0156     return ret;
0157 }
0158 
0159 /**
0160  * test__insn_x86 - test x86 instruction decoder - new instructions.
0161  *
0162  * This function implements a test that decodes a selection of instructions and
0163  * checks the results.  The Intel PT function that further categorizes
0164  * instructions (i.e. intel_pt_get_insn()) is also checked.
0165  *
0166  * The instructions are originally in insn-x86-dat-src.c which has been
0167  * processed by scripts gen-insn-x86-dat.sh and gen-insn-x86-dat.awk to produce
0168  * insn-x86-dat-32.c and insn-x86-dat-64.c which are included into this program.
0169  * i.e. to add new instructions to the test, edit insn-x86-dat-src.c, run the
0170  * gen-insn-x86-dat.sh script, make perf, and then run the test.
0171  *
0172  * If the test passes %0 is returned, otherwise %-1 is returned.  Use the
0173  * verbose (-v) option to see all the instructions and whether or not they
0174  * decoded successfully.
0175  */
0176 int test__insn_x86(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0177 {
0178     int ret = 0;
0179 
0180     if (test_data_set(test_data_32, 0))
0181         ret = -1;
0182 
0183     if (test_data_set(test_data_64, 1))
0184         ret = -1;
0185 
0186     return ret;
0187 }