0

Fix EtwConsumerTest failures in Win x86 builds

Make EtwConsumerTest aware of pointer size when encoding events.

Bug: 395029279
Change-Id: Ica77c290f871871d6f3335da9fd6d37eded31abe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6242939
Commit-Queue: Primiano Tucci <primiano@chromium.org>
Reviewed-by: Primiano Tucci <primiano@chromium.org>
Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org>
Auto-Submit: Tomasz Moniuszko <tmoniuszko@opera.com>
Cr-Commit-Position: refs/heads/main@{#1418974}
This commit is contained in:
Tomasz Moniuszko
2025-02-11 16:04:07 -08:00
committed by Chromium LUCI CQ
parent 47b6b55954
commit b62585763c
3 changed files with 72 additions and 39 deletions

@ -43,27 +43,6 @@ struct IsGuidLess {
}
};
// Returns the size, in bytes, of a pointer-sized value in an event based on the
// `Flags` member of an event's `EVENT_HEADER`.
size_t GetPointerSize(uint16_t event_header_flags) {
// Default to the native pointer size with the expectation that, in the
// general case, the bitness of this binary matches the bitness of the OS.
#if defined(ARCH_CPU_64_BITS)
static constexpr size_t kThisPointerSize = 8;
static constexpr size_t kOtherPointerSize = 4;
static constexpr uint16_t kOtherSizeFlag = EVENT_HEADER_FLAG_32_BIT_HEADER;
#elif defined(ARCH_CPU_32_BITS)
static constexpr size_t kThisPointerSize = 4;
static constexpr size_t kOtherPointerSize = 8;
static constexpr uint16_t kOtherSizeFlag = EVENT_HEADER_FLAG_64_BIT_HEADER;
#else
#error Unsupported architecture
#endif
return (event_header_flags & kOtherSizeFlag) == kOtherSizeFlag
? kOtherPointerSize
: kThisPointerSize;
}
} // namespace
EtwConsumer::EtwConsumer(
@ -150,6 +129,26 @@ bool EtwConsumer::ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
return true; // Continue processing events.
}
// static
size_t EtwConsumer::GetPointerSize(uint16_t event_header_flags) {
// Default to the native pointer size with the expectation that, in the
// general case, the bitness of this binary matches the bitness of the OS.
#if defined(ARCH_CPU_64_BITS)
static constexpr size_t kThisPointerSize = 8;
static constexpr size_t kOtherPointerSize = 4;
static constexpr uint16_t kOtherSizeFlag = EVENT_HEADER_FLAG_32_BIT_HEADER;
#elif defined(ARCH_CPU_32_BITS)
static constexpr size_t kThisPointerSize = 4;
static constexpr size_t kOtherPointerSize = 8;
static constexpr uint16_t kOtherSizeFlag = EVENT_HEADER_FLAG_64_BIT_HEADER;
#else
#error Unsupported architecture
#endif
return (event_header_flags & kOtherSizeFlag) == kOtherSizeFlag
? kOtherPointerSize
: kThisPointerSize;
}
void EtwConsumer::HandleProcessEvent(const EVENT_HEADER& header,
const ETW_BUFFER_CONTEXT& buffer_context,
size_t pointer_size,

@ -68,6 +68,10 @@ class TRACING_EXPORT EtwConsumer
size_t pointer_size,
base::span<const uint8_t> packet_data);
// Returns the size, in bytes, of a pointer-sized value in an event based on
// the `Flags` member of an event's `EVENT_HEADER`.
static size_t GetPointerSize(uint16_t event_header_flags);
// Per-provider event handlers. `ProcessEventRecord` dispatches to these based
// on the ProviderId in the record's EventHeader.
void HandleProcessEvent(const EVENT_HEADER& header,

@ -14,6 +14,7 @@
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/containers/heap_array.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
@ -93,44 +94,62 @@ struct CSwitchData {
// Returns the MOF encoding of a sid, including the leading uint32_t and
// TOKEN_USER.
base::HeapArray<uint8_t> EncodeSid() {
static constexpr uint8_t kBytes[] = {
0x04, 0x00, 0x00, 0x00, 0x20, 0xA8, 0xA4, 0x5C, 0x86, 0xD1, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00};
return base::HeapArray<uint8_t>::CopiedFrom({kBytes});
base::HeapArray<uint8_t> EncodeSid(size_t pointer_size) {
static constexpr uint8_t kLeadingBytes[] = {0x04, 0x00, 0x00, 0x00};
static constexpr uint8_t kTokenUserBytes[] = {
0x20, 0xA8, 0xA4, 0x5C, 0x86, 0xD1, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static constexpr uint8_t kSidBytes[] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x05, 0x12, 0x00, 0x00, 0x00};
std::vector<uint8_t> buffer;
auto iter = std::back_inserter(buffer);
std::ranges::copy(base::as_byte_span(kLeadingBytes), iter);
std::ranges::copy(base::span(kTokenUserBytes).first(2 * pointer_size), iter);
std::ranges::copy(base::as_byte_span(kSidBytes), iter);
return base::HeapArray<uint8_t>::CopiedFrom({buffer});
}
// Returns the MOF encoding of a Process event (v4 by default).
// Returns the MOF encoding of a Process event.
base::HeapArray<uint8_t> EncodeProcess(const ProcessData& process,
int version = 4) {
int version,
size_t pointer_size) {
std::vector<uint8_t> buffer;
auto iter = std::back_inserter(buffer);
if (version == 0) {
// ProcessId and ParentId are pointer-sized in version 0.
uintptr_t value = process.process_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
value = process.parent_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
std::ranges::copy(EncodeSid(), iter);
if (pointer_size == sizeof(uint64_t)) {
uint64_t value = process.process_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
value = process.parent_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
} else {
CHECK_EQ(pointer_size, sizeof(uint32_t));
uint32_t value = process.process_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
value = process.parent_id;
std::ranges::copy(base::byte_span_from_ref(value), iter);
}
std::ranges::copy(EncodeSid(pointer_size), iter);
std::ranges::copy(process.image_file_name, iter);
buffer.insert(buffer.end(), '\0'); // ImageFileName terminator
} else {
if (version == 1) {
// PageDirectoryBase
buffer.insert(buffer.end(), sizeof(void*), 0);
buffer.insert(buffer.end(), pointer_size, 0);
} else if (version >= 2) {
// UniqueProcessKey
buffer.insert(buffer.end(), sizeof(void*), 0);
buffer.insert(buffer.end(), pointer_size, 0);
}
std::ranges::copy(base::byte_span_from_ref(process.process_id), iter);
std::ranges::copy(base::byte_span_from_ref(process.parent_id), iter);
std::ranges::copy(base::byte_span_from_ref(process.session_id), iter);
buffer.insert(buffer.end(), sizeof(int32_t), 0); // ExitStatus
if (version >= 3) {
buffer.insert(buffer.end(), sizeof(void*), 0); // DirectoryTableBase
buffer.insert(buffer.end(), pointer_size, 0); // DirectoryTableBase
}
std::ranges::copy(EncodeSid(), iter);
std::ranges::copy(EncodeSid(pointer_size), iter);
std::ranges::copy(process.image_file_name, iter);
buffer.insert(buffer.end(), '\0'); // ImageFileName terminator
if (version >= 2) {
@ -409,8 +428,19 @@ class EtwConsumerTest : public testing::Test {
version, opcode, packet_data);
}
// Returns the MOF encoding of a Process event (v4 by default).
base::HeapArray<uint8_t> EncodeProcess(const ProcessData& process,
int version = 4) {
// We are using EVENT_HEADER_FLAG_64_BIT_HEADER flag, so the pointer size
// should be 8 bytes.
const size_t pointer_size = EtwConsumer::GetPointerSize(kEventHeaderFlags);
CHECK_EQ(pointer_size, sizeof(uint64_t));
return ::tracing::EncodeProcess(process, version, pointer_size);
}
private:
static constexpr uint16_t kTestProcessorIndex = 47;
static constexpr uint16_t kEventHeaderFlags = EVENT_HEADER_FLAG_64_BIT_HEADER;
// Generates an ETW EVENT_RECORD for a given trace provider of a particular
// version and opcode with `packet_data` as its payload and sends it to the
@ -421,7 +451,7 @@ class EtwConsumerTest : public testing::Test {
uint8_t opcode,
base::span<const uint8_t> packet_data) {
EVENT_RECORD event_record = {
.EventHeader = {.Flags = EVENT_HEADER_FLAG_64_BIT_HEADER,
.EventHeader = {.Flags = kEventHeaderFlags,
.ProviderId = provider,
.EventDescriptor = {.Version = version,
.Opcode = opcode}},