]>
Commit | Line | Data |
---|---|---|
a4e92590 AH |
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 | ||
3d498078 AH |
27 | #define NR_FLAG BIT63 |
28 | ||
a4e92590 AH |
29 | #if __BYTE_ORDER == __BIG_ENDIAN |
30 | #define le16_to_cpu bswap_16 | |
31 | #define le32_to_cpu bswap_32 | |
32 | #define le64_to_cpu bswap_64 | |
33 | #define memcpy_le64(d, s, n) do { \ | |
34 | memcpy((d), (s), (n)); \ | |
35 | *(d) = le64_to_cpu(*(d)); \ | |
36 | } while (0) | |
37 | #else | |
38 | #define le16_to_cpu | |
39 | #define le32_to_cpu | |
40 | #define le64_to_cpu | |
41 | #define memcpy_le64 memcpy | |
42 | #endif | |
43 | ||
44 | static const char * const packet_name[] = { | |
45 | [INTEL_PT_BAD] = "Bad Packet!", | |
46 | [INTEL_PT_PAD] = "PAD", | |
47 | [INTEL_PT_TNT] = "TNT", | |
48 | [INTEL_PT_TIP_PGD] = "TIP.PGD", | |
49 | [INTEL_PT_TIP_PGE] = "TIP.PGE", | |
50 | [INTEL_PT_TSC] = "TSC", | |
3d498078 | 51 | [INTEL_PT_TMA] = "TMA", |
a4e92590 AH |
52 | [INTEL_PT_MODE_EXEC] = "MODE.Exec", |
53 | [INTEL_PT_MODE_TSX] = "MODE.TSX", | |
3d498078 | 54 | [INTEL_PT_MTC] = "MTC", |
a4e92590 AH |
55 | [INTEL_PT_TIP] = "TIP", |
56 | [INTEL_PT_FUP] = "FUP", | |
3d498078 AH |
57 | [INTEL_PT_CYC] = "CYC", |
58 | [INTEL_PT_VMCS] = "VMCS", | |
a4e92590 AH |
59 | [INTEL_PT_PSB] = "PSB", |
60 | [INTEL_PT_PSBEND] = "PSBEND", | |
61 | [INTEL_PT_CBR] = "CBR", | |
3d498078 | 62 | [INTEL_PT_TRACESTOP] = "TraceSTOP", |
a4e92590 AH |
63 | [INTEL_PT_PIP] = "PIP", |
64 | [INTEL_PT_OVF] = "OVF", | |
3d498078 | 65 | [INTEL_PT_MNT] = "MNT", |
a4e92590 AH |
66 | }; |
67 | ||
68 | const char *intel_pt_pkt_name(enum intel_pt_pkt_type type) | |
69 | { | |
70 | return packet_name[type]; | |
71 | } | |
72 | ||
73 | static int intel_pt_get_long_tnt(const unsigned char *buf, size_t len, | |
74 | struct intel_pt_pkt *packet) | |
75 | { | |
76 | uint64_t payload; | |
77 | int count; | |
78 | ||
79 | if (len < 8) | |
80 | return INTEL_PT_NEED_MORE_BYTES; | |
81 | ||
82 | payload = le64_to_cpu(*(uint64_t *)buf); | |
83 | ||
84 | for (count = 47; count; count--) { | |
85 | if (payload & BIT63) | |
86 | break; | |
87 | payload <<= 1; | |
88 | } | |
89 | ||
90 | packet->type = INTEL_PT_TNT; | |
91 | packet->count = count; | |
92 | packet->payload = payload << 1; | |
93 | return 8; | |
94 | } | |
95 | ||
96 | static int intel_pt_get_pip(const unsigned char *buf, size_t len, | |
97 | struct intel_pt_pkt *packet) | |
98 | { | |
99 | uint64_t payload = 0; | |
100 | ||
101 | if (len < 8) | |
102 | return INTEL_PT_NEED_MORE_BYTES; | |
103 | ||
104 | packet->type = INTEL_PT_PIP; | |
105 | memcpy_le64(&payload, buf + 2, 6); | |
106 | packet->payload = payload >> 1; | |
3d498078 AH |
107 | if (payload & 1) |
108 | packet->payload |= NR_FLAG; | |
a4e92590 AH |
109 | |
110 | return 8; | |
111 | } | |
112 | ||
3d498078 AH |
113 | static int intel_pt_get_tracestop(struct intel_pt_pkt *packet) |
114 | { | |
115 | packet->type = INTEL_PT_TRACESTOP; | |
116 | return 2; | |
117 | } | |
118 | ||
a4e92590 AH |
119 | static int intel_pt_get_cbr(const unsigned char *buf, size_t len, |
120 | struct intel_pt_pkt *packet) | |
121 | { | |
122 | if (len < 4) | |
123 | return INTEL_PT_NEED_MORE_BYTES; | |
124 | packet->type = INTEL_PT_CBR; | |
125 | packet->payload = buf[2]; | |
126 | return 4; | |
127 | } | |
128 | ||
3d498078 AH |
129 | static int intel_pt_get_vmcs(const unsigned char *buf, size_t len, |
130 | struct intel_pt_pkt *packet) | |
131 | { | |
132 | unsigned int count = (52 - 5) >> 3; | |
133 | ||
134 | if (count < 1 || count > 7) | |
135 | return INTEL_PT_BAD_PACKET; | |
136 | ||
137 | if (len < count + 2) | |
138 | return INTEL_PT_NEED_MORE_BYTES; | |
139 | ||
140 | packet->type = INTEL_PT_VMCS; | |
141 | packet->count = count; | |
142 | memcpy_le64(&packet->payload, buf + 2, count); | |
143 | ||
144 | return count + 2; | |
145 | } | |
146 | ||
a4e92590 AH |
147 | static int intel_pt_get_ovf(struct intel_pt_pkt *packet) |
148 | { | |
149 | packet->type = INTEL_PT_OVF; | |
150 | return 2; | |
151 | } | |
152 | ||
153 | static int intel_pt_get_psb(const unsigned char *buf, size_t len, | |
154 | struct intel_pt_pkt *packet) | |
155 | { | |
156 | int i; | |
157 | ||
158 | if (len < 16) | |
159 | return INTEL_PT_NEED_MORE_BYTES; | |
160 | ||
161 | for (i = 2; i < 16; i += 2) { | |
162 | if (buf[i] != 2 || buf[i + 1] != 0x82) | |
163 | return INTEL_PT_BAD_PACKET; | |
164 | } | |
165 | ||
166 | packet->type = INTEL_PT_PSB; | |
167 | return 16; | |
168 | } | |
169 | ||
170 | static int intel_pt_get_psbend(struct intel_pt_pkt *packet) | |
171 | { | |
172 | packet->type = INTEL_PT_PSBEND; | |
173 | return 2; | |
174 | } | |
175 | ||
3d498078 AH |
176 | static int intel_pt_get_tma(const unsigned char *buf, size_t len, |
177 | struct intel_pt_pkt *packet) | |
178 | { | |
179 | if (len < 7) | |
180 | return INTEL_PT_NEED_MORE_BYTES; | |
181 | ||
182 | packet->type = INTEL_PT_TMA; | |
183 | packet->payload = buf[2] | (buf[3] << 8); | |
184 | packet->count = buf[5] | ((buf[6] & BIT(0)) << 8); | |
185 | return 7; | |
186 | } | |
187 | ||
a4e92590 AH |
188 | static int intel_pt_get_pad(struct intel_pt_pkt *packet) |
189 | { | |
190 | packet->type = INTEL_PT_PAD; | |
191 | return 1; | |
192 | } | |
193 | ||
3d498078 AH |
194 | static int intel_pt_get_mnt(const unsigned char *buf, size_t len, |
195 | struct intel_pt_pkt *packet) | |
196 | { | |
197 | if (len < 11) | |
198 | return INTEL_PT_NEED_MORE_BYTES; | |
199 | packet->type = INTEL_PT_MNT; | |
200 | memcpy_le64(&packet->payload, buf + 3, 8); | |
201 | return 11 | |
202 | ; | |
203 | } | |
204 | ||
205 | static int intel_pt_get_3byte(const unsigned char *buf, size_t len, | |
206 | struct intel_pt_pkt *packet) | |
207 | { | |
208 | if (len < 3) | |
209 | return INTEL_PT_NEED_MORE_BYTES; | |
210 | ||
211 | switch (buf[2]) { | |
212 | case 0x88: /* MNT */ | |
213 | return intel_pt_get_mnt(buf, len, packet); | |
214 | default: | |
215 | return INTEL_PT_BAD_PACKET; | |
216 | } | |
217 | } | |
218 | ||
a4e92590 AH |
219 | static int intel_pt_get_ext(const unsigned char *buf, size_t len, |
220 | struct intel_pt_pkt *packet) | |
221 | { | |
222 | if (len < 2) | |
223 | return INTEL_PT_NEED_MORE_BYTES; | |
224 | ||
225 | switch (buf[1]) { | |
226 | case 0xa3: /* Long TNT */ | |
227 | return intel_pt_get_long_tnt(buf, len, packet); | |
228 | case 0x43: /* PIP */ | |
229 | return intel_pt_get_pip(buf, len, packet); | |
3d498078 AH |
230 | case 0x83: /* TraceStop */ |
231 | return intel_pt_get_tracestop(packet); | |
a4e92590 AH |
232 | case 0x03: /* CBR */ |
233 | return intel_pt_get_cbr(buf, len, packet); | |
3d498078 AH |
234 | case 0xc8: /* VMCS */ |
235 | return intel_pt_get_vmcs(buf, len, packet); | |
a4e92590 AH |
236 | case 0xf3: /* OVF */ |
237 | return intel_pt_get_ovf(packet); | |
238 | case 0x82: /* PSB */ | |
239 | return intel_pt_get_psb(buf, len, packet); | |
240 | case 0x23: /* PSBEND */ | |
241 | return intel_pt_get_psbend(packet); | |
3d498078 AH |
242 | case 0x73: /* TMA */ |
243 | return intel_pt_get_tma(buf, len, packet); | |
244 | case 0xC3: /* 3-byte header */ | |
245 | return intel_pt_get_3byte(buf, len, packet); | |
a4e92590 AH |
246 | default: |
247 | return INTEL_PT_BAD_PACKET; | |
248 | } | |
249 | } | |
250 | ||
251 | static int intel_pt_get_short_tnt(unsigned int byte, | |
252 | struct intel_pt_pkt *packet) | |
253 | { | |
254 | int count; | |
255 | ||
256 | for (count = 6; count; count--) { | |
257 | if (byte & BIT(7)) | |
258 | break; | |
259 | byte <<= 1; | |
260 | } | |
261 | ||
262 | packet->type = INTEL_PT_TNT; | |
263 | packet->count = count; | |
264 | packet->payload = (uint64_t)byte << 57; | |
265 | ||
266 | return 1; | |
267 | } | |
268 | ||
3d498078 AH |
269 | static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf, |
270 | size_t len, struct intel_pt_pkt *packet) | |
271 | { | |
272 | unsigned int offs = 1, shift; | |
273 | uint64_t payload = byte >> 3; | |
274 | ||
275 | byte >>= 2; | |
276 | len -= 1; | |
277 | for (shift = 5; byte & 1; shift += 7) { | |
278 | if (offs > 9) | |
279 | return INTEL_PT_BAD_PACKET; | |
280 | if (len < offs) | |
281 | return INTEL_PT_NEED_MORE_BYTES; | |
282 | byte = buf[offs++]; | |
283 | payload |= (byte >> 1) << shift; | |
284 | } | |
285 | ||
286 | packet->type = INTEL_PT_CYC; | |
287 | packet->payload = payload; | |
288 | return offs; | |
289 | } | |
290 | ||
a4e92590 AH |
291 | static int intel_pt_get_ip(enum intel_pt_pkt_type type, unsigned int byte, |
292 | const unsigned char *buf, size_t len, | |
293 | struct intel_pt_pkt *packet) | |
294 | { | |
e1717e04 AH |
295 | int ip_len; |
296 | ||
297 | packet->count = byte >> 5; | |
298 | ||
299 | switch (packet->count) { | |
a4e92590 | 300 | case 0: |
e1717e04 | 301 | ip_len = 0; |
a4e92590 AH |
302 | break; |
303 | case 1: | |
304 | if (len < 3) | |
305 | return INTEL_PT_NEED_MORE_BYTES; | |
e1717e04 | 306 | ip_len = 2; |
a4e92590 AH |
307 | packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1)); |
308 | break; | |
309 | case 2: | |
310 | if (len < 5) | |
311 | return INTEL_PT_NEED_MORE_BYTES; | |
e1717e04 | 312 | ip_len = 4; |
a4e92590 AH |
313 | packet->payload = le32_to_cpu(*(uint32_t *)(buf + 1)); |
314 | break; | |
315 | case 3: | |
e1717e04 | 316 | case 4: |
a4e92590 AH |
317 | if (len < 7) |
318 | return INTEL_PT_NEED_MORE_BYTES; | |
e1717e04 | 319 | ip_len = 6; |
a4e92590 AH |
320 | memcpy_le64(&packet->payload, buf + 1, 6); |
321 | break; | |
e1717e04 AH |
322 | case 6: |
323 | if (len < 9) | |
324 | return INTEL_PT_NEED_MORE_BYTES; | |
325 | ip_len = 8; | |
326 | packet->payload = le64_to_cpu(*(uint64_t *)(buf + 1)); | |
327 | break; | |
a4e92590 AH |
328 | default: |
329 | return INTEL_PT_BAD_PACKET; | |
330 | } | |
331 | ||
332 | packet->type = type; | |
333 | ||
e1717e04 | 334 | return ip_len + 1; |
a4e92590 AH |
335 | } |
336 | ||
337 | static int intel_pt_get_mode(const unsigned char *buf, size_t len, | |
338 | struct intel_pt_pkt *packet) | |
339 | { | |
340 | if (len < 2) | |
341 | return INTEL_PT_NEED_MORE_BYTES; | |
342 | ||
343 | switch (buf[1] >> 5) { | |
344 | case 0: | |
345 | packet->type = INTEL_PT_MODE_EXEC; | |
346 | switch (buf[1] & 3) { | |
347 | case 0: | |
348 | packet->payload = 16; | |
349 | break; | |
350 | case 1: | |
351 | packet->payload = 64; | |
352 | break; | |
353 | case 2: | |
354 | packet->payload = 32; | |
355 | break; | |
356 | default: | |
357 | return INTEL_PT_BAD_PACKET; | |
358 | } | |
359 | break; | |
360 | case 1: | |
361 | packet->type = INTEL_PT_MODE_TSX; | |
362 | if ((buf[1] & 3) == 3) | |
363 | return INTEL_PT_BAD_PACKET; | |
364 | packet->payload = buf[1] & 3; | |
365 | break; | |
366 | default: | |
367 | return INTEL_PT_BAD_PACKET; | |
368 | } | |
369 | ||
370 | return 2; | |
371 | } | |
372 | ||
373 | static int intel_pt_get_tsc(const unsigned char *buf, size_t len, | |
374 | struct intel_pt_pkt *packet) | |
375 | { | |
376 | if (len < 8) | |
377 | return INTEL_PT_NEED_MORE_BYTES; | |
378 | packet->type = INTEL_PT_TSC; | |
379 | memcpy_le64(&packet->payload, buf + 1, 7); | |
380 | return 8; | |
381 | } | |
382 | ||
3d498078 AH |
383 | static int intel_pt_get_mtc(const unsigned char *buf, size_t len, |
384 | struct intel_pt_pkt *packet) | |
385 | { | |
386 | if (len < 2) | |
387 | return INTEL_PT_NEED_MORE_BYTES; | |
388 | packet->type = INTEL_PT_MTC; | |
389 | packet->payload = buf[1]; | |
390 | return 2; | |
391 | } | |
392 | ||
a4e92590 AH |
393 | static int intel_pt_do_get_packet(const unsigned char *buf, size_t len, |
394 | struct intel_pt_pkt *packet) | |
395 | { | |
396 | unsigned int byte; | |
397 | ||
398 | memset(packet, 0, sizeof(struct intel_pt_pkt)); | |
399 | ||
400 | if (!len) | |
401 | return INTEL_PT_NEED_MORE_BYTES; | |
402 | ||
403 | byte = buf[0]; | |
404 | if (!(byte & BIT(0))) { | |
405 | if (byte == 0) | |
406 | return intel_pt_get_pad(packet); | |
407 | if (byte == 2) | |
408 | return intel_pt_get_ext(buf, len, packet); | |
409 | return intel_pt_get_short_tnt(byte, packet); | |
410 | } | |
411 | ||
3d498078 AH |
412 | if ((byte & 2)) |
413 | return intel_pt_get_cyc(byte, buf, len, packet); | |
414 | ||
a4e92590 AH |
415 | switch (byte & 0x1f) { |
416 | case 0x0D: | |
417 | return intel_pt_get_ip(INTEL_PT_TIP, byte, buf, len, packet); | |
418 | case 0x11: | |
419 | return intel_pt_get_ip(INTEL_PT_TIP_PGE, byte, buf, len, | |
420 | packet); | |
421 | case 0x01: | |
422 | return intel_pt_get_ip(INTEL_PT_TIP_PGD, byte, buf, len, | |
423 | packet); | |
424 | case 0x1D: | |
425 | return intel_pt_get_ip(INTEL_PT_FUP, byte, buf, len, packet); | |
426 | case 0x19: | |
427 | switch (byte) { | |
428 | case 0x99: | |
429 | return intel_pt_get_mode(buf, len, packet); | |
430 | case 0x19: | |
431 | return intel_pt_get_tsc(buf, len, packet); | |
3d498078 AH |
432 | case 0x59: |
433 | return intel_pt_get_mtc(buf, len, packet); | |
a4e92590 AH |
434 | default: |
435 | return INTEL_PT_BAD_PACKET; | |
436 | } | |
437 | default: | |
438 | return INTEL_PT_BAD_PACKET; | |
439 | } | |
440 | } | |
441 | ||
442 | int intel_pt_get_packet(const unsigned char *buf, size_t len, | |
443 | struct intel_pt_pkt *packet) | |
444 | { | |
445 | int ret; | |
446 | ||
447 | ret = intel_pt_do_get_packet(buf, len, packet); | |
448 | if (ret > 0) { | |
449 | while (ret < 8 && len > (size_t)ret && !buf[ret]) | |
450 | ret += 1; | |
451 | } | |
452 | return ret; | |
453 | } | |
454 | ||
455 | int intel_pt_pkt_desc(const struct intel_pt_pkt *packet, char *buf, | |
456 | size_t buf_len) | |
457 | { | |
3d498078 | 458 | int ret, i, nr; |
a4e92590 AH |
459 | unsigned long long payload = packet->payload; |
460 | const char *name = intel_pt_pkt_name(packet->type); | |
461 | ||
462 | switch (packet->type) { | |
463 | case INTEL_PT_BAD: | |
464 | case INTEL_PT_PAD: | |
465 | case INTEL_PT_PSB: | |
466 | case INTEL_PT_PSBEND: | |
3d498078 | 467 | case INTEL_PT_TRACESTOP: |
a4e92590 AH |
468 | case INTEL_PT_OVF: |
469 | return snprintf(buf, buf_len, "%s", name); | |
470 | case INTEL_PT_TNT: { | |
471 | size_t blen = buf_len; | |
472 | ||
473 | ret = snprintf(buf, blen, "%s ", name); | |
474 | if (ret < 0) | |
475 | return ret; | |
476 | buf += ret; | |
477 | blen -= ret; | |
478 | for (i = 0; i < packet->count; i++) { | |
479 | if (payload & BIT63) | |
480 | ret = snprintf(buf, blen, "T"); | |
481 | else | |
482 | ret = snprintf(buf, blen, "N"); | |
483 | if (ret < 0) | |
484 | return ret; | |
485 | buf += ret; | |
486 | blen -= ret; | |
487 | payload <<= 1; | |
488 | } | |
489 | ret = snprintf(buf, blen, " (%d)", packet->count); | |
490 | if (ret < 0) | |
491 | return ret; | |
492 | blen -= ret; | |
493 | return buf_len - blen; | |
494 | } | |
495 | case INTEL_PT_TIP_PGD: | |
496 | case INTEL_PT_TIP_PGE: | |
497 | case INTEL_PT_TIP: | |
498 | case INTEL_PT_FUP: | |
499 | if (!(packet->count)) | |
500 | return snprintf(buf, buf_len, "%s no ip", name); | |
3d498078 AH |
501 | case INTEL_PT_CYC: |
502 | case INTEL_PT_VMCS: | |
503 | case INTEL_PT_MTC: | |
504 | case INTEL_PT_MNT: | |
a4e92590 | 505 | case INTEL_PT_CBR: |
a4e92590 | 506 | case INTEL_PT_TSC: |
3d498078 AH |
507 | return snprintf(buf, buf_len, "%s 0x%llx", name, payload); |
508 | case INTEL_PT_TMA: | |
509 | return snprintf(buf, buf_len, "%s CTC 0x%x FC 0x%x", name, | |
510 | (unsigned)payload, packet->count); | |
a4e92590 AH |
511 | case INTEL_PT_MODE_EXEC: |
512 | return snprintf(buf, buf_len, "%s %lld", name, payload); | |
513 | case INTEL_PT_MODE_TSX: | |
514 | return snprintf(buf, buf_len, "%s TXAbort:%u InTX:%u", | |
515 | name, (unsigned)(payload >> 1) & 1, | |
516 | (unsigned)payload & 1); | |
517 | case INTEL_PT_PIP: | |
3d498078 AH |
518 | nr = packet->payload & NR_FLAG ? 1 : 0; |
519 | payload &= ~NR_FLAG; | |
520 | ret = snprintf(buf, buf_len, "%s 0x%llx (NR=%d)", | |
521 | name, payload, nr); | |
a4e92590 AH |
522 | return ret; |
523 | default: | |
524 | break; | |
525 | } | |
526 | return snprintf(buf, buf_len, "%s 0x%llx (%d)", | |
527 | name, payload, packet->count); | |
528 | } |