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 #if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
31 #error Instruction buffer size too small
34 /* Based on branch_type() from arch/x86/events/intel/lbr.c */
35 static void intel_pt_insn_decoder(struct insn
*insn
,
36 struct intel_pt_insn
*intel_pt_insn
)
38 enum intel_pt_insn_op op
= INTEL_PT_OP_OTHER
;
39 enum intel_pt_insn_branch branch
= INTEL_PT_BR_NO_BRANCH
;
42 if (insn_is_avx(insn
)) {
43 intel_pt_insn
->op
= INTEL_PT_OP_OTHER
;
44 intel_pt_insn
->branch
= INTEL_PT_BR_NO_BRANCH
;
45 intel_pt_insn
->length
= insn
->length
;
49 switch (insn
->opcode
.bytes
[0]) {
51 switch (insn
->opcode
.bytes
[1]) {
52 case 0x05: /* syscall */
53 case 0x34: /* sysenter */
54 op
= INTEL_PT_OP_SYSCALL
;
55 branch
= INTEL_PT_BR_INDIRECT
;
57 case 0x07: /* sysret */
58 case 0x35: /* sysexit */
59 op
= INTEL_PT_OP_SYSRET
;
60 branch
= INTEL_PT_BR_INDIRECT
;
62 case 0x80 ... 0x8f: /* jcc */
64 branch
= INTEL_PT_BR_CONDITIONAL
;
70 case 0x70 ... 0x7f: /* jcc */
72 branch
= INTEL_PT_BR_CONDITIONAL
;
74 case 0xc2: /* near ret */
75 case 0xc3: /* near ret */
76 case 0xca: /* far ret */
77 case 0xcb: /* far ret */
79 branch
= INTEL_PT_BR_INDIRECT
;
82 op
= INTEL_PT_OP_IRET
;
83 branch
= INTEL_PT_BR_INDIRECT
;
85 case 0xcc ... 0xce: /* int */
87 branch
= INTEL_PT_BR_INDIRECT
;
89 case 0xe8: /* call near rel */
90 op
= INTEL_PT_OP_CALL
;
91 branch
= INTEL_PT_BR_UNCONDITIONAL
;
93 case 0x9a: /* call far absolute */
94 op
= INTEL_PT_OP_CALL
;
95 branch
= INTEL_PT_BR_INDIRECT
;
97 case 0xe0 ... 0xe2: /* loop */
98 op
= INTEL_PT_OP_LOOP
;
99 branch
= INTEL_PT_BR_CONDITIONAL
;
102 op
= INTEL_PT_OP_JCC
;
103 branch
= INTEL_PT_BR_CONDITIONAL
;
107 op
= INTEL_PT_OP_JMP
;
108 branch
= INTEL_PT_BR_UNCONDITIONAL
;
110 case 0xea: /* far jmp */
111 op
= INTEL_PT_OP_JMP
;
112 branch
= INTEL_PT_BR_INDIRECT
;
114 case 0xff: /* call near absolute, call far absolute ind */
115 ext
= (insn
->modrm
.bytes
[0] >> 3) & 0x7;
117 case 2: /* near ind call */
118 case 3: /* far ind call */
119 op
= INTEL_PT_OP_CALL
;
120 branch
= INTEL_PT_BR_INDIRECT
;
124 op
= INTEL_PT_OP_JMP
;
125 branch
= INTEL_PT_BR_INDIRECT
;
135 intel_pt_insn
->op
= op
;
136 intel_pt_insn
->branch
= branch
;
137 intel_pt_insn
->length
= insn
->length
;
139 if (branch
== INTEL_PT_BR_CONDITIONAL
||
140 branch
== INTEL_PT_BR_UNCONDITIONAL
) {
141 #if __BYTE_ORDER == __BIG_ENDIAN
142 switch (insn
->immediate
.nbytes
) {
144 intel_pt_insn
->rel
= insn
->immediate
.value
;
148 bswap_16((short)insn
->immediate
.value
);
151 intel_pt_insn
->rel
= bswap_32(insn
->immediate
.value
);
154 intel_pt_insn
->rel
= 0;
158 intel_pt_insn
->rel
= insn
->immediate
.value
;
163 int intel_pt_get_insn(const unsigned char *buf
, size_t len
, int x86_64
,
164 struct intel_pt_insn
*intel_pt_insn
)
168 insn_init(&insn
, buf
, len
, x86_64
);
169 insn_get_length(&insn
);
170 if (!insn_complete(&insn
) || insn
.length
> len
)
172 intel_pt_insn_decoder(&insn
, intel_pt_insn
);
173 if (insn
.length
< INTEL_PT_INSN_BUF_SZ
)
174 memcpy(intel_pt_insn
->buf
, buf
, insn
.length
);
176 memcpy(intel_pt_insn
->buf
, buf
, INTEL_PT_INSN_BUF_SZ
);
180 const char *branch_name
[] = {
181 [INTEL_PT_OP_OTHER
] = "Other",
182 [INTEL_PT_OP_CALL
] = "Call",
183 [INTEL_PT_OP_RET
] = "Ret",
184 [INTEL_PT_OP_JCC
] = "Jcc",
185 [INTEL_PT_OP_JMP
] = "Jmp",
186 [INTEL_PT_OP_LOOP
] = "Loop",
187 [INTEL_PT_OP_IRET
] = "IRet",
188 [INTEL_PT_OP_INT
] = "Int",
189 [INTEL_PT_OP_SYSCALL
] = "Syscall",
190 [INTEL_PT_OP_SYSRET
] = "Sysret",
193 const char *intel_pt_insn_name(enum intel_pt_insn_op op
)
195 return branch_name
[op
];
198 int intel_pt_insn_desc(const struct intel_pt_insn
*intel_pt_insn
, char *buf
,
201 switch (intel_pt_insn
->branch
) {
202 case INTEL_PT_BR_CONDITIONAL
:
203 case INTEL_PT_BR_UNCONDITIONAL
:
204 return snprintf(buf
, buf_len
, "%s %s%d",
205 intel_pt_insn_name(intel_pt_insn
->op
),
206 intel_pt_insn
->rel
> 0 ? "+" : "",
208 case INTEL_PT_BR_NO_BRANCH
:
209 case INTEL_PT_BR_INDIRECT
:
210 return snprintf(buf
, buf_len
, "%s",
211 intel_pt_insn_name(intel_pt_insn
->op
));
218 int intel_pt_insn_type(enum intel_pt_insn_op op
)
221 case INTEL_PT_OP_OTHER
:
223 case INTEL_PT_OP_CALL
:
224 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
;
225 case INTEL_PT_OP_RET
:
226 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
;
227 case INTEL_PT_OP_JCC
:
228 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CONDITIONAL
;
229 case INTEL_PT_OP_JMP
:
230 return PERF_IP_FLAG_BRANCH
;
231 case INTEL_PT_OP_LOOP
:
232 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CONDITIONAL
;
233 case INTEL_PT_OP_IRET
:
234 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
|
235 PERF_IP_FLAG_INTERRUPT
;
236 case INTEL_PT_OP_INT
:
237 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
|
238 PERF_IP_FLAG_INTERRUPT
;
239 case INTEL_PT_OP_SYSCALL
:
240 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
|
241 PERF_IP_FLAG_SYSCALLRET
;
242 case INTEL_PT_OP_SYSRET
:
243 return PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
|
244 PERF_IP_FLAG_SYSCALLRET
;