-
Notifications
You must be signed in to change notification settings - Fork 62
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 #170 from vvuk/new-etw-crates
Pull etw-reader back in at the root
- Loading branch information
Showing
25 changed files
with
1,046 additions
and
35 deletions.
There are no files selected for viewing
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,30 @@ | ||
[package] | ||
name = "etw-reader" | ||
version = "0.1.0" | ||
edition = "2021" | ||
license = "MIT" | ||
repository = "https://github.com/jrmuizel/etw-profiler" | ||
documentation = "https://docs.rs/etw-reader" | ||
description = "library for reading ETW etl files" | ||
category = "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.3" | ||
once_cell = "1.8.0" | ||
fxhash = "0.2.1" | ||
memoffset = "0.6" | ||
|
||
|
||
[dependencies.windows] | ||
version = "0.51" | ||
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,221 @@ | ||
use etw_reader::{ | ||
open_trace, | ||
parser::{Parser, TryParse}, | ||
print_property, | ||
schema::SchemaLocator, | ||
GUID, | ||
}; | ||
use std::{collections::HashMap, path::Path}; | ||
use windows::Win32::System::{ | ||
Diagnostics::Etw::{ | ||
self, EtwProviderTraitDecodeGuid, EtwProviderTraitTypeGroup, ETW_PROVIDER_TRAIT_TYPE, | ||
}, | ||
SystemInformation::PRODUCT_CORE_COUNTRYSPECIFIC, | ||
}; | ||
|
||
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 mut metadata_end = metadata_start; | ||
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 | ||
); | ||
} | ||
} | ||
}); | ||
} |
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,76 @@ | ||
use etw_reader::{open_trace, schema::SchemaLocator, GUID}; | ||
use std::{cmp::Reverse, collections::HashMap, path::Path}; | ||
|
||
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; | ||
} | ||
}); | ||
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); | ||
} | ||
} |
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 @@ | ||
use etw_reader::{ | ||
open_trace, | ||
parser::{Parser, TryParse}, | ||
schema::SchemaLocator, | ||
}; | ||
use std::path::Path; | ||
|
||
fn main() { | ||
let mut schema_locator = SchemaLocator::new(); | ||
etw_reader::add_custom_schemas(&mut schema_locator); | ||
open_trace(Path::new(&std::env::args().nth(1).unwrap()), |e| { | ||
let s = schema_locator.event_schema(e); | ||
if let Ok(s) = s { | ||
// DCEnd is used '-Buffering' traces | ||
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"); | ||
let command_line: String = parser.parse("CommandLine"); | ||
|
||
println!("{} {} {}", image_file_name, process_id, command_line); | ||
} | ||
} | ||
}); | ||
} |
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,6 @@ | ||
use etw_reader::{enumerate_trace_guids_ex, tdh}; | ||
|
||
pub fn main() { | ||
tdh::list_etw_providers(); | ||
enumerate_trace_guids_ex(false); | ||
} |
Oops, something went wrong.