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 void log(llvm::raw_ostream &OS) const override; 57 58 private: 59 int m_libipt_error_code; 60 lldb::addr_t m_address; 61 }; 62 63 /// Helper struct for building an instruction or error from the decoder. 64 /// It holds associated events and timing information. 65 struct DecodedInstruction { 66 DecodedInstruction() { 67 pt_insn.ip = LLDB_INVALID_ADDRESS; 68 libipt_error = pte_ok; 69 } 70 71 DecodedInstruction(int libipt_error_code) : DecodedInstruction() { 72 libipt_error = libipt_error_code; 73 } 74 75 /// \return \b true if and only if this struct holds a libipt error. 76 explicit operator bool() const; 77 78 int libipt_error; 79 lldb::TraceEvents events = (lldb::TraceEvents)0; 80 llvm::Optional<uint64_t> tsc = llvm::None; 81 pt_insn pt_insn; 82 }; 83 84 /// \class DecodedThread 85 /// Class holding the instructions and function call hierarchy obtained from 86 /// decoding a trace, as well as a position cursor used when reverse debugging 87 /// the trace. 88 /// 89 /// Each decoded thread contains a cursor to the current position the user is 90 /// stopped at. See \a Trace::GetCursorPosition for more information. 91 class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 92 public: 93 /// \class TscRange 94 /// Class that represents the trace range associated with a given TSC. 95 /// It provides efficient iteration to the previous or next TSC range in the 96 /// decoded trace. 97 /// 98 /// TSC timestamps are emitted by the decoder infrequently, which means 99 /// that each TSC covers a range of instruction indices, which can be used to 100 /// speed up TSC lookups. 101 class TscRange { 102 public: 103 /// Check if this TSC range includes the given instruction index. 104 bool InRange(size_t insn_index) const; 105 106 /// Get the next range chronologically. 107 llvm::Optional<TscRange> Next() const; 108 109 /// Get the previous range chronologically. 110 llvm::Optional<TscRange> Prev() const; 111 112 /// Get the TSC value. 113 size_t GetTsc() const; 114 /// Get the smallest instruction index that has this TSC. 115 size_t GetStartInstructionIndex() const; 116 /// Get the largest instruction index that has this TSC. 117 size_t GetEndInstructionIndex() const; 118 119 private: 120 friend class DecodedThread; 121 122 TscRange(std::map<size_t, uint64_t>::const_iterator it, 123 const DecodedThread &decoded_thread); 124 125 /// The iterator pointing to the beginning of the range. 126 std::map<size_t, uint64_t>::const_iterator m_it; 127 /// The largest instruction index that has this TSC. 128 size_t m_end_index; 129 130 const DecodedThread *m_decoded_thread; 131 }; 132 133 // Struct holding counts for libipts errors; 134 struct LibiptErrorsStats { 135 // libipt error -> count 136 llvm::DenseMap<const char *, int> libipt_errors_counts; 137 size_t total_count = 0; 138 139 void RecordError(int libipt_error_code); 140 }; 141 142 // Struct holding counts for events; 143 struct EventsStats { 144 /// A count for each individual event kind. We use an unordered map instead 145 /// of a DenseMap because DenseMap can't understand enums. 146 std::unordered_map<lldb::TraceEvents, size_t> events_counts; 147 size_t total_count = 0; 148 size_t total_instructions_with_events = 0; 149 150 void RecordEventsForInstruction(lldb::TraceEvents events); 151 }; 152 153 DecodedThread(lldb::ThreadSP thread_sp); 154 155 /// Utility constructor that initializes the trace with a provided error. 156 DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err); 157 158 /// Append an instruction or a libipt error. 159 void Append(const DecodedInstruction &insn); 160 161 /// Append an error signaling that decoding completely failed. 162 void SetAsFailed(llvm::Error &&error); 163 164 /// Get a bitmask with the events that happened chronologically right before 165 /// the instruction pointed by the given instruction index, but after the 166 /// previous instruction. 167 lldb::TraceEvents GetEvents(int insn_index); 168 169 /// Get the total number of instruction pointers from the decoded trace. 170 /// This will include instructions that indicate errors (or gaps) in the 171 /// trace. For an instruction error, you can access its underlying error 172 /// message with the \a GetErrorByInstructionIndex() method. 173 size_t GetInstructionsCount() const; 174 175 /// \return 176 /// The load address of the instruction at the given index, or \a 177 /// LLDB_INVALID_ADDRESS if it is an error. 178 lldb::addr_t GetInstructionLoadAddress(size_t insn_index) const; 179 180 /// Get the \a lldb::TraceInstructionControlFlowType categories of the 181 /// instruction. 182 /// 183 /// \return 184 /// The control flow categories, or \b 0 if the instruction is an error. 185 lldb::TraceInstructionControlFlowType 186 GetInstructionControlFlowType(size_t insn_index) const; 187 188 /// Construct the TSC range that covers the given instruction index. 189 /// This operation is O(logn) and should be used sparingly. 190 /// If the trace was collected with TSC support, all the instructions of 191 /// the trace will have associated TSCs. This means that this method will 192 /// only return \b llvm::None if there are no TSCs whatsoever in the trace. 193 /// 194 /// \param[in] insn_index 195 /// The instruction index in question. 196 /// 197 /// \param[in] hint_range 198 /// An optional range that might include the given index or might be a 199 /// neighbor of it. It might help speed it traversals of the trace with 200 /// short jumps. 201 llvm::Optional<TscRange> CalculateTscRange( 202 size_t insn_index, 203 const llvm::Optional<DecodedThread::TscRange> &hint_range) const; 204 205 /// Check if an instruction given by its index is an error. 206 bool IsInstructionAnError(size_t insn_idx) const; 207 208 /// Get the error associated with a given instruction index. 209 /// 210 /// \return 211 /// The error message of \b nullptr if the given index 212 /// points to a valid instruction. 213 const char *GetErrorByInstructionIndex(size_t ins_idx); 214 215 /// Get a new cursor for the decoded thread. 216 lldb::TraceCursorUP GetCursor(); 217 218 /// Return an object with statistics of the TSC decoding errors that happened. 219 /// A TSC error is not a fatal error and doesn't create gaps in the trace. 220 /// Instead we only keep track of them as statistics. 221 /// 222 /// \return 223 /// An object with the statistics of TSC decoding errors. 224 const LibiptErrorsStats &GetTscErrorsStats() const; 225 226 /// Return an object with statistics of the trace events that happened. 227 /// 228 /// \return 229 /// The stats object of all the events. 230 const EventsStats &GetEventsStats() const; 231 232 /// Record an error decoding a TSC timestamp. 233 /// 234 /// See \a GetTscErrors() for more documentation. 235 /// 236 /// \param[in] libipt_error_code 237 /// An error returned by the libipt library. 238 void RecordTscError(int libipt_error_code); 239 240 /// The approximate size in bytes used by this instance, 241 /// including all the already decoded instructions. 242 size_t CalculateApproximateMemoryUsage() const; 243 244 lldb::ThreadSP GetThread(); 245 246 private: 247 /// Append a decoding error given an llvm::Error. 248 void AppendError(llvm::Error &&error); 249 250 /// Notify this class that the last added instruction or error has 251 /// an associated TSC. 252 void RecordTscForLastInstruction(uint64_t tsc); 253 254 /// When adding new members to this class, make sure 255 /// to update \a CalculateApproximateMemoryUsage() accordingly. 256 lldb::ThreadSP m_thread_sp; 257 /// The low level storage of all instruction addresses. Each instruction has 258 /// an index in this vector and it will be used in other parts of the code. 259 std::vector<lldb::addr_t> m_instruction_ips; 260 /// The size in bytes of each instruction. 261 std::vector<uint8_t> m_instruction_sizes; 262 /// The libipt instruction class for each instruction. 263 std::vector<pt_insn_class> m_instruction_classes; 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_instruction_timestamps; 272 /// This is the chronologically last TSC that has been added. 273 llvm::Optional<uint64_t> m_last_tsc = llvm::None; 274 // This variables stores the messages of all the error instructions in the 275 // trace. It maps `instruction index -> error message`. 276 llvm::DenseMap<uint64_t, std::string> m_errors; 277 /// This variable stores the bitmask of events that happened right before 278 /// the instruction given as a key. It maps `instruction index -> events`. 279 llvm::DenseMap<uint64_t, lldb::TraceEvents> m_events; 280 281 /// Statistics of all tracing events. 282 EventsStats m_events_stats; 283 /// Statistics of libipt errors when decoding TSCs. 284 LibiptErrorsStats m_tsc_errors_stats; 285 /// Total amount of time spent decoding. 286 std::chrono::milliseconds m_total_decoding_time{0}; 287 }; 288 289 using DecodedThreadSP = std::shared_ptr<DecodedThread>; 290 291 } // namespace trace_intel_pt 292 } // namespace lldb_private 293 294 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 295