-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #172 from mstange/etw-reader-at-root
Merge etw-reader-at-root to main
- Loading branch information
Showing
27 changed files
with
1,112 additions
and
122 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[package] | ||
name = "etw-reader" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "MIT" | ||
repository = "https://github.com/mstange/samply" | ||
documentation = "https://docs.rs/etw-reader" | ||
description = "library for reading ETW etl files" | ||
categories = ["os::windows-apis"] | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
bitflags = "2.4.2" | ||
num-traits = "0.2" | ||
num-derive = "0.4" | ||
once_cell = "1.8.0" | ||
fxhash = "0.2.1" | ||
memoffset = "0.9" | ||
|
||
[dependencies.windows] | ||
version = "0.56" | ||
features = ["Win32_System_Diagnostics_Etw", | ||
"Win32_System_Diagnostics_Debug", | ||
"Win32_System_SystemInformation", | ||
"Win32_Security_Authorization", | ||
"Win32_System_Memory", | ||
"Win32_System_Time", | ||
"Win32_Foundation"] |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
use std::collections::HashMap; | ||
use std::path::Path; | ||
|
||
use etw_reader::parser::{Parser, TryParse}; | ||
use etw_reader::schema::SchemaLocator; | ||
use etw_reader::{open_trace, print_property, GUID}; | ||
use windows::Win32::System::Diagnostics::Etw::{ | ||
self, EtwProviderTraitDecodeGuid, EtwProviderTraitTypeGroup, | ||
}; | ||
|
||
fn main() { | ||
let mut schema_locator = SchemaLocator::new(); | ||
etw_reader::add_custom_schemas(&mut schema_locator); | ||
let pattern = std::env::args().nth(2); | ||
let mut processes = HashMap::new(); | ||
open_trace(Path::new(&std::env::args().nth(1).unwrap()), |e| { | ||
//dbg!(e.EventHeader.TimeStamp); | ||
|
||
let s = schema_locator.event_schema(e); | ||
if let Ok(s) = s { | ||
if let "MSNT_SystemTrace/Process/Start" | ||
| "MSNT_SystemTrace/Process/DCStart" | ||
| "MSNT_SystemTrace/Process/DCEnd" = s.name() | ||
{ | ||
let mut parser = Parser::create(&s); | ||
|
||
let image_file_name: String = parser.parse("ImageFileName"); | ||
let process_id: u32 = parser.parse("ProcessId"); | ||
processes.insert(process_id, image_file_name); | ||
} | ||
|
||
if let Some(pattern) = &pattern { | ||
if !s.name().contains(pattern) { | ||
return; | ||
} | ||
} | ||
println!( | ||
"{:?} {} {} {}-{} {} {}", | ||
e.EventHeader.ProviderId, | ||
s.name(), | ||
s.provider_name(), | ||
e.EventHeader.EventDescriptor.Opcode, | ||
e.EventHeader.EventDescriptor.Id, | ||
s.property_count(), | ||
e.EventHeader.TimeStamp | ||
); | ||
println!( | ||
"pid: {} {:?}", | ||
s.process_id(), | ||
processes.get(&s.process_id()) | ||
); | ||
if e.EventHeader.ActivityId != GUID::zeroed() { | ||
println!("ActivityId: {:?}", e.EventHeader.ActivityId); | ||
} | ||
if e.ExtendedDataCount > 0 { | ||
let items = unsafe { | ||
std::slice::from_raw_parts(e.ExtendedData, e.ExtendedDataCount as usize) | ||
}; | ||
for i in items { | ||
match i.ExtType as u32 { | ||
Etw::EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL => { | ||
println!("extended: SCHEMA_TL"); | ||
let data: &[u8] = unsafe { | ||
std::slice::from_raw_parts( | ||
i.DataPtr as *const u8, | ||
i.DataSize as usize, | ||
) | ||
}; | ||
|
||
// from TraceLoggingProvider.h | ||
let size = | ||
u16::from_ne_bytes(<[u8; 2]>::try_from(&data[0..2]).unwrap()); | ||
println!(" size: {}", size); | ||
let mut extension_size = 1; | ||
while data[2 + extension_size] & 0x80 != 0 { | ||
extension_size += 1; | ||
} | ||
println!(" extension: {:?}", &data[2..2 + extension_size]); | ||
let name_start = 2 + extension_size; | ||
let mut name_end = name_start; | ||
while data[name_end] != 0 { | ||
name_end += 1; | ||
} | ||
let name = | ||
String::from_utf8(data[name_start..name_end].to_owned()).unwrap(); | ||
println!(" name: {}", name); | ||
|
||
let mut field_start = name_end + 1; | ||
|
||
while field_start < data.len() { | ||
let field_name_start = field_start; | ||
let mut field_name_end = field_name_start; | ||
while data[field_name_end] != 0 { | ||
field_name_end += 1; | ||
} | ||
let field_name = String::from_utf8( | ||
data[field_name_start..field_name_end].to_owned(), | ||
) | ||
.unwrap(); | ||
println!(" field_name: {}", field_name); | ||
let mut field_pos = field_name_end + 1; | ||
let field_in_type = data[field_pos]; | ||
dbg!(field_in_type); | ||
field_pos += 1; | ||
if field_in_type & 128 == 128 { | ||
let field_out_type = data[field_pos]; | ||
field_pos += 1; | ||
dbg!(field_out_type); | ||
if field_out_type & 128 == 128 { | ||
// field extension | ||
println!(" field extension"); | ||
while data[field_pos] & 0x80 != 0 { | ||
field_pos += 1; | ||
} | ||
field_pos += 1; | ||
} | ||
} | ||
let c_count = 32; | ||
let v_count = 64; | ||
let custom = v_count | c_count; | ||
let count_mask = v_count | c_count; | ||
if field_in_type & count_mask == c_count { | ||
// value count | ||
field_pos += 2 | ||
} | ||
if field_in_type & count_mask == custom { | ||
let type_info_size = u16::from_ne_bytes( | ||
<[u8; 2]>::try_from(&data[field_pos..field_pos + 2]) | ||
.unwrap(), | ||
); | ||
field_pos += 2; | ||
field_pos += type_info_size as usize; | ||
} | ||
field_start = field_pos; | ||
} | ||
} | ||
Etw::EVENT_HEADER_EXT_TYPE_PROV_TRAITS => { | ||
println!("extended: PROV_TRAITS"); | ||
let data: &[u8] = unsafe { | ||
std::slice::from_raw_parts( | ||
i.DataPtr as *const u8, | ||
i.DataSize as usize, | ||
) | ||
}; | ||
// ProviderMetadata | ||
let size = | ||
u16::from_ne_bytes(<[u8; 2]>::try_from(&data[0..2]).unwrap()); | ||
println!(" size: {}", size); | ||
let name_start = 2; | ||
let mut name_end = name_start; | ||
while data[name_end] != 0 { | ||
name_end += 1; | ||
} | ||
let name = | ||
String::from_utf8(data[name_start..name_end].to_owned()).unwrap(); | ||
println!(" name: {}", name); | ||
let mut metadata_start = name_end + 1; | ||
// ProviderMetadataChunk | ||
while metadata_start < data.len() { | ||
let metadata_size = u16::from_ne_bytes( | ||
<[u8; 2]>::try_from(&data[metadata_start..metadata_start + 2]) | ||
.unwrap(), | ||
); | ||
let metadata_type = data[metadata_start + 2]; | ||
println!(" metadata_size: {}", metadata_size); | ||
if metadata_type as i32 == EtwProviderTraitTypeGroup.0 { | ||
println!(" EtwProviderTraitTypeGroup"); | ||
// read GUID | ||
let guid = &data[(metadata_start + 3)..]; | ||
let guid = GUID::from_values( | ||
u32::from_ne_bytes((&guid[0..4]).try_into().unwrap()), | ||
u16::from_ne_bytes((&guid[4..6]).try_into().unwrap()), | ||
u16::from_ne_bytes((&guid[6..8]).try_into().unwrap()), | ||
[ | ||
guid[8], guid[9], guid[10], guid[11], guid[12], | ||
guid[13], guid[14], guid[15], | ||
], | ||
); | ||
println!(" GUID {:?}", guid); | ||
} else if metadata_type as i32 == EtwProviderTraitDecodeGuid.0 { | ||
println!(" EtwProviderTraitDecodeGuid"); | ||
} else { | ||
println!(" Unexpected {}", metadata_type); | ||
} | ||
metadata_start += metadata_size as usize; | ||
} | ||
} | ||
_ => { | ||
println!("extended: {:?}", i); | ||
} | ||
} | ||
} | ||
} | ||
let formatted_message = s.event_message(); | ||
if let Some(message) = formatted_message { | ||
println!("message: {}", message); | ||
} | ||
let mut parser = Parser::create(&s); | ||
for i in 0..s.property_count() { | ||
let property = s.property(i); | ||
//dbg!(&property); | ||
print_property(&mut parser, &property, true); | ||
} | ||
} else if pattern.is_none() { | ||
println!( | ||
"unknown event {:x?}:{} size: {}", | ||
e.EventHeader.ProviderId, e.EventHeader.EventDescriptor.Opcode, e.UserDataLength | ||
); | ||
} | ||
}) | ||
.unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
use std::cmp::Reverse; | ||
use std::collections::HashMap; | ||
use std::path::Path; | ||
|
||
use etw_reader::schema::SchemaLocator; | ||
use etw_reader::{open_trace, GUID}; | ||
|
||
fn main() { | ||
let mut schema_locator = SchemaLocator::new(); | ||
etw_reader::add_custom_schemas(&mut schema_locator); | ||
let mut event_counts = HashMap::new(); | ||
open_trace(Path::new(&std::env::args().nth(1).unwrap()), |e| { | ||
let s = schema_locator.event_schema(e); | ||
if let Ok(s) = s { | ||
let name = format!( | ||
"{} {:?}/{}/{}", | ||
s.name(), | ||
e.EventHeader.ProviderId, | ||
e.EventHeader.EventDescriptor.Id, | ||
e.EventHeader.EventDescriptor.Opcode | ||
); | ||
if let Some(count) = event_counts.get_mut(&name) { | ||
*count += 1; | ||
} else { | ||
event_counts.insert(name, 1); | ||
} | ||
} else { | ||
let provider_name = match e.EventHeader.ProviderId { | ||
GUID { | ||
data1: 0x9B79EE91, | ||
data2: 0xB5FD, | ||
data3: 0x41C0, | ||
data4: [0xA2, 0x43, 0x42, 0x48, 0xE2, 0x66, 0xE9, 0xD0], | ||
} => "SysConfig ", | ||
GUID { | ||
data1: 0xB3E675D7, | ||
data2: 0x2554, | ||
data3: 0x4F18, | ||
data4: [0x83, 0x0B, 0x27, 0x62, 0x73, 0x25, 0x60, 0xDE], | ||
} => "KernelTraceControl ", | ||
GUID { | ||
data1: 0xED54DFF8, | ||
data2: 0xC409, | ||
data3: 0x4CF6, | ||
data4: [0xBF, 0x83, 0x05, 0xE1, 0xE6, 0x1A, 0x09, 0xC4], | ||
} => "WinSat ", | ||
// see https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/umdprovider/nf-umdprovider-umdetwregister | ||
GUID { | ||
data1: 0xa688ee40, | ||
data2: 0xd8d9, | ||
data3: 0x4736, | ||
data4: [0xb6, 0xf9, 0x6b, 0x74, 0x93, 0x5b, 0xa3, 0xb1], | ||
} => "D3DUmdLogging ", | ||
GUID { | ||
data1: 0x3d6fa8d3, | ||
data2: 0xfe05, | ||
data3: 0x11d0, | ||
data4: [0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c], | ||
} => "PageFault_V2 ", | ||
_ => "", | ||
}; | ||
|
||
let provider = format!( | ||
"{}{:?}/{}-{}/{}", | ||
provider_name, | ||
e.EventHeader.ProviderId, | ||
e.EventHeader.EventDescriptor.Id, | ||
e.EventHeader.EventDescriptor.Version, | ||
e.EventHeader.EventDescriptor.Task | ||
); | ||
*event_counts.entry(provider).or_insert(0) += 1; | ||
} | ||
}) | ||
.unwrap(); | ||
let mut event_counts: Vec<_> = event_counts.into_iter().collect(); | ||
// event_counts.sort_by_key(|x| x.0.clone()); //alphabetical | ||
event_counts.sort_by_key(|x| Reverse(x.1)); | ||
for (k, v) in event_counts { | ||
println!("{} {}", k, v); | ||
} | ||
} |
Oops, something went wrong.