#![doc = include_str!("../README.md")]
#![no_std]
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
pub mod error;
pub mod packet_handler;
mod raw_packet_handler;
pub mod utils;
use core::num::NonZero;
pub use raw_packet_handler::{level1::IpReconstructionPattern, level2::PtwPayload};
use crate::error::{DecoderError, DecoderResult};
pub trait HandlePacket {
type Error: core::error::Error;
fn at_decode_begin(&mut self) -> Result<(), Self::Error>;
#[expect(unused)]
fn on_short_tnt_packet(
&mut self,
context: &DecoderContext,
packet_byte: NonZero<u8>,
highest_bit: u32,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_long_tnt_packet(
&mut self,
context: &DecoderContext,
packet_bytes: NonZero<u64>,
highest_bit: u32,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_tip_packet(
&mut self,
context: &DecoderContext,
ip_reconstruction_pattern: IpReconstructionPattern,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_tip_pgd_packet(
&mut self,
context: &DecoderContext,
ip_reconstruction_pattern: IpReconstructionPattern,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_tip_pge_packet(
&mut self,
context: &DecoderContext,
ip_reconstruction_pattern: IpReconstructionPattern,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_fup_packet(
&mut self,
context: &DecoderContext,
ip_reconstruction_pattern: IpReconstructionPattern,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_pad_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_cyc_packet(
&mut self,
context: &DecoderContext,
cyc_packet: &[u8],
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_mode_packet(
&mut self,
context: &DecoderContext,
leaf_id: u8,
mode: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_mtc_packet(
&mut self,
context: &DecoderContext,
ctc_payload: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_tsc_packet(
&mut self,
context: &DecoderContext,
tsc_value: u64,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_cbr_packet(
&mut self,
context: &DecoderContext,
core_bus_ratio: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_tma_packet(
&mut self,
context: &DecoderContext,
ctc: u16,
fast_counter: u8,
fc8: bool,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_vmcs_packet(
&mut self,
context: &DecoderContext,
vmcs_pointer: u64,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_ovf_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_psb_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_psbend_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_trace_stop_packet(&mut self, context: &DecoderContext) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_pip_packet(
&mut self,
context: &DecoderContext,
cr3: u64,
rsvd_nr: bool,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_mnt_packet(&mut self, context: &DecoderContext, payload: u64) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_ptw_packet(
&mut self,
context: &DecoderContext,
ip_bit: bool,
payload: PtwPayload,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_exstop_packet(
&mut self,
context: &DecoderContext,
ip_bit: bool,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_mwait_packet(
&mut self,
context: &DecoderContext,
mwait_hints: u8,
ext: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_pwre_packet(
&mut self,
context: &DecoderContext,
hw: bool,
resolved_thread_c_state: u8,
resolved_thread_sub_c_state: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_pwrx_packet(
&mut self,
context: &DecoderContext,
last_core_c_state: u8,
deepest_core_c_state: u8,
wake_reason: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_evd_packet(
&mut self,
context: &DecoderContext,
r#type: u8,
payload: u64,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_cfe_packet(
&mut self,
context: &DecoderContext,
ip_bit: bool,
r#type: u8,
vector: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_bbp_packet(
&mut self,
context: &DecoderContext,
sz_bit: bool,
r#type: u8,
) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_bep_packet(&mut self, context: &DecoderContext, ip_bit: bool) -> Result<(), Self::Error> {
Ok(())
}
#[expect(unused)]
fn on_bip_packet(
&mut self,
context: &DecoderContext,
id: u8,
payload: &[u8],
bbp_type: u8,
) -> Result<(), Self::Error> {
Ok(())
}
}
#[derive(Clone, Copy)]
pub enum TraceeMode {
Mode16 = 16,
Mode32 = 32,
Mode64 = 64,
}
impl TraceeMode {
#[must_use]
pub fn bitness(self) -> u32 {
self as u32
}
}
pub struct DecoderContext {
pos: usize,
tracee_mode: TraceeMode,
packet_block: Option<PacketBlockInformation>,
}
#[derive(Clone, Copy)]
enum PacketBlockSize {
Dword = 4,
Qword = 8,
}
impl PacketBlockSize {
#[must_use]
fn from_sz_bit(sz: bool) -> Self {
if sz { Self::Qword } else { Self::Dword }
}
const fn size(self) -> usize {
self as usize
}
}
#[derive(Clone, Copy)]
struct PacketBlockInformation {
size: PacketBlockSize,
r#type: u8,
}
impl DecoderContext {
#[must_use]
pub fn tracee_mode(&self) -> TraceeMode {
self.tracee_mode
}
#[must_use]
pub fn is_in_packet_blocks(&self) -> bool {
self.packet_block.is_some()
}
}
#[derive(Clone, Copy)]
pub struct DecodeOptions {
tracee_mode: TraceeMode,
no_sync: bool,
}
impl Default for DecodeOptions {
fn default() -> Self {
Self {
tracee_mode: TraceeMode::Mode64,
no_sync: false,
}
}
}
impl DecodeOptions {
pub fn tracee_mode(&mut self, tracee_mode: TraceeMode) -> &mut Self {
self.tracee_mode = tracee_mode;
self
}
pub fn sync(&mut self, sync: bool) -> &mut Self {
self.no_sync = !sync;
self
}
}
const PSB_BYTES: [u8; 16] = [
0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82,
];
pub fn decode<H: HandlePacket>(
buf: &[u8],
options: DecodeOptions,
packet_handler: &mut H,
) -> DecoderResult<(), H> {
let DecodeOptions {
tracee_mode,
no_sync,
} = options;
packet_handler
.at_decode_begin()
.map_err(DecoderError::PacketHandler)?;
let start_pos = if no_sync {
0
} else {
let Some(start_pos) = memchr::memmem::find(buf, &PSB_BYTES) else {
return Err(DecoderError::NoPsb);
};
start_pos
};
let mut context = DecoderContext {
pos: start_pos,
tracee_mode,
packet_block: None,
};
raw_packet_handler::level1::decode(buf, &mut context, packet_handler)
}