iptr_decoder/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![deny(missing_docs)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8
9pub mod error;
10pub mod packet_handler;
11mod raw_packet_handler;
12pub mod utils;
13
14use core::num::NonZero;
15
16pub use raw_packet_handler::{level1::IpReconstructionPattern, level2::PtwPayload};
17
18use crate::error::{DecoderError, DecoderResult};
19
20/// Packet handler trait
21///
22/// The default implementations of all packet handlers
23/// are nops.
24pub trait HandlePacket {
25    /// Custom error type
26    type Error: core::error::Error;
27
28    /// Callback at begin of decoding.
29    ///
30    /// This is useful when using the same handler to process multiple Intel PT
31    /// traces
32    fn at_decode_begin(&mut self) -> Result<(), Self::Error>;
33
34    /// Handle short TNT packet
35    ///
36    /// `packet_byte` is the whole byte of short TNT packet. `highest_bit`
37    /// is the index of highest bit that represents a valid Taken/Not-taken bit,
38    /// guaranteed to be in range 0..=6
39    ///
40    /// If `highest_bit` is 0, this means there is no Taken/Not-taken bits.
41    #[expect(unused)]
42    fn on_short_tnt_packet(
43        &mut self,
44        context: &DecoderContext,
45        packet_byte: NonZero<u8>,
46        highest_bit: u32,
47    ) -> Result<(), Self::Error> {
48        Ok(())
49    }
50
51    /// Handle short TNT packet
52    ///
53    /// `packet_bytes` is the whole 6 bytes of long TNT packet payload. The
54    /// upper 2 bytes are guaranteed to be cleared.
55    /// `highest_bit` is the index of highest bit that represents a valid
56    /// Taken/Not-taken bit, guaranteed to be in range 0..=46 or [`u32::MAX`]
57    ///
58    /// If `highest_bit` is [`u32::MAX`], this means there is no Taken/Not-taken bits.
59    #[expect(unused)]
60    fn on_long_tnt_packet(
61        &mut self,
62        context: &DecoderContext,
63        packet_bytes: NonZero<u64>,
64        highest_bit: u32,
65    ) -> Result<(), Self::Error> {
66        Ok(())
67    }
68
69    /// Handle TIP packet
70    #[expect(unused)]
71    fn on_tip_packet(
72        &mut self,
73        context: &DecoderContext,
74        ip_reconstruction_pattern: IpReconstructionPattern,
75    ) -> Result<(), Self::Error> {
76        Ok(())
77    }
78
79    /// Handle TIP.PGD packet
80    #[expect(unused)]
81    fn on_tip_pgd_packet(
82        &mut self,
83        context: &DecoderContext,
84        ip_reconstruction_pattern: IpReconstructionPattern,
85    ) -> Result<(), Self::Error> {
86        Ok(())
87    }
88
89    /// Handle TIP.PGE packet
90    #[expect(unused)]
91    fn on_tip_pge_packet(
92        &mut self,
93        context: &DecoderContext,
94        ip_reconstruction_pattern: IpReconstructionPattern,
95    ) -> Result<(), Self::Error> {
96        Ok(())
97    }
98
99    /// Handle FUP packet
100    #[expect(unused)]
101    fn on_fup_packet(
102        &mut self,
103        context: &DecoderContext,
104        ip_reconstruction_pattern: IpReconstructionPattern,
105    ) -> Result<(), Self::Error> {
106        Ok(())
107    }
108
109    /// Handle PAD packet
110    #[expect(unused)]
111    fn on_pad_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
112        Ok(())
113    }
114
115    /// Handle CYC packet
116    ///
117    /// `cyc_packet` is the total content of the CYC packet
118    #[expect(unused)]
119    fn on_cyc_packet(
120        &mut self,
121        context: &DecoderContext,
122        cyc_packet: &[u8],
123    ) -> Result<(), Self::Error> {
124        Ok(())
125    }
126
127    /// Handle MODE packet
128    ///
129    /// `leaf_id` and `mode` is the leaf ID and mode of MODE packet.
130    #[expect(unused)]
131    fn on_mode_packet(
132        &mut self,
133        context: &DecoderContext,
134        leaf_id: u8,
135        mode: u8,
136    ) -> Result<(), Self::Error> {
137        Ok(())
138    }
139
140    /// Handle MTC packet
141    ///
142    /// `ctc_payload` is the 8-bit CTC payload value
143    #[expect(unused)]
144    fn on_mtc_packet(
145        &mut self,
146        context: &DecoderContext,
147        ctc_payload: u8,
148    ) -> Result<(), Self::Error> {
149        Ok(())
150    }
151
152    /// Handle TSC packet
153    ///
154    /// `tsc_value` is the lower 7 bytes of current TSC value
155    #[expect(unused)]
156    fn on_tsc_packet(
157        &mut self,
158        context: &DecoderContext,
159        tsc_value: u64,
160    ) -> Result<(), Self::Error> {
161        Ok(())
162    }
163
164    /// Handle CBR packet
165    ///
166    /// `core_bus_ratio` is Core:Bus Ratio
167    #[expect(unused)]
168    fn on_cbr_packet(
169        &mut self,
170        context: &DecoderContext,
171        core_bus_ratio: u8,
172    ) -> Result<(), Self::Error> {
173        Ok(())
174    }
175
176    /// Handle TMA packet
177    ///
178    /// `ctc` is `CTC[15:0]`, `fast_counter` is `FastCounter[7:0]`, `fc8` is `FC[8]`
179    #[expect(unused)]
180    fn on_tma_packet(
181        &mut self,
182        context: &DecoderContext,
183        ctc: u16,
184        fast_counter: u8,
185        fc8: bool,
186    ) -> Result<(), Self::Error> {
187        Ok(())
188    }
189
190    /// Handle VMCS packet
191    ///
192    /// `vmcs_pointer`'s 12..=51 bits are `VMCS pointer [51:12]` (other bits guaranteed cleared)
193    #[expect(unused)]
194    fn on_vmcs_packet(
195        &mut self,
196        context: &DecoderContext,
197        vmcs_pointer: u64,
198    ) -> Result<(), Self::Error> {
199        Ok(())
200    }
201
202    /// Handle OVF packet
203    #[expect(unused)]
204    fn on_ovf_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
205        Ok(())
206    }
207
208    /// Handle PSB packet
209    #[expect(unused)]
210    fn on_psb_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
211        Ok(())
212    }
213
214    /// Handle PSBEND packet
215    #[expect(unused)]
216    fn on_psbend_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
217        Ok(())
218    }
219
220    /// Handle TraceStop packet
221    #[expect(unused)]
222    fn on_trace_stop_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
223        Ok(())
224    }
225
226    /// Handle PIP packet
227    ///
228    /// `cr3`'s 5..=51 bits are `CR3[51:5]` (other bits guaranteed cleared),
229    /// `rsvd_nr` is RSVD/NR
230    #[expect(unused)]
231    fn on_pip_packet(
232        &mut self,
233        context: &DecoderContext,
234        cr3: u64,
235        rsvd_nr: bool,
236    ) -> Result<(), Self::Error> {
237        Ok(())
238    }
239
240    /// Handle MNT packet
241    ///
242    /// `payload` is `Payload[63:0]`
243    #[expect(unused)]
244    fn on_mnt_packet(&mut self, context: &DecoderContext, payload: u64) -> Result<(), Self::Error> {
245        Ok(())
246    }
247
248    /// Handle PTW packet
249    ///
250    /// `ip_bit` is the IP bit, `payload` is either 4 bytes or 8 bytes
251    #[expect(unused)]
252    fn on_ptw_packet(
253        &mut self,
254        context: &DecoderContext,
255        ip_bit: bool,
256        payload: PtwPayload,
257    ) -> Result<(), Self::Error> {
258        Ok(())
259    }
260
261    /// Handle EXSTOP packet
262    ///
263    /// `ip_bit` is the IP bit
264    #[expect(unused)]
265    fn on_exstop_packet(
266        &mut self,
267        context: &DecoderContext,
268        ip_bit: bool,
269    ) -> Result<(), Self::Error> {
270        Ok(())
271    }
272
273    /// Handle MWAIT packet
274    ///
275    /// `mwait_hints` is `MWAIT Hints[7:0]`, `ext` is `EXT[1:0]` (upper 6 bits guaranteed cleared)
276    #[expect(unused)]
277    fn on_mwait_packet(
278        &mut self,
279        context: &DecoderContext,
280        mwait_hints: u8,
281        ext: u8,
282    ) -> Result<(), Self::Error> {
283        Ok(())
284    }
285
286    /// Handle PWRE packet
287    ///
288    /// `hw` is HW, `resolved_thread_c_state` is Resolved Thread C-State (upper 4 bits guaranteed cleared),
289    /// `resolved_thread_sub_c_state` is Resolved Thread Sub C-State (upper 4 bits guaranteed cleared)
290    #[expect(unused)]
291    fn on_pwre_packet(
292        &mut self,
293        context: &DecoderContext,
294        hw: bool,
295        resolved_thread_c_state: u8,
296        resolved_thread_sub_c_state: u8,
297    ) -> Result<(), Self::Error> {
298        Ok(())
299    }
300
301    /// Handle PWRX packet
302    ///
303    /// `last_core_c_state` is Last Core C-State (upper 4 bits guaranteed cleared),
304    /// `deepest_core_c_state` is Deepest Core C-State (upper 4 bits guaranteed cleared),
305    /// `wake_reason` is Wake Reason (upper 4 bits guaranteed cleared)
306    #[expect(unused)]
307    fn on_pwrx_packet(
308        &mut self,
309        context: &DecoderContext,
310        last_core_c_state: u8,
311        deepest_core_c_state: u8,
312        wake_reason: u8,
313    ) -> Result<(), Self::Error> {
314        Ok(())
315    }
316
317    /// Handle EVD packet
318    ///
319    /// `r#type` is `Type[5:0]` (upper 2 bits guaranteed cleared), `payload` is `Payload[63:0]`
320    #[expect(unused)]
321    fn on_evd_packet(
322        &mut self,
323        context: &DecoderContext,
324        r#type: u8,
325        payload: u64,
326    ) -> Result<(), Self::Error> {
327        Ok(())
328    }
329
330    /// Handle CFE packet
331    ///
332    /// `ip_bit` is the IP bit, `r#type` is `Type[4:0]` (upper 3 bits guaranteed cleared),
333    /// `vector` is the `Vector[7:0]`
334    #[expect(unused)]
335    fn on_cfe_packet(
336        &mut self,
337        context: &DecoderContext,
338        ip_bit: bool,
339        r#type: u8,
340        vector: u8,
341    ) -> Result<(), Self::Error> {
342        Ok(())
343    }
344
345    /// Handle BBP packet
346    ///
347    /// `sz_bit` is the SZ bit, `r#type` is `Type[4:0]` (upper 3 bits guaranteed cleared).
348    #[expect(unused)]
349    fn on_bbp_packet(
350        &mut self,
351        context: &DecoderContext,
352        sz_bit: bool,
353        r#type: u8,
354    ) -> Result<(), Self::Error> {
355        Ok(())
356    }
357
358    /// Handle BEP packet
359    ///
360    /// `ip_bit` is the IP bit.
361    #[expect(unused)]
362    fn on_bep_packet(&mut self, context: &DecoderContext, ip_bit: bool) -> Result<(), Self::Error> {
363        Ok(())
364    }
365
366    /// Handle BIP packet
367    ///
368    /// `id` is `ID[5:0]`, `payload`'s size is 4 or 8 according to
369    /// the `SZ` bit in BBP packet. `bbp_type` is the `type` field
370    /// of the preceding BBP packet.
371    #[expect(unused)]
372    fn on_bip_packet(
373        &mut self,
374        context: &DecoderContext,
375        id: u8,
376        payload: &[u8],
377        bbp_type: u8,
378    ) -> Result<(), Self::Error> {
379        Ok(())
380    }
381}
382
383/// Execution mode
384#[derive(Clone, Copy)]
385pub enum TraceeMode {
386    /// 16-bit mode
387    Mode16 = 16,
388    /// 32-bit mode
389    Mode32 = 32,
390    /// 64-bit mode
391    Mode64 = 64,
392}
393
394impl TraceeMode {
395    /// Get the bitness of current tracee mode
396    #[must_use]
397    pub fn bitness(self) -> u32 {
398        self as u32
399    }
400}
401
402/// Decoder context during decoding
403pub struct DecoderContext {
404    /// Next position in target buffer
405    pos: usize,
406    /// Current tracee mode (will be modified by MODE.exec packet)
407    tracee_mode: TraceeMode,
408    /// Information about packet block.
409    ///
410    /// If this field is [`Some`], this indicates that current mode
411    /// is packet block mode, which means we are between a BBP and BEP
412    packet_block: Option<PacketBlockInformation>,
413}
414
415/// Size of packet block
416#[derive(Clone, Copy)]
417enum PacketBlockSize {
418    /// 4-byte block items
419    Dword = 4,
420    /// 8-byte block items
421    Qword = 8,
422}
423
424impl PacketBlockSize {
425    /// Create from the `SZ` bit in BBP packet
426    #[must_use]
427    fn from_sz_bit(sz: bool) -> Self {
428        if sz { Self::Qword } else { Self::Dword }
429    }
430
431    /// Get block items size
432    const fn size(self) -> usize {
433        self as usize
434    }
435}
436
437/// Information about packet blocks, derived from BBP packet
438#[derive(Clone, Copy)]
439struct PacketBlockInformation {
440    /// Size of packet block items
441    size: PacketBlockSize,
442    /// Type of packet block items, retrieved from BBP packet's `Type[4:0]`
443    r#type: u8,
444}
445
446impl DecoderContext {
447    /// Get current tracee mode
448    #[must_use]
449    pub fn tracee_mode(&self) -> TraceeMode {
450        self.tracee_mode
451    }
452
453    /// Whether we are between a BBP and BEP packets.
454    ///
455    /// When you invokes this method in a BBP packet handler,
456    /// this will return the status **before** current BBP packet.
457    /// Same for BEP and OVF packet.
458    #[must_use]
459    pub fn is_in_packet_blocks(&self) -> bool {
460        self.packet_block.is_some()
461    }
462}
463
464/// Options for [`decode`].
465///
466/// You can create default options via [`DecodeOptions::default`].
467#[derive(Clone, Copy)]
468pub struct DecodeOptions {
469    tracee_mode: TraceeMode,
470    no_sync: bool,
471}
472
473impl Default for DecodeOptions {
474    fn default() -> Self {
475        Self {
476            tracee_mode: TraceeMode::Mode64,
477            no_sync: false,
478        }
479    }
480}
481
482impl DecodeOptions {
483    /// Set default mode of tracee before encountering any valid MODE.exec packets.
484    ///
485    /// Default is [`TraceeMode::Mode64`]
486    pub fn tracee_mode(&mut self, tracee_mode: TraceeMode) -> &mut Self {
487        self.tracee_mode = tracee_mode;
488        self
489    }
490
491    /// Set whether the decoder will firstly sync forward for a PSB packet instead of
492    /// decoding at 0 offset.
493    ///
494    /// Default is `true`.
495    pub fn sync(&mut self, sync: bool) -> &mut Self {
496        self.no_sync = !sync;
497        self
498    }
499}
500
501const PSB_BYTES: [u8; 16] = [
502    0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82,
503];
504
505/// Decode the given Intel PT buffer.
506///
507/// Note that the Linux Perf tool records more than raw Intel PT packets,
508/// some sideband data is also recorded. As a result, you need to extract AUX data
509/// from the `perf.data` in order to use this method.
510///
511/// # SAFETY
512///
513/// We assume that you can never construct a buf whose length can overflow a usize.
514/// As a result, we do not check any arithmetic overflow when manipulating the postion
515/// of buf cursor (unless you use a debug-build or enable `overflow-checks` in your
516/// build profile).
517pub fn decode<H: HandlePacket>(
518    buf: &[u8],
519    options: DecodeOptions,
520    packet_handler: &mut H,
521) -> DecoderResult<(), H> {
522    let DecodeOptions {
523        tracee_mode,
524        no_sync,
525    } = options;
526
527    packet_handler
528        .at_decode_begin()
529        .map_err(DecoderError::PacketHandler)?;
530
531    let start_pos = if no_sync {
532        0
533    } else {
534        let Some(start_pos) = memchr::memmem::find(buf, &PSB_BYTES) else {
535            return Err(DecoderError::NoPsb);
536        };
537        start_pos
538    };
539
540    let mut context = DecoderContext {
541        pos: start_pos,
542        tracee_mode,
543        packet_block: None,
544    };
545
546    raw_packet_handler::level1::decode(buf, &mut context, packet_handler)
547}