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 */
intel_pt_insn_decoder(struct insn * insn,struct intel_pt_insn * intel_pt_insn)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
intel_pt_get_insn(const unsigned char * buf,size_t len,int x86_64,struct intel_pt_insn * intel_pt_insn)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
arch_is_uncond_branch(const unsigned char * buf,size_t len,int x86_64)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
dump_insn(struct perf_insn * x,uint64_t ip __maybe_unused,u8 * inbuf,int inlen,int * lenp)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
intel_pt_insn_name(enum intel_pt_insn_op op)258 const char *intel_pt_insn_name(enum intel_pt_insn_op op)
259 {
260 return branch_name[op];
261 }
262
intel_pt_insn_desc(const struct intel_pt_insn * intel_pt_insn,char * buf,size_t buf_len)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
intel_pt_insn_type(enum intel_pt_insn_op op)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