File: etw_consumer_win.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (159 lines) | stat: -rw-r--r-- 7,067 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_TRACING_COMMON_ETW_CONSUMER_WIN_H_
#define COMPONENTS_TRACING_COMMON_ETW_CONSUMER_WIN_H_

#include <stdint.h>

#include <memory>

#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/process/process_handle.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/win/event_trace_consumer.h"
#include "components/tracing/common/active_processes_win.h"
#include "components/tracing/common/inclusion_policy_win.h"
#include "components/tracing/tracing_export.h"
#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
#include "third_party/perfetto/include/perfetto/tracing/trace_writer_base.h"

namespace perfetto::protos::pbzero {
class EtwTraceEvent;
class EtwTraceEventBundle;
}  // namespace perfetto::protos::pbzero

namespace tracing {

// A consumer of events from the Windows system trace provider that emits
// corresponding Perfetto trace events. An instance may be constructed on any
// sequence. Its `ConsumeEvents()` method and its destructor must be called on
// the same sequence.
class TRACING_EXPORT EtwConsumer
    : public base::win::EtwTraceConsumerBase<EtwConsumer> {
 public:
  // Receive events in the new EVENT_RECORD format.
  static constexpr bool kEnableRecordMode = true;
  // Do not convert timestampts to system time.
  static constexpr bool kRawTimestamp = true;

  // Constructs an instance that will consume ETW events on behalf of the client
  // process identified by `client_pid` and emit Perfetto events via
  // `trace_writer`.
  EtwConsumer(base::ProcessId client_pid,
              std::unique_ptr<perfetto::TraceWriterBase> trace_writer);
  EtwConsumer(const EtwConsumer&) = delete;
  EtwConsumer& operator=(const EtwConsumer&) = delete;
  ~EtwConsumer();

  // Consumes ETW events; blocking the calling thread. Returns when the ETW
  // trace session is stopped.
  void ConsumeEvents();

  // base::win::EtwTraceConsumerBase<>:
  static void ProcessEventRecord(EVENT_RECORD* event_record);
  static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer);

 private:
  friend class EtwConsumerTest;

  // The type of a member function that handles an event originating from a
  // specific provider.
  using EventHandlerFunction =
      void (EtwConsumer::*)(const EVENT_HEADER& header,
                            const ETW_BUFFER_CONTEXT& buffer_context,
                            size_t pointer_size,
                            base::span<const uint8_t> packet_data);

  // Returns the size, in bytes, of a pointer-sized value in an event based on
  // the `Flags` member of an event's `EVENT_HEADER`.
  static size_t GetPointerSize(uint16_t event_header_flags);

  // Per-provider event handlers. `ProcessEventRecord` dispatches to these based
  // on the ProviderId in the record's EventHeader.
  void HandleProcessEvent(const EVENT_HEADER& header,
                          const ETW_BUFFER_CONTEXT& buffer_context,
                          size_t pointer_size,
                          base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void HandleThreadEvent(const EVENT_HEADER& header,
                         const ETW_BUFFER_CONTEXT& buffer_context,
                         size_t pointer_size,
                         base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void HandleLostEvent(const EVENT_HEADER& header,
                       const ETW_BUFFER_CONTEXT& buffer_context,
                       size_t pointer_size,
                       base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  void OnProcessStart(const EVENT_HEADER& header,
                      const ETW_BUFFER_CONTEXT& buffer_context,
                      size_t pointer_size,
                      base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void OnProcessEnd(const EVENT_HEADER& header,
                    const ETW_BUFFER_CONTEXT& buffer_context,
                    size_t pointer_size,
                    base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void OnThreadStart(const EVENT_HEADER& header,
                     const ETW_BUFFER_CONTEXT& buffer_context,
                     size_t pointer_size,
                     base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void OnThreadEnd(const EVENT_HEADER& header,
                   const ETW_BUFFER_CONTEXT& buffer_context,
                   size_t pointer_size,
                   base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);
  void OnThreadSetName(const EVENT_HEADER& header,
                       const ETW_BUFFER_CONTEXT& buffer_context,
                       base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  // Decodes a CSwitch Event and emits a Perfetto trace event; see
  // https://learn.microsoft.com/en-us/windows/win32/etw/cswitch.
  // Returns true on success, or false if `packet_data` is invalid.
  bool DecodeCSwitchEvent(const EVENT_HEADER& header,
                          const ETW_BUFFER_CONTEXT& buffer_context,
                          base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  // Decodes a ReadyThread Event and emits a Perfetto trace event; see
  // https://learn.microsoft.com/en-us/windows/win32/etw/readythread.
  // Returns true on success, or false if `packet_data` is invalid.
  bool DecodeReadyThreadEvent(const EVENT_HEADER& header,
                              const ETW_BUFFER_CONTEXT& buffer_context,
                              base::span<const uint8_t> packet_data)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  // Returns a new perfetto trace event to be emitted for an ETW event with a
  // given event header. The timestamp and cpu fields of the returned event are
  // prepopulated.
  perfetto::protos::pbzero::EtwTraceEvent* MakeNextEvent(
      const EVENT_HEADER& header,
      const ETW_BUFFER_CONTEXT& buffer_context)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  const ActiveProcesses& active_processes() const { return active_processes_; }

  ActiveProcesses active_processes_ GUARDED_BY_CONTEXT(sequence_checker_);
  InclusionPolicy inclusion_policy_ GUARDED_BY_CONTEXT(sequence_checker_){
      active_processes_};
  std::unique_ptr<perfetto::TraceWriterBase> trace_writer_
      GUARDED_BY_CONTEXT(sequence_checker_);
  perfetto::TraceWriter::TracePacketHandle packet_handle_
      GUARDED_BY_CONTEXT(sequence_checker_);
  raw_ptr<perfetto::protos::pbzero::EtwTraceEventBundle> etw_events_
      GUARDED_BY_CONTEXT(sequence_checker_) = nullptr;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace tracing

#endif  // COMPONENTS_TRACING_COMMON_ETW_CONSUMER_WIN_H_