diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2015-07-17 12:33:37 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-08-17 10:11:36 -0400 |
commit | a4e925905c98fb83538c164878946d77d0df1433 (patch) | |
tree | 40cfe0f857d3ad76fd676f0c6bed8b71fca901a1 /tools | |
parent | 55ea4ab4260f42b824450faa47fe4d129fce0918 (diff) |
perf tools: Add Intel PT packet decoder
Add support for decoding Intel Processor Trace packets.
This essentially provides intel_pt_get_packet() which takes a buffer of
binary data and returns the decoded packet.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1437150840-31811-3-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/util/intel-pt-decoder/Build | 1 | ||||
-rw-r--r-- | tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | 400 | ||||
-rw-r--r-- | tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h | 64 |
4 files changed, 466 insertions, 0 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 1ce0adc8b3cb..615ca12c2e44 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -78,6 +78,7 @@ libperf-$(CONFIG_X86) += tsc.o | |||
78 | libperf-y += cloexec.o | 78 | libperf-y += cloexec.o |
79 | libperf-y += thread-stack.o | 79 | libperf-y += thread-stack.o |
80 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o | 80 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o |
81 | libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ | ||
81 | libperf-y += parse-branch-options.o | 82 | libperf-y += parse-branch-options.o |
82 | 83 | ||
83 | libperf-$(CONFIG_LIBELF) += symbol-elf.o | 84 | libperf-$(CONFIG_LIBELF) += symbol-elf.o |
diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build new file mode 100644 index 000000000000..9d67381a9bd3 --- /dev/null +++ b/tools/perf/util/intel-pt-decoder/Build | |||
@@ -0,0 +1 @@ | |||
libperf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o | |||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c new file mode 100644 index 000000000000..988c82c6652d --- /dev/null +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * intel_pt_pkt_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 "intel-pt-pkt-decoder.h" | ||
22 | |||
23 | #define BIT(n) (1 << (n)) | ||
24 | |||
25 | #define BIT63 ((uint64_t)1 << 63) | ||
26 | |||
27 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
28 | #define le16_to_cpu bswap_16 | ||
29 | #define le32_to_cpu bswap_32 | ||
30 | #define le64_to_cpu bswap_64 | ||
31 | #define memcpy_le64(d, s, n) do { \ | ||
32 | memcpy((d), (s), (n)); \ | ||
33 | *(d) = le64_to_cpu(*(d)); \ | ||
34 | } while (0) | ||
35 | #else | ||
36 | #define le16_to_cpu | ||
37 | #define le32_to_cpu | ||
38 | #define le64_to_cpu | ||
39 | #define memcpy_le64 memcpy | ||
40 | #endif | ||
41 | |||
42 | static const char * const packet_name[] = { | ||
43 | [INTEL_PT_BAD] = "Bad Packet!", | ||
44 | [INTEL_PT_PAD] = "PAD", | ||
45 | [INTEL_PT_TNT] = "TNT", | ||
46 | [INTEL_PT_TIP_PGD] = "TIP.PGD", | ||
47 | [INTEL_PT_TIP_PGE] = "TIP.PGE", | ||
48 | [INTEL_PT_TSC] = "TSC", | ||
49 | [INTEL_PT_MODE_EXEC] = "MODE.Exec", | ||
50 | [INTEL_PT_MODE_TSX] = "MODE.TSX", | ||
51 | [INTEL_PT_TIP] = "TIP", | ||
52 | [INTEL_PT_FUP] = "FUP", | ||
53 | [INTEL_PT_PSB] = "PSB", | ||
54 | [INTEL_PT_PSBEND] = "PSBEND", | ||
55 | [INTEL_PT_CBR] = "CBR", | ||
56 | [INTEL_PT_PIP] = "PIP", | ||
57 | [INTEL_PT_OVF] = "OVF", | ||
58 | }; | ||
59 | |||
60 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) | ||
61 | { | ||
62 | return packet_name[type]; | ||
63 | } | ||
64 | |||
65 | static int intel_pt_get_long_tnt(const unsigned char *buf, size_t len, | ||
66 | struct intel_pt_pkt *packet) | ||
67 | { | ||
68 | uint64_t payload; | ||
69 | int count; | ||
70 | |||
71 | if (len < 8) | ||
72 | return INTEL_PT_NEED_MORE_BYTES; | ||
73 | |||
74 | payload = le64_to_cpu(*(uint64_t *)buf); | ||
75 | |||
76 | for (count = 47; count; count--) { | ||
77 | if (payload & BIT63) | ||
78 | break; | ||
79 | payload <<= 1; | ||
80 | } | ||
81 | |||
82 | packet->type = INTEL_PT_TNT; | ||
83 | packet->count = count; | ||
84 | packet->payload = payload << 1; | ||
85 | return 8; | ||
86 | } | ||
87 | |||
88 | static int intel_pt_get_pip(const unsigned char *buf, size_t len, | ||
89 | struct intel_pt_pkt *packet) | ||
90 | { | ||
91 | uint64_t payload = 0; | ||
92 | |||
93 | if (len < 8) | ||
94 | return INTEL_PT_NEED_MORE_BYTES; | ||
95 | |||
96 | packet->type = INTEL_PT_PIP; | ||
97 | memcpy_le64(&payload, buf + 2, 6); | ||
98 | packet->payload = payload >> 1; | ||
99 | |||
100 | return 8; | ||
101 | } | ||
102 | |||
103 | static int intel_pt_get_cbr(const unsigned char *buf, size_t len, | ||
104 | struct intel_pt_pkt *packet) | ||
105 | { | ||
106 | if (len < 4) | ||
107 | return INTEL_PT_NEED_MORE_BYTES; | ||
108 | packet->type = INTEL_PT_CBR; | ||
109 | packet->payload = buf[2]; | ||
110 | return 4; | ||
111 | } | ||
112 | |||
113 | static int intel_pt_get_ovf(struct intel_pt_pkt *packet) | ||
114 | { | ||
115 | packet->type = INTEL_PT_OVF; | ||
116 | return 2; | ||
117 | } | ||
118 | |||
119 | static int intel_pt_get_psb(const unsigned char *buf, size_t len, | ||
120 | struct intel_pt_pkt *packet) | ||
121 | { | ||
122 | int i; | ||
123 | |||
124 | if (len < 16) | ||
125 | return INTEL_PT_NEED_MORE_BYTES; | ||
126 | |||
127 | for (i = 2; i < 16; i += 2) { | ||
128 | if (buf[i] != 2 || buf[i + 1] != 0x82) | ||
129 | return INTEL_PT_BAD_PACKET; | ||
130 | } | ||
131 | |||
132 | packet->type = INTEL_PT_PSB; | ||
133 | return 16; | ||
134 | } | ||
135 | |||
136 | static int intel_pt_get_psbend(struct intel_pt_pkt *packet) | ||
137 | { | ||
138 | packet->type = INTEL_PT_PSBEND; | ||
139 | return 2; | ||
140 | } | ||
141 | |||
142 | static int intel_pt_get_pad(struct intel_pt_pkt *packet) | ||
143 | { | ||
144 | packet->type = INTEL_PT_PAD; | ||
145 | return 1; | ||
146 | } | ||
147 | |||
148 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, | ||
149 | struct intel_pt_pkt *packet) | ||
150 | { | ||
151 | if (len < 2) | ||
152 | return INTEL_PT_NEED_MORE_BYTES; | ||
153 | |||
154 | switch (buf[1]) { | ||
155 | case 0xa3: /* Long TNT */ | ||
156 | return intel_pt_get_long_tnt(buf, len, packet); | ||
157 | case 0x43: /* PIP */ | ||
158 | return intel_pt_get_pip(buf, len, packet); | ||
159 | case 0x03: /* CBR */ | ||
160 | return intel_pt_get_cbr(buf, len, packet); | ||
161 | case 0xf3: /* OVF */ | ||
162 | return intel_pt_get_ovf(packet); | ||
163 | case 0x82: /* PSB */ | ||
164 | return intel_pt_get_psb(buf, len, packet); | ||
165 | case 0x23: /* PSBEND */ | ||
166 | return intel_pt_get_psbend(packet); | ||
167 | default: | ||
168 | return INTEL_PT_BAD_PACKET; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static int intel_pt_get_short_tnt(unsigned int byte, | ||
173 | struct intel_pt_pkt *packet) | ||
174 | { | ||
175 | int count; | ||
176 | |||
177 | for (count = 6; count; count--) { | ||
178 | if (byte & BIT(7)) | ||
179 | break; | ||
180 | byte <<= 1; | ||
181 | } | ||
182 | |||
183 | packet->type = INTEL_PT_TNT; | ||
184 | packet->count = count; | ||
185 | packet->payload = (uint64_t)byte << 57; | ||
186 | |||
187 | return 1; | ||
188 | } | ||
189 | |||
190 | static int intel_pt_get_ip(enum intel_pt_pkt_type type, unsigned int byte, | ||
191 | const unsigned char *buf, size_t len, | ||
192 | struct intel_pt_pkt *packet) | ||
193 | { | ||
194 | switch (byte >> 5) { | ||
195 | case 0: | ||
196 | packet->count = 0; | ||
197 | break; | ||
198 | case 1: | ||
199 | if (len < 3) | ||
200 | return INTEL_PT_NEED_MORE_BYTES; | ||
201 | packet->count = 2; | ||
202 | packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1)); | ||
203 | break; | ||
204 | case 2: | ||
205 | if (len < 5) | ||
206 | return INTEL_PT_NEED_MORE_BYTES; | ||
207 | packet->count = 4; | ||
208 | packet->payload = le32_to_cpu(*(uint32_t *)(buf + 1)); | ||
209 | break; | ||
210 | case 3: | ||
211 | case 6: | ||
212 | if (len < 7) | ||
213 | return INTEL_PT_NEED_MORE_BYTES; | ||
214 | packet->count = 6; | ||
215 | memcpy_le64(&packet->payload, buf + 1, 6); | ||
216 | break; | ||
217 | default: | ||
218 | return INTEL_PT_BAD_PACKET; | ||
219 | } | ||
220 | |||
221 | packet->type = type; | ||
222 | |||
223 | return packet->count + 1; | ||
224 | } | ||
225 | |||
226 | static int intel_pt_get_mode(const unsigned char *buf, size_t len, | ||
227 | struct intel_pt_pkt *packet) | ||
228 | { | ||
229 | if (len < 2) | ||
230 | return INTEL_PT_NEED_MORE_BYTES; | ||
231 | |||
232 | switch (buf[1] >> 5) { | ||
233 | case 0: | ||
234 | packet->type = INTEL_PT_MODE_EXEC; | ||
235 | switch (buf[1] & 3) { | ||
236 | case 0: | ||
237 | packet->payload = 16; | ||
238 | break; | ||
239 | case 1: | ||
240 | packet->payload = 64; | ||
241 | break; | ||
242 | case 2: | ||
243 | packet->payload = 32; | ||
244 | break; | ||
245 | default: | ||
246 | return INTEL_PT_BAD_PACKET; | ||
247 | } | ||
248 | break; | ||
249 | case 1: | ||
250 | packet->type = INTEL_PT_MODE_TSX; | ||
251 | if ((buf[1] & 3) == 3) | ||
252 | return INTEL_PT_BAD_PACKET; | ||
253 | packet->payload = buf[1] & 3; | ||
254 | break; | ||
255 | default: | ||
256 | return INTEL_PT_BAD_PACKET; | ||
257 | } | ||
258 | |||
259 | return 2; | ||
260 | } | ||
261 | |||
262 | static int intel_pt_get_tsc(const unsigned char *buf, size_t len, | ||
263 | struct intel_pt_pkt *packet) | ||
264 | { | ||
265 | if (len < 8) | ||
266 | return INTEL_PT_NEED_MORE_BYTES; | ||
267 | packet->type = INTEL_PT_TSC; | ||
268 | memcpy_le64(&packet->payload, buf + 1, 7); | ||
269 | return 8; | ||
270 | } | ||
271 | |||
272 | static int intel_pt_do_get_packet(const unsigned char *buf, size_t len, | ||
273 | struct intel_pt_pkt *packet) | ||
274 | { | ||
275 | unsigned int byte; | ||
276 | |||
277 | memset(packet, 0, sizeof(struct intel_pt_pkt)); | ||
278 | |||
279 | if (!len) | ||
280 | return INTEL_PT_NEED_MORE_BYTES; | ||
281 | |||
282 | byte = buf[0]; | ||
283 | if (!(byte & BIT(0))) { | ||
284 | if (byte == 0) | ||
285 | return intel_pt_get_pad(packet); | ||
286 | if (byte == 2) | ||
287 | return intel_pt_get_ext(buf, len, packet); | ||
288 | return intel_pt_get_short_tnt(byte, packet); | ||
289 | } | ||
290 | |||
291 | switch (byte & 0x1f) { | ||
292 | case 0x0D: | ||
293 | return intel_pt_get_ip(INTEL_PT_TIP, byte, buf, len, packet); | ||
294 | case 0x11: | ||
295 | return intel_pt_get_ip(INTEL_PT_TIP_PGE, byte, buf, len, | ||
296 | packet); | ||
297 | case 0x01: | ||
298 | return intel_pt_get_ip(INTEL_PT_TIP_PGD, byte, buf, len, | ||
299 | packet); | ||
300 | case 0x1D: | ||
301 | return intel_pt_get_ip(INTEL_PT_FUP, byte, buf, len, packet); | ||
302 | case 0x19: | ||
303 | switch (byte) { | ||
304 | case 0x99: | ||
305 | return intel_pt_get_mode(buf, len, packet); | ||
306 | case 0x19: | ||
307 | return intel_pt_get_tsc(buf, len, packet); | ||
308 | default: | ||
309 | return INTEL_PT_BAD_PACKET; | ||
310 | } | ||
311 | default: | ||
312 | return INTEL_PT_BAD_PACKET; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | int intel_pt_get_packet(const unsigned char *buf, size_t len, | ||
317 | struct intel_pt_pkt *packet) | ||
318 | { | ||
319 | int ret; | ||
320 | |||
321 | ret = intel_pt_do_get_packet(buf, len, packet); | ||
322 | if (ret > 0) { | ||
323 | while (ret < 8 && len > (size_t)ret && !buf[ret]) | ||
324 | ret += 1; | ||
325 | } | ||
326 | return ret; | ||
327 | } | ||
328 | |||
329 | int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, | ||
330 | size_t buf_len) | ||
331 | { | ||
332 | int ret, i; | ||
333 | unsigned long long payload = packet->payload; | ||
334 | const char *name = intel_pt_pkt_name(packet->type); | ||
335 | |||
336 | switch (packet->type) { | ||
337 | case INTEL_PT_BAD: | ||
338 | case INTEL_PT_PAD: | ||
339 | case INTEL_PT_PSB: | ||
340 | case INTEL_PT_PSBEND: | ||
341 | case INTEL_PT_OVF: | ||
342 | return snprintf(buf, buf_len, "%s", name); | ||
343 | case INTEL_PT_TNT: { | ||
344 | size_t blen = buf_len; | ||
345 | |||
346 | ret = snprintf(buf, blen, "%s ", name); | ||
347 | if (ret < 0) | ||
348 | return ret; | ||
349 | buf += ret; | ||
350 | blen -= ret; | ||
351 | for (i = 0; i < packet->count; i++) { | ||
352 | if (payload & BIT63) | ||
353 | ret = snprintf(buf, blen, "T"); | ||
354 | else | ||
355 | ret = snprintf(buf, blen, "N"); | ||
356 | if (ret < 0) | ||
357 | return ret; | ||
358 | buf += ret; | ||
359 | blen -= ret; | ||
360 | payload <<= 1; | ||
361 | } | ||
362 | ret = snprintf(buf, blen, " (%d)", packet->count); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | blen -= ret; | ||
366 | return buf_len - blen; | ||
367 | } | ||
368 | case INTEL_PT_TIP_PGD: | ||
369 | case INTEL_PT_TIP_PGE: | ||
370 | case INTEL_PT_TIP: | ||
371 | case INTEL_PT_FUP: | ||
372 | if (!(packet->count)) | ||
373 | return snprintf(buf, buf_len, "%s no ip", name); | ||
374 | case INTEL_PT_CBR: | ||
375 | return snprintf(buf, buf_len, "%s 0x%llx", name, payload); | ||
376 | case INTEL_PT_TSC: | ||
377 | if (packet->count) | ||
378 | return snprintf(buf, buf_len, | ||
379 | "%s 0x%llx CTC 0x%x FC 0x%x", | ||
380 | name, payload, packet->count & 0xffff, | ||
381 | (packet->count >> 16) & 0x1ff); | ||
382 | else | ||
383 | return snprintf(buf, buf_len, "%s 0x%llx", | ||
384 | name, payload); | ||
385 | case INTEL_PT_MODE_EXEC: | ||
386 | return snprintf(buf, buf_len, "%s %lld", name, payload); | ||
387 | case INTEL_PT_MODE_TSX: | ||
388 | return snprintf(buf, buf_len, "%s TXAbort:%u InTX:%u", | ||
389 | name, (unsigned)(payload >> 1) & 1, | ||
390 | (unsigned)payload & 1); | ||
391 | case INTEL_PT_PIP: | ||
392 | ret = snprintf(buf, buf_len, "%s 0x%llx", | ||
393 | name, payload); | ||
394 | return ret; | ||
395 | default: | ||
396 | break; | ||
397 | } | ||
398 | return snprintf(buf, buf_len, "%s 0x%llx (%d)", | ||
399 | name, payload, packet->count); | ||
400 | } | ||
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h new file mode 100644 index 000000000000..53404fa942b3 --- /dev/null +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * intel_pt_pkt_decoder.h: 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 | #ifndef INCLUDE__INTEL_PT_PKT_DECODER_H__ | ||
17 | #define INCLUDE__INTEL_PT_PKT_DECODER_H__ | ||
18 | |||
19 | #include <stddef.h> | ||
20 | #include <stdint.h> | ||
21 | |||
22 | #define INTEL_PT_PKT_DESC_MAX 256 | ||
23 | |||
24 | #define INTEL_PT_NEED_MORE_BYTES -1 | ||
25 | #define INTEL_PT_BAD_PACKET -2 | ||
26 | |||
27 | #define INTEL_PT_PSB_STR "\002\202\002\202\002\202\002\202" \ | ||
28 | "\002\202\002\202\002\202\002\202" | ||
29 | #define INTEL_PT_PSB_LEN 16 | ||
30 | |||
31 | #define INTEL_PT_PKT_MAX_SZ 16 | ||
32 | |||
33 | enum intel_pt_pkt_type { | ||
34 | INTEL_PT_BAD, | ||
35 | INTEL_PT_PAD, | ||
36 | INTEL_PT_TNT, | ||
37 | INTEL_PT_TIP_PGD, | ||
38 | INTEL_PT_TIP_PGE, | ||
39 | INTEL_PT_TSC, | ||
40 | INTEL_PT_MODE_EXEC, | ||
41 | INTEL_PT_MODE_TSX, | ||
42 | INTEL_PT_TIP, | ||
43 | INTEL_PT_FUP, | ||
44 | INTEL_PT_PSB, | ||
45 | INTEL_PT_PSBEND, | ||
46 | INTEL_PT_CBR, | ||
47 | INTEL_PT_PIP, | ||
48 | INTEL_PT_OVF, | ||
49 | }; | ||
50 | |||
51 | struct intel_pt_pkt { | ||
52 | enum intel_pt_pkt_type type; | ||
53 | int count; | ||
54 | uint64_t payload; | ||
55 | }; | ||
56 | |||
57 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type); | ||
58 | |||
59 | int intel_pt_get_packet(const unsigned char *buf, size_t len, | ||
60 | struct intel_pt_pkt *packet); | ||
61 | |||
62 | int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, size_t len); | ||
63 | |||
64 | #endif | ||