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 
21 namespace lldb_private {
22 namespace trace_intel_pt {
23 
24 class TraceIntelPT : public Trace {
25 public:
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 
198 private:
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