1 //===-- DecodedThread.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_DECODEDTHREAD_H 10 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 11 12 #include <utility> 13 #include <vector> 14 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/Error.h" 17 18 #include "lldb/Target/Trace.h" 19 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 20 21 #include "intel-pt.h" 22 23 namespace lldb_private { 24 namespace trace_intel_pt { 25 26 /// libipt status utils 27 /// \{ 28 bool IsLibiptError(int libipt_status); 29 30 bool IsEndOfStream(int libipt_status); 31 32 bool IsTscUnavailable(int libipt_status); 33 /// \} 34 35 /// Class for representing a libipt decoding error. 36 class IntelPTError : public llvm::ErrorInfo<IntelPTError> { 37 public: 38 static char ID; 39 40 /// \param[in] libipt_error_code 41 /// Negative number returned by libipt when decoding the trace and 42 /// signaling errors. 43 /// 44 /// \param[in] address 45 /// Optional instruction address. When decoding an individual instruction, 46 /// its address might be available in the \a pt_insn object, and should be 47 /// passed to this constructor. Other errors don't have an associated 48 /// address. 49 IntelPTError(int libipt_error_code, 50 lldb::addr_t address = LLDB_INVALID_ADDRESS); 51 52 std::error_code convertToErrorCode() const override { 53 return llvm::errc::not_supported; 54 } 55 56 int GetLibiptErrorCode() const { return m_libipt_error_code; } 57 58 void log(llvm::raw_ostream &OS) const override; 59 60 private: 61 int m_libipt_error_code; 62 lldb::addr_t m_address; 63 }; 64 65 /// \class DecodedThread 66 /// Class holding the instructions and function call hierarchy obtained from 67 /// decoding a trace, as well as a position cursor used when reverse debugging 68 /// the trace. 69 /// 70 /// Each decoded thread contains a cursor to the current position the user is 71 /// stopped at. See \a Trace::GetCursorPosition for more information. 72 class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 73 public: 74 /// \class TscRange 75 /// Class that represents the trace range associated with a given TSC. 76 /// It provides efficient iteration to the previous or next TSC range in the 77 /// decoded trace. 78 /// 79 /// TSC timestamps are emitted by the decoder infrequently, which means 80 /// that each TSC covers a range of instruction indices, which can be used to 81 /// speed up TSC lookups. 82 class TscRange { 83 public: 84 /// Check if this TSC range includes the given instruction index. 85 bool InRange(size_t insn_index) const; 86 87 /// Get the next range chronologically. 88 llvm::Optional<TscRange> Next() const; 89 90 /// Get the previous range chronologically. 91 llvm::Optional<TscRange> Prev() const; 92 93 /// Get the TSC value. 94 size_t GetTsc() const; 95 /// Get the smallest instruction index that has this TSC. 96 size_t GetStartInstructionIndex() const; 97 /// Get the largest instruction index that has this TSC. 98 size_t GetEndInstructionIndex() const; 99 100 private: 101 friend class DecodedThread; 102 103 TscRange(std::map<size_t, uint64_t>::const_iterator it, 104 const DecodedThread &decoded_thread); 105 106 /// The iterator pointing to the beginning of the range. 107 std::map<size_t, uint64_t>::const_iterator m_it; 108 /// The largest instruction index that has this TSC. 109 size_t m_end_index; 110 111 const DecodedThread *m_decoded_thread; 112 }; 113 114 // Struct holding counts for libipts errors; 115 struct LibiptErrorsStats { 116 // libipt error -> count 117 llvm::DenseMap<const char *, int> libipt_errors_counts; 118 size_t total_count = 0; 119 120 void RecordError(int libipt_error_code); 121 }; 122 123 // Struct holding counts for events; 124 struct EventsStats { 125 /// A count for each individual event kind. We use an unordered map instead 126 /// of a DenseMap because DenseMap can't understand enums. 127 std::unordered_map<lldb::TraceEvent, size_t> events_counts; 128 size_t total_count = 0; 129 130 void RecordEvent(lldb::TraceEvent event); 131 }; 132 133 DecodedThread(lldb::ThreadSP thread_sp); 134 135 /// Utility constructor that initializes the trace with a provided error. 136 DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err); 137 138 /// Get the total number of instruction, errors and events from the decoded 139 /// trace. 140 int64_t GetItemsCount() const; 141 142 /// Construct the TSC range that covers the given instruction index. 143 /// This operation is O(logn) and should be used sparingly. 144 /// If the trace was collected with TSC support, all the instructions of 145 /// the trace will have associated TSCs. This means that this method will 146 /// only return \b llvm::None if there are no TSCs whatsoever in the trace. 147 /// 148 /// \param[in] insn_index 149 /// The instruction index in question. 150 /// 151 /// \param[in] hint_range 152 /// An optional range that might include the given index or might be a 153 /// neighbor of it. It might help speed it traversals of the trace with 154 /// short jumps. 155 llvm::Optional<TscRange> CalculateTscRange( 156 size_t insn_index, 157 const llvm::Optional<DecodedThread::TscRange> &hint_range) const; 158 159 /// \return 160 /// The error associated with a given trace item. 161 const char *GetErrorByIndex(size_t item_index) const; 162 163 /// \return 164 /// The trace item kind given an item index. 165 lldb::TraceItemKind GetItemKindByIndex(size_t item_index) const; 166 167 /// \return 168 /// The underlying event type for the given trace item index. 169 lldb::TraceEvent GetEventByIndex(int item_index) const; 170 171 /// Get the most recent CPU id before or at the given trace item index. 172 /// 173 /// \param[in] item_index 174 /// The trace item index to compare with. 175 /// 176 /// \return 177 /// The requested cpu id, or \a llvm::None if not available. 178 llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const; 179 180 /// \return 181 /// The load address of the instruction at the given index. 182 lldb::addr_t GetInstructionLoadAddress(size_t item_index) const; 183 184 /// Get a new cursor for the decoded thread. 185 lldb::TraceCursorUP CreateNewCursor(); 186 187 /// Return an object with statistics of the TSC decoding errors that happened. 188 /// A TSC error is not a fatal error and doesn't create gaps in the trace. 189 /// Instead we only keep track of them as statistics. 190 /// 191 /// \return 192 /// An object with the statistics of TSC decoding errors. 193 const LibiptErrorsStats &GetTscErrorsStats() const; 194 195 /// Return an object with statistics of the trace events that happened. 196 /// 197 /// \return 198 /// The stats object of all the events. 199 const EventsStats &GetEventsStats() const; 200 201 /// Record an error decoding a TSC timestamp. 202 /// 203 /// See \a GetTscErrors() for more documentation. 204 /// 205 /// \param[in] libipt_error_code 206 /// An error returned by the libipt library. 207 void RecordTscError(int libipt_error_code); 208 209 /// The approximate size in bytes used by this instance, 210 /// including all the already decoded instructions. 211 size_t CalculateApproximateMemoryUsage() const; 212 213 lldb::ThreadSP GetThread(); 214 215 /// Notify this object that a new tsc has been seen. 216 /// If this a new TSC, an event will be created. 217 void NotifyTsc(uint64_t tsc); 218 219 /// Notify this object that a CPU has been seen. 220 /// If this a new CPU, an event will be created. 221 void NotifyCPU(lldb::cpu_id_t cpu_id); 222 223 /// Append a decoding error. 224 void AppendError(const IntelPTError &error); 225 226 /// Append a custom decoding. 227 void AppendCustomError(llvm::StringRef error); 228 229 /// Append an event. 230 void AppendEvent(lldb::TraceEvent); 231 232 /// Append an instruction. 233 void AppendInstruction(const pt_insn &insn); 234 235 private: 236 /// When adding new members to this class, make sure 237 /// to update \a CalculateApproximateMemoryUsage() accordingly. 238 lldb::ThreadSP m_thread_sp; 239 240 /// We use a union to optimize the memory usage for the different kinds of 241 /// trace items. 242 union TraceItemStorage { 243 /// The load addresses of this item if it's an instruction. 244 uint64_t load_address; 245 246 /// The event kind of this item if it's an event 247 lldb::TraceEvent event; 248 249 /// The string message of this item if it's an error 250 const char *error; 251 }; 252 253 /// Create a new trace item. 254 /// 255 /// \return 256 /// The index of the new item. 257 DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind); 258 259 /// Most of the trace data is stored here. 260 std::vector<TraceItemStorage> m_item_data; 261 /// The TraceItemKind for each trace item encoded as uint8_t. We don't include 262 /// it in TraceItemStorage to avoid padding. 263 std::vector<uint8_t> m_item_kinds; 264 265 /// This map contains the TSCs of the decoded instructions. It maps 266 /// `instruction index -> TSC`, where `instruction index` is the first index 267 /// at which the mapped TSC appears. We use this representation because TSCs 268 /// are sporadic and we can think of them as ranges. If TSCs are present in 269 /// the trace, all instructions will have an associated TSC, including the 270 /// first one. Otherwise, this map will be empty. 271 std::map<uint64_t, uint64_t> m_timestamps; 272 /// This is the chronologically last TSC that has been added. 273 llvm::Optional<uint64_t> m_last_tsc = llvm::None; 274 275 // The cpu information is stored as a map. It maps `instruction index -> CPU` 276 // A CPU is associated with the next instructions that follow until the next 277 // cpu is seen. 278 std::map<uint64_t, lldb::cpu_id_t> m_cpus; 279 /// This is the chronologically last CPU ID. 280 llvm::Optional<uint64_t> m_last_cpu = llvm::None; 281 282 /// Statistics of all tracing events. 283 EventsStats m_events_stats; 284 /// Statistics of libipt errors when decoding TSCs. 285 LibiptErrorsStats m_tsc_errors_stats; 286 /// Total amount of time spent decoding. 287 std::chrono::milliseconds m_total_decoding_time{0}; 288 }; 289 290 using DecodedThreadSP = std::shared_ptr<DecodedThread>; 291 292 } // namespace trace_intel_pt 293 } // namespace lldb_private 294 295 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 296