1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * intel_pt_insn_decoder.c: Intel Processor Trace support 4 * Copyright (c) 2013-2014, Intel Corporation. 5 */ 6 7 #include <linux/kernel.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <endian.h> 11 #include <byteswap.h> 12 #include "../../../arch/x86/include/asm/insn.h" 13 14 #include "../../../arch/x86/lib/inat.c" 15 #include "../../../arch/x86/lib/insn.c" 16 17 #include "event.h" 18 19 #include "intel-pt-insn-decoder.h" 20 #include "dump-insn.h" 21 22 #if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN 23 #error Instruction buffer size too small 24 #endif 25 26 /* Based on branch_type() from arch/x86/events/intel/lbr.c */ 27 static void intel_pt_insn_decoder(struct insn *insn, 28 struct intel_pt_insn *intel_pt_insn) 29 { 30 enum intel_pt_insn_op op = INTEL_PT_OP_OTHER; 31 enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH; 32 int ext; 33 34 intel_pt_insn->rel = 0; 35 36 if (insn_is_avx(insn)) { 37 intel_pt_insn->op = INTEL_PT_OP_OTHER; 38 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; 39 intel_pt_insn->length = insn->length; 40 return; 41 } 42 43 switch (insn->opcode.bytes[0]) { 44 case 0xf: 45 switch (insn->opcode.bytes[1]) { 46 case 0x05: /* syscall */ 47 case 0x34: /* sysenter */ 48 op = INTEL_PT_OP_SYSCALL; 49 branch = INTEL_PT_BR_INDIRECT; 50 break; 51 case 0x07: /* sysret */ 52 case 0x35: /* sysexit */ 53 op = INTEL_PT_OP_SYSRET; 54 branch = INTEL_PT_BR_INDIRECT; 55 break; 56 case 0x80 ... 0x8f: /* jcc */ 57 op = INTEL_PT_OP_JCC; 58 branch = INTEL_PT_BR_CONDITIONAL; 59 break; 60 default: 61 break; 62 } 63 break; 64 case 0x70 ... 0x7f: /* jcc */ 65 op = INTEL_PT_OP_JCC; 66 branch = INTEL_PT_BR_CONDITIONAL; 67 break; 68 case 0xc2: /* near ret */ 69 case 0xc3: /* near ret */ 70 case 0xca: /* far ret */ 71 case 0xcb: /* far ret */ 72 op = INTEL_PT_OP_RET; 73 branch = INTEL_PT_BR_INDIRECT; 74 break; 75 case 0xcf: /* iret */ 76 op = INTEL_PT_OP_IRET; 77 branch = INTEL_PT_BR_INDIRECT; 78 break; 79 case 0xcc ... 0xce: /* int */ 80 op = INTEL_PT_OP_INT; 81 branch = INTEL_PT_BR_INDIRECT; 82 break; 83 case 0xe8: /* call near rel */ 84 op = INTEL_PT_OP_CALL; 85 branch = INTEL_PT_BR_UNCONDITIONAL; 86 break; 87 case 0x9a: /* call far absolute */ 88 op = INTEL_PT_OP_CALL; 89 branch = INTEL_PT_BR_INDIRECT; 90 break; 91 case 0xe0 ... 0xe2: /* loop */ 92 op = INTEL_PT_OP_LOOP; 93 branch = INTEL_PT_BR_CONDITIONAL; 94 break; 95 case 0xe3: /* jcc */ 96 op = INTEL_PT_OP_JCC; 97 branch = INTEL_PT_BR_CONDITIONAL; 98 break; 99 case 0xe9: /* jmp */ 100 case 0xeb: /* jmp */ 101 op = INTEL_PT_OP_JMP; 102 branch = INTEL_PT_BR_UNCONDITIONAL; 103 break; 104 case 0xea: /* far jmp */ 105 op = INTEL_PT_OP_JMP; 106 branch = INTEL_PT_BR_INDIRECT; 107 break; 108 case 0xff: /* call near absolute, call far absolute ind */ 109 ext = (insn->modrm.bytes[0] >> 3) & 0x7; 110 switch (ext) { 111 case 2: /* near ind call */ 112 case 3: /* far ind call */ 113 op = INTEL_PT_OP_CALL; 114 branch = INTEL_PT_BR_INDIRECT; 115 break; 116 case 4: 117 case 5: 118 op = INTEL_PT_OP_JMP; 119 branch = INTEL_PT_BR_INDIRECT; 120 break; 121 default: 122 break; 123 } 124 break; 125 default: 126 break; 127 } 128 129 intel_pt_insn->op = op; 130 intel_pt_insn->branch = branch; 131 intel_pt_insn->length = insn->length; 132 133 if (branch == INTEL_PT_BR_CONDITIONAL || 134 branch == INTEL_PT_BR_UNCONDITIONAL) { 135 #if __BYTE_ORDER == __BIG_ENDIAN 136 switch (insn->immediate.nbytes) { 137 case 1: 138 intel_pt_insn->rel = insn->immediate.value; 139 break; 140 case 2: 141 intel_pt_insn->rel = 142 bswap_16((short)insn->immediate.value); 143 break; 144 case 4: 145 intel_pt_insn->rel = bswap_32(insn->immediate.value); 146 break; 147 default: 148 intel_pt_insn->rel = 0; 149 break; 150 } 151 #else 152 intel_pt_insn->rel = insn->immediate.value; 153 #endif 154 } 155 } 156 157 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64, 158 struct intel_pt_insn *intel_pt_insn) 159 { 160 struct insn insn; 161 162 insn_init(&insn, buf, len, x86_64); 163 insn_get_length(&insn); 164 if (!insn_complete(&insn) || insn.length > len) 165 return -1; 166 intel_pt_insn_decoder(&insn, intel_pt_insn); 167 if (insn.length < INTEL_PT_INSN_BUF_SZ) 168 memcpy(intel_pt_insn->buf, buf, insn.length); 169 else 170 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ); 171 return 0; 172 } 173 174 int arch_is_branch(const unsigned char *buf, size_t len, int x86_64) 175 { 176 struct intel_pt_insn in; 177 if (intel_pt_get_insn(buf, len, x86_64, &in) < 0) 178 return -1; 179 return in.branch != INTEL_PT_BR_NO_BRANCH; 180 } 181 182 const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused, 183 u8 *inbuf, int inlen, int *lenp) 184 { 185 struct insn insn; 186 int n, i; 187 int left; 188 189 insn_init(&insn, inbuf, inlen, x->is64bit); 190 insn_get_length(&insn); 191 if (!insn_complete(&insn) || insn.length > inlen) 192 return "<bad>"; 193 if (lenp) 194 *lenp = insn.length; 195 left = sizeof(x->out); 196 n = snprintf(x->out, left, "insn: "); 197 left -= n; 198 for (i = 0; i < insn.length; i++) { 199 n += snprintf(x->out + n, left, "%02x ", inbuf[i]); 200 left -= n; 201 } 202 return x->out; 203 } 204 205 const char *branch_name[] = { 206 [INTEL_PT_OP_OTHER] = "Other", 207 [INTEL_PT_OP_CALL] = "Call", 208 [INTEL_PT_OP_RET] = "Ret", 209 [INTEL_PT_OP_JCC] = "Jcc", 210 [INTEL_PT_OP_JMP] = "Jmp", 211 [INTEL_PT_OP_LOOP] = "Loop", 212 [INTEL_PT_OP_IRET] = "IRet", 213 [INTEL_PT_OP_INT] = "Int", 214 [INTEL_PT_OP_SYSCALL] = "Syscall", 215 [INTEL_PT_OP_SYSRET] = "Sysret", 216 }; 217 218 const char *intel_pt_insn_name(enum intel_pt_insn_op op) 219 { 220 return branch_name[op]; 221 } 222 223 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf, 224 size_t buf_len) 225 { 226 switch (intel_pt_insn->branch) { 227 case INTEL_PT_BR_CONDITIONAL: 228 case INTEL_PT_BR_UNCONDITIONAL: 229 return snprintf(buf, buf_len, "%s %s%d", 230 intel_pt_insn_name(intel_pt_insn->op), 231 intel_pt_insn->rel > 0 ? "+" : "", 232 intel_pt_insn->rel); 233 case INTEL_PT_BR_NO_BRANCH: 234 case INTEL_PT_BR_INDIRECT: 235 return snprintf(buf, buf_len, "%s", 236 intel_pt_insn_name(intel_pt_insn->op)); 237 default: 238 break; 239 } 240 return 0; 241 } 242 243 int intel_pt_insn_type(enum intel_pt_insn_op op) 244 { 245 switch (op) { 246 case INTEL_PT_OP_OTHER: 247 return 0; 248 case INTEL_PT_OP_CALL: 249 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL; 250 case INTEL_PT_OP_RET: 251 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN; 252 case INTEL_PT_OP_JCC: 253 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 254 case INTEL_PT_OP_JMP: 255 return PERF_IP_FLAG_BRANCH; 256 case INTEL_PT_OP_LOOP: 257 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 258 case INTEL_PT_OP_IRET: 259 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 260 PERF_IP_FLAG_INTERRUPT; 261 case INTEL_PT_OP_INT: 262 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 263 PERF_IP_FLAG_INTERRUPT; 264 case INTEL_PT_OP_SYSCALL: 265 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 266 PERF_IP_FLAG_SYSCALLRET; 267 case INTEL_PT_OP_SYSRET: 268 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 269 PERF_IP_FLAG_SYSCALLRET; 270 default: 271 return 0; 272 } 273 } 274