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 "event.h" 15 16 #include "intel-pt-insn-decoder.h" 17 #include "dump-insn.h" 18 #include "util/sample.h" 19 20 #if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN 21 #error Instruction buffer size too small 22 #endif 23 24 /* Based on branch_type() from arch/x86/events/intel/lbr.c */ 25 static void intel_pt_insn_decoder(struct insn *insn, 26 struct intel_pt_insn *intel_pt_insn) 27 { 28 enum intel_pt_insn_op op = INTEL_PT_OP_OTHER; 29 enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH; 30 int ext; 31 32 intel_pt_insn->rel = 0; 33 intel_pt_insn->emulated_ptwrite = false; 34 35 if (insn_is_avx(insn)) { 36 intel_pt_insn->op = INTEL_PT_OP_OTHER; 37 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; 38 intel_pt_insn->length = insn->length; 39 return; 40 } 41 42 switch (insn->opcode.bytes[0]) { 43 case 0xf: 44 switch (insn->opcode.bytes[1]) { 45 case 0x01: 46 switch (insn->modrm.bytes[0]) { 47 case 0xc2: /* vmlaunch */ 48 case 0xc3: /* vmresume */ 49 op = INTEL_PT_OP_VMENTRY; 50 branch = INTEL_PT_BR_INDIRECT; 51 break; 52 case 0xca: 53 switch (insn->prefixes.bytes[3]) { 54 case 0xf2: /* erets */ 55 op = INTEL_PT_OP_ERETS; 56 branch = INTEL_PT_BR_INDIRECT; 57 break; 58 case 0xf3: /* eretu */ 59 op = INTEL_PT_OP_ERETU; 60 branch = INTEL_PT_BR_INDIRECT; 61 break; 62 default: 63 break; 64 } 65 break; 66 default: 67 break; 68 } 69 break; 70 case 0x05: /* syscall */ 71 case 0x34: /* sysenter */ 72 op = INTEL_PT_OP_SYSCALL; 73 branch = INTEL_PT_BR_INDIRECT; 74 break; 75 case 0x07: /* sysret */ 76 case 0x35: /* sysexit */ 77 op = INTEL_PT_OP_SYSRET; 78 branch = INTEL_PT_BR_INDIRECT; 79 break; 80 case 0x80 ... 0x8f: /* jcc */ 81 op = INTEL_PT_OP_JCC; 82 branch = INTEL_PT_BR_CONDITIONAL; 83 break; 84 default: 85 break; 86 } 87 break; 88 case 0x70 ... 0x7f: /* jcc */ 89 op = INTEL_PT_OP_JCC; 90 branch = INTEL_PT_BR_CONDITIONAL; 91 break; 92 case 0xa1: 93 if (insn_is_rex2(insn)) { /* jmpabs */ 94 intel_pt_insn->op = INTEL_PT_OP_JMP; 95 /* jmpabs causes a TIP packet like an indirect branch */ 96 intel_pt_insn->branch = INTEL_PT_BR_INDIRECT; 97 intel_pt_insn->length = insn->length; 98 return; 99 } 100 break; 101 case 0xc2: /* near ret */ 102 case 0xc3: /* near ret */ 103 case 0xca: /* far ret */ 104 case 0xcb: /* far ret */ 105 op = INTEL_PT_OP_RET; 106 branch = INTEL_PT_BR_INDIRECT; 107 break; 108 case 0xcf: /* iret */ 109 op = INTEL_PT_OP_IRET; 110 branch = INTEL_PT_BR_INDIRECT; 111 break; 112 case 0xcc ... 0xce: /* int */ 113 op = INTEL_PT_OP_INT; 114 branch = INTEL_PT_BR_INDIRECT; 115 break; 116 case 0xe8: /* call near rel */ 117 op = INTEL_PT_OP_CALL; 118 branch = INTEL_PT_BR_UNCONDITIONAL; 119 break; 120 case 0x9a: /* call far absolute */ 121 op = INTEL_PT_OP_CALL; 122 branch = INTEL_PT_BR_INDIRECT; 123 break; 124 case 0xe0 ... 0xe2: /* loop */ 125 op = INTEL_PT_OP_LOOP; 126 branch = INTEL_PT_BR_CONDITIONAL; 127 break; 128 case 0xe3: /* jcc */ 129 op = INTEL_PT_OP_JCC; 130 branch = INTEL_PT_BR_CONDITIONAL; 131 break; 132 case 0xe9: /* jmp */ 133 case 0xeb: /* jmp */ 134 op = INTEL_PT_OP_JMP; 135 branch = INTEL_PT_BR_UNCONDITIONAL; 136 break; 137 case 0xea: /* far jmp */ 138 op = INTEL_PT_OP_JMP; 139 branch = INTEL_PT_BR_INDIRECT; 140 break; 141 case 0xff: /* call near absolute, call far absolute ind */ 142 ext = (insn->modrm.bytes[0] >> 3) & 0x7; 143 switch (ext) { 144 case 2: /* near ind call */ 145 case 3: /* far ind call */ 146 op = INTEL_PT_OP_CALL; 147 branch = INTEL_PT_BR_INDIRECT; 148 break; 149 case 4: 150 case 5: 151 op = INTEL_PT_OP_JMP; 152 branch = INTEL_PT_BR_INDIRECT; 153 break; 154 default: 155 break; 156 } 157 break; 158 default: 159 break; 160 } 161 162 intel_pt_insn->op = op; 163 intel_pt_insn->branch = branch; 164 intel_pt_insn->length = insn->length; 165 166 if (branch == INTEL_PT_BR_CONDITIONAL || 167 branch == INTEL_PT_BR_UNCONDITIONAL) { 168 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 169 switch (insn->immediate.nbytes) { 170 case 1: 171 intel_pt_insn->rel = insn->immediate.value; 172 break; 173 case 2: 174 intel_pt_insn->rel = 175 bswap_16((short)insn->immediate.value); 176 break; 177 case 4: 178 intel_pt_insn->rel = bswap_32(insn->immediate.value); 179 break; 180 default: 181 intel_pt_insn->rel = 0; 182 break; 183 } 184 #else 185 intel_pt_insn->rel = insn->immediate.value; 186 #endif 187 } 188 } 189 190 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64, 191 struct intel_pt_insn *intel_pt_insn) 192 { 193 struct insn insn; 194 int ret; 195 196 ret = insn_decode(&insn, buf, len, 197 x86_64 ? INSN_MODE_64 : INSN_MODE_32); 198 if (ret < 0 || insn.length > len) 199 return -1; 200 201 intel_pt_insn_decoder(&insn, intel_pt_insn); 202 if (insn.length < INTEL_PT_INSN_BUF_SZ) 203 memcpy(intel_pt_insn->buf, buf, insn.length); 204 else 205 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ); 206 return 0; 207 } 208 209 int arch_is_uncond_branch(const unsigned char *buf, size_t len, int x86_64) 210 { 211 struct intel_pt_insn in; 212 if (intel_pt_get_insn(buf, len, x86_64, &in) < 0) 213 return -1; 214 return in.branch == INTEL_PT_BR_UNCONDITIONAL || 215 in.branch == INTEL_PT_BR_INDIRECT; 216 } 217 218 const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused, 219 u8 *inbuf, int inlen, int *lenp) 220 { 221 struct insn insn; 222 int n, i, ret; 223 int left; 224 225 ret = insn_decode(&insn, inbuf, inlen, 226 x->is64bit ? INSN_MODE_64 : INSN_MODE_32); 227 228 if (ret < 0 || insn.length > inlen) 229 return "<bad>"; 230 if (lenp) 231 *lenp = insn.length; 232 left = sizeof(x->out); 233 n = snprintf(x->out, left, "insn: "); 234 left -= n; 235 for (i = 0; i < insn.length; i++) { 236 n += snprintf(x->out + n, left, "%02x ", inbuf[i]); 237 left -= n; 238 } 239 return x->out; 240 } 241 242 const char *branch_name[] = { 243 [INTEL_PT_OP_OTHER] = "Other", 244 [INTEL_PT_OP_CALL] = "Call", 245 [INTEL_PT_OP_RET] = "Ret", 246 [INTEL_PT_OP_JCC] = "Jcc", 247 [INTEL_PT_OP_JMP] = "Jmp", 248 [INTEL_PT_OP_LOOP] = "Loop", 249 [INTEL_PT_OP_IRET] = "IRet", 250 [INTEL_PT_OP_INT] = "Int", 251 [INTEL_PT_OP_SYSCALL] = "Syscall", 252 [INTEL_PT_OP_SYSRET] = "Sysret", 253 [INTEL_PT_OP_VMENTRY] = "VMentry", 254 [INTEL_PT_OP_ERETS] = "Erets", 255 [INTEL_PT_OP_ERETU] = "Eretu", 256 }; 257 258 const char *intel_pt_insn_name(enum intel_pt_insn_op op) 259 { 260 return branch_name[op]; 261 } 262 263 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf, 264 size_t buf_len) 265 { 266 switch (intel_pt_insn->branch) { 267 case INTEL_PT_BR_CONDITIONAL: 268 case INTEL_PT_BR_UNCONDITIONAL: 269 return snprintf(buf, buf_len, "%s %s%d", 270 intel_pt_insn_name(intel_pt_insn->op), 271 intel_pt_insn->rel > 0 ? "+" : "", 272 intel_pt_insn->rel); 273 case INTEL_PT_BR_NO_BRANCH: 274 case INTEL_PT_BR_INDIRECT: 275 return snprintf(buf, buf_len, "%s", 276 intel_pt_insn_name(intel_pt_insn->op)); 277 default: 278 break; 279 } 280 return 0; 281 } 282 283 int intel_pt_insn_type(enum intel_pt_insn_op op) 284 { 285 switch (op) { 286 case INTEL_PT_OP_OTHER: 287 return 0; 288 case INTEL_PT_OP_CALL: 289 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL; 290 case INTEL_PT_OP_RET: 291 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN; 292 case INTEL_PT_OP_JCC: 293 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 294 case INTEL_PT_OP_JMP: 295 return PERF_IP_FLAG_BRANCH; 296 case INTEL_PT_OP_LOOP: 297 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 298 case INTEL_PT_OP_IRET: 299 case INTEL_PT_OP_ERETS: 300 case INTEL_PT_OP_ERETU: 301 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 302 PERF_IP_FLAG_INTERRUPT; 303 case INTEL_PT_OP_INT: 304 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 305 PERF_IP_FLAG_INTERRUPT; 306 case INTEL_PT_OP_SYSCALL: 307 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 308 PERF_IP_FLAG_SYSCALLRET; 309 case INTEL_PT_OP_SYSRET: 310 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 311 PERF_IP_FLAG_SYSCALLRET; 312 case INTEL_PT_OP_VMENTRY: 313 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 314 PERF_IP_FLAG_VMENTRY; 315 default: 316 return 0; 317 } 318 } 319