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 <vector> 13 14 #include "llvm/Support/Errc.h" 15 #include "llvm/Support/Error.h" 16 17 #include "lldb/Target/Trace.h" 18 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 19 20 #include "intel-pt.h" 21 22 namespace lldb_private { 23 namespace trace_intel_pt { 24 25 /// Class for representing a libipt decoding error. 26 class IntelPTError : public llvm::ErrorInfo<IntelPTError> { 27 public: 28 static char ID; 29 30 /// \param[in] libipt_error_code 31 /// Negative number returned by libipt when decoding the trace and 32 /// signaling errors. 33 /// 34 /// \param[in] address 35 /// Optional instruction address. When decoding an individual instruction, 36 /// its address might be available in the \a pt_insn object, and should be 37 /// passed to this constructor. Other errors don't have an associated 38 /// address. 39 IntelPTError(int libipt_error_code, 40 lldb::addr_t address = LLDB_INVALID_ADDRESS); 41 42 std::error_code convertToErrorCode() const override { 43 return llvm::errc::not_supported; 44 } 45 46 void log(llvm::raw_ostream &OS) const override; 47 48 private: 49 int m_libipt_error_code; 50 lldb::addr_t m_address; 51 }; 52 53 /// \class IntelPTInstruction 54 /// An instruction obtained from decoding a trace. It is either an actual 55 /// instruction or an error indicating a gap in the trace. 56 /// 57 /// Gaps in the trace can come in a few flavors: 58 /// - tracing gaps (e.g. tracing was paused and then resumed) 59 /// - tracing errors (e.g. buffer overflow) 60 /// - decoding errors (e.g. some memory region couldn't be decoded) 61 /// As mentioned, any gap is represented as an error in this class. 62 class IntelPTInstruction { 63 public: 64 IntelPTInstruction(const pt_insn &pt_insn, uint64_t timestamp) 65 : m_pt_insn(pt_insn), m_timestamp(timestamp) {} 66 67 IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {} 68 69 /// Error constructor 70 /// 71 /// libipt errors should use the underlying \a IntelPTError class. 72 IntelPTInstruction(llvm::Error err); 73 74 /// Check if this object represents an error (i.e. a gap). 75 /// 76 /// \return 77 /// Whether this object represents an error. 78 bool IsError() const; 79 80 /// \return 81 /// The instruction pointer address, or \a LLDB_INVALID_ADDRESS if it is 82 /// an error. 83 lldb::addr_t GetLoadAddress() const; 84 85 /// \return 86 /// An \a llvm::Error object if this class corresponds to an Error, or an 87 /// \a llvm::Error::success otherwise. 88 llvm::Error ToError() const; 89 90 /// Get the timestamp associated with the current instruction. The timestamp 91 /// is similar to what a rdtsc instruction would return. 92 /// 93 /// \return 94 /// The timestamp or \b llvm::None if not available. 95 llvm::Optional<uint64_t> GetTimestampCounter() const; 96 97 /// Get the \a lldb::TraceInstructionControlFlowType categories of the 98 /// instruction. 99 /// 100 /// \param[in] next_load_address 101 /// The address of the next instruction in the trace or \b 102 /// LLDB_INVALID_ADDRESS if not available. 103 /// 104 /// \return 105 /// The control flow categories, or \b 0 if the instruction is an error. 106 lldb::TraceInstructionControlFlowType 107 GetControlFlowType(lldb::addr_t next_load_address) const; 108 109 IntelPTInstruction(IntelPTInstruction &&other) = default; 110 111 private: 112 IntelPTInstruction(const IntelPTInstruction &other) = delete; 113 const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete; 114 115 pt_insn m_pt_insn; 116 llvm::Optional<uint64_t> m_timestamp; 117 std::unique_ptr<llvm::ErrorInfoBase> m_error; 118 }; 119 120 /// \class DecodedThread 121 /// Class holding the instructions and function call hierarchy obtained from 122 /// decoding a trace, as well as a position cursor used when reverse debugging 123 /// the trace. 124 /// 125 /// Each decoded thread contains a cursor to the current position the user is 126 /// stopped at. See \a Trace::GetCursorPosition for more information. 127 class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 128 public: 129 DecodedThread(lldb::ThreadSP thread_sp, 130 std::vector<IntelPTInstruction> &&instructions, 131 size_t raw_trace_size); 132 133 /// Constructor with a single error signaling a complete failure of the 134 /// decoding process. 135 DecodedThread(lldb::ThreadSP thread_sp, llvm::Error error); 136 137 /// Get the instructions from the decoded trace. Some of them might indicate 138 /// errors (i.e. gaps) in the trace. 139 /// 140 /// \return 141 /// The instructions of the trace. 142 llvm::ArrayRef<IntelPTInstruction> GetInstructions() const; 143 144 /// Get a new cursor for the decoded thread. 145 lldb::TraceCursorUP GetCursor(); 146 147 /// Get the size in bytes of the corresponding Intel PT raw trace 148 /// 149 /// \return 150 /// The size of the trace. 151 size_t GetRawTraceSize() const; 152 153 private: 154 lldb::ThreadSP m_thread_sp; 155 std::vector<IntelPTInstruction> m_instructions; 156 size_t m_raw_trace_size; 157 }; 158 159 using DecodedThreadSP = std::shared_ptr<DecodedThread>; 160 161 } // namespace trace_intel_pt 162 } // namespace lldb_private 163 164 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 165