263 lines
8.9 KiB
C++
263 lines
8.9 KiB
C++
|
|
// Copyright 2020 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "base/trace_event/trace_logging_minimal_win.h"
|
||
|
|
|
||
|
|
#include <evntrace.h>
|
||
|
|
|
||
|
|
#include "base/check_op.h"
|
||
|
|
#include "base/logging.h"
|
||
|
|
#include "base/numerics/checked_math.h"
|
||
|
|
|
||
|
|
TlmProvider::~TlmProvider() {
|
||
|
|
Unregister();
|
||
|
|
}
|
||
|
|
|
||
|
|
TlmProvider::TlmProvider(const char* provider_name,
|
||
|
|
const GUID& provider_guid,
|
||
|
|
PENABLECALLBACK enable_callback,
|
||
|
|
void* enable_callback_context) noexcept {
|
||
|
|
ULONG status = Register(provider_name, provider_guid, enable_callback,
|
||
|
|
enable_callback_context);
|
||
|
|
LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider resistration failure";
|
||
|
|
}
|
||
|
|
|
||
|
|
// Appends a nul-terminated string to a metadata block.
|
||
|
|
// Returns new meta_data_index value, or -1 for overflow.
|
||
|
|
uint16_t TlmProvider::AppendNameToMetadata(char* metadata,
|
||
|
|
uint16_t metadata_size,
|
||
|
|
uint16_t metadata_index,
|
||
|
|
const char* name) const noexcept {
|
||
|
|
uint16_t index = metadata_index;
|
||
|
|
DCHECK_LE(index, metadata_size);
|
||
|
|
|
||
|
|
const size_t cch = strlen(name) + 1;
|
||
|
|
if (cch > static_cast<unsigned>(metadata_size - index))
|
||
|
|
return static_cast<uint16_t>(-1);
|
||
|
|
|
||
|
|
memcpy(metadata + index, name, cch);
|
||
|
|
index += static_cast<uint16_t>(cch);
|
||
|
|
return index;
|
||
|
|
}
|
||
|
|
|
||
|
|
void TlmProvider::Unregister() noexcept {
|
||
|
|
if (reg_handle_ == 0)
|
||
|
|
return;
|
||
|
|
|
||
|
|
ULONG status = EventUnregister(reg_handle_);
|
||
|
|
LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider unregistration failure";
|
||
|
|
reg_handle_ = 0;
|
||
|
|
level_plus1_ = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
ULONG TlmProvider::Register(const char* provider_name,
|
||
|
|
const GUID& provider_guid,
|
||
|
|
PENABLECALLBACK enable_callback,
|
||
|
|
void* enable_callback_context) noexcept {
|
||
|
|
// Calling Register when already registered is a fatal error.
|
||
|
|
CHECK_EQ(reg_handle_, 0ULL);
|
||
|
|
|
||
|
|
// provider_metadata_ for tracelogging has the following format:
|
||
|
|
// UINT16 metadata_size;
|
||
|
|
// char NullTerminatedUtf8ProviderName[];
|
||
|
|
// ( + optional extension data, not used here)
|
||
|
|
|
||
|
|
// Append the provider name starting at offset 2 (skip MetadataSize).
|
||
|
|
provider_metadata_size_ = AppendNameToMetadata(
|
||
|
|
provider_metadata_, kMaxProviderMetadataSize, 2, provider_name);
|
||
|
|
if (provider_metadata_size_ > kMaxProviderMetadataSize)
|
||
|
|
return ERROR_BUFFER_OVERFLOW;
|
||
|
|
|
||
|
|
// Fill in MetadataSize field at offset 0.
|
||
|
|
*reinterpret_cast<uint16_t*>(provider_metadata_) = provider_metadata_size_;
|
||
|
|
|
||
|
|
enable_callback_ = enable_callback;
|
||
|
|
enable_callback_context_ = enable_callback_context;
|
||
|
|
ULONG status =
|
||
|
|
EventRegister(&provider_guid, StaticEnableCallback, this, ®_handle_);
|
||
|
|
if (status != ERROR_SUCCESS)
|
||
|
|
return status;
|
||
|
|
|
||
|
|
// Best-effort, ignore failure.
|
||
|
|
return ::EventSetInformation(reg_handle_, EventProviderSetTraits,
|
||
|
|
provider_metadata_, provider_metadata_size_);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TlmProvider::IsEnabled() const noexcept {
|
||
|
|
return 0 < level_plus1_;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TlmProvider::IsEnabled(uint8_t level) const noexcept {
|
||
|
|
return level < level_plus1_;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TlmProvider::IsEnabled(uint8_t level, uint64_t keyword) const noexcept {
|
||
|
|
return level < level_plus1_ && KeywordEnabled(keyword);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TlmProvider::IsEnabled(
|
||
|
|
const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
|
||
|
|
return event_descriptor.Level < level_plus1_ &&
|
||
|
|
KeywordEnabled(event_descriptor.Keyword);
|
||
|
|
}
|
||
|
|
|
||
|
|
void TlmProvider::StaticEnableCallback(const GUID* source_id,
|
||
|
|
ULONG is_enabled,
|
||
|
|
UCHAR level,
|
||
|
|
ULONGLONG match_any_keyword,
|
||
|
|
ULONGLONG match_all_keyword,
|
||
|
|
PEVENT_FILTER_DESCRIPTOR filter_data,
|
||
|
|
PVOID callback_context) {
|
||
|
|
if (!callback_context)
|
||
|
|
return;
|
||
|
|
|
||
|
|
TlmProvider* pProvider = static_cast<TlmProvider*>(callback_context);
|
||
|
|
switch (is_enabled) {
|
||
|
|
case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
|
||
|
|
pProvider->level_plus1_ = 0;
|
||
|
|
break;
|
||
|
|
case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
|
||
|
|
pProvider->level_plus1_ =
|
||
|
|
level != 0 ? static_cast<unsigned>(level) + 1u : 256u;
|
||
|
|
pProvider->keyword_any_ = match_any_keyword;
|
||
|
|
pProvider->keyword_all_ = match_all_keyword;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pProvider->enable_callback_) {
|
||
|
|
pProvider->enable_callback_(source_id, is_enabled, level, match_any_keyword,
|
||
|
|
match_all_keyword, filter_data,
|
||
|
|
pProvider->enable_callback_context_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t TlmProvider::EventBegin(char* metadata,
|
||
|
|
const char* event_name) const noexcept {
|
||
|
|
// EventMetadata for tracelogging has the following format
|
||
|
|
// UINT16 MetadataSize;
|
||
|
|
// BYTE SpecialFlags[]; // Not used, so always size 1.
|
||
|
|
// char NullTerminatedUtf8EventName[];
|
||
|
|
// ( + field definitions)
|
||
|
|
|
||
|
|
uint16_t index = 2; // Skip MetadataSize field.
|
||
|
|
|
||
|
|
metadata[index] = 0; // Set SpecialFlags[0] = 0.
|
||
|
|
index++; // sizeof(SpecialFlags) == 1.
|
||
|
|
|
||
|
|
index =
|
||
|
|
AppendNameToMetadata(metadata, kMaxEventMetadataSize, index, event_name);
|
||
|
|
return index;
|
||
|
|
}
|
||
|
|
|
||
|
|
char TlmProvider::EventAddField(char* metadata,
|
||
|
|
uint16_t* metadata_index,
|
||
|
|
uint8_t in_type,
|
||
|
|
uint8_t out_type,
|
||
|
|
const char* field_name) const noexcept {
|
||
|
|
DCHECK_LT(in_type, 0x80);
|
||
|
|
DCHECK_LT(out_type, 0x80);
|
||
|
|
|
||
|
|
// FieldDefinition =
|
||
|
|
// char NullTerminatedUtf8FieldName[];
|
||
|
|
// BYTE InType;
|
||
|
|
// BYTE OutType; // Only present if high bit set in InType.
|
||
|
|
// ( + optional extension data not used here)
|
||
|
|
|
||
|
|
if (*metadata_index >= kMaxEventMetadataSize)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
*metadata_index = AppendNameToMetadata(metadata, kMaxEventMetadataSize,
|
||
|
|
*metadata_index, field_name);
|
||
|
|
if (*metadata_index >= kMaxEventMetadataSize)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
if (out_type == 0) {
|
||
|
|
// 1-byte encoding: inType + TlgOutNULL.
|
||
|
|
if (1 > kMaxEventMetadataSize - *metadata_index) {
|
||
|
|
*metadata_index = static_cast<uint16_t>(-1);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
metadata[*metadata_index] = static_cast<char>(in_type);
|
||
|
|
*metadata_index += 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
// 2-byte encoding: in_type + out_type.
|
||
|
|
if (kMaxEventMetadataSize - *metadata_index < 2) {
|
||
|
|
*metadata_index = static_cast<uint16_t>(-1);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set high bit to indicate presence of OutType.
|
||
|
|
metadata[*metadata_index] = static_cast<char>(in_type | 0x80);
|
||
|
|
*metadata_index += 1;
|
||
|
|
metadata[*metadata_index] = static_cast<char>(out_type);
|
||
|
|
*metadata_index += 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
ULONG TlmProvider::EventEnd(
|
||
|
|
char* metadata,
|
||
|
|
uint16_t meta_data_index,
|
||
|
|
EVENT_DATA_DESCRIPTOR* descriptors,
|
||
|
|
uint32_t descriptors_index,
|
||
|
|
const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
|
||
|
|
if (meta_data_index > kMaxEventMetadataSize) {
|
||
|
|
return ERROR_BUFFER_OVERFLOW;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fill in EventMetadata's MetadataSize field.
|
||
|
|
*reinterpret_cast<uint16_t*>(metadata) = meta_data_index;
|
||
|
|
|
||
|
|
descriptors[0].Ptr = reinterpret_cast<ULONG_PTR>(provider_metadata_);
|
||
|
|
descriptors[0].Size = provider_metadata_size_;
|
||
|
|
descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA;
|
||
|
|
|
||
|
|
descriptors[1].Ptr = reinterpret_cast<ULONG_PTR>(metadata);
|
||
|
|
descriptors[1].Size = meta_data_index;
|
||
|
|
descriptors[1].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA;
|
||
|
|
|
||
|
|
return EventWrite(reg_handle_, &event_descriptor, descriptors_index,
|
||
|
|
descriptors);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool TlmProvider::KeywordEnabled(uint64_t keyword) const noexcept {
|
||
|
|
return keyword == 0 ||
|
||
|
|
((keyword & keyword_any_) && (keyword & keyword_all_) == keyword_all_);
|
||
|
|
}
|
||
|
|
|
||
|
|
TlmMbcsStringField::TlmMbcsStringField(const char* name,
|
||
|
|
const char* value) noexcept
|
||
|
|
: TlmFieldBase(name), value_(value) {
|
||
|
|
DCHECK_NE(Name(), nullptr);
|
||
|
|
DCHECK_NE(value_, nullptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
const char* TlmMbcsStringField::Value() const noexcept {
|
||
|
|
return value_;
|
||
|
|
}
|
||
|
|
|
||
|
|
void TlmMbcsStringField::FillEventDescriptor(
|
||
|
|
EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
|
||
|
|
EventDataDescCreate(&descriptors[0], value_,
|
||
|
|
base::checked_cast<ULONG>(strlen(value_) + 1));
|
||
|
|
}
|
||
|
|
|
||
|
|
TlmUtf8StringField::TlmUtf8StringField(const char* name,
|
||
|
|
const char* value) noexcept
|
||
|
|
: TlmFieldBase(name), value_(value) {
|
||
|
|
DCHECK_NE(Name(), nullptr);
|
||
|
|
DCHECK_NE(value_, nullptr);
|
||
|
|
}
|
||
|
|
|
||
|
|
const char* TlmUtf8StringField::Value() const noexcept {
|
||
|
|
return value_;
|
||
|
|
}
|
||
|
|
|
||
|
|
void TlmUtf8StringField::FillEventDescriptor(
|
||
|
|
EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
|
||
|
|
EventDataDescCreate(&descriptors[0], value_,
|
||
|
|
base::checked_cast<ULONG>(strlen(value_) + 1));
|
||
|
|
}
|