1 /*
2 * Copyright (c) 2013-2019, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "pt_packet.h"
30 #include "pt_opcodes.h"
31
32 #include "intel-pt.h"
33
34 #include <limits.h>
35
36
pt_pkt_read_value(const uint8_t * pos,int size)37 static uint64_t pt_pkt_read_value(const uint8_t *pos, int size)
38 {
39 uint64_t val;
40 int idx;
41
42 for (val = 0, idx = 0; idx < size; ++idx) {
43 uint64_t byte = *pos++;
44
45 byte <<= (idx * 8);
46 val |= byte;
47 }
48
49 return val;
50 }
51
pt_pkt_read_unknown(struct pt_packet * packet,const uint8_t * pos,const struct pt_config * config)52 int pt_pkt_read_unknown(struct pt_packet *packet, const uint8_t *pos,
53 const struct pt_config *config)
54 {
55 int (*decode)(struct pt_packet_unknown *, const struct pt_config *,
56 const uint8_t *, void *);
57 int size;
58
59 if (!packet || !pos || !config)
60 return -pte_internal;
61
62 decode = config->decode.callback;
63 if (!decode)
64 return -pte_bad_opc;
65
66 /* Fill in some default values. */
67 packet->payload.unknown.packet = pos;
68 packet->payload.unknown.priv = NULL;
69
70 /* We accept a size of zero to allow the callback to modify the
71 * trace buffer and resume normal decoding.
72 */
73 size = (*decode)(&packet->payload.unknown, config, pos,
74 config->decode.context);
75 if (size < 0)
76 return size;
77
78 if (size > UCHAR_MAX)
79 return -pte_invalid;
80
81 packet->type = ppt_unknown;
82 packet->size = (uint8_t) size;
83
84 if (config->end < pos + size)
85 return -pte_eos;
86
87 return size;
88 }
89
pt_pkt_read_psb(const uint8_t * pos,const struct pt_config * config)90 int pt_pkt_read_psb(const uint8_t *pos, const struct pt_config *config)
91 {
92 int count;
93
94 if (!pos || !config)
95 return -pte_internal;
96
97 if (config->end < pos + ptps_psb)
98 return -pte_eos;
99
100 pos += pt_opcs_psb;
101
102 for (count = 0; count < pt_psb_repeat_count; ++count) {
103 if (*pos++ != pt_psb_hi)
104 return -pte_bad_packet;
105 if (*pos++ != pt_psb_lo)
106 return -pte_bad_packet;
107 }
108
109 return ptps_psb;
110 }
111
pt_pkt_ip_size(enum pt_ip_compression ipc)112 static int pt_pkt_ip_size(enum pt_ip_compression ipc)
113 {
114 switch (ipc) {
115 case pt_ipc_suppressed:
116 return 0;
117
118 case pt_ipc_update_16:
119 return 2;
120
121 case pt_ipc_update_32:
122 return 4;
123
124 case pt_ipc_update_48:
125 case pt_ipc_sext_48:
126 return 6;
127
128 case pt_ipc_full:
129 return 8;
130 }
131
132 return -pte_bad_packet;
133 }
134
pt_pkt_read_ip(struct pt_packet_ip * packet,const uint8_t * pos,const struct pt_config * config)135 int pt_pkt_read_ip(struct pt_packet_ip *packet, const uint8_t *pos,
136 const struct pt_config *config)
137 {
138 uint64_t ip;
139 uint8_t ipc;
140 int ipsize;
141
142 if (!packet || !pos || !config)
143 return -pte_internal;
144
145 ipc = (*pos++ >> pt_opm_ipc_shr) & pt_opm_ipc_shr_mask;
146
147 ip = 0ull;
148 ipsize = pt_pkt_ip_size((enum pt_ip_compression) ipc);
149 if (ipsize < 0)
150 return ipsize;
151
152 if (config->end < pos + ipsize)
153 return -pte_eos;
154
155 if (ipsize)
156 ip = pt_pkt_read_value(pos, ipsize);
157
158 packet->ipc = (enum pt_ip_compression) ipc;
159 packet->ip = ip;
160
161 return ipsize + 1;
162 }
163
pt_pkt_tnt_bit_size(uint64_t payload)164 static uint8_t pt_pkt_tnt_bit_size(uint64_t payload)
165 {
166 uint8_t size;
167
168 /* The payload bit-size is the bit-index of the payload's stop-bit,
169 * which itself is not part of the payload proper.
170 */
171 for (size = 0; ; size += 1) {
172 payload >>= 1;
173 if (!payload)
174 break;
175 }
176
177 return size;
178 }
179
pt_pkt_read_tnt(struct pt_packet_tnt * packet,uint64_t payload)180 static int pt_pkt_read_tnt(struct pt_packet_tnt *packet, uint64_t payload)
181 {
182 uint8_t bit_size;
183
184 if (!packet)
185 return -pte_internal;
186
187 bit_size = pt_pkt_tnt_bit_size(payload);
188 if (!bit_size)
189 return -pte_bad_packet;
190
191 /* Remove the stop bit from the payload. */
192 payload &= ~(1ull << bit_size);
193
194 packet->payload = payload;
195 packet->bit_size = bit_size;
196
197 return 0;
198 }
199
pt_pkt_read_tnt_8(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)200 int pt_pkt_read_tnt_8(struct pt_packet_tnt *packet, const uint8_t *pos,
201 const struct pt_config *config)
202 {
203 int errcode;
204
205 (void) config;
206
207 if (!pos)
208 return -pte_internal;
209
210 errcode = pt_pkt_read_tnt(packet, pos[0] >> pt_opm_tnt_8_shr);
211 if (errcode < 0)
212 return errcode;
213
214 return ptps_tnt_8;
215 }
216
pt_pkt_read_tnt_64(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)217 int pt_pkt_read_tnt_64(struct pt_packet_tnt *packet, const uint8_t *pos,
218 const struct pt_config *config)
219 {
220 uint64_t payload;
221 int errcode;
222
223 if (!pos || !config)
224 return -pte_internal;
225
226 if (config->end < pos + ptps_tnt_64)
227 return -pte_eos;
228
229 payload = pt_pkt_read_value(pos + pt_opcs_tnt_64, pt_pl_tnt_64_size);
230
231 errcode = pt_pkt_read_tnt(packet, payload);
232 if (errcode < 0)
233 return errcode;
234
235 return ptps_tnt_64;
236 }
237
pt_pkt_read_pip(struct pt_packet_pip * packet,const uint8_t * pos,const struct pt_config * config)238 int pt_pkt_read_pip(struct pt_packet_pip *packet, const uint8_t *pos,
239 const struct pt_config *config)
240 {
241 uint64_t payload;
242
243 if (!packet || !pos || !config)
244 return -pte_internal;
245
246 if (config->end < pos + ptps_pip)
247 return -pte_eos;
248
249 /* Read the payload. */
250 payload = pt_pkt_read_value(pos + pt_opcs_pip, pt_pl_pip_size);
251
252 /* Extract the non-root information from the payload. */
253 packet->nr = payload & pt_pl_pip_nr;
254
255 /* Create the cr3 value. */
256 payload >>= pt_pl_pip_shr;
257 payload <<= pt_pl_pip_shl;
258 packet->cr3 = payload;
259
260 return ptps_pip;
261 }
262
pt_pkt_read_mode_exec(struct pt_packet_mode_exec * packet,uint8_t mode)263 static int pt_pkt_read_mode_exec(struct pt_packet_mode_exec *packet,
264 uint8_t mode)
265 {
266 if (!packet)
267 return -pte_internal;
268
269 packet->csl = (mode & pt_mob_exec_csl) != 0;
270 packet->csd = (mode & pt_mob_exec_csd) != 0;
271
272 return ptps_mode;
273 }
274
pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx * packet,uint8_t mode)275 static int pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx *packet,
276 uint8_t mode)
277 {
278 if (!packet)
279 return -pte_internal;
280
281 packet->intx = (mode & pt_mob_tsx_intx) != 0;
282 packet->abrt = (mode & pt_mob_tsx_abrt) != 0;
283
284 return ptps_mode;
285 }
286
pt_pkt_read_mode(struct pt_packet_mode * packet,const uint8_t * pos,const struct pt_config * config)287 int pt_pkt_read_mode(struct pt_packet_mode *packet, const uint8_t *pos,
288 const struct pt_config *config)
289 {
290 uint8_t payload, mode, leaf;
291
292 if (!packet || !pos || !config)
293 return -pte_internal;
294
295 if (config->end < pos + ptps_mode)
296 return -pte_eos;
297
298 payload = pos[pt_opcs_mode];
299 leaf = payload & pt_mom_leaf;
300 mode = payload & pt_mom_bits;
301
302 packet->leaf = (enum pt_mode_leaf) leaf;
303 switch (leaf) {
304 default:
305 return -pte_bad_packet;
306
307 case pt_mol_exec:
308 return pt_pkt_read_mode_exec(&packet->bits.exec, mode);
309
310 case pt_mol_tsx:
311 return pt_pkt_read_mode_tsx(&packet->bits.tsx, mode);
312 }
313 }
314
pt_pkt_read_tsc(struct pt_packet_tsc * packet,const uint8_t * pos,const struct pt_config * config)315 int pt_pkt_read_tsc(struct pt_packet_tsc *packet, const uint8_t *pos,
316 const struct pt_config *config)
317 {
318 if (!packet || !pos || !config)
319 return -pte_internal;
320
321 if (config->end < pos + ptps_tsc)
322 return -pte_eos;
323
324 packet->tsc = pt_pkt_read_value(pos + pt_opcs_tsc, pt_pl_tsc_size);
325
326 return ptps_tsc;
327 }
328
pt_pkt_read_cbr(struct pt_packet_cbr * packet,const uint8_t * pos,const struct pt_config * config)329 int pt_pkt_read_cbr(struct pt_packet_cbr *packet, const uint8_t *pos,
330 const struct pt_config *config)
331 {
332 if (!packet || !pos || !config)
333 return -pte_internal;
334
335 if (config->end < pos + ptps_cbr)
336 return -pte_eos;
337
338 packet->ratio = pos[2];
339
340 return ptps_cbr;
341 }
342
pt_pkt_read_tma(struct pt_packet_tma * packet,const uint8_t * pos,const struct pt_config * config)343 int pt_pkt_read_tma(struct pt_packet_tma *packet, const uint8_t *pos,
344 const struct pt_config *config)
345 {
346 uint16_t ctc, fc;
347
348 if (!packet || !pos || !config)
349 return -pte_internal;
350
351 if (config->end < pos + ptps_tma)
352 return -pte_eos;
353
354 ctc = pos[pt_pl_tma_ctc_0];
355 ctc |= pos[pt_pl_tma_ctc_1] << 8;
356
357 fc = pos[pt_pl_tma_fc_0];
358 fc |= pos[pt_pl_tma_fc_1] << 8;
359
360 if (fc & ~pt_pl_tma_fc_mask)
361 return -pte_bad_packet;
362
363 packet->ctc = ctc;
364 packet->fc = fc;
365
366 return ptps_tma;
367 }
368
pt_pkt_read_mtc(struct pt_packet_mtc * packet,const uint8_t * pos,const struct pt_config * config)369 int pt_pkt_read_mtc(struct pt_packet_mtc *packet, const uint8_t *pos,
370 const struct pt_config *config)
371 {
372 if (!packet || !pos || !config)
373 return -pte_internal;
374
375 if (config->end < pos + ptps_mtc)
376 return -pte_eos;
377
378 packet->ctc = pos[pt_opcs_mtc];
379
380 return ptps_mtc;
381 }
382
pt_pkt_read_cyc(struct pt_packet_cyc * packet,const uint8_t * pos,const struct pt_config * config)383 int pt_pkt_read_cyc(struct pt_packet_cyc *packet, const uint8_t *pos,
384 const struct pt_config *config)
385 {
386 const uint8_t *begin, *end;
387 uint64_t value;
388 uint8_t cyc, ext, shl;
389
390 if (!packet || !pos || !config)
391 return -pte_internal;
392
393 begin = pos;
394 end = config->end;
395
396 /* The first byte contains the opcode and part of the payload.
397 * We already checked that this first byte is within bounds.
398 */
399 cyc = *pos++;
400
401 ext = cyc & pt_opm_cyc_ext;
402 cyc >>= pt_opm_cyc_shr;
403
404 value = cyc;
405 shl = (8 - pt_opm_cyc_shr);
406
407 while (ext) {
408 uint64_t bits;
409
410 if (end <= pos)
411 return -pte_eos;
412
413 bits = *pos++;
414 ext = bits & pt_opm_cycx_ext;
415
416 bits >>= pt_opm_cycx_shr;
417 bits <<= shl;
418
419 shl += (8 - pt_opm_cycx_shr);
420 if (sizeof(value) * 8 < shl)
421 return -pte_bad_packet;
422
423 value |= bits;
424 }
425
426 packet->value = value;
427
428 return (int) (pos - begin);
429 }
430
pt_pkt_read_vmcs(struct pt_packet_vmcs * packet,const uint8_t * pos,const struct pt_config * config)431 int pt_pkt_read_vmcs(struct pt_packet_vmcs *packet, const uint8_t *pos,
432 const struct pt_config *config)
433 {
434 uint64_t payload;
435
436 if (!packet || !pos || !config)
437 return -pte_internal;
438
439 if (config->end < pos + ptps_vmcs)
440 return -pte_eos;
441
442 payload = pt_pkt_read_value(pos + pt_opcs_vmcs, pt_pl_vmcs_size);
443
444 packet->base = payload << pt_pl_vmcs_shl;
445
446 return ptps_vmcs;
447 }
448
pt_pkt_read_mnt(struct pt_packet_mnt * packet,const uint8_t * pos,const struct pt_config * config)449 int pt_pkt_read_mnt(struct pt_packet_mnt *packet, const uint8_t *pos,
450 const struct pt_config *config)
451 {
452 if (!packet || !pos || !config)
453 return -pte_internal;
454
455 if (config->end < pos + ptps_mnt)
456 return -pte_eos;
457
458 packet->payload = pt_pkt_read_value(pos + pt_opcs_mnt, pt_pl_mnt_size);
459
460 return ptps_mnt;
461 }
462
pt_pkt_read_exstop(struct pt_packet_exstop * packet,const uint8_t * pos,const struct pt_config * config)463 int pt_pkt_read_exstop(struct pt_packet_exstop *packet, const uint8_t *pos,
464 const struct pt_config *config)
465 {
466 if (!packet || !pos || !config)
467 return -pte_internal;
468
469 if (config->end < pos + ptps_exstop)
470 return -pte_eos;
471
472 packet->ip = pos[1] & pt_pl_exstop_ip_mask ? 1 : 0;
473
474 return ptps_exstop;
475 }
476
pt_pkt_read_mwait(struct pt_packet_mwait * packet,const uint8_t * pos,const struct pt_config * config)477 int pt_pkt_read_mwait(struct pt_packet_mwait *packet, const uint8_t *pos,
478 const struct pt_config *config)
479 {
480 if (!packet || !pos || !config)
481 return -pte_internal;
482
483 if (config->end < pos + ptps_mwait)
484 return -pte_eos;
485
486 packet->hints = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait,
487 pt_pl_mwait_hints_size);
488 packet->ext = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait +
489 pt_pl_mwait_hints_size,
490 pt_pl_mwait_ext_size);
491 return ptps_mwait;
492 }
493
pt_pkt_read_pwre(struct pt_packet_pwre * packet,const uint8_t * pos,const struct pt_config * config)494 int pt_pkt_read_pwre(struct pt_packet_pwre *packet, const uint8_t *pos,
495 const struct pt_config *config)
496 {
497 uint64_t payload;
498
499 if (!packet || !pos || !config)
500 return -pte_internal;
501
502 if (config->end < pos + ptps_pwre)
503 return -pte_eos;
504
505 payload = pt_pkt_read_value(pos + pt_opcs_pwre, pt_pl_pwre_size);
506
507 memset(packet, 0, sizeof(*packet));
508 packet->state = (uint8_t) ((payload & pt_pl_pwre_state_mask) >>
509 pt_pl_pwre_state_shr);
510 packet->sub_state = (uint8_t) ((payload & pt_pl_pwre_sub_state_mask) >>
511 pt_pl_pwre_sub_state_shr);
512 if (payload & pt_pl_pwre_hw_mask)
513 packet->hw = 1;
514
515 return ptps_pwre;
516 }
517
pt_pkt_read_pwrx(struct pt_packet_pwrx * packet,const uint8_t * pos,const struct pt_config * config)518 int pt_pkt_read_pwrx(struct pt_packet_pwrx *packet, const uint8_t *pos,
519 const struct pt_config *config)
520 {
521 uint64_t payload;
522
523 if (!packet || !pos || !config)
524 return -pte_internal;
525
526 if (config->end < pos + ptps_pwrx)
527 return -pte_eos;
528
529 payload = pt_pkt_read_value(pos + pt_opcs_pwrx, pt_pl_pwrx_size);
530
531 memset(packet, 0, sizeof(*packet));
532 packet->last = (uint8_t) ((payload & pt_pl_pwrx_last_mask) >>
533 pt_pl_pwrx_last_shr);
534 packet->deepest = (uint8_t) ((payload & pt_pl_pwrx_deepest_mask) >>
535 pt_pl_pwrx_deepest_shr);
536 if (payload & pt_pl_pwrx_wr_int)
537 packet->interrupt = 1;
538 if (payload & pt_pl_pwrx_wr_store)
539 packet->store = 1;
540 if (payload & pt_pl_pwrx_wr_hw)
541 packet->autonomous = 1;
542
543 return ptps_pwrx;
544 }
545
pt_pkt_read_ptw(struct pt_packet_ptw * packet,const uint8_t * pos,const struct pt_config * config)546 int pt_pkt_read_ptw(struct pt_packet_ptw *packet, const uint8_t *pos,
547 const struct pt_config *config)
548 {
549 uint8_t opc, plc;
550 int size;
551
552 if (!packet || !pos || !config)
553 return -pte_internal;
554
555 /* Skip the ext opcode. */
556 pos++;
557
558 opc = *pos++;
559 plc = (opc >> pt_opm_ptw_pb_shr) & pt_opm_ptw_pb_shr_mask;
560
561 size = pt_ptw_size(plc);
562 if (size < 0)
563 return size;
564
565 if (config->end < pos + size)
566 return -pte_eos;
567
568 packet->payload = pt_pkt_read_value(pos, size);
569 packet->plc = plc;
570 packet->ip = opc & pt_opm_ptw_ip ? 1 : 0;
571
572 return pt_opcs_ptw + size;
573 }
574