// 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 #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(metadata_size - index)) return static_cast(-1); memcpy(metadata + index, name, cch); index += static_cast(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(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(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(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(-1); return 0; } metadata[*metadata_index] = static_cast(in_type); *metadata_index += 1; return 0; } // 2-byte encoding: in_type + out_type. if (kMaxEventMetadataSize - *metadata_index < 2) { *metadata_index = static_cast(-1); return 0; } // Set high bit to indicate presence of OutType. metadata[*metadata_index] = static_cast(in_type | 0x80); *metadata_index += 1; metadata[*metadata_index] = static_cast(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(metadata) = meta_data_index; descriptors[0].Ptr = reinterpret_cast(provider_metadata_); descriptors[0].Size = provider_metadata_size_; descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA; descriptors[1].Ptr = reinterpret_cast(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(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(strlen(value_) + 1)); }