2 * intel_pt_insn_decoder.c: Intel Processor Trace support
3 * Copyright (c) 2013-2014, Intel Corporation.
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.
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
28 #include "intel-pt-insn-decoder.h"
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
)
34 enum intel_pt_insn_op op
= INTEL_PT_OP_OTHER
;
35 enum intel_pt_insn_branch branch
= INTEL_PT_BR_NO_BRANCH
;
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
;
45 switch (insn
->opcode
.bytes
[0]) {
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
;
53 case 0x07: /* sysret */
54 case 0x35: /* sysexit */
55 op
= INTEL_PT_OP_SYSRET
;
56 branch
= INTEL_PT_BR_INDIRECT
;
58 case 0x80 ... 0x8f: /* jcc */
60 branch
= INTEL_PT_BR_CONDITIONAL
;
66 case 0x70 ... 0x7f: /* jcc */
68 branch
= INTEL_PT_BR_CONDITIONAL
;
70 case 0xc2: /* near ret */
71 case 0xc3: /* near ret */
72 case 0xca: /* far ret */
73 case 0xcb: /* far ret */
75 branch
= INTEL_PT_BR_INDIRECT
;
78 op
= INTEL_PT_OP_IRET
;
79 branch
= INTEL_PT_BR_INDIRECT
;
81 case 0xcc ... 0xce: /* int */
83 branch
= INTEL_PT_BR_INDIRECT
;
85 case 0xe8: /* call near rel */
86 op
= INTEL_PT_OP_CALL
;
87 branch
= INTEL_PT_BR_UNCONDITIONAL
;
89 case 0x9a: /* call far absolute */
90 op
= INTEL_PT_OP_CALL
;
91 branch
= INTEL_PT_BR_INDIRECT
;
93 case 0xe0 ... 0xe2: /* loop */
94 op
= INTEL_PT_OP_LOOP
;
95 branch
= INTEL_PT_BR_CONDITIONAL
;
99 branch
= INTEL_PT_BR_CONDITIONAL
;
103 op
= INTEL_PT_OP_JMP
;
104 branch
= INTEL_PT_BR_UNCONDITIONAL
;
106 case 0xea: /* far jmp */
107 op
= INTEL_PT_OP_JMP
;
108 branch
= INTEL_PT_BR_INDIRECT
;
110 case 0xff: /* call near absolute, call far absolute ind */
111 ext
= (insn
->modrm
.bytes
[0] >> 3) & 0x7;
113 case 2: /* near ind call */
114 case 3: /* far ind call */
115 op
= INTEL_PT_OP_CALL
;
116 branch
= INTEL_PT_BR_INDIRECT
;
120 op
= INTEL_PT_OP_JMP
;
121 branch
= INTEL_PT_BR_INDIRECT
;
131 intel_pt_insn
->op
= op
;
132 intel_pt_insn
->branch
= branch
;
133 intel_pt_insn
->length
= insn
->length
;
135 if (branch
== INTEL_PT_BR_CONDITIONAL
||
136 branch
== INTEL_PT_BR_UNCONDITIONAL
) {
137 #if __BYTE_ORDER == __BIG_ENDIAN
138 switch (insn
->immediate
.nbytes
) {
140 intel_pt_insn
->rel
= insn
->immediate
.value
;
144 bswap_16((short)insn
->immediate
.value
);
147 intel_pt_insn
->rel
= bswap_32(insn
->immediate
.value
);
150 intel_pt_insn
->rel
= 0;
154 intel_pt_insn
->rel
= insn
->immediate
.value
;
159 int intel_pt_get_insn(const unsigned char *buf
, size_t len
, int x86_64
,
160 struct intel_pt_insn
*intel_pt_insn
)
164 insn_init(&insn
, buf
, len
, x86_64
);
165 insn_get_length(&insn
);
166 if (!insn_complete(&insn
) || insn
.length
> len
)
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
);
172 memcpy(intel_pt_insn
->buf
, buf
, INTEL_PT_INSN_DBG_BUF_SZ
);
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",
189 const char *intel_pt_insn_name(enum intel_pt_insn_op op
)
191 return branch_name
[op
];
194 int intel_pt_insn_desc(const struct intel_pt_insn
*intel_pt_insn
, char *buf
,
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 ? "+" : "",
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
));
214 size_t intel_pt_insn_max_size(void)
216 return MAX_INSN_SIZE
;
219 int intel_pt_insn_type(enum intel_pt_insn_op op
)
222 case INTEL_PT_OP_OTHER
:
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
;