1 /* 2 * intel_pt_insn_decoder.c: Intel Processor Trace support 3 * Copyright (c) 2013-2014, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 */ 15 16 #include <stdio.h> 17 #include <string.h> 18 #include <endian.h> 19 #include <byteswap.h> 20 21 #include "event.h" 22 23 #include "insn.h" 24 25 #include "inat.c" 26 #include "insn.c" 27 28 #include "intel-pt-insn-decoder.h" 29 30 /* Based on branch_type() from perf_event_intel_lbr.c */ 31 static void intel_pt_insn_decoder(struct insn *insn, 32 struct intel_pt_insn *intel_pt_insn) 33 { 34 enum intel_pt_insn_op op = INTEL_PT_OP_OTHER; 35 enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH; 36 int ext; 37 38 if (insn_is_avx(insn)) { 39 intel_pt_insn->op = INTEL_PT_OP_OTHER; 40 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH; 41 intel_pt_insn->length = insn->length; 42 return; 43 } 44 45 switch (insn->opcode.bytes[0]) { 46 case 0xf: 47 switch (insn->opcode.bytes[1]) { 48 case 0x05: /* syscall */ 49 case 0x34: /* sysenter */ 50 op = INTEL_PT_OP_SYSCALL; 51 branch = INTEL_PT_BR_INDIRECT; 52 break; 53 case 0x07: /* sysret */ 54 case 0x35: /* sysexit */ 55 op = INTEL_PT_OP_SYSRET; 56 branch = INTEL_PT_BR_INDIRECT; 57 break; 58 case 0x80 ... 0x8f: /* jcc */ 59 op = INTEL_PT_OP_JCC; 60 branch = INTEL_PT_BR_CONDITIONAL; 61 break; 62 default: 63 break; 64 } 65 break; 66 case 0x70 ... 0x7f: /* jcc */ 67 op = INTEL_PT_OP_JCC; 68 branch = INTEL_PT_BR_CONDITIONAL; 69 break; 70 case 0xc2: /* near ret */ 71 case 0xc3: /* near ret */ 72 case 0xca: /* far ret */ 73 case 0xcb: /* far ret */ 74 op = INTEL_PT_OP_RET; 75 branch = INTEL_PT_BR_INDIRECT; 76 break; 77 case 0xcf: /* iret */ 78 op = INTEL_PT_OP_IRET; 79 branch = INTEL_PT_BR_INDIRECT; 80 break; 81 case 0xcc ... 0xce: /* int */ 82 op = INTEL_PT_OP_INT; 83 branch = INTEL_PT_BR_INDIRECT; 84 break; 85 case 0xe8: /* call near rel */ 86 op = INTEL_PT_OP_CALL; 87 branch = INTEL_PT_BR_UNCONDITIONAL; 88 break; 89 case 0x9a: /* call far absolute */ 90 op = INTEL_PT_OP_CALL; 91 branch = INTEL_PT_BR_INDIRECT; 92 break; 93 case 0xe0 ... 0xe2: /* loop */ 94 op = INTEL_PT_OP_LOOP; 95 branch = INTEL_PT_BR_CONDITIONAL; 96 break; 97 case 0xe3: /* jcc */ 98 op = INTEL_PT_OP_JCC; 99 branch = INTEL_PT_BR_CONDITIONAL; 100 break; 101 case 0xe9: /* jmp */ 102 case 0xeb: /* jmp */ 103 op = INTEL_PT_OP_JMP; 104 branch = INTEL_PT_BR_UNCONDITIONAL; 105 break; 106 case 0xea: /* far jmp */ 107 op = INTEL_PT_OP_JMP; 108 branch = INTEL_PT_BR_INDIRECT; 109 break; 110 case 0xff: /* call near absolute, call far absolute ind */ 111 ext = (insn->modrm.bytes[0] >> 3) & 0x7; 112 switch (ext) { 113 case 2: /* near ind call */ 114 case 3: /* far ind call */ 115 op = INTEL_PT_OP_CALL; 116 branch = INTEL_PT_BR_INDIRECT; 117 break; 118 case 4: 119 case 5: 120 op = INTEL_PT_OP_JMP; 121 branch = INTEL_PT_BR_INDIRECT; 122 break; 123 default: 124 break; 125 } 126 break; 127 default: 128 break; 129 } 130 131 intel_pt_insn->op = op; 132 intel_pt_insn->branch = branch; 133 intel_pt_insn->length = insn->length; 134 135 if (branch == INTEL_PT_BR_CONDITIONAL || 136 branch == INTEL_PT_BR_UNCONDITIONAL) { 137 #if __BYTE_ORDER == __BIG_ENDIAN 138 switch (insn->immediate.nbytes) { 139 case 1: 140 intel_pt_insn->rel = insn->immediate.value; 141 break; 142 case 2: 143 intel_pt_insn->rel = 144 bswap_16((short)insn->immediate.value); 145 break; 146 case 4: 147 intel_pt_insn->rel = bswap_32(insn->immediate.value); 148 break; 149 default: 150 intel_pt_insn->rel = 0; 151 break; 152 } 153 #else 154 intel_pt_insn->rel = insn->immediate.value; 155 #endif 156 } 157 } 158 159 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64, 160 struct intel_pt_insn *intel_pt_insn) 161 { 162 struct insn insn; 163 164 insn_init(&insn, buf, len, x86_64); 165 insn_get_length(&insn); 166 if (!insn_complete(&insn) || insn.length > len) 167 return -1; 168 intel_pt_insn_decoder(&insn, intel_pt_insn); 169 if (insn.length < INTEL_PT_INSN_DBG_BUF_SZ) 170 memcpy(intel_pt_insn->buf, buf, insn.length); 171 else 172 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_DBG_BUF_SZ); 173 return 0; 174 } 175 176 const char *branch_name[] = { 177 [INTEL_PT_OP_OTHER] = "Other", 178 [INTEL_PT_OP_CALL] = "Call", 179 [INTEL_PT_OP_RET] = "Ret", 180 [INTEL_PT_OP_JCC] = "Jcc", 181 [INTEL_PT_OP_JMP] = "Jmp", 182 [INTEL_PT_OP_LOOP] = "Loop", 183 [INTEL_PT_OP_IRET] = "IRet", 184 [INTEL_PT_OP_INT] = "Int", 185 [INTEL_PT_OP_SYSCALL] = "Syscall", 186 [INTEL_PT_OP_SYSRET] = "Sysret", 187 }; 188 189 const char *intel_pt_insn_name(enum intel_pt_insn_op op) 190 { 191 return branch_name[op]; 192 } 193 194 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf, 195 size_t buf_len) 196 { 197 switch (intel_pt_insn->branch) { 198 case INTEL_PT_BR_CONDITIONAL: 199 case INTEL_PT_BR_UNCONDITIONAL: 200 return snprintf(buf, buf_len, "%s %s%d", 201 intel_pt_insn_name(intel_pt_insn->op), 202 intel_pt_insn->rel > 0 ? "+" : "", 203 intel_pt_insn->rel); 204 case INTEL_PT_BR_NO_BRANCH: 205 case INTEL_PT_BR_INDIRECT: 206 return snprintf(buf, buf_len, "%s", 207 intel_pt_insn_name(intel_pt_insn->op)); 208 default: 209 break; 210 } 211 return 0; 212 } 213 214 size_t intel_pt_insn_max_size(void) 215 { 216 return MAX_INSN_SIZE; 217 } 218 219 int intel_pt_insn_type(enum intel_pt_insn_op op) 220 { 221 switch (op) { 222 case INTEL_PT_OP_OTHER: 223 return 0; 224 case INTEL_PT_OP_CALL: 225 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL; 226 case INTEL_PT_OP_RET: 227 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN; 228 case INTEL_PT_OP_JCC: 229 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 230 case INTEL_PT_OP_JMP: 231 return PERF_IP_FLAG_BRANCH; 232 case INTEL_PT_OP_LOOP: 233 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL; 234 case INTEL_PT_OP_IRET: 235 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 236 PERF_IP_FLAG_INTERRUPT; 237 case INTEL_PT_OP_INT: 238 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 239 PERF_IP_FLAG_INTERRUPT; 240 case INTEL_PT_OP_SYSCALL: 241 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | 242 PERF_IP_FLAG_SYSCALLRET; 243 case INTEL_PT_OP_SYSRET: 244 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | 245 PERF_IP_FLAG_SYSCALLRET; 246 default: 247 return 0; 248 } 249 } 250