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 "lldb/Utility/Status.h" 13 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 14 #include "lldb/lldb-types.h" 15 #include "llvm/ADT/DenseMap.h" 16 #include "llvm/ADT/DenseSet.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 35 class munmap_delete { 36 size_t m_length; 37 38 public: 39 munmap_delete(size_t length) : m_length(length) {} 40 void operator()(void *ptr) { 41 if (m_length) 42 munmap(ptr, m_length); 43 } 44 }; 45 46 class file_close { 47 48 public: 49 file_close() = default; 50 void operator()(int *ptr) { 51 if (ptr == nullptr) 52 return; 53 if (*ptr == -1) 54 return; 55 close(*ptr); 56 std::default_delete<int>()(ptr); 57 } 58 }; 59 60 std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta; 61 std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux; 62 std::unique_ptr<int, file_close> m_fd; 63 lldb::tid_t m_tid; 64 65 /// Start tracing a thread 66 /// 67 /// \param[in] pid 68 /// The pid of the process whose thread will be traced. 69 /// 70 /// \param[in] buffer_size 71 /// Size of the thread buffer in bytes. 72 /// 73 /// \param[in] enable_tsc 74 /// Whether to use enable TSC timestamps or not. 75 /// More information in TraceIntelPT::GetStartConfigurationHelp(). 76 /// 77 /// \param[in] psb_period 78 /// This value defines the period in which PSB packets will be generated. 79 /// More information in TraceIntelPT::GetStartConfigurationHelp(). 80 /// 81 /// \return 82 /// \a llvm::Error::success if tracing was successful, or an 83 /// \a llvm::Error otherwise. 84 llvm::Error StartTrace(lldb::pid_t pid, lldb::tid_t tid, uint64_t buffer_size, 85 bool enable_tsc, llvm::Optional<size_t> psb_period); 86 87 llvm::MutableArrayRef<uint8_t> GetAuxBuffer() const; 88 llvm::MutableArrayRef<uint8_t> GetDataBuffer() const; 89 90 IntelPTThreadTrace() 91 : m_mmap_meta(nullptr, munmap_delete(0)), 92 m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()) {} 93 94 public: 95 /// Get the content of /proc/cpuinfo that can be later used to decode traces. 96 static llvm::Expected<llvm::ArrayRef<uint8_t>> GetCPUInfo(); 97 98 /// Start tracing a thread. 99 /// 100 /// See \a StartTrace. 101 /// 102 /// \return 103 /// A \a IntelPTThreadTrace instance if tracing was successful, or 104 /// an \a llvm::Error otherwise. 105 static llvm::Expected<IntelPTThreadTraceUP> 106 Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, bool enable_tsc, 107 llvm::Optional<size_t> psb_period); 108 109 /// Read the trace buffer of the currently traced thread. 110 /// 111 /// \param[in] offset 112 /// Offset of the data to read. 113 /// 114 /// \param[in] size 115 /// Number of bytes to read. 116 /// 117 /// \return 118 /// A vector with the requested binary data. The vector will have the 119 /// size of the requested \a size. Non-available positions will be 120 /// filled with zeroes. 121 llvm::Expected<std::vector<uint8_t>> GetIntelPTBuffer(size_t offset, 122 size_t size) const; 123 124 Status ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer, 125 size_t offset = 0) const; 126 127 Status ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer, 128 size_t offset = 0) const; 129 130 /// Get the size in bytes of the aux section of the thread or process traced 131 /// by this object. 132 size_t GetTraceBufferSize() const; 133 134 /// Read data from a cyclic buffer 135 /// 136 /// \param[in] [out] buf 137 /// Destination buffer, the buffer will be truncated to written size. 138 /// 139 /// \param[in] src 140 /// Source buffer which must be a cyclic buffer. 141 /// 142 /// \param[in] src_cyc_index 143 /// The index pointer (start of the valid data in the cyclic 144 /// buffer). 145 /// 146 /// \param[in] offset 147 /// The offset to begin reading the data in the cyclic buffer. 148 static void ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst, 149 llvm::MutableArrayRef<uint8_t> src, 150 size_t src_cyc_index, size_t offset); 151 152 /// Return the thread-specific part of the jLLDBTraceGetState packet. 153 TraceThreadState GetState() const; 154 }; 155 156 /// Manages a list of thread traces. 157 class IntelPTThreadTraceCollection { 158 public: 159 IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {} 160 161 /// Dispose of all traces 162 void Clear(); 163 164 bool TracesThread(lldb::tid_t tid) const; 165 166 size_t GetTotalBufferSize() const; 167 168 std::vector<TraceThreadState> GetThreadStates() const; 169 170 llvm::Expected<const IntelPTThreadTrace &> 171 GetTracedThread(lldb::tid_t tid) const; 172 173 llvm::Error TraceStart(lldb::tid_t tid, 174 const TraceIntelPTStartRequest &request); 175 176 llvm::Error TraceStop(lldb::tid_t tid); 177 178 private: 179 lldb::pid_t m_pid; 180 llvm::DenseMap<lldb::tid_t, IntelPTThreadTraceUP> m_thread_traces; 181 /// Total actual thread buffer size in bytes 182 size_t m_total_buffer_size = 0; 183 }; 184 185 /// Manages a "process trace" instance. 186 class IntelPTProcessTrace { 187 public: 188 IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request) 189 : m_thread_traces(pid), m_tracing_params(request) {} 190 191 bool TracesThread(lldb::tid_t tid) const; 192 193 const IntelPTThreadTraceCollection &GetThreadTraces() const; 194 195 llvm::Error TraceStart(lldb::tid_t tid); 196 197 llvm::Error TraceStop(lldb::tid_t tid); 198 199 private: 200 IntelPTThreadTraceCollection m_thread_traces; 201 /// Params used to trace threads when the user started "process tracing". 202 TraceIntelPTStartRequest m_tracing_params; 203 }; 204 205 /// Main class that manages intel-pt process and thread tracing. 206 class IntelPTCollector { 207 public: 208 IntelPTCollector(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {} 209 210 static bool IsSupported(); 211 212 /// If "process tracing" is enabled, then trace the given thread. 213 llvm::Error OnThreadCreated(lldb::tid_t tid); 214 215 /// Stops tracing a tracing upon a destroy event. 216 llvm::Error OnThreadDestroyed(lldb::tid_t tid); 217 218 /// Implementation of the jLLDBTraceStop packet 219 llvm::Error TraceStop(const TraceStopRequest &request); 220 221 /// Implementation of the jLLDBTraceStart packet 222 /// 223 /// \param[in] process_threads 224 /// A list of all threads owned by the process. 225 llvm::Error TraceStart(const TraceIntelPTStartRequest &request, 226 const std::vector<lldb::tid_t> &process_threads); 227 228 /// Implementation of the jLLDBTraceGetState packet 229 llvm::Expected<llvm::json::Value> GetState() const; 230 231 /// Implementation of the jLLDBTraceGetBinaryData packet 232 llvm::Expected<std::vector<uint8_t>> 233 GetBinaryData(const TraceGetBinaryDataRequest &request) const; 234 235 /// Dispose of all traces 236 void Clear(); 237 238 private: 239 llvm::Error TraceStop(lldb::tid_t tid); 240 241 /// Start tracing a specific thread. 242 llvm::Error TraceStart(lldb::tid_t tid, 243 const TraceIntelPTStartRequest &request); 244 245 llvm::Expected<const IntelPTThreadTrace &> 246 GetTracedThread(lldb::tid_t tid) const; 247 248 bool IsProcessTracingEnabled() const; 249 250 void ClearProcessTracing(); 251 252 lldb::pid_t m_pid; 253 /// Threads traced due to "thread tracing" 254 IntelPTThreadTraceCollection m_thread_traces; 255 /// Threads traced due to "process tracing". Only one active "process tracing" 256 /// instance is assumed for a single process. 257 llvm::Optional<IntelPTProcessTrace> m_process_trace; 258 }; 259 260 } // namespace process_linux 261 } // namespace lldb_private 262 263 #endif // liblldb_IntelPTCollector_H_ 264