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 /// Class for representing a libipt decoding error. 27 class IntelPTError : public llvm::ErrorInfo<IntelPTError> { 28 public: 29 static char ID; 30 31 /// \param[in] libipt_error_code 32 /// Negative number returned by libipt when decoding the trace and 33 /// signaling errors. 34 /// 35 /// \param[in] address 36 /// Optional instruction address. When decoding an individual instruction, 37 /// its address might be available in the \a pt_insn object, and should be 38 /// passed to this constructor. Other errors don't have an associated 39 /// address. 40 IntelPTError(int libipt_error_code, 41 lldb::addr_t address = LLDB_INVALID_ADDRESS); 42 43 std::error_code convertToErrorCode() const override { 44 return llvm::errc::not_supported; 45 } 46 47 void log(llvm::raw_ostream &OS) const override; 48 49 private: 50 int m_libipt_error_code; 51 lldb::addr_t m_address; 52 }; 53 54 /// \class IntelPTInstruction 55 /// An instruction obtained from decoding a trace. It is either an actual 56 /// instruction or an error indicating a gap in the trace. 57 /// 58 /// Gaps in the trace can come in a few flavors: 59 /// - tracing gaps (e.g. tracing was paused and then resumed) 60 /// - tracing errors (e.g. buffer overflow) 61 /// - decoding errors (e.g. some memory region couldn't be decoded) 62 /// As mentioned, any gap is represented as an error in this class. 63 class IntelPTInstruction { 64 public: 65 IntelPTInstruction(const pt_insn &pt_insn) 66 : m_pt_insn(pt_insn), m_is_error(false) {} 67 68 /// Error constructor 69 IntelPTInstruction(); 70 71 /// Check if this object represents an error (i.e. a gap). 72 /// 73 /// \return 74 /// Whether this object represents an error. 75 bool IsError() const; 76 77 /// \return 78 /// The instruction pointer address, or \a LLDB_INVALID_ADDRESS if it is 79 /// an error. 80 lldb::addr_t GetLoadAddress() const; 81 82 /// Get the size in bytes of an instance of this class 83 static size_t GetMemoryUsage(); 84 85 /// Get the \a lldb::TraceInstructionControlFlowType categories of the 86 /// instruction. 87 /// 88 /// \param[in] next_load_address 89 /// The address of the next instruction in the trace or \b 90 /// LLDB_INVALID_ADDRESS if not available. 91 /// 92 /// \return 93 /// The control flow categories, or \b 0 if the instruction is an error. 94 lldb::TraceInstructionControlFlowType 95 GetControlFlowType(lldb::addr_t next_load_address) const; 96 97 IntelPTInstruction(IntelPTInstruction &&other) = default; 98 99 private: 100 IntelPTInstruction(const IntelPTInstruction &other) = delete; 101 const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete; 102 103 // When adding new members to this class, make sure to update 104 // IntelPTInstruction::GetMemoryUsage() if needed. 105 pt_insn m_pt_insn; 106 bool m_is_error; 107 }; 108 109 /// \class DecodedThread 110 /// Class holding the instructions and function call hierarchy obtained from 111 /// decoding a trace, as well as a position cursor used when reverse debugging 112 /// the trace. 113 /// 114 /// Each decoded thread contains a cursor to the current position the user is 115 /// stopped at. See \a Trace::GetCursorPosition for more information. 116 class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 117 public: 118 /// \class TscRange 119 /// Class that represents the trace range associated with a given TSC. 120 /// It provides efficient iteration to the previous or next TSC range in the 121 /// decoded trace. 122 /// 123 /// TSC timestamps are emitted by the decoder infrequently, which means 124 /// that each TSC covers a range of instruction indices, which can be used to 125 /// speed up TSC lookups. 126 class TscRange { 127 public: 128 /// Check if this TSC range includes the given instruction index. 129 bool InRange(size_t insn_index); 130 131 /// Get the next range chronologically. 132 llvm::Optional<TscRange> Next(); 133 134 /// Get the previous range chronologically. 135 llvm::Optional<TscRange> Prev(); 136 137 /// Get the TSC value. 138 size_t GetTsc() const; 139 /// Get the smallest instruction index that has this TSC. 140 size_t GetStartInstructionIndex() const; 141 /// Get the largest instruction index that has this TSC. 142 size_t GetEndInstructionIndex() const; 143 144 private: 145 friend class DecodedThread; 146 147 TscRange(std::map<size_t, uint64_t>::const_iterator it, 148 const DecodedThread &decoded_thread); 149 150 /// The iterator pointing to the beginning of the range. 151 std::map<size_t, uint64_t>::const_iterator m_it; 152 /// The largest instruction index that has this TSC. 153 size_t m_end_index; 154 155 const DecodedThread *m_decoded_thread; 156 }; 157 158 // Struct holding counts for libipts errors; 159 struct LibiptErrors { 160 // libipt error -> count 161 llvm::DenseMap<const char *, int> libipt_errors; 162 int total_count = 0; 163 164 void RecordError(int libipt_error_code); 165 }; 166 167 DecodedThread(lldb::ThreadSP thread_sp); 168 169 /// Utility constructor that initializes the trace with a provided error. 170 DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err); 171 172 /// Append a successfully decoded instruction. 173 void AppendInstruction(const pt_insn &instruction); 174 175 /// Append a sucessfully decoded instruction with an associated TSC timestamp. 176 void AppendInstruction(const pt_insn &instruction, uint64_t tsc); 177 178 /// Append a decoding error (i.e. an instruction that failed to be decoded). 179 void AppendError(llvm::Error &&error); 180 181 /// Get the instructions from the decoded trace. Some of them might indicate 182 /// errors (i.e. gaps) in the trace. For an instruction error, you can access 183 /// its underlying error message with the \a GetErrorByInstructionIndex() 184 /// method. 185 /// 186 /// \return 187 /// The instructions of the trace. 188 llvm::ArrayRef<IntelPTInstruction> GetInstructions() const; 189 190 /// Construct the TSC range that covers the given instruction index. 191 /// This operation is O(logn) and should be used sparingly. 192 /// If the trace was collected with TSC support, all the instructions of 193 /// the trace will have associated TSCs. This means that this method will 194 /// only return \b llvm::None if there are no TSCs whatsoever in the trace. 195 llvm::Optional<TscRange> CalculateTscRange(size_t insn_index) const; 196 197 /// Check if an instruction given by its index is an error. 198 bool IsInstructionAnError(size_t insn_idx) const; 199 200 /// Get the error associated with a given instruction index. 201 /// 202 /// \return 203 /// The error message of \b nullptr if the given index 204 /// points to a valid instruction. 205 const char *GetErrorByInstructionIndex(size_t ins_idx); 206 207 /// Append a decoding error with a corresponding TSC. 208 void AppendError(llvm::Error &&error, uint64_t TSC); 209 210 /// Record an error decoding a TSC timestamp. 211 /// 212 /// See \a GetTscErrors() for more documentation. 213 /// 214 /// \param[in] libipt_error_code 215 /// An error returned by the libipt library. 216 void RecordTscError(int libipt_error_code); 217 218 /// Get a new cursor for the decoded thread. 219 lldb::TraceCursorUP GetCursor(); 220 221 /// Set the size in bytes of the corresponding Intel PT raw trace. 222 void SetRawTraceSize(size_t size); 223 224 /// Get the size in bytes of the corresponding Intel PT raw trace. 225 /// 226 /// \return 227 /// The size of the trace, or \b llvm::None if not available. 228 llvm::Optional<size_t> GetRawTraceSize() const; 229 230 /// Return the number of TSC decoding errors that happened. A TSC error 231 /// is not a fatal error and doesn't create gaps in the trace. Instead 232 /// we only keep track of them as a statistic. 233 /// 234 /// \return 235 /// The number of TSC decoding errors. 236 const LibiptErrors &GetTscErrors() const; 237 238 /// The approximate size in bytes used by this instance, 239 /// including all the already decoded instructions. 240 size_t CalculateApproximateMemoryUsage() const; 241 242 lldb::ThreadSP GetThread(); 243 244 private: 245 /// Notify this class that the last added instruction or error has 246 /// an associated TSC. 247 void RecordTscForLastInstruction(uint64_t tsc); 248 249 /// When adding new members to this class, make sure 250 /// to update \a CalculateApproximateMemoryUsage() accordingly. 251 lldb::ThreadSP m_thread_sp; 252 /// The low level storage of all instruction addresses. Each instruction has 253 /// an index in this vector and it will be used in other parts of the code. 254 std::vector<IntelPTInstruction> m_instructions; 255 /// This map contains the TSCs of the decoded instructions. It maps 256 /// `instruction index -> TSC`, where `instruction index` is the first index 257 /// at which the mapped TSC appears. We use this representation because TSCs 258 /// are sporadic and we can think of them as ranges. If TSCs are present in 259 /// the trace, all instructions will have an associated TSC, including the 260 /// first one. Otherwise, this map will be empty. 261 std::map<size_t, uint64_t> m_instruction_timestamps; 262 /// This is the chronologically last TSC that has been added. 263 llvm::Optional<uint64_t> m_last_tsc = llvm::None; 264 // This variables stores the messages of all the error instructions in the 265 // trace. It maps `instruction index -> error message`. 266 llvm::DenseMap<uint64_t, std::string> m_errors; 267 /// The size in bytes of the raw buffer before decoding. It might be None if 268 /// the decoding failed. 269 llvm::Optional<size_t> m_raw_trace_size; 270 /// All occurrences of libipt errors when decoding TSCs. 271 LibiptErrors m_tsc_errors; 272 }; 273 274 using DecodedThreadSP = std::shared_ptr<DecodedThread>; 275 276 } // namespace trace_intel_pt 277 } // namespace lldb_private 278 279 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 280