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 #include "base/trace_event/trace_logging_minimal_win.h"
6
7 #include <evntrace.h>
8
9 #include "base/check_op.h"
10 #include "base/logging.h"
11 #include "base/numerics/checked_math.h"
12
13 TlmProvider::TlmProvider() noexcept = default;
14
~TlmProvider()15 TlmProvider::~TlmProvider() {
16 Unregister();
17 }
18
TlmProvider(const char * provider_name,const GUID & provider_guid,base::RepeatingCallback<void (EventControlCode)> on_updated_callback)19 TlmProvider::TlmProvider(const char* provider_name,
20 const GUID& provider_guid,
21 base::RepeatingCallback<void(EventControlCode)>
22 on_updated_callback) noexcept {
23 ULONG status =
24 Register(provider_name, provider_guid, std::move(on_updated_callback));
25 LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider resistration failure";
26 }
27
28 // Appends a nul-terminated string to a metadata block.
29 // 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) const30 uint16_t TlmProvider::AppendNameToMetadata(
31 char* metadata,
32 uint16_t metadata_size,
33 uint16_t metadata_index,
34 std::string_view name) const noexcept {
35 uint16_t index = metadata_index;
36 DCHECK_LE(index, metadata_size);
37
38 const size_t cch = name.size();
39 if (cch + 1 > static_cast<unsigned>(metadata_size - index)) {
40 return static_cast<uint16_t>(-1);
41 }
42
43 memcpy(metadata + index, name.data(), cch);
44 metadata[index + cch] = 0;
45 index += static_cast<uint16_t>(cch) + 1;
46 return index;
47 }
48
Unregister()49 void TlmProvider::Unregister() noexcept {
50 if (reg_handle_ == 0)
51 return;
52
53 ULONG status = EventUnregister(reg_handle_);
54 LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider unregistration failure";
55 reg_handle_ = 0;
56 level_plus1_ = 0;
57 }
58
Register(const char * provider_name,const GUID & provider_guid,base::RepeatingCallback<void (EventControlCode)> on_updated_callback)59 ULONG TlmProvider::Register(const char* provider_name,
60 const GUID& provider_guid,
61 base::RepeatingCallback<void(EventControlCode)>
62 on_updated_callback) noexcept {
63 // Calling Register when already registered is a fatal error.
64 CHECK_EQ(reg_handle_, 0ULL);
65
66 // provider_metadata_ for tracelogging has the following format:
67 // UINT16 metadata_size;
68 // char NullTerminatedUtf8ProviderName[];
69 // ( + optional extension data, not used here)
70
71 // Append the provider name starting at offset 2 (skip MetadataSize).
72 provider_metadata_size_ = AppendNameToMetadata(
73 provider_metadata_, kMaxProviderMetadataSize, 2, provider_name);
74 if (provider_metadata_size_ > kMaxProviderMetadataSize)
75 return ERROR_BUFFER_OVERFLOW;
76
77 // Fill in MetadataSize field at offset 0.
78 *reinterpret_cast<uint16_t*>(provider_metadata_) = provider_metadata_size_;
79
80 on_updated_callback_ = std::move(on_updated_callback);
81 ULONG status =
82 EventRegister(&provider_guid, StaticEnableCallback, this, ®_handle_);
83 if (status != ERROR_SUCCESS)
84 return status;
85
86 // Best-effort, ignore failure.
87 return ::EventSetInformation(reg_handle_, EventProviderSetTraits,
88 provider_metadata_, provider_metadata_size_);
89 }
90
IsEnabled() const91 bool TlmProvider::IsEnabled() const noexcept {
92 return 0 < level_plus1_;
93 }
94
IsEnabled(uint8_t level) const95 bool TlmProvider::IsEnabled(uint8_t level) const noexcept {
96 return level < level_plus1_;
97 }
98
IsEnabled(uint8_t level,uint64_t keyword) const99 bool TlmProvider::IsEnabled(uint8_t level, uint64_t keyword) const noexcept {
100 return level < level_plus1_ && KeywordEnabled(keyword);
101 }
102
IsEnabled(const EVENT_DESCRIPTOR & event_descriptor) const103 bool TlmProvider::IsEnabled(
104 const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
105 return event_descriptor.Level < level_plus1_ &&
106 KeywordEnabled(event_descriptor.Keyword);
107 }
108
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)109 void TlmProvider::StaticEnableCallback(const GUID* source_id,
110 ULONG is_enabled,
111 UCHAR level,
112 ULONGLONG match_any_keyword,
113 ULONGLONG match_all_keyword,
114 PEVENT_FILTER_DESCRIPTOR filter_data,
115 PVOID callback_context) {
116 if (!callback_context)
117 return;
118
119 TlmProvider* provider = static_cast<TlmProvider*>(callback_context);
120 switch (is_enabled) {
121 case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
122 provider->level_plus1_ = 0;
123 break;
124 case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
125 provider->level_plus1_ =
126 level != 0 ? static_cast<unsigned>(level) + 1u : 256u;
127 break;
128 }
129 provider->keyword_any_ = match_any_keyword;
130 provider->keyword_all_ = match_all_keyword;
131
132 if (provider->on_updated_callback_ &&
133 is_enabled <= static_cast<size_t>(EventControlCode::kHighest)) {
134 provider->on_updated_callback_.Run(
135 static_cast<EventControlCode>(is_enabled));
136 }
137 }
138
EventBegin(char * metadata,std::string_view event_name) const139 uint16_t TlmProvider::EventBegin(char* metadata,
140 std::string_view event_name) const noexcept {
141 // EventMetadata for tracelogging has the following format
142 // UINT16 MetadataSize;
143 // BYTE SpecialFlags[]; // Not used, so always size 1.
144 // char NullTerminatedUtf8EventName[];
145 // ( + field definitions)
146
147 uint16_t index = 2; // Skip MetadataSize field.
148
149 metadata[index] = 0; // Set SpecialFlags[0] = 0.
150 index++; // sizeof(SpecialFlags) == 1.
151
152 index =
153 AppendNameToMetadata(metadata, kMaxEventMetadataSize, index, event_name);
154 return index;
155 }
156
EventAddField(char * metadata,uint16_t * metadata_index,uint8_t in_type,uint8_t out_type,const char * field_name) const157 char TlmProvider::EventAddField(char* metadata,
158 uint16_t* metadata_index,
159 uint8_t in_type,
160 uint8_t out_type,
161 const char* field_name) const noexcept {
162 DCHECK_LT(in_type, 0x80);
163 DCHECK_LT(out_type, 0x80);
164
165 // FieldDefinition =
166 // char NullTerminatedUtf8FieldName[];
167 // BYTE InType;
168 // BYTE OutType; // Only present if high bit set in InType.
169 // ( + optional extension data not used here)
170
171 if (*metadata_index >= kMaxEventMetadataSize)
172 return 0;
173
174 *metadata_index = AppendNameToMetadata(metadata, kMaxEventMetadataSize,
175 *metadata_index, field_name);
176 if (*metadata_index >= kMaxEventMetadataSize)
177 return 0;
178
179 if (out_type == 0) {
180 // 1-byte encoding: inType + TlgOutNULL.
181 if (1 > kMaxEventMetadataSize - *metadata_index) {
182 *metadata_index = static_cast<uint16_t>(-1);
183 return 0;
184 }
185
186 metadata[*metadata_index] = static_cast<char>(in_type);
187 *metadata_index += 1;
188 return 0;
189 }
190 // 2-byte encoding: in_type + out_type.
191 if (kMaxEventMetadataSize - *metadata_index < 2) {
192 *metadata_index = static_cast<uint16_t>(-1);
193 return 0;
194 }
195
196 // Set high bit to indicate presence of OutType.
197 metadata[*metadata_index] = static_cast<char>(in_type | 0x80);
198 *metadata_index += 1;
199 metadata[*metadata_index] = static_cast<char>(out_type);
200 *metadata_index += 1;
201 return 0;
202 }
203
EventEnd(char * metadata,uint16_t meta_data_index,EVENT_DATA_DESCRIPTOR * descriptors,uint32_t descriptors_index,const EVENT_DESCRIPTOR & event_descriptor) const204 ULONG TlmProvider::EventEnd(
205 char* metadata,
206 uint16_t meta_data_index,
207 EVENT_DATA_DESCRIPTOR* descriptors,
208 uint32_t descriptors_index,
209 const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
210 if (meta_data_index > kMaxEventMetadataSize) {
211 return ERROR_BUFFER_OVERFLOW;
212 }
213
214 // Fill in EventMetadata's MetadataSize field.
215 *reinterpret_cast<uint16_t*>(metadata) = meta_data_index;
216
217 descriptors[0].Ptr = reinterpret_cast<ULONG_PTR>(provider_metadata_);
218 descriptors[0].Size = provider_metadata_size_;
219 descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA;
220
221 descriptors[1].Ptr = reinterpret_cast<ULONG_PTR>(metadata);
222 descriptors[1].Size = meta_data_index;
223 descriptors[1].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA;
224
225 return EventWrite(reg_handle_, &event_descriptor, descriptors_index,
226 descriptors);
227 }
228
KeywordEnabled(uint64_t keyword) const229 bool TlmProvider::KeywordEnabled(uint64_t keyword) const noexcept {
230 return keyword == 0 ||
231 ((keyword & keyword_any_) && (keyword & keyword_all_) == keyword_all_);
232 }
233
TlmInt64Field(const char * name,const int64_t value)234 TlmInt64Field::TlmInt64Field(const char* name, const int64_t value) noexcept
235 : TlmFieldBase(name), value_(value) {
236 DCHECK_NE(Name(), nullptr);
237 }
Value() const238 int64_t TlmInt64Field::Value() const noexcept {
239 return value_;
240 }
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const241 void TlmInt64Field::FillEventDescriptor(
242 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
243 EventDataDescCreate(&descriptors[0], (void*)&value_, sizeof(value_));
244 }
245
TlmUInt64Field(const char * name,const uint64_t value)246 TlmUInt64Field::TlmUInt64Field(const char* name, const uint64_t value) noexcept
247 : TlmFieldBase(name), value_(value) {
248 DCHECK_NE(Name(), nullptr);
249 }
Value() const250 uint64_t TlmUInt64Field::Value() const noexcept {
251 return value_;
252 }
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const253 void TlmUInt64Field::FillEventDescriptor(
254 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
255 EventDataDescCreate(&descriptors[0], (void*)&value_, sizeof(value_));
256 }
257
TlmMbcsStringField(const char * name,const char * value)258 TlmMbcsStringField::TlmMbcsStringField(const char* name,
259 const char* value) noexcept
260 : TlmFieldBase(name), value_(value) {
261 DCHECK_NE(Name(), nullptr);
262 DCHECK_NE(value_, nullptr);
263 }
264
Value() const265 const char* TlmMbcsStringField::Value() const noexcept {
266 return value_;
267 }
268
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const269 void TlmMbcsStringField::FillEventDescriptor(
270 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
271 EventDataDescCreate(&descriptors[0], value_,
272 base::checked_cast<ULONG>(strlen(value_) + 1));
273 }
274
TlmUtf8StringField(const char * name,const char * value)275 TlmUtf8StringField::TlmUtf8StringField(const char* name,
276 const char* value) noexcept
277 : TlmFieldBase(name), value_(value) {
278 DCHECK_NE(Name(), nullptr);
279 DCHECK_NE(value_, nullptr);
280 }
281
Value() const282 const char* TlmUtf8StringField::Value() const noexcept {
283 return value_;
284 }
285
FillEventDescriptor(EVENT_DATA_DESCRIPTOR * descriptors) const286 void TlmUtf8StringField::FillEventDescriptor(
287 EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
288 EventDataDescCreate(&descriptors[0], value_,
289 base::checked_cast<ULONG>(strlen(value_) + 1));
290 }
291