• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &reg_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