Skip to content

Commit

Permalink
Hardcode schemas for SampleProf and CSwitch events.
Browse files Browse the repository at this point in the history
Fixes #348.

This works around missing schemas after a recent Windows 11 update.
Specifically, version 10.0.26100 24H2 was affected by this.

See microsoft/krabsetw#249 for some more details.
  • Loading branch information
mstange committed Dec 6, 2024
1 parent 384e7fe commit 715498f
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 0 deletions.
243 changes: 243 additions & 0 deletions etw-reader/src/custom_schemas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,249 @@ impl EventSchema for ThreadStart {
}
}

pub struct SampledProfile {}

/// The schema for the SampledProfile event, version 2.
///
/// This schema is hardcoded because, for a brief time
/// at the end of 2024, Windows was missing the schema
/// definition for this event type, so our queries to
/// look up the schema failed. One of the affected Windows
/// versions was 10.0.26100 24H2.
const SampledProfile_PROPS: [PropDesc; 4] = [
PropDesc {
name: "InstructionPointer",
in_type: TdhInType::InTypePointer,
out_type: TdhOutType::OutTypeCodePointer,
},
PropDesc {
name: "ThreadId",
in_type: TdhInType::InTypeUInt32,
out_type: TdhOutType::OutTypeUInt32,
},
PropDesc {
name: "Count",
in_type: TdhInType::InTypeUInt16,
out_type: TdhOutType::OutTypeUInt16,
},
PropDesc {
name: "Reserved",
in_type: TdhInType::InTypeUInt16,
out_type: TdhOutType::OutTypeUInt16,
},
];

impl EventSchema for SampledProfile {
fn provider_guid(&self) -> GUID {
GUID::from("ce1dbfb4-137e-4da6-87b0-3f59aa102cbc")
}

fn event_id(&self) -> u16 {
0
}

fn opcode(&self) -> u8 {
46
}

fn event_version(&self) -> u8 {
2
}

fn level(&self) -> u8 {
0
}

fn decoding_source(&self) -> DecodingSource {
panic!()
}

fn provider_name(&self) -> String {
"MSNT_SystemTrace".to_owned()
}

fn task_name(&self) -> String {
"PerfInfo".to_owned()
}

fn opcode_name(&self) -> String {
"SampleProf".to_string()
}

fn property_count(&self) -> u32 {
SampledProfile_PROPS.len() as u32
}

fn property(&self, index: u32) -> Property {
let prop = &SampledProfile_PROPS[index as usize];
Property {
name: prop.name.to_owned(),
desc: PropertyDesc::Primitive(PrimitiveDesc {
in_type: prop.in_type,
out_type: prop.out_type,
}),
count: 1,
length: PropertyLength::Length(0),
map_info: None,
flags: PropertyFlags::empty(),
}
}
}

pub struct CSwitch {}

