trace_logging_minimal_win.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/trace_event/trace_logging_minimal_win.h"
  5. #include <evntrace.h>
  6. #include "base/check_op.h"
  7. #include "base/logging.h"
  8. #include "base/numerics/checked_math.h"
  9. /*
  10. EventSetInformation configuration macros:
  11. TraceLogging works best if the EventSetInformation API can be used to notify
  12. ETW that the provider uses TraceLogging event encoding.
  13. The EventSetInformation API is available on Windows 8 and later. (It is also
  14. available on fully-patched Windows 7, but not on Windows 7 RTM).
  15. The TLM_HAVE_EVENT_SET_INFORMATION and TLM_EVENT_SET_INFORMATION macros can
  16. be set before compiling this file to control how the TlmProvider class deals
  17. with the EventSetInformation API.
  18. If these macros are not set, the default behavior is to check the WINVER
  19. macro at compile time:
  20. - If WINVER is set to Windows 7 or before, TlmProvider will use GetProcAddress
  21. to locate EventSetInformation, and then invoke it if present. This is less
  22. efficient, but works on older versions of Windows.
  23. - If WINVER is set to Windows 8 or later, TlmProvider will directly invoke
  24. EventSetInformation. This is more efficient, but the resulting application
  25. will only work correctly on newer versions of Windows.
  26. If you need to run on Windows 7 RTM, but for some reason need to set WINVER to
  27. Windows 8 or higher, you can override the default behavior by defining
  28. TLM_HAVE_EVENT_SET_INFORMATION=2 when compiling this file.
  29. Details:
  30. - The TLM_EVENT_SET_INFORMATION macro can be set the name of a replacement
  31. function that TlmProvider should use instead of EventSetInformation.
  32. - The TLM_HAVE_EVENT_SET_INFORMATION macro can be set to 0 (disable the use of
  33. EventSetInformation), 1 (directly invoke EventSetInformation), or 2 (try to
  34. locate EventSetInformation via GetProcAddress, and invoke if found).
  35. */
  36. // This code needs to run on Windows 7 and this is magic which
  37. // removes static linking to EventSetInformation
  38. #define TLM_HAVE_EVENT_SET_INFORMATION 2
  39. #ifndef TLM_EVENT_SET_INFORMATION
  40. #define TLM_EVENT_SET_INFORMATION EventSetInformation
  41. #ifndef TLM_HAVE_EVENT_SET_INFORMATION
  42. #if WINVER < 0x0602 || !defined(EVENT_FILTER_TYPE_SCHEMATIZED)
  43. // Find "EventSetInformation" via GetModuleHandleExW+GetProcAddress
  44. #define TLM_HAVE_EVENT_SET_INFORMATION 2
  45. #else
  46. // Directly invoke TLM_EVENT_SET_INFORMATION(...)
  47. #define TLM_HAVE_EVENT_SET_INFORMATION 1
  48. #endif
  49. #endif
  50. #elif !defined(TLM_HAVE_EVENT_SET_INFORMATION)
  51. // Directly invoke TLM_EVENT_SET_INFORMATION(...)
  52. #define TLM_HAVE_EVENT_SET_INFORMATION 1
  53. #endif
  54. TlmProvider::~TlmProvider() {
  55. Unregister();
  56. }
  57. TlmProvider::TlmProvider(const char* provider_name,
  58. const GUID& provider_guid,
  59. PENABLECALLBACK enable_callback,
  60. void* enable_callback_context) noexcept {
  61. ULONG status = Register(provider_name, provider_guid, enable_callback,
  62. enable_callback_context);
  63. LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider resistration failure";
  64. }
  65. // Appends a nul-terminated string to a metadata block.
  66. // Returns new meta_data_index value, or -1 for overflow.
  67. uint16_t TlmProvider::AppendNameToMetadata(char* metadata,
  68. uint16_t metadata_size,
  69. uint16_t metadata_index,
  70. const char* name) const noexcept {
  71. uint16_t index = metadata_index;
  72. DCHECK_LE(index, metadata_size);
  73. const size_t cch = strlen(name) + 1;
  74. if (cch > static_cast<unsigned>(metadata_size - index))
  75. return static_cast<uint16_t>(-1);
  76. memcpy(metadata + index, name, cch);
  77. index += static_cast<uint16_t>(cch);
  78. return index;
  79. }
  80. void TlmProvider::Unregister() noexcept {
  81. if (reg_handle_ == 0)
  82. return;
  83. ULONG status = EventUnregister(reg_handle_);
  84. LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider unregistration failure";
  85. reg_handle_ = 0;
  86. level_plus1_ = 0;
  87. }
  88. ULONG TlmProvider::Register(const char* provider_name,
  89. const GUID& provider_guid,
  90. PENABLECALLBACK enable_callback,
  91. void* enable_callback_context) noexcept {
  92. // Calling Register when already registered is a fatal error.
  93. CHECK_EQ(reg_handle_, 0ULL);
  94. // provider_metadata_ for tracelogging has the following format:
  95. // UINT16 metadata_size;
  96. // char NullTerminatedUtf8ProviderName[];
  97. // ( + optional extension data, not used here)
  98. // Append the provider name starting at offset 2 (skip MetadataSize).
  99. provider_metadata_size_ = AppendNameToMetadata(
  100. provider_metadata_, kMaxProviderMetadataSize, 2, provider_name);
  101. if (provider_metadata_size_ > kMaxProviderMetadataSize)
  102. return ERROR_BUFFER_OVERFLOW;
  103. // Fill in MetadataSize field at offset 0.
  104. *reinterpret_cast<uint16_t*>(provider_metadata_) = provider_metadata_size_;
  105. enable_callback_ = enable_callback;
  106. enable_callback_context_ = enable_callback_context;
  107. ULONG status =
  108. EventRegister(&provider_guid, StaticEnableCallback, this, &reg_handle_);
  109. if (status != ERROR_SUCCESS)
  110. return status;
  111. #if TLM_HAVE_EVENT_SET_INFORMATION == 1
  112. // Best-effort, ignore failure.
  113. status =
  114. TLM_EVENT_SET_INFORMATION(reg_handle_, EventProviderSetTraits,
  115. provider_metadata_, provider_metadata_size_);
  116. #elif TLM_HAVE_EVENT_SET_INFORMATION == 2
  117. HMODULE eventing_lib;
  118. if (GetModuleHandleExW(0, L"api-ms-win-eventing-provider-l1-1-0.dll",
  119. &eventing_lib) ||
  120. GetModuleHandleExW(0, L"advapi32.dll", &eventing_lib)) {
  121. typedef ULONG(WINAPI * PFEventSetInformation)(
  122. REGHANDLE reg_handle, EVENT_INFO_CLASS information_class,
  123. PVOID event_information, ULONG information_length);
  124. PFEventSetInformation event_set_information_ptr =
  125. reinterpret_cast<decltype(&::EventSetInformation)>(
  126. GetProcAddress(eventing_lib, "EventSetInformation"));
  127. if (event_set_information_ptr) {
  128. // Best-effort, ignore failure.
  129. status = event_set_information_ptr(reg_handle_, EventProviderSetTraits,
  130. provider_metadata_,
  131. provider_metadata_size_);
  132. }
  133. FreeLibrary(eventing_lib);
  134. }
  135. #else // TLM_HAVE_EVENT_SET_INFORMATION == 0
  136. // Make no attempt to invoke EventSetInformation.
  137. #endif // TLM_HAVE_EVENT_SET_INFORMATION
  138. return status;
  139. }
  140. bool TlmProvider::IsEnabled() const noexcept {
  141. return 0 < level_plus1_;
  142. }
  143. bool TlmProvider::IsEnabled(uint8_t level) const noexcept {
  144. return level < level_plus1_;
  145. }
  146. bool TlmProvider::IsEnabled(uint8_t level, uint64_t keyword) const noexcept {
  147. return level < level_plus1_ && KeywordEnabled(keyword);
  148. }
  149. bool TlmProvider::IsEnabled(
  150. const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
  151. return event_descriptor.Level < level_plus1_ &&
  152. KeywordEnabled(event_descriptor.Keyword);
  153. }
  154. void TlmProvider::StaticEnableCallback(const GUID* source_id,
  155. ULONG is_enabled,
  156. UCHAR level,
  157. ULONGLONG match_any_keyword,
  158. ULONGLONG match_all_keyword,
  159. PEVENT_FILTER_DESCRIPTOR filter_data,
  160. PVOID callback_context) {
  161. if (!callback_context)
  162. return;
  163. TlmProvider* pProvider = static_cast<TlmProvider*>(callback_context);
  164. switch (is_enabled) {
  165. case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
  166. pProvider->level_plus1_ = 0;
  167. break;
  168. case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
  169. pProvider->level_plus1_ =
  170. level != 0 ? static_cast<unsigned>(level) + 1u : 256u;
  171. pProvider->keyword_any_ = match_any_keyword;
  172. pProvider->keyword_all_ = match_all_keyword;
  173. break;
  174. }
  175. if (pProvider->enable_callback_) {
  176. pProvider->enable_callback_(source_id, is_enabled, level, match_any_keyword,
  177. match_all_keyword, filter_data,
  178. pProvider->enable_callback_context_);
  179. }
  180. }
  181. uint16_t TlmProvider::EventBegin(char* metadata,
  182. const char* event_name) const noexcept {
  183. // EventMetadata for tracelogging has the following format
  184. // UINT16 MetadataSize;
  185. // BYTE SpecialFlags[]; // Not used, so always size 1.
  186. // char NullTerminatedUtf8EventName[];
  187. // ( + field definitions)
  188. uint16_t index = 2; // Skip MetadataSize field.
  189. metadata[index] = 0; // Set SpecialFlags[0] = 0.
  190. index++; // sizeof(SpecialFlags) == 1.
  191. index =
  192. AppendNameToMetadata(metadata, kMaxEventMetadataSize, index, event_name);
  193. return index;
  194. }
  195. char TlmProvider::EventAddField(char* metadata,
  196. uint16_t* metadata_index,
  197. uint8_t in_type,
  198. uint8_t out_type,
  199. const char* field_name) const noexcept {
  200. DCHECK_LT(in_type, 0x80);
  201. DCHECK_LT(out_type, 0x80);
  202. // FieldDefinition =
  203. // char NullTerminatedUtf8FieldName[];
  204. // BYTE InType;
  205. // BYTE OutType; // Only present if high bit set in InType.
  206. // ( + optional extension data not used here)
  207. if (*metadata_index >= kMaxEventMetadataSize)
  208. return 0;
  209. *metadata_index = AppendNameToMetadata(metadata, kMaxEventMetadataSize,
  210. *metadata_index, field_name);
  211. if (*metadata_index >= kMaxEventMetadataSize)
  212. return 0;
  213. if (out_type == 0) {
  214. // 1-byte encoding: inType + TlgOutNULL.
  215. if (1 > kMaxEventMetadataSize - *metadata_index) {
  216. *metadata_index = static_cast<uint16_t>(-1);
  217. return 0;
  218. }
  219. metadata[*metadata_index] = static_cast<char>(in_type);
  220. *metadata_index += 1;
  221. return 0;
  222. }
  223. // 2-byte encoding: in_type + out_type.
  224. if (kMaxEventMetadataSize - *metadata_index < 2) {
  225. *metadata_index = static_cast<uint16_t>(-1);
  226. return 0;
  227. }
  228. // Set high bit to indicate presence of OutType.
  229. metadata[*metadata_index] = static_cast<char>(in_type | 0x80);
  230. *metadata_index += 1;
  231. metadata[*metadata_index] = static_cast<char>(out_type);
  232. *metadata_index += 1;
  233. return 0;
  234. }
  235. ULONG TlmProvider::EventEnd(
  236. char* metadata,
  237. uint16_t meta_data_index,
  238. EVENT_DATA_DESCRIPTOR* descriptors,
  239. uint32_t descriptors_index,
  240. const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
  241. if (meta_data_index > kMaxEventMetadataSize) {
  242. return ERROR_BUFFER_OVERFLOW;
  243. }
  244. // Fill in EventMetadata's MetadataSize field.
  245. *reinterpret_cast<uint16_t*>(metadata) = meta_data_index;
  246. descriptors[0].Ptr = reinterpret_cast<ULONG_PTR>(provider_metadata_);
  247. descriptors[0].Size = provider_metadata_size_;
  248. descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA;
  249. descriptors[1].Ptr = reinterpret_cast<ULONG_PTR>(metadata);
  250. descriptors[1].Size = meta_data_index;
  251. descriptors[1].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA;
  252. return EventWrite(reg_handle_, &event_descriptor, descriptors_index,
  253. descriptors);
  254. }
  255. bool TlmProvider::KeywordEnabled(uint64_t keyword) const noexcept {
  256. return keyword == 0 ||
  257. ((keyword & keyword_any_) && (keyword & keyword_all_) == keyword_all_);
  258. }
  259. TlmMbcsStringField::TlmMbcsStringField(const char* name,
  260. const char* value) noexcept
  261. : TlmFieldBase(name), value_(value) {
  262. DCHECK_NE(Name(), nullptr);
  263. DCHECK_NE(value_, nullptr);
  264. }
  265. const char* TlmMbcsStringField::Value() const noexcept {
  266. return value_;
  267. }
  268. void TlmMbcsStringField::FillEventDescriptor(
  269. EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
  270. EventDataDescCreate(&descriptors[0], value_,
  271. base::checked_cast<ULONG>(strlen(value_) + 1));
  272. }
  273. TlmUtf8StringField::TlmUtf8StringField(const char* name,
  274. const char* value) noexcept
  275. : TlmFieldBase(name), value_(value) {
  276. DCHECK_NE(Name(), nullptr);
  277. DCHECK_NE(value_, nullptr);
  278. }
  279. const char* TlmUtf8StringField::Value() const noexcept {
  280. return value_;
  281. }
  282. void TlmUtf8StringField::FillEventDescriptor(
  283. EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
  284. EventDataDescCreate(&descriptors[0], value_,
  285. base::checked_cast<ULONG>(strlen(value_) + 1));
  286. }