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