• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2011 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 // Declaration of a Windows event trace provider class, to allow using
11 // Windows Event Tracing for logging transport and control.
12 #ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
13 #define BASE_WIN_EVENT_TRACE_PROVIDER_H_
14 
15 #include <windows.h>
16 
17 #include <cguid.h>
18 #include <evntrace.h>
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <wmistr.h>
22 
23 #include <limits>
24 
25 #include "base/base_export.h"
26 #include "base/compiler_specific.h"
27 
28 namespace base {
29 namespace win {
30 
31 using EtwEventClass = GUID;
32 using EtwEventType = UCHAR;
33 using EtwEventLevel = UCHAR;
34 using EtwEventVersion = USHORT;
35 using EtwEventFlags = ULONG;
36 
37 // Base class is a POD for correctness.
38 template <size_t N>
39 struct EtwMofEventBase {
40   EVENT_TRACE_HEADER header;
41   MOF_FIELD fields[N];
42 };
43 
44 // Utility class to auto-initialize event trace header structures.
45 template <size_t N>
46 class EtwMofEvent : public EtwMofEventBase<N> {
47  public:
48   using Super = EtwMofEventBase<N>;
49 
50   // Clang and the C++ standard don't allow unqualified lookup into dependent
51   // bases, hence these using decls to explicitly pull the names out.
52   using EtwMofEventBase<N>::header;
53   using EtwMofEventBase<N>::fields;
54 
EtwMofEvent()55   EtwMofEvent() { memset(static_cast<Super*>(this), 0, sizeof(Super)); }
56 
EtwMofEvent(const EtwEventClass & event_class,EtwEventType type,EtwEventLevel level)57   EtwMofEvent(const EtwEventClass& event_class,
58               EtwEventType type,
59               EtwEventLevel level) {
60     memset(static_cast<Super*>(this), 0, sizeof(Super));
61     header.Size = sizeof(Super);
62     header.Guid = event_class;
63     header.Class.Type = type;
64     header.Class.Level = level;
65     header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
66   }
67 
EtwMofEvent(const EtwEventClass & event_class,EtwEventType type,EtwEventVersion version,EtwEventLevel level)68   EtwMofEvent(const EtwEventClass& event_class,
69               EtwEventType type,
70               EtwEventVersion version,
71               EtwEventLevel level) {
72     memset(static_cast<Super*>(this), 0, sizeof(Super));
73     header.Size = sizeof(Super);
74     header.Guid = event_class;
75     header.Class.Type = type;
76     header.Class.Version = version;
77     header.Class.Level = level;
78     header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
79   }
80 
81   EtwMofEvent(const EtwMofEvent&) = delete;
82   EtwMofEvent& operator=(const EtwMofEvent&) = delete;
83 
SetField(size_t field,size_t size,const void * data)84   void SetField(size_t field, size_t size, const void* data) {
85     // DCHECK(field < N);
86     if ((field < N) && (size <= std::numeric_limits<uint32_t>::max())) {
87       fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
88       fields[field].Length = static_cast<ULONG>(size);
89     }
90   }
91 
get()92   EVENT_TRACE_HEADER* get() { return &header; }
93 };
94 
95 // Trace provider with Event Tracing for Windows. The trace provider
96 // registers with ETW by its name which is a GUID. ETW calls back to
97 // the object whenever the trace level or enable flags for this provider
98 // name changes.
99 // Users of this class can test whether logging is currently enabled at
100 // a particular trace level, and whether particular enable flags are set,
101 // before other resources are consumed to generate and issue the log
102 // messages themselves.
103 class BASE_EXPORT EtwTraceProvider {
104  public:
105   // Creates an event trace provider identified by provider_name, which
106   // will be the name registered with Event Tracing for Windows (ETW).
107   explicit EtwTraceProvider(const GUID& provider_name);
108 
109   // Creates an unnamed event trace provider, the provider must be given
110   // a name before registration.
111   EtwTraceProvider();
112 
113   EtwTraceProvider(const EtwTraceProvider&) = delete;
114   EtwTraceProvider& operator=(const EtwTraceProvider&) = delete;
115 
116   virtual ~EtwTraceProvider();
117 
118   // Registers the trace provider with Event Tracing for Windows.
119   // Note: from this point forward ETW may call the provider's control
120   //    callback. If the provider's name is enabled in some trace session
121   //    already, the callback may occur recursively from this call, so
122   //    call this only when you're ready to handle callbacks.
123   ULONG Register();
124   // Unregisters the trace provider with ETW.
125   ULONG Unregister();
126 
127   // Accessors.
set_provider_name(const GUID & provider_name)128   void set_provider_name(const GUID& provider_name) {
129     provider_name_ = provider_name;
130   }
provider_name()131   const GUID& provider_name() const LIFETIME_BOUND { return provider_name_; }
registration_handle()132   TRACEHANDLE registration_handle() const { return registration_handle_; }
session_handle()133   TRACEHANDLE session_handle() const { return session_handle_; }
enable_flags()134   EtwEventFlags enable_flags() const { return enable_flags_; }
enable_level()135   EtwEventLevel enable_level() const { return enable_level_; }
136 
137   // Returns true iff logging should be performed for "level" and "flags".
138   // Note: flags is treated as a bitmask, and should normally have a single
139   //      bit set, to test whether to log for a particular sub "facility".
ShouldLog(EtwEventLevel level,EtwEventFlags flags)140   bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
141     return NULL != session_handle_ && level >= enable_level_ &&
142            (0 != (flags & enable_flags_));
143   }
144 
145   // Simple wrappers to log Unicode and ANSI strings.
146   // Do nothing if !ShouldLog(level, 0xFFFFFFFF).
147   ULONG Log(const EtwEventClass& event_class,
148             EtwEventType type,
149             EtwEventLevel level,
150             const char* message);
151   ULONG Log(const EtwEventClass& event_class,
152             EtwEventType type,
153             EtwEventLevel level,
154             const wchar_t* message);
155 
156   // Log the provided event.
157   ULONG Log(EVENT_TRACE_HEADER* event);
158 
159  protected:
160   // Called after events have been enabled, override in subclasses
161   // to set up state or log at the start of a session.
162   // Note: This function may be called ETW's thread and may be racy,
163   //    bring your own locking if needed.
OnEventsEnabled()164   virtual void OnEventsEnabled() {}
165 
166   // Called just before events are disabled, override in subclasses
167   // to tear down state or log at the end of a session.
168   // Note: This function may be called ETW's thread and may be racy,
169   //    bring your own locking if needed.
OnEventsDisabled()170   virtual void OnEventsDisabled() {}
171 
172   // Called just after events have been disabled, override in subclasses
173   // to tear down state at the end of a session. At this point it's
174   // to late to log anything to the session.
175   // Note: This function may be called ETW's thread and may be racy,
176   //    bring your own locking if needed.
PostEventsDisabled()177   virtual void PostEventsDisabled() {}
178 
179  private:
180   ULONG EnableEvents(PVOID buffer);
181   ULONG DisableEvents();
182   ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
183   static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request,
184                                       PVOID context,
185                                       ULONG* reserved,
186                                       PVOID buffer);
187 
188   GUID provider_name_ = GUID_NULL;
189   TRACEHANDLE registration_handle_ = NULL;
190   TRACEHANDLE session_handle_ = NULL;
191   EtwEventFlags enable_flags_ = 0;
192   EtwEventLevel enable_level_ = 0;
193 
194   // We don't use this, but on XP we're obliged to pass one in to
195   // RegisterTraceGuids. Non-const, because that's how the API needs it.
196   static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
197 };
198 
199 }  // namespace win
200 }  // namespace base
201 
202 #endif  // BASE_WIN_EVENT_TRACE_PROVIDER_H_
203