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