/// The schema for the CSwitch event, version 4.
///
/// This schema is hardcoded because, for a brief time
/// at the end of 2024, Windows was missing the schema
/// definition for this event type, so our queries to
/// look up the schema failed. One of the affected Windows
/// versions was 10.0.26100 24H2.
//
// ```mof
// [dynamic: ToInstance, EventType(36)]
// class CSwitch_V4 : Thread_V4
// {
// [WmiDataId(1), format("x"), read] uint32 NewThreadId;
// [WmiDataId(2), format("x"), read] uint32 OldThreadId;
// [WmiDataId(3), read] sint8 NewThreadPriority;
// [WmiDataId(4), read] sint8 OldThreadPriority;
// [WmiDataId(5), read] uint8 PreviousCState;
// [WmiDataId(6), read] sint8 SpareByte;
// [WmiDataId(7), read] sint8 OldThreadWaitReason;
// [WmiDataId(8), read] sint8 ThreadFlags;
// [WmiDataId(9), read] sint8 OldThreadState;
// [WmiDataId(10), read] sint8 OldThreadWaitIdealProcessor;
// [WmiDataId(11), format("x"), read] uint32 NewThreadWaitTime;
// [WmiDataId(12), read] uint32 Reserved;
// };
// ```
const CSwitch_V4_PROPS: [PropDesc; 12] = [
PropDesc {
name: "NewThreadId",
in_type: TdhInType::InTypeUInt32,
out_type: TdhOutType::OutTypeUInt32,
},
PropDesc {
name: "OldThreadId",
in_type: TdhInType::InTypeUInt32,
out_type: TdhOutType::OutTypeUInt32,
},
PropDesc {
name: "NewThreadPriority",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "OldThreadPriority",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "PreviousCState",
in_type: TdhInType::InTypeUInt8,
out_type: TdhOutType::OutTypeUInt8,
},
PropDesc {
name: "SpareByte",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "OldThreadWaitReason",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "ThreadFlags",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "OldThreadState",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "OldThreadWaitIdealProcessor",
in_type: TdhInType::InTypeInt8,
out_type: TdhOutType::OutTypeInt8,
},
PropDesc {
name: "NewThreadWaitTime",
in_type: TdhInType::InTypeUInt32,
out_type: TdhOutType::OutTypeUInt32,
},
PropDesc {
name: "Reserved",
in_type: TdhInType::InTypeUInt32,
out_type: TdhOutType::OutTypeUInt32,
},
];

impl EventSchema for CSwitch {
fn provider_guid(&self) -> GUID {
GUID::from("3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c") // class Thread_V4 : MSNT_SystemTrace
}

fn event_id(&self) -> u16 {
0
}

fn opcode(&self) -> u8 {
36
}

fn event_version(&self) -> u8 {
// Warning: We are pretending to be version 5, because that's
// what matches the events observed on Windows 10.0.26100 Build 26100,
// which is the Windows version where the schema was missing.
// But we don't actually know the correct V5 schema! There are likely
// one or two fields added at the end which our hardcoded V4 schema
// doesn't have.
5
}

fn level(&self) -> u8 {
0
}

fn decoding_source(&self) -> DecodingSource {
panic!()
}

fn provider_name(&self) -> String {
"MSNT_SystemTrace".to_owned()
}

fn task_name(&self) -> String {
"Thread".to_owned()
}

fn opcode_name(&self) -> String {
"CSwitch".to_string()
}

fn property_count(&self) -> u32 {
CSwitch_V4_PROPS.len() as u32
}

fn property(&self, index: u32) -> Property {
let prop = &CSwitch_V4_PROPS[index as usize];
Property {
name: prop.name.to_owned(),
desc: PropertyDesc::Primitive(PrimitiveDesc {
in_type: prop.in_type,
out_type: prop.out_type,
}),
count: 1,
length: PropertyLength::Length(0),
map_info: None,
flags: PropertyFlags::empty(),
}
}
}

// from umdprovider.h
pub struct D3DUmdLogging_MapAllocation {}

Expand Down
2 changes: 2 additions & 0 deletions etw-reader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ pub fn add_custom_schemas(locator: &mut SchemaLocator) {
locator.add_custom_schema(Box::new(custom_schemas::DbgID {}));
locator.add_custom_schema(Box::new(custom_schemas::EventInfo {}));
locator.add_custom_schema(Box::new(custom_schemas::ThreadStart {}));
locator.add_custom_schema(Box::new(custom_schemas::CSwitch {}));
locator.add_custom_schema(Box::new(custom_schemas::SampledProfile {}));
locator.add_custom_schema(Box::new(custom_schemas::D3DUmdLogging_MapAllocation {}));
locator.add_custom_schema(Box::new(custom_schemas::D3DUmdLogging_RundownAllocation {}));
locator.add_custom_schema(Box::new(custom_schemas::D3DUmdLogging_UnmapAllocation {}));
Expand Down

0 comments on commit 715498f

Please sign in to comment.