1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/trace_event/trace_logging_minimal_win.h"
11
12 #include <evntrace.h>
13
14 #include "base/check_op.h"
15 #include "base/logging.h"
16 #include "base/numerics/checked_math.h"
17
18 TlmProvider::TlmProvider() noexcept = default;
19
~TlmProvider()20 TlmProvider::~TlmProvider() {
21 Unregister();
22 }
23
TlmProvider(const char * provider_name,const GUID & provider_guid,base::RepeatingCallback<void (EventControlCode)> on_updated_callback)24 TlmProvider::TlmProvider(const char* provider_name,
25 const GUID& provider_guid,
26 base::RepeatingCallback<void(EventControlCode)>
27 on_updated_callback) noexcept {
28 ULONG status =
29 Register(provider_name, provider_guid, std::move(on_updated_callback));
30 LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider resistration failure";
31 }
32
33 // Appends a nul-terminated string to a metadata block.
34 // Returns new meta_data_index value, or -1 for overflow.
AppendNameToMetadata(char * metadata,uint16_t metadata_size,uint16_t metadata_index,std::string_view name) const35 uint16_t TlmProvider::AppendNameToMetadata(
36 char* metadata,
37 uint16_t metadata_size,
38 uint16_t metadata_index,
39 std::string_view name) const noexcept {
40 uint16_t index = metadata_index;
41 DCHECK_LE(index, metadata_size);
42
43 const size_t cch = name.size();
44 if (cch + 1 > static_cast<unsigned>(metadata_size - index)) {
45 return static_cast<uint16_t>(-1);
46 }
47
48 memcpy(metadata + index, name.data(), cch);
49 metadata[index + cch] = 0;
50 index += static_cast<uint16_t>(cch) + 1;
51 return index;
52 }
53
Unregister()54 void TlmProvider::Unregister() noexcept {
55 if (reg_handle_ == 0)
56 return;
57
58 ULONG status = EventUnregister(reg_handle_);
59 LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider unregistration failure";
60 reg_handle_ = 0;
61 level_plus1_ = 0;
62 }
63
Register(const char * provider_name,const GUID & provider_guid,base::RepeatingCallback<void (EventControlCode)> on_updated_callback)64 ULONG TlmProvider::Register(const char* provider_name,
65 const GUID& provider_guid,
66 base::RepeatingCallback<void(EventControlCode)>
67 on_updated_callback) noexcept {
68 // Calling Register when already registered is a fatal error.
69 CHECK_EQ(reg_handle_, 0ULL);
70
71 // provider_metadata_ for tracelogging has the following format:
72 // UINT16 metadata_size;
73 // char NullTerminatedUtf8ProviderName[];
74 // ( + optional extension data, not used here)
75
76 // Append the provider name starting at offset 2 (skip MetadataSize).
77 provider_metadata_size_ = AppendNameToMetadata(
78 provider_metadata_, kMaxProviderMetadataSize, 2, provider_name);
79 if (provider_metadata_size_ > kMaxProviderMetadataSize)
80 return ERROR_BUFFER_OVERFLOW;
81
82 // Fill in MetadataSize field at offset 0.
83 *reinterpret_cast<uint16_t*>(provider_metadata_) = provider_metadata_size_;
84
85 on_updated_callback_ = std::move(on_updated_callback);
86 ULONG status =
87 EventRegister(&provider_guid, StaticEnableCallback, this, ®_handle_);
88 if (status != ERROR_SUCCESS)
89 return status;
90
91 // Best-effort, ignore failure.
92 return ::EventSetInformation(reg_handle_, EventProviderSetTraits,
93 provider_metadata_, provider_metadata_size_);
94 }
95
IsEnabled() const96 bool TlmProvider::IsEnabled() const noexcept {
97 return 0 < level_plus1_;
98 }
99
IsEnabled(uint8_t level) const100 bool TlmProvider::IsEnabled(uint8_t level) const noexcept {
101 return level < level_plus1_;
102 }
103
IsEnabled(uint8_t level,uint64_t keyword) const104 bool TlmProvider::IsEnabled(uint8_t level, uint64_t keyword) const noexcept {
105 return level < level_plus1_ && KeywordEnabled(keyword);
106 }
107
IsEnabled(const EVENT_DESCRIPTOR & event_descriptor) const108 bool TlmProvider::IsEnabled(
109 const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
110 return event_descriptor.Level < level_plus1_ &&
111 KeywordEnabled(event_descriptor.Keyword);
112 }
113
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)114 void TlmProvider::StaticEnableCallback(const GUID* source_id,
115 ULONG is_enabled,
116 UCHAR level,
117 ULONGLONG match_any_keyword,
118 ULONGLONG match_all_keyword,
119 PEVENT_FILTER_DESCRIPTOR filter_data,
120 PVOID callback_context) {
121 if (!callback_context)
122 return;
123
124 TlmProvider* provider = static_cast<TlmProvider*>(callback_context);
125 switch (is_enabled) {
126 case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
127 provider->level_plus1_ = 0;
128 break;
129 case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
130 provider->level_plus1_ =
131 level != 0 ? static_cast<unsigned>(level) + 1u : 256u;
132 break;
133 }
134 provider->keyword_any_ = match_any_keyword;
135 provider->keyword_all_ = match_all_keyword;
136
137 if (provider->on_updated_callback_ &&
138 is_enabled <= static_cast<size_t>(EventControlCode::kHighest)) {
139 provider->on_updated_callback_.Run(
140 static_cast<EventControlCode>(is_enabled));
141 }
142 }
143
EventBegin(char * metadata,std::string_view event_name) const144 uint16_t TlmProvider::EventBegin(char* metadata,
145 std::string_view event_name) const noexcept {
146 // EventMetadata for tracelogging has the following format
147 // UINT16 MetadataSize;
148 // BYTE SpecialFlags[]; // Not used, so always size 1.
149 // char NullTerminatedUtf8EventName[];
150 // ( + field definitions)
151
152 uint16_t index = 2; // Skip MetadataSize field.
153
154 metadata[index] = 0; // Set SpecialFlags[0] = 0.
155 index++; // sizeof(SpecialFlags) == 1.
156
157 index =
158 AppendNameToMetadata(metadata, kMaxEventMetadataSize, index, event_name);
159 return index;
160 }
161
EventAddField(char * metadata,uint16_t * metadata_index,uint8_t in_type,uint8_t out_type,std::string_view field_name) const162 char TlmProvider::EventAddField(char* metadata,
163 uint16_t* metadata_index,
164 uint8_t in_type,
165 uint8_t out_type,
166 std::string_view field_name) const noexcept {
167 DCHECK_LT(in_type, 0x80);
168 DCHECK_LT(out_type, 0x80);
169
170 // FieldDefinition =
171 // char NullTerminatedUtf8FieldName[];
172 // BYTE InType;
173 // BYTE OutType; // Only present if high bit set in InType.
174 // ( + optional extension data not used here)
175
176 if (*metadata_index >= kMaxEventMetadataSize)
177 return 0;
178
179 *metadata_index = AppendNameToMetadata(metadata, kMaxEventMetadataSize,
180 *metadata_index, field_name);
181 if (*metadata_index >= kMaxEventMetadataSize)
182 return 0;
183
184 if (out_type == 0) {
185 // 1-byte encoding: inType + TlgOutNULL.
186 if (1 > kMaxEventMetadataSize - *metadata_index) {
187 *metadata_index = static_cast<uint16_t>(-1);
188 return 0;
189 }
190
191 metadata[*metadata_index] = static_cast<char>(in_type);
192 *metadata_index += 1;
193 return 0;
194 }
195 // 2-byte encoding: in_type + out_type.
196 if (kMaxEventMetadataSize - *metadata_index < 2) {
197 *metadata_index = static_cast<uint16_t>(-1);
198 return 0;
199 }
200
201 // Set high bit to indicate presence of OutType.
202 metadata[*metadata_index] = static_cast<char>(in_type | 0x80);
203 *metadata_index += 1;
204 metadata[*metadata_index] = static_cast<char>(out_type);
205 *metadata_index += 1;
206 return 0;
207 }
208
EventEnd(char * metadata,uint16_t meta_data_index,EVENT_DATA_DESCRIPTOR * descriptors,uint32_t descriptors_index,const EVENT_DESCRIPTOR & event_descriptor) const209 ULONG TlmProvider::EventEnd(
210 char* metadata,
211 uint16_t meta_data_index,
212 EVENT_DATA_DESCRIPTOR* descriptors,
213 uint32_t descriptors_index,
214 const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
215 if (meta_data_index > kMaxEventMetadataSize) {
216 return ERROR_BUFFER_OVERFLOW;
217 }
218
219 // Fill in EventMetadata's MetadataSize field.
220 *reinterpret_cast<uint16_t*>(metadata) = meta_data_index;
221
222 descriptors[0].Ptr = reinterpret_cast<ULONG_PTR>(provider_metadata_);
223 descriptors[0].Size = provider_metadata_size_;
224 descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA;
225
226 descriptors[1].Ptr = reinterpret_cast<ULONG_PTR>(metadata);
227 descriptors[1].Size = meta_data_index;
228 descriptors[1].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA;
229
230 return EventWrite(reg_handle_, &event_descriptor, descriptors_index,
231 descriptors);
232 }
233
KeywordEnabled(uint64_t keyword) const234 bool TlmProvider::KeywordEnabled(uint64_t keyword) const noexcept {
235 return keyword == 0 ||
236 ((keyword & keyword_any_) && (keyword & keyword_all_) == keyword_all_);
237 }
238
TlmInt64Field(const char * name,const int64_t value)239 TlmInt64Field::TlmInt64Field(const char* name, const int64_t value) noexcept
240 : TlmFieldWithConstants(name), value_(value) {
241 DCHECK_NE(Name().data(), nullptr);
242 }
Value() const243 int64_t TlmInt64Field::Value() const noexcept {
244 return value_;
245 }
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const246 void TlmInt64Field::FillEventDescriptor(
247 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
248 EventDataDescCreate(&descriptors[0], (void*)&value_, sizeof(value_));
249 }
250
TlmUInt64Field(const char * name,const uint64_t value)251 TlmUInt64Field::TlmUInt64Field(const char* name, const uint64_t value) noexcept
252 : TlmFieldWithConstants(name), value_(value) {
253 DCHECK_NE(Name().data(), nullptr);
254 }
Value() const255 uint64_t TlmUInt64Field::Value() const noexcept {
256 return value_;
257 }
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const258 void TlmUInt64Field::FillEventDescriptor(
259 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
260 EventDataDescCreate(&descriptors[0], (void*)&value_, sizeof(value_));
261 }
262
TlmMbcsStringField(const char * name,const char * value)263 TlmMbcsStringField::TlmMbcsStringField(const char* name,
264 const char* value) noexcept
265 : TlmFieldWithConstants(name), value_(value) {
266 DCHECK_NE(Name().data(), nullptr);
267 DCHECK_NE(value_, nullptr);
268 }
269
Value() const270 const char* TlmMbcsStringField::Value() const noexcept {
271 return value_;
272 }
273
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const274 void TlmMbcsStringField::FillEventDescriptor(
275 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
276 EventDataDescCreate(&descriptors[0], value_,
277 base::checked_cast<ULONG>(strlen(value_) + 1));
278 }
279
TlmUtf8StringField(const char * name,const char * value)280 TlmUtf8StringField::TlmUtf8StringField(const char* name,
281 const char* value) noexcept
282 : TlmFieldWithConstants(name), value_(value) {
283 DCHECK_NE(Name().data(), nullptr);
284 DCHECK_NE(value_, nullptr);
285 }
286
Value() const287 const char* TlmUtf8StringField::Value() const noexcept {
288 return value_;
289 }
290
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const291 void TlmUtf8StringField::FillEventDescriptor(
292 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
293 EventDataDescCreate(&descriptors[0], value_,
294 base::checked_cast<ULONG>(strlen(value_) + 1));
295 }
296
TlmFieldBase(const char * name)297 TlmFieldBase::TlmFieldBase(const char* name) noexcept : name_(name) {}
TlmFieldBase(std::string_view name)298 TlmFieldBase::TlmFieldBase(std::string_view name) noexcept : name_(name) {}
299
300 TlmFieldBase::~TlmFieldBase() = default;
301
302 TlmFieldBase::TlmFieldBase(TlmFieldBase&&) noexcept = default;
303 TlmFieldBase& TlmFieldBase::operator=(TlmFieldBase&&) noexcept = default;
304