Skip to content

Commit

Permalink
Merge pull request #67 from daladim/stronger_types
Browse files Browse the repository at this point in the history
Stronger types
  • Loading branch information
daladim authored Nov 14, 2022
2 parents 1f86e6c + 8dead92 commit 11d4292
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 63 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ repository = "https://github.com/n4r1b/ferrisetw"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
# Enable the conversion of timestamps to time::OffsetDateTime
time_rs = ["time"]

[dependencies]
windows = { version = "0.39", features = [
"Win32_Foundation",
Expand All @@ -30,6 +34,7 @@ num-derive = "0.3"
bitflags = "1.3.2"
widestring = "1.0"
zerocopy = "0.6"
time = { version = "0.3", features = ["large-dates"], optional = true }
# thiserror = "~1.0"
# anyhow = "~1.0"

Expand Down
92 changes: 35 additions & 57 deletions src/native/etw_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,58 +77,35 @@ pub(crate) enum ControlValues {
Update = 2,
}

#[allow(dead_code)]
enum LoggingMode {
None,
Sequential,
Circular,
Append,
NewFile,
NonStoppable,
Secure,
RealTime,
Buffering,
SystemLogger,
DelayOpenFile,
PrivateLogger,
NoPerProcBuffering,
}

impl From<LoggingMode> for u32 {
fn from(val: LoggingMode) -> Self {
match val {
// Not all but pretty much...
LoggingMode::None => Etw::EVENT_TRACE_FILE_MODE_NONE,
LoggingMode::Sequential => Etw::EVENT_TRACE_FILE_MODE_SEQUENTIAL,
LoggingMode::Circular => Etw::EVENT_TRACE_FILE_MODE_CIRCULAR,
LoggingMode::Append => Etw::EVENT_TRACE_FILE_MODE_APPEND,
LoggingMode::NewFile => Etw::EVENT_TRACE_FILE_MODE_NEWFILE,
LoggingMode::NonStoppable => Etw::EVENT_TRACE_NONSTOPPABLE_MODE,
LoggingMode::Secure => Etw::EVENT_TRACE_SECURE_MODE,
LoggingMode::RealTime => Etw::EVENT_TRACE_REAL_TIME_MODE,
LoggingMode::DelayOpenFile => Etw::EVENT_TRACE_DELAY_OPEN_FILE_MODE,
LoggingMode::Buffering => Etw::EVENT_TRACE_BUFFERING_MODE,
LoggingMode::PrivateLogger => Etw::EVENT_TRACE_PRIVATE_LOGGER_MODE,
LoggingMode::SystemLogger => Etw::EVENT_TRACE_SYSTEM_LOGGER_MODE,
LoggingMode::NoPerProcBuffering => Etw::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING,
}
}
}

#[allow(dead_code)]
enum ProcessTraceMode {
RealTime,
EventRecord,
RawTimestamp,
}

impl From<ProcessTraceMode> for u32 {
fn from(val: ProcessTraceMode) -> Self {
match val {
ProcessTraceMode::RealTime => Etw::PROCESS_TRACE_MODE_EVENT_RECORD,
ProcessTraceMode::EventRecord => Etw::PROCESS_TRACE_MODE_REAL_TIME,
ProcessTraceMode::RawTimestamp => Etw::PROCESS_TRACE_MODE_RAW_TIMESTAMP,
}
bitflags! {
/// Logging Mode constants
///
/// See <https://learn.microsoft.com/en-us/windows/win32/etw/logging-mode-constants>
pub struct LoggingMode: u32 {
const EVENT_TRACE_FILE_MODE_NONE = Etw::EVENT_TRACE_FILE_MODE_NONE;
const EVENT_TRACE_FILE_MODE_SEQUENTIAL = Etw::EVENT_TRACE_FILE_MODE_SEQUENTIAL;
const EVENT_TRACE_FILE_MODE_CIRCULAR = Etw::EVENT_TRACE_FILE_MODE_CIRCULAR;
const EVENT_TRACE_FILE_MODE_APPEND = Etw::EVENT_TRACE_FILE_MODE_APPEND;
const EVENT_TRACE_FILE_MODE_NEWFILE = Etw::EVENT_TRACE_FILE_MODE_NEWFILE;
const EVENT_TRACE_FILE_MODE_PREALLOCATE = Etw::EVENT_TRACE_FILE_MODE_PREALLOCATE;
const EVENT_TRACE_NONSTOPPABLE_MODE = Etw::EVENT_TRACE_NONSTOPPABLE_MODE;
const EVENT_TRACE_SECURE_MODE = Etw::EVENT_TRACE_SECURE_MODE;
const EVENT_TRACE_REAL_TIME_MODE = Etw::EVENT_TRACE_REAL_TIME_MODE;
const EVENT_TRACE_DELAY_OPEN_FILE_MODE = Etw::EVENT_TRACE_DELAY_OPEN_FILE_MODE;
const EVENT_TRACE_BUFFERING_MODE = Etw::EVENT_TRACE_BUFFERING_MODE;
const EVENT_TRACE_PRIVATE_LOGGER_MODE = Etw::EVENT_TRACE_PRIVATE_LOGGER_MODE;
const EVENT_TRACE_USE_KBYTES_FOR_SIZE = Etw::EVENT_TRACE_USE_KBYTES_FOR_SIZE;
const EVENT_TRACE_USE_GLOBAL_SEQUENCE = Etw::EVENT_TRACE_USE_GLOBAL_SEQUENCE;
const EVENT_TRACE_USE_LOCAL_SEQUENCE = Etw::EVENT_TRACE_USE_LOCAL_SEQUENCE;
const EVENT_TRACE_PRIVATE_IN_PROC = Etw::EVENT_TRACE_PRIVATE_IN_PROC;
const EVENT_TRACE_MODE_RESERVED = Etw::EVENT_TRACE_MODE_RESERVED;
const EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN = Etw::EVENT_TRACE_STOP_ON_HYBRID_SHUTDOWN;
const EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN = Etw::EVENT_TRACE_PERSIST_ON_HYBRID_SHUTDOWN;
const EVENT_TRACE_USE_PAGED_MEMORY = Etw::EVENT_TRACE_USE_PAGED_MEMORY;
const EVENT_TRACE_SYSTEM_LOGGER_MODE = Etw::EVENT_TRACE_SYSTEM_LOGGER_MODE;
const EVENT_TRACE_INDEPENDENT_SESSION_MODE = Etw::EVENT_TRACE_INDEPENDENT_SESSION_MODE;
const EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = Etw::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING;
const EVENT_TRACE_ADDTO_TRIAGE_DUMP = Etw::EVENT_TRACE_ADDTO_TRIAGE_DUMP;
}
}

Expand Down Expand Up @@ -178,13 +155,13 @@ impl EventTraceProperties {
etw_trace_properties.BufferSize = trace_properties.buffer_size;
etw_trace_properties.MinimumBuffers = trace_properties.min_buffer;
etw_trace_properties.MaximumBuffers = trace_properties.max_buffer;
etw_trace_properties.FlushTimer = trace_properties.flush_timer;
etw_trace_properties.FlushTimer = trace_properties.flush_timer.as_secs().clamp(1, u32::MAX as u64) as u32; // See https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties

if trace_properties.log_file_mode != 0 {
etw_trace_properties.LogFileMode = trace_properties.log_file_mode;
if trace_properties.log_file_mode.is_empty() == false {
etw_trace_properties.LogFileMode = trace_properties.log_file_mode.bits();
} else {
etw_trace_properties.LogFileMode =
u32::from(LoggingMode::RealTime) | u32::from(LoggingMode::NoPerProcBuffering);
(LoggingMode::EVENT_TRACE_REAL_TIME_MODE | LoggingMode::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING).bits()
}

etw_trace_properties.LogFileMode |= T::augmented_file_mode();
Expand Down Expand Up @@ -252,7 +229,8 @@ impl<'callbackdata> EventTraceLogfile<'callbackdata> {

native.LoggerName = PWSTR(wide_logger_name.as_mut_ptr());
native.Anonymous1.ProcessTraceMode =
u32::from(ProcessTraceMode::RealTime) | u32::from(ProcessTraceMode::EventRecord);
Etw::PROCESS_TRACE_MODE_REAL_TIME | Etw::PROCESS_TRACE_MODE_EVENT_RECORD;
// In case you really want to use PROCESS_TRACE_MODE_RAW_TIMESTAMP, please review EventRecord::timestamp(), which could not be valid anymore

native.Anonymous2.EventRecordCallback = Some(callback);

Expand Down
24 changes: 23 additions & 1 deletion src/native/etw_types/event_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,32 @@ impl EventRecord {
/// > contains the `PROCESS_TRACE_MODE_RAW_TIMESTAMP` flag, in which case the resolution depends
/// > on the value of the `Wnode.ClientContext` member of `EVENT_TRACE_PROPERTIES` at the time
/// > the controller created the session.
pub fn timestamp(&self) -> i64 {
///
/// Note: the `time_rs` Cargo feature enables to convert this into strongly-typed values
pub fn raw_timestamp(&self) -> i64 {
self.0.EventHeader.TimeStamp
}

/// The `TimeStamp` field from the wrapped `EVENT_RECORD`, as a strongly-typed `time::OffsetDateTime`
#[cfg(feature = "time_rs")]
pub fn timestamp(&self) -> time::OffsetDateTime {
// "system time" means the count of hundreds of nanoseconds since midnight, January 1, 1601
let system_time = self.0.EventHeader.TimeStamp;

const SECONDS_BETWEEN_1601_AND_1970: i128 = 11_644_473_600;
const HUNDREDS_OF_NANOS_IN_SECOND: i128 = 10_000_000;
const HUNDREDS_OF_NANOSECONDS_BETWEEN_1601_AND_1970: i128 =
SECONDS_BETWEEN_1601_AND_1970 * HUNDREDS_OF_NANOS_IN_SECOND;

let unix_as_hundreds_of_nano_seconds = (system_time as i128) - HUNDREDS_OF_NANOSECONDS_BETWEEN_1601_AND_1970;
let unix_as_nano_seconds = unix_as_hundreds_of_nano_seconds * 100;

// Can't panic.
// A filetime can go from 1601 to 30828.
// OffsetDateTime (with the 'large-dates' feature) can represent any time from year -999_999 to +999_999. Meanwhile, .
time::OffsetDateTime::from_unix_timestamp_nanos(unix_as_nano_seconds).unwrap()
}

pub(crate) fn user_buffer(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
Expand Down
26 changes: 21 additions & 5 deletions src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ use std::ffi::OsString;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;

use self::private::PrivateTraceTrait;

use crate::native::etw_types::{EventRecord, EventTraceProperties};
use crate::native::etw_types::{EventRecord, EventTraceProperties, LoggingMode};
use crate::native::{evntrace, version_helper};
use crate::native::evntrace::{ControlHandle, TraceHandle, start_trace, open_trace, process_trace, enable_provider, control_trace, close_trace};
use crate::provider::Provider;
Expand Down Expand Up @@ -52,18 +53,33 @@ type TraceResult<T> = Result<T, TraceError>;
/// These are some configuration settings that will be included in an [`EVENT_TRACE_PROPERTIES`](https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties)
///
/// [More info](https://docs.microsoft.com/en-us/message-analyzer/specifying-advanced-etw-session-configuration-settings#configuring-the-etw-session)
#[derive(Debug, Copy, Clone, Default)]
#[derive(Debug, Copy, Clone)]
pub struct TraceProperties {
/// Represents the ETW Session in KB
pub buffer_size: u32,
/// Represents the ETW Session minimum number of buffers to use
pub min_buffer: u32,
/// Represents the ETW Session maximum number of buffers in the buffer pool
pub max_buffer: u32,
/// Represents the ETW Session flush interval in seconds
pub flush_timer: u32,
/// Represents the ETW Session flush interval.
///
/// This duration will be rounded to the closest second (and 0 will be translated as 1 second)
pub flush_timer: Duration,
/// Represents the ETW Session [Logging Mode](https://docs.microsoft.com/en-us/windows/win32/etw/logging-mode-constants)
pub log_file_mode: u32,
pub log_file_mode: LoggingMode,
}

impl Default for TraceProperties {
fn default() -> Self {
// Sane defaults, inspired by https://learn.microsoft.com/en-us/windows/win32/api/evntrace/ns-evntrace-event_trace_properties
TraceProperties {
buffer_size: 32,
min_buffer: 0,
max_buffer: 0,
flush_timer: Duration::from_secs(1),
log_file_mode: LoggingMode::EVENT_TRACE_REAL_TIME_MODE | LoggingMode::EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING,
}
}
}

/// Data used by callbacks when the trace is running
Expand Down

0 comments on commit 11d4292

Please sign in to comment.