Linux Perf
intel-pt-insn-decoder.c
Go to the documentation of this file.
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 #include "dump-insn.h"
30 
31 #if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
32 #error Instruction buffer size too small
33 #endif
34 
35 /* Based on branch_type() from arch/x86/events/intel/lbr.c */
36 static void intel_pt_insn_decoder(struct insn *insn,
38 {
41  int ext;
42 
43  intel_pt_insn->rel = 0;
44 
45  if (insn_is_avx(insn)) {
46  intel_pt_insn->op = INTEL_PT_OP_OTHER;
47  intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
48  intel_pt_insn->length = insn->length;
49  return;
50  }
51 
52  switch (insn->opcode.bytes[0]) {
53  case 0xf:
54  switch (insn->opcode.bytes[1]) {
55  case 0x05: /* syscall */
56  case 0x34: /* sysenter */
58  branch = INTEL_PT_BR_INDIRECT;
59  break;
60  case 0x07: /* sysret */
61  case 0x35: /* sysexit */
62  op = INTEL_PT_OP_SYSRET;
63  branch = INTEL_PT_BR_INDIRECT;
64  break;
65  case 0x80 ... 0x8f: /* jcc */
66  op = INTEL_PT_OP_JCC;
67  branch = INTEL_PT_BR_CONDITIONAL;
68  break;
69  default:
70  break;
71  }
72  break;
73  case 0x70 ... 0x7f: /* jcc */
74  op = INTEL_PT_OP_JCC;
75  branch = INTEL_PT_BR_CONDITIONAL;
76  break;
77  case 0xc2: /* near ret */
78  case 0xc3: /* near ret */
79  case 0xca: /* far ret */
80  case 0xcb: /* far ret */
81  op = INTEL_PT_OP_RET;
82  branch = INTEL_PT_BR_INDIRECT;
83  break;
84  case 0xcf: /* iret */
85  op = INTEL_PT_OP_IRET;
86  branch = INTEL_PT_BR_INDIRECT;
87  break;
88  case 0xcc ... 0xce: /* int */
89  op = INTEL_PT_OP_INT;
90  branch = INTEL_PT_BR_INDIRECT;
91  break;
92  case 0xe8: /* call near rel */
93  op = INTEL_PT_OP_CALL;
95  break;
96  case 0x9a: /* call far absolute */
97  op = INTEL_PT_OP_CALL;
98  branch = INTEL_PT_BR_INDIRECT;
99  break;
100  case 0xe0 ... 0xe2: /* loop */
101  op = INTEL_PT_OP_LOOP;
102  branch = INTEL_PT_BR_CONDITIONAL;
103  break;
104  case 0xe3: /* jcc */
105  op = INTEL_PT_OP_JCC;
106  branch = INTEL_PT_BR_CONDITIONAL;
107  break;
108  case 0xe9: /* jmp */
109  case 0xeb: /* jmp */
110  op = INTEL_PT_OP_JMP;
111  branch = INTEL_PT_BR_UNCONDITIONAL;
112  break;
113  case 0xea: /* far jmp */
114  op = INTEL_PT_OP_JMP;
115  branch = INTEL_PT_BR_INDIRECT;
116  break;
117  case 0xff: /* call near absolute, call far absolute ind */
118  ext = (insn->modrm.bytes[0] >> 3) & 0x7;
119  switch (ext) {
120  case 2: /* near ind call */
121  case 3: /* far ind call */
122  op = INTEL_PT_OP_CALL;
123  branch = INTEL_PT_BR_INDIRECT;
124  break;
125  case 4:
126  case 5:
127  op = INTEL_PT_OP_JMP;
128  branch = INTEL_PT_BR_INDIRECT;
129  break;
130  default:
131  break;
132  }
133  break;
134  default:
135  break;
136  }
137 
138  intel_pt_insn->op = op;
139  intel_pt_insn->branch = branch;
140  intel_pt_insn->length = insn->length;
141 
142  if (branch == INTEL_PT_BR_CONDITIONAL ||
143  branch == INTEL_PT_BR_UNCONDITIONAL) {
144 #if __BYTE_ORDER == __BIG_ENDIAN
145  switch (insn->immediate.nbytes) {
146  case 1:
147  intel_pt_insn->rel = insn->immediate.value;
148  break;
149  case 2:
150  intel_pt_insn->rel =
151  bswap_16((short)insn->immediate.value);
152  break;
153  case 4:
154  intel_pt_insn->rel = bswap_32(insn->immediate.value);
155  break;
156  default:
157  intel_pt_insn->rel = 0;
158  break;
159  }
160 #else
161  intel_pt_insn->rel = insn->immediate.value;
162 #endif
163  }
164 }
165 
166 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
168 {
169  struct insn insn;
170 
171  insn_init(&insn, buf, len, x86_64);
172  insn_get_length(&insn);
173  if (!insn_complete(&insn) || insn.length > len)
174  return -1;
175  intel_pt_insn_decoder(&insn, intel_pt_insn);
176  if (insn.length < INTEL_PT_INSN_BUF_SZ)
177  memcpy(intel_pt_insn->buf, buf, insn.length);
178  else
179  memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ);
180  return 0;
181 }
182 
183 const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
184  u8 *inbuf, int inlen, int *lenp)
185 {
186  struct insn insn;
187  int n, i;
188  int left;
189 
190  insn_init(&insn, inbuf, inlen, x->is64bit);
191  insn_get_length(&insn);
192  if (!insn_complete(&insn) || insn.length > inlen)
193  return "<bad>";
194  if (lenp)
195  *lenp = insn.length;
196  left = sizeof(x->out);
197  n = snprintf(x->out, left, "insn: ");
198  left -= n;
199  for (i = 0; i < insn.length; i++) {
200  n += snprintf(x->out + n, left, "%02x ", inbuf[i]);
201  left -= n;
202  }
203  return x->out;
204 }
205 
206 const char *branch_name[] = {
207  [INTEL_PT_OP_OTHER] = "Other",
208  [INTEL_PT_OP_CALL] = "Call",
209  [INTEL_PT_OP_RET] = "Ret",
210  [INTEL_PT_OP_JCC] = "Jcc",
211  [INTEL_PT_OP_JMP] = "Jmp",
212  [INTEL_PT_OP_LOOP] = "Loop",
213  [INTEL_PT_OP_IRET] = "IRet",
214  [INTEL_PT_OP_INT] = "Int",
215  [INTEL_PT_OP_SYSCALL] = "Syscall",
216  [INTEL_PT_OP_SYSRET] = "Sysret",
217 };
218 
220 {
221  return branch_name[op];
222 }
223 
224 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
225  size_t buf_len)
226 {
227  switch (intel_pt_insn->branch) {
230  return snprintf(buf, buf_len, "%s %s%d",
231  intel_pt_insn_name(intel_pt_insn->op),
232  intel_pt_insn->rel > 0 ? "+" : "",
233  intel_pt_insn->rel);
236  return snprintf(buf, buf_len, "%s",
237  intel_pt_insn_name(intel_pt_insn->op));
238  default:
239  break;
240  }
241  return 0;
242 }
243 
245 {
246  switch (op) {
247  case INTEL_PT_OP_OTHER:
248  return 0;
249  case INTEL_PT_OP_CALL:
251  case INTEL_PT_OP_RET:
253  case INTEL_PT_OP_JCC:
255  case INTEL_PT_OP_JMP:
256  return PERF_IP_FLAG_BRANCH;
257  case INTEL_PT_OP_LOOP:
259  case INTEL_PT_OP_IRET:
262  case INTEL_PT_OP_INT:
265  case INTEL_PT_OP_SYSCALL:
268  case INTEL_PT_OP_SYSRET:
271  default:
272  return 0;
273  }
274 }
Definition: insn.h:36
const char * branch_name[]
intel_pt_insn_op
#define INTEL_PT_INSN_BUF_SZ
int intel_pt_insn_type(enum intel_pt_insn_op op)
void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
Definition: insn.c:53
enum intel_pt_insn_branch branch
insn_value_t value
Definition: insn.h:28
struct insn_field modrm
Definition: insn.h:48
char out[256]
Definition: dump-insn.h:18
unsigned char buf[INTEL_PT_INSN_BUF_SZ]
enum intel_pt_insn_op op
struct insn_field opcode
Definition: insn.h:43
void insn_get_length(struct insn *insn)
Definition: insn.c:598
static int insn_complete(struct insn *insn)
Definition: insn.h:145
struct insn_field immediate
Definition: insn.h:52
int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf, size_t buf_len)
const char * intel_pt_insn_name(enum intel_pt_insn_op op)
int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64, struct intel_pt_insn *intel_pt_insn)
intel_pt_insn_branch
insn_byte_t bytes[4]
Definition: insn.h:29
unsigned char length
Definition: insn.h:64
x86 movsq based memcpy() in arch/x86/lib/memcpy_64.S") MEMCPY_FN(memcpy_erms
static void intel_pt_insn_decoder(struct insn *insn, struct intel_pt_insn *intel_pt_insn)
const char * dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused, u8 *inbuf, int inlen, int *lenp)
bool is64bit
Definition: dump-insn.h:15
static int insn_is_avx(struct insn *insn)
Definition: insn.h:130
unsigned char nbytes
Definition: insn.h:33