1//===-- TraceIntelPT.h ------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H
10#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H
11
12#include "TaskTimer.h"
13#include "ThreadDecoder.h"
14#include "TraceIntelPTBundleLoader.h"
15#include "TraceIntelPTMultiCpuDecoder.h"
16#include "lldb/Utility/FileSpec.h"
17#include "lldb/lldb-types.h"
18#include "llvm/Support/raw_ostream.h"
19#include <optional>
20
21namespace lldb_private {
22namespace trace_intel_pt {
23
24class TraceIntelPT : public Trace {
25public:
26  /// Properties to be used with the `settings` command.
27  class PluginProperties : public Properties {
28  public:
29    static llvm::StringRef GetSettingName();
30
31    PluginProperties();
32
33    ~PluginProperties() override = default;
34
35    uint64_t GetInfiniteDecodingLoopVerificationThreshold();
36
37    uint64_t GetExtremelyLargeDecodingThreshold();
38  };
39
40  /// Return the global properties for this trace plug-in.
41  static PluginProperties &GetGlobalProperties();
42
43  void Dump(Stream *s) const override;
44
45  llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
46                                      bool compact) override;
47
48  ~TraceIntelPT() override = default;
49
50  /// PluginInterface protocol
51  /// \{
52  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
53
54  static void Initialize();
55
56  static void Terminate();
57
58  /// Create an instance of this class from a trace bundle.
59  ///
60  /// \param[in] trace_bundle_description
61  ///     The description of the trace bundle. See \a Trace::FindPlugin.
62  ///
63  /// \param[in] bundle_dir
64  ///     The path to the directory that contains the trace bundle.
65  ///
66  /// \param[in] debugger
67  ///     The debugger instance where new Targets will be created as part of the
68  ///     JSON data parsing.
69  ///
70  /// \return
71  ///     A trace instance or an error in case of failures.
72  static llvm::Expected<lldb::TraceSP> CreateInstanceForTraceBundle(
73      const llvm::json::Value &trace_bundle_description,
74      llvm::StringRef bundle_dir, Debugger &debugger);
75
76  static llvm::Expected<lldb::TraceSP>
77  CreateInstanceForLiveProcess(Process &process);
78
79  static llvm::StringRef GetPluginNameStatic() { return "intel-pt"; }
80
81  static void DebuggerInitialize(Debugger &debugger);
82  /// \}
83
84  lldb::CommandObjectSP
85  GetProcessTraceStartCommand(CommandInterpreter &interpreter) override;
86
87  lldb::CommandObjectSP
88  GetThreadTraceStartCommand(CommandInterpreter &interpreter) override;
89
90  llvm::StringRef GetSchema() override;
91
92  llvm::Expected<lldb::TraceCursorSP> CreateNewCursor(Thread &thread) override;
93
94  void DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
95                     bool json) override;
96
97  llvm::Expected<std::optional<uint64_t>> GetRawTraceSize(Thread &thread);
98
99  llvm::Error DoRefreshLiveProcessState(TraceGetStateResponse state,
100                                        llvm::StringRef json_response) override;
101
102  bool IsTraced(lldb::tid_t tid) override;
103
104  const char *GetStartConfigurationHelp() override;
105
106  /// Start tracing a live process.
107  ///
108  /// More information on the parameters below can be found in the
109  /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt.
110  ///
111  /// \param[in] ipt_trace_size
112  ///     Trace size per thread in bytes.
113  ///
114  /// \param[in] total_buffer_size_limit
115  ///     Maximum total trace size per process in bytes.
116  ///
117  /// \param[in] enable_tsc
118  ///     Whether to use enable TSC timestamps or not.
119  ///
120  /// \param[in] psb_period
121  ///     This value defines the period in which PSB packets will be generated.
122  ///
123  /// \param[in] per_cpu_tracing
124  ///     This value defines whether to have an intel pt trace buffer per thread
125  ///     or per cpu core.
126  ///
127  /// \param[in] disable_cgroup_filtering
128  ///     Disable the cgroup filtering that is automatically applied when doing
129  ///     per cpu tracing.
130  ///
131  /// \return
132  ///     \a llvm::Error::success if the operation was successful, or
133  ///     \a llvm::Error otherwise.
134  llvm::Error Start(uint64_t ipt_trace_size, uint64_t total_buffer_size_limit,
135                    bool enable_tsc, std::optional<uint64_t> psb_period,
136                    bool m_per_cpu_tracing, bool disable_cgroup_filtering);
137
138  /// \copydoc Trace::Start
139  llvm::Error Start(StructuredData::ObjectSP configuration =
140                        StructuredData::ObjectSP()) override;
141
142  /// Start tracing live threads.
143  ///
144  /// More information on the parameters below can be found in the
145  /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt.
146  ///
147  /// \param[in] tids
148  ///     Threads to trace.
149  ///
150  /// \param[in] ipt_trace_size
151  ///     Trace size per thread or per cpu core in bytes.
152  ///
153  /// \param[in] enable_tsc
154  ///     Whether to use enable TSC timestamps or not.
155  ///
156  /// \param[in] psb_period
157  ///     This value defines the period in which PSB packets will be generated.
158  ///
159  /// \return
160  ///     \a llvm::Error::success if the operation was successful, or
161  ///     \a llvm::Error otherwise.
162  llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, uint64_t ipt_trace_size,
163                    bool enable_tsc, std::optional<uint64_t> psb_period);
164
165  /// \copydoc Trace::Start
166  llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids,
167                    StructuredData::ObjectSP configuration =
168                        StructuredData::ObjectSP()) override;
169
170  /// See \a Trace::OnThreadBinaryDataRead().
171  llvm::Error OnThreadBufferRead(lldb::tid_t tid,
172                                 OnBinaryDataReadCallback callback);
173
174  /// Get or fetch the cpu information from, for example, /proc/cpuinfo.
175  llvm::Expected<pt_cpu> GetCPUInfo();
176
177  /// Get or fetch the values used to convert to and from TSCs and nanos.
178  std::optional<LinuxPerfZeroTscConversion> GetPerfZeroTscConversion();
179
180  /// \return
181  ///     The timer object for this trace.
182  TaskTimer &GetTimer();
183
184  /// \return
185  ///     The ScopedTaskTimer object for the given thread in this trace.
186  ScopedTaskTimer &GetThreadTimer(lldb::tid_t tid);
187
188  /// \return
189  ///     The global copedTaskTimer object for this trace.
190  ScopedTaskTimer &GetGlobalTimer();
191
192  TraceIntelPTSP GetSharedPtr();
193
194  enum class TraceMode { UserMode, KernelMode };
195
196  TraceMode GetTraceMode();
197
198private:
199  friend class TraceIntelPTBundleLoader;
200
201  llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess();
202
203  /// Postmortem trace constructor
204  ///
205  /// \param[in] bundle_description
206  ///     The definition file for the postmortem bundle.
207  ///
208  /// \param[in] traced_processes
209  ///     The processes traced in the postmortem session.
210  ///
211  /// \param[in] trace_threads
212  ///     The threads traced in the postmortem session. They must belong to the
213  ///     processes mentioned above.
214  ///
215  /// \param[in] trace_mode
216  ///     The tracing mode of the postmortem session.
217  ///
218  /// \return
219  ///     A TraceIntelPT shared pointer instance.
220  /// \{
221  static TraceIntelPTSP CreateInstanceForPostmortemTrace(
222      JSONTraceBundleDescription &bundle_description,
223      llvm::ArrayRef<lldb::ProcessSP> traced_processes,
224      llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads,
225      TraceMode trace_mode);
226
227  /// This constructor is used by CreateInstanceForPostmortemTrace to get the
228  /// instance ready before using shared pointers, which is a limitation of C++.
229  TraceIntelPT(JSONTraceBundleDescription &bundle_description,
230               llvm::ArrayRef<lldb::ProcessSP> traced_processes,
231               TraceMode trace_mode);
232  /// \}
233
234  /// Constructor for live processes
235  TraceIntelPT(Process &live_process)
236      : Trace(live_process), trace_mode(TraceMode::UserMode){};
237
238  /// Decode the trace of the given thread that, i.e. recontruct the traced
239  /// instructions.
240  ///
241  /// \param[in] thread
242  ///     If \a thread is a \a ThreadTrace, then its internal trace file will be
243  ///     decoded. Live threads are not currently supported.
244  ///
245  /// \return
246  ///     A \a DecodedThread shared pointer with the decoded instructions. Any
247  ///     errors are embedded in the instruction list. An \a llvm::Error is
248  ///     returned if the decoder couldn't be properly set up.
249  llvm::Expected<DecodedThreadSP> Decode(Thread &thread);
250
251  /// \return
252  ///     The lowest timestamp in nanoseconds in all traces if available, \a
253  ///     std::nullopt if all the traces were empty or no trace contained no
254  ///     timing information, or an \a llvm::Error if it was not possible to set
255  ///     up the decoder for some trace.
256  llvm::Expected<std::optional<uint64_t>> FindBeginningOfTimeNanos();
257
258  // Dump out trace info in JSON format
259  void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose);
260
261  /// We package all the data that can change upon process stops to make sure
262  /// this contract is very visible.
263  /// This variable should only be accessed directly by constructores or live
264  /// process data refreshers.
265  struct Storage {
266    std::optional<TraceIntelPTMultiCpuDecoder> multicpu_decoder;
267    /// These decoders are used for the non-per-cpu case
268    llvm::DenseMap<lldb::tid_t, std::unique_ptr<ThreadDecoder>> thread_decoders;
269    /// Helper variable used to track long running operations for telemetry.
270    TaskTimer task_timer;
271    /// It is provided by either a trace bundle or a live process to convert TSC
272    /// counters to and from nanos. It might not be available on all hosts.
273    std::optional<LinuxPerfZeroTscConversion> tsc_conversion;
274    std::optional<uint64_t> beginning_of_time_nanos;
275    bool beginning_of_time_nanos_calculated = false;
276  } m_storage;
277
278  /// It is provided by either a trace bundle or a live process' "cpuInfo"
279  /// binary data. We don't put it in the Storage because this variable doesn't
280  /// change.
281  std::optional<pt_cpu> m_cpu_info;
282
283  /// Get the storage after refreshing the data in the case of a live process.
284  Storage &GetUpdatedStorage();
285
286  /// The tracing mode of post mortem trace.
287  TraceMode trace_mode;
288};
289
290} // namespace trace_intel_pt
291} // namespace lldb_private
292
293#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H
294