Skip to content

Commit

Permalink
Merge pull request #69 from albertziegenhagel/header-events
Browse files Browse the repository at this point in the history
Support more ETL header events
  • Loading branch information
albertziegenhagel authored Oct 13, 2024
2 parents 3118eda + a3dbb10 commit 18760e6
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 0 deletions.
76 changes: 76 additions & 0 deletions snail/etl/parser/records/kernel/header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,80 @@ struct event_trace_v2_header_event_view : private extract_view_dynamic_base
mutable std::optional<std::size_t> log_file_name_string_length;
};

// `Header_Extension_TypeGroup:EventTraceEvent` from wmicore.mof in WDK 10.0.22621.0
struct event_trace_v2_header_extension_type_group_event_view : private extract_view_dynamic_base
{
static inline constexpr std::string_view event_name = "EventTrace-HeaderExtension";
static inline constexpr std::uint16_t event_version = 2;
static inline constexpr auto event_types = std::array{
event_identifier_group{event_trace_group::header, 5, "Extension" },
event_identifier_group{event_trace_group::header, 32, "EndExtension"}
};

using extract_view_dynamic_base::buffer;
using extract_view_dynamic_base::extract_view_dynamic_base;

inline auto group_mask_1() const { return extract<std::uint32_t>(dynamic_offset(0, 0)); }
inline auto group_mask_2() const { return extract<std::uint32_t>(dynamic_offset(4, 0)); }
inline auto group_mask_3() const { return extract<std::uint32_t>(dynamic_offset(8, 0)); }
inline auto group_mask_4() const { return extract<std::uint32_t>(dynamic_offset(12, 0)); }
inline auto group_mask_5() const { return extract<std::uint32_t>(dynamic_offset(16, 0)); }
inline auto group_mask_6() const { return extract<std::uint32_t>(dynamic_offset(20, 0)); }
inline auto group_mask_7() const { return extract<std::uint32_t>(dynamic_offset(24, 0)); }
inline auto group_mask_8() const { return extract<std::uint32_t>(dynamic_offset(28, 0)); }

inline auto kernel_event_version() const { return extract<std::uint32_t>(dynamic_offset(32, 0)); }

inline std::size_t dynamic_size() const { return dynamic_offset(36, 0); }
};

// `Header_PartitionInfoExtensionV2_TypeGroup:EventTraceEvent` from wmicore.mof in WDK 10.0.22621.0
struct event_trace_v2_header_partition_info_extension_type_group_event_view : private extract_view_dynamic_base
{
static inline constexpr std::string_view event_name = "EventTrace-HeaderPartitionInfoExtension";
static inline constexpr std::uint16_t event_version = 2;
static inline constexpr auto event_types = std::array{
event_identifier_group{event_trace_group::header, 80, "PartitionInfoExtension"}
};

using extract_view_dynamic_base::buffer;
using extract_view_dynamic_base::extract_view_dynamic_base;

// For some reason, this has an event version build into the event data itself...
inline auto event_version_() const { return extract<std::uint16_t>(dynamic_offset(0, 0)); }

inline auto reserved() const { return extract<std::uint16_t>(dynamic_offset(2, 0)); }
inline auto partition_type() const { return extract<std::uint32_t>(dynamic_offset(4, 0)); }
inline auto qpc_offset_from_root() const { return extract<std::int64_t>(dynamic_offset(8, 0)); }

inline auto partition_id_str() const
{
assert(event_version_() == 2);
return extract_u16string(dynamic_offset(16, 0), partition_id_string_length);
}
inline auto parent_id_str() const
{
assert(event_version_() == 2);
return extract_u16string(dynamic_offset(16, 0) + partition_id_str().size() * 2 + 2, parent_id_string_length);
}

inline auto partition_id_guid() const
{
assert(event_version_() == 0);
return guid_view(buffer().subspan(16));
}
inline auto parent_id_guid() const
{
assert(event_version_() == 0);
return guid_view(buffer().subspan(32));
}

inline std::size_t dynamic_size() const { return event_version_() == 0 ? dynamic_offset(48, 0) :
dynamic_offset(16, 0) + partition_id_str().size() * 2 + 2 + parent_id_str().size() * 2 + 2; }

private:
mutable std::optional<std::size_t> partition_id_string_length;
mutable std::optional<std::size_t> parent_id_string_length;
};

} // namespace snail::etl::parser
47 changes: 47 additions & 0 deletions tests/unit/etl/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,53 @@ TEST(EtlParser, Kernel_EventTraceV2HeaderEventView)
EXPECT_EQ(event.file_name(), std::u16string(u"[multiple files]"));
}

TEST(EtlParser, Kernel_EventTraceV2HeaderPartitionInfoExtensionTypeGroup)
{
// Seems that this event is always only written with all zeros?
const std::array<std::uint8_t, 48> buffer = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

const auto event = etl::parser::event_trace_v2_header_partition_info_extension_type_group_event_view(std::as_bytes(std::span(buffer)), 8);

EXPECT_EQ(event.dynamic_size(), event.buffer().size());

EXPECT_EQ(event.event_version_(), 0);
EXPECT_EQ(event.reserved(), 0);
EXPECT_EQ(event.partition_type(), 0);
EXPECT_EQ(event.qpc_offset_from_root(), 0);
EXPECT_EQ(event.partition_id_guid().instantiate(), (common::guid{
0x0000'0000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}));
EXPECT_EQ(event.parent_id_guid().instantiate(), (common::guid{
0x0000'0000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}));
}

TEST(EtlParser, Kernel_EventTraceV2HeaderExtensionTypeGroup)
{
const std::array<std::uint8_t, 36> buffer = {
0x0f, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x00, 0x00, 0x00};

const auto event = etl::parser::event_trace_v2_header_extension_type_group_event_view(std::as_bytes(std::span(buffer)), 8);

EXPECT_EQ(event.dynamic_size(), event.buffer().size());

EXPECT_EQ(event.group_mask_1(), 0x0000'000f);
EXPECT_EQ(event.group_mask_2(), 0x0000'0406);
EXPECT_EQ(event.group_mask_3(), 0x0001'0000);
EXPECT_EQ(event.group_mask_4(), 0x0000'0000);
EXPECT_EQ(event.group_mask_5(), 0x0000'0000);
EXPECT_EQ(event.group_mask_6(), 0x0000'0000);
EXPECT_EQ(event.group_mask_7(), 0x0000'0000);
EXPECT_EQ(event.group_mask_8(), 0x0000'0000);

EXPECT_EQ(event.kernel_event_version(), 85);
}

TEST(EtlParser, Kernel_PerfinfoV2SampledProfileEventView)
{
const std::array<std::uint8_t, 16> buffer = {
Expand Down
46 changes: 46 additions & 0 deletions tools/etl_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,52 @@ int main(int argc, char* argv[])
std::cout << std::format(" session_name: '{}'\n", utf8::utf16to8(event.session_name()));
std::cout << std::format(" file_name: '{}'\n", utf8::utf16to8(event.file_name()));

if(options.dump_trace_headers) common::detail::dump_buffer(header.buffer, 0, header.buffer.size(), "header");
if(options.dump_events) common::detail::dump_buffer(event.buffer(), 0, event.buffer().size(), "event");
});
register_known_event_names<etl::parser::event_trace_v2_header_extension_type_group_event_view>(observer.known_group_event_names);
observer.register_event<etl::parser::event_trace_v2_header_extension_type_group_event_view>(
[&options, &observer]([[maybe_unused]] const etl::etl_file::header_data& file_header,
[[maybe_unused]] const etl::common_trace_header& header,
const etl::parser::event_trace_v2_header_extension_type_group_event_view& event)
{
assert(event.dynamic_size() == event.buffer().size());

if(!options.show_header) return;
if(should_ignore(options, observer.current_event_name)) return;

std::cout << std::format("@{} {:30}: kernel event version {} mask 1 {:#010x} mask 2 {:#010x} mask 3 {:#010x} mask 4 {:#010x} mask 5 {:#010x} mask 6 {:#010x} mask 7 {:#010x} mask 8 {:#010x}\n", header.timestamp, observer.current_event_name, event.kernel_event_version(), event.group_mask_1(), event.group_mask_2(), event.group_mask_3(), event.group_mask_4(), event.group_mask_5(), event.group_mask_6(), event.group_mask_7(), event.group_mask_8());

if(options.dump_trace_headers) common::detail::dump_buffer(header.buffer, 0, header.buffer.size(), "header");
if(options.dump_events) common::detail::dump_buffer(event.buffer(), 0, event.buffer().size(), "event");
});
register_known_event_names<etl::parser::event_trace_v2_header_partition_info_extension_type_group_event_view>(observer.known_group_event_names);
observer.register_event<etl::parser::event_trace_v2_header_partition_info_extension_type_group_event_view>(
[&options, &observer]([[maybe_unused]] const etl::etl_file::header_data& file_header,
[[maybe_unused]] const etl::common_trace_header& header,
const etl::parser::event_trace_v2_header_partition_info_extension_type_group_event_view& event)
{
assert(event.dynamic_size() == event.buffer().size());

if(!options.show_header) return;
if(should_ignore(options, observer.current_event_name)) return;

std::cout << std::format("@{} {:30} event version {}:\n", header.timestamp, observer.current_event_name, event.event_version_());
std::cout << std::format(" reserved: {}\n", event.reserved());
std::cout << std::format(" os_version_major: {}\n", event.partition_type());
std::cout << std::format(" qpc_offset_from_root: {}\n", event.qpc_offset_from_root());
std::cout << std::format(" partition_type: {}\n", event.partition_type());
if(event.event_version_() == 2)
{
std::cout << std::format(" partition_id: {}\n", utf8::utf16to8(event.partition_id_str()));
std::cout << std::format(" parent_id: {}\n", utf8::utf16to8(event.parent_id_str()));
}
else
{
std::cout << std::format(" partition_id: {}\n", event.partition_id_guid().instantiate().to_string(true));
std::cout << std::format(" parent_id: {}\n", event.parent_id_guid().instantiate().to_string(true));
}

if(options.dump_trace_headers) common::detail::dump_buffer(header.buffer, 0, header.buffer.size(), "header");
if(options.dump_events) common::detail::dump_buffer(event.buffer(), 0, event.buffer().size(), "event");
});
Expand Down

0 comments on commit 18760e6

Please sign in to comment.