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