use std::alloc::Layout;
use std::error::Error;
use windows::Win32::Foundation::BOOLEAN;
use windows::Win32::System::Diagnostics::Etw::{
EVENT_FILTER_DESCRIPTOR, EVENT_FILTER_EVENT_ID, EVENT_FILTER_TYPE_EVENT_ID,
EVENT_FILTER_TYPE_PID,
};
use windows::Win32::System::Diagnostics::Etw::{
MAX_EVENT_FILTER_EVENT_ID_COUNT, MAX_EVENT_FILTER_PID_COUNT,
};
#[derive(Debug)]
pub enum EventFilter {
ByPids(Vec<u16>),
ByEventIds(Vec<u16>),
}
impl EventFilter {
pub fn to_event_filter_descriptor(&self) -> Result<EventFilterDescriptor, Box<dyn Error>> {
match self {
EventFilter::ByPids(pids) => EventFilterDescriptor::try_new_by_process_ids(pids),
EventFilter::ByEventIds(ids) => EventFilterDescriptor::try_new_by_event_ids(ids),
}
}
}
#[derive(Debug)]
pub struct EventFilterDescriptor {
data: *mut u8,
layout: Layout,
ty: u32,
}
impl EventFilterDescriptor {
fn try_new<T>(data_size: usize) -> Result<Self, Box<dyn Error>> {
let data_size = match data_size {
0 => return Err("Filter must not be empty".into()),
1..=1024 => data_size as u32,
_ => {
return Err("Exceeded filter size limits".into());
}
};
let layout = Layout::from_size_align(data_size as usize, std::mem::align_of::<T>())?;
let data = unsafe {
std::alloc::alloc(layout)
};
if data.is_null() {
return Err("Invalid allocation".into());
}
Ok(Self {
data,
layout,
ty: 0,
})
}
pub fn try_new_by_event_ids(eids: &[u16]) -> Result<Self, Box<dyn Error>> {
if eids.len() > MAX_EVENT_FILTER_EVENT_ID_COUNT as usize {
return Err("Too many event IDs are filtered".into());
}
let data_size = std::mem::size_of::<EVENT_FILTER_EVENT_ID>()
+ ((eids.len().saturating_sub(1)) * std::mem::size_of::<u16>());
let mut s = Self::try_new::<EVENT_FILTER_EVENT_ID>(data_size)?;
s.ty = EVENT_FILTER_TYPE_EVENT_ID;
let p = s.data.cast::<EVENT_FILTER_EVENT_ID>();
unsafe {
(*p).FilterIn = BOOLEAN(1);
(*p).Reserved = 0;
(*p).Count = eids.len() as u16; }
let evts = unsafe {
std::slice::from_raw_parts_mut(
&((*p).Events[0]) as *const u16 as *mut u16,
std::cmp::max(1, eids.len()),
)
};
if eids.is_empty() {
evts[0] = 0;
return Ok(s);
}
evts.copy_from_slice(eids);
Ok(s)
}
pub fn try_new_by_process_ids(pids: &[u16]) -> Result<Self, Box<dyn Error>> {
if pids.len() > MAX_EVENT_FILTER_PID_COUNT as usize {
return Err("Too many PIDs are filtered".into());
}
let data_size = std::mem::size_of_val(pids);
let mut s = Self::try_new::<u16>(data_size)?;
s.ty = EVENT_FILTER_TYPE_PID;
if pids.is_empty() {
s.data = std::ptr::null_mut();
} else {
let mut p = s.data.cast::<u16>();
for pid in pids {
unsafe {
*p = *pid;
};
p = unsafe {
p.offset(1)
};
}
}
Ok(s)
}
pub fn as_event_filter_descriptor(&self) -> EVENT_FILTER_DESCRIPTOR {
EVENT_FILTER_DESCRIPTOR {
Ptr: self.data as u64,
Size: self.layout.size() as u32,
Type: self.ty,
}
}
}
impl Drop for EventFilterDescriptor {
fn drop(&mut self) {
unsafe {
std::alloc::dealloc(self.data, self.layout);
}
}
}