1 //===-- IntelPTCollector.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 liblldb_IntelPTCollector_H_
10 #define liblldb_IntelPTCollector_H_
11 
12 #include "Perf.h"
13 
14 #include "lldb/Utility/Status.h"
15 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
16 #include "lldb/lldb-types.h"
17 
18 #include <linux/perf_event.h>
19 #include <sys/mman.h>
20 #include <unistd.h>
21 
22 namespace lldb_private {
23 
24 namespace process_linux {
25 
26 /// This class keeps track of one tracing instance of
27 /// Intel(R) Processor Trace on Linux OS at thread level.
28 ///
29 /// The kernel interface for us is the perf_event_open.
30 class IntelPTThreadTrace;
31 typedef std::unique_ptr<IntelPTThreadTrace> IntelPTThreadTraceUP;
32 
33 class IntelPTThreadTrace {
34 public:
35   /// Create a new \a IntelPTThreadTrace and start tracing the thread.
36   ///
37   /// \param[in] pid
38   ///     The pid of the process whose thread will be traced.
39   ///
40   /// \param[in] tid
41   ///     The tid of the thread to be traced.
42   ///
43   /// \param[in] buffer_size
44   ///     Size of the thread buffer in bytes.
45   ///
46   /// \param[in] enable_tsc
47   ///     Whether to use enable TSC timestamps or not.
48   ///     More information in TraceIntelPT::GetStartConfigurationHelp().
49   ///
50   /// \param[in] psb_period
51   ///     This value defines the period in which PSB packets will be generated.
52   ///     More information in TraceIntelPT::GetStartConfigurationHelp().
53   ///
54   /// \return
55   ///   A \a IntelPTThreadTrace instance if tracing was successful, or
56   ///   an \a llvm::Error otherwise.
57   static llvm::Expected<IntelPTThreadTraceUP>
58   Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, bool enable_tsc,
59          llvm::Optional<size_t> psb_period);
60 
61   /// Create a \a perf_event_attr configured for
62   /// an IntelPT event.
63   ///
64   /// \return
65   ///   A \a perf_event_attr if successful,
66   ///   or an \a llvm::Error otherwise.
67   static llvm::Expected<perf_event_attr>
68   CreateIntelPTPerfEventConfiguration(bool enable_tsc,
69                                       llvm::Optional<size_t> psb_period);
70 
71   /// Read the trace buffer of the currently traced thread.
72   ///
73   /// \param[in] offset
74   ///     Offset of the data to read.
75   ///
76   /// \param[in] size
77   ///     Number of bytes to read.
78   ///
79   /// \return
80   ///     A vector with the requested binary data. The vector will have the
81   ///     size of the requested \a size. Non-available positions will be
82   ///     filled with zeroes.
83   llvm::Expected<std::vector<uint8_t>> GetIntelPTBuffer(size_t offset,
84                                                         size_t size) const;
85 
86   Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
87                           size_t offset = 0) const;
88 
89   Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
90                            size_t offset = 0) const;
91 
92   /// Get the size in bytes of the aux section of the thread or process traced
93   /// by this object.
94   size_t GetTraceBufferSize() const;
95 
96   /// Read data from a cyclic buffer
97   ///
98   /// \param[in] [out] buf
99   ///     Destination buffer, the buffer will be truncated to written size.
100   ///
101   /// \param[in] src
102   ///     Source buffer which must be a cyclic buffer.
103   ///
104   /// \param[in] src_cyc_index
105   ///     The index pointer (start of the valid data in the cyclic
106   ///     buffer).
107   ///
108   /// \param[in] offset
109   ///     The offset to begin reading the data in the cyclic buffer.
110   static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
111                                llvm::ArrayRef<uint8_t> src,
112                                size_t src_cyc_index, size_t offset);
113 
114   /// Return the thread-specific part of the jLLDBTraceGetState packet.
115   TraceThreadState GetState() const;
116 
117 private:
118   /// Construct new \a IntelPTThreadTrace. Users are supposed to create
119   /// instances of this class via the \a Create() method and not invoke this one
120   /// directly.
121   ///
122   /// \param[in] perf_event
123   ///   perf event configured for IntelPT.
124   ///
125   /// \param[in] tid
126   ///   The thread being traced.
127   IntelPTThreadTrace(PerfEvent &&perf_event, lldb::tid_t tid)
128       : m_perf_event(std::move(perf_event)), m_tid(tid) {}
129 
130   /// perf event configured for IntelPT.
131   PerfEvent m_perf_event;
132   /// The thread being traced.
133   lldb::tid_t m_tid;
134 };
135 
136 /// Manages a list of thread traces.
137 class IntelPTThreadTraceCollection {
138 public:
139   IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {}
140 
141   /// Dispose of all traces
142   void Clear();
143 
144   bool TracesThread(lldb::tid_t tid) const;
145 
146   size_t GetTotalBufferSize() const;
147 
148   std::vector<TraceThreadState> GetThreadStates() const;
149 
150   llvm::Expected<const IntelPTThreadTrace &>
151   GetTracedThread(lldb::tid_t tid) const;
152 
153   llvm::Error TraceStart(lldb::tid_t tid,
154                          const TraceIntelPTStartRequest &request);
155 
156   llvm::Error TraceStop(lldb::tid_t tid);
157 
158 private:
159   lldb::pid_t m_pid;
160   llvm::DenseMap<lldb::tid_t, IntelPTThreadTraceUP> m_thread_traces;
161   /// Total actual thread buffer size in bytes
162   size_t m_total_buffer_size = 0;
163 };
164 
165 /// Manages a "process trace" instance.
166 class IntelPTProcessTrace {
167 public:
168   IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request)
169       : m_thread_traces(pid), m_tracing_params(request) {}
170 
171   bool TracesThread(lldb::tid_t tid) const;
172 
173   const IntelPTThreadTraceCollection &GetThreadTraces() const;
174 
175   llvm::Error TraceStart(lldb::tid_t tid);
176 
177   llvm::Error TraceStop(lldb::tid_t tid);
178 
179 private:
180   IntelPTThreadTraceCollection m_thread_traces;
181   /// Params used to trace threads when the user started "process tracing".
182   TraceIntelPTStartRequest m_tracing_params;
183 };
184 
185 /// Main class that manages intel-pt process and thread tracing.
186 class IntelPTCollector {
187 public:
188   IntelPTCollector(lldb::pid_t pid);
189 
190   static bool IsSupported();
191 
192   /// If "process tracing" is enabled, then trace the given thread.
193   llvm::Error OnThreadCreated(lldb::tid_t tid);
194 
195   /// Stops tracing a tracing upon a destroy event.
196   llvm::Error OnThreadDestroyed(lldb::tid_t tid);
197 
198   /// Implementation of the jLLDBTraceStop packet
199   llvm::Error TraceStop(const TraceStopRequest &request);
200 
201   /// Implementation of the jLLDBTraceStart packet
202   ///
203   /// \param[in] process_threads
204   ///     A list of all threads owned by the process.
205   llvm::Error TraceStart(const TraceIntelPTStartRequest &request,
206                          const std::vector<lldb::tid_t> &process_threads);
207 
208   /// Implementation of the jLLDBTraceGetState packet
209   llvm::Expected<llvm::json::Value> GetState() const;
210 
211   /// Implementation of the jLLDBTraceGetBinaryData packet
212   llvm::Expected<std::vector<uint8_t>>
213   GetBinaryData(const TraceGetBinaryDataRequest &request) const;
214 
215   /// Dispose of all traces
216   void Clear();
217 
218 private:
219   llvm::Error TraceStop(lldb::tid_t tid);
220 
221   /// Start tracing a specific thread.
222   llvm::Error TraceStart(lldb::tid_t tid,
223                          const TraceIntelPTStartRequest &request);
224 
225   llvm::Expected<const IntelPTThreadTrace &>
226   GetTracedThread(lldb::tid_t tid) const;
227 
228   bool IsProcessTracingEnabled() const;
229 
230   void ClearProcessTracing();
231 
232   lldb::pid_t m_pid;
233   /// Threads traced due to "thread tracing"
234   IntelPTThreadTraceCollection m_thread_traces;
235   /// Threads traced due to "process tracing". Only one active "process tracing"
236   /// instance is assumed for a single process.
237   llvm::Optional<IntelPTProcessTrace> m_process_trace;
238   /// TSC to wall time conversion.
239   TraceTscConversionUP m_tsc_conversion;
240 };
241 
242 } // namespace process_linux
243 } // namespace lldb_private
244 
245 #endif // liblldb_IntelPTCollector_H_
246