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   /// Get the size in bytes of a non-error instance of this class
86   static size_t GetNonErrorMemoryUsage();
87 
88   /// \return
89   ///     An \a llvm::Error object if this class corresponds to an Error, or an
90   ///     \a llvm::Error::success otherwise.
91   llvm::Error ToError() const;
92 
93   /// Get the timestamp associated with the current instruction. The timestamp
94   /// is similar to what a rdtsc instruction would return.
95   ///
96   /// \return
97   ///     The timestamp or \b llvm::None if not available.
98   llvm::Optional<uint64_t> GetTimestampCounter() const;
99 
100   /// Get the \a lldb::TraceInstructionControlFlowType categories of the
101   /// instruction.
102   ///
103   /// \param[in] next_load_address
104   ///     The address of the next instruction in the trace or \b
105   ///     LLDB_INVALID_ADDRESS if not available.
106   ///
107   /// \return
108   ///     The control flow categories, or \b 0 if the instruction is an error.
109   lldb::TraceInstructionControlFlowType
110   GetControlFlowType(lldb::addr_t next_load_address) const;
111 
112   IntelPTInstruction(IntelPTInstruction &&other) = default;
113 
114 private:
115   IntelPTInstruction(const IntelPTInstruction &other) = delete;
116   const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete;
117 
118   // When adding new members to this class, make sure to update
119   // IntelPTInstruction::GetNonErrorMemoryUsage() if needed.
120   pt_insn m_pt_insn;
121   llvm::Optional<uint64_t> m_timestamp;
122   std::unique_ptr<llvm::ErrorInfoBase> m_error;
123 };
124 
125 /// \class DecodedThread
126 /// Class holding the instructions and function call hierarchy obtained from
127 /// decoding a trace, as well as a position cursor used when reverse debugging
128 /// the trace.
129 ///
130 /// Each decoded thread contains a cursor to the current position the user is
131 /// stopped at. See \a Trace::GetCursorPosition for more information.
132 class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
133 public:
134   DecodedThread(lldb::ThreadSP thread_sp,
135                 std::vector<IntelPTInstruction> &&instructions,
136                 size_t raw_trace_size);
137 
138   /// Constructor with a single error signaling a complete failure of the
139   /// decoding process.
140   DecodedThread(lldb::ThreadSP thread_sp, llvm::Error error);
141 
142   /// Get the instructions from the decoded trace. Some of them might indicate
143   /// errors (i.e. gaps) in the trace.
144   ///
145   /// \return
146   ///   The instructions of the trace.
147   llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
148 
149   /// Get a new cursor for the decoded thread.
150   lldb::TraceCursorUP GetCursor();
151 
152   /// Get the size in bytes of the corresponding Intel PT raw trace
153   ///
154   /// \return
155   ///   The size of the trace.
156   size_t GetRawTraceSize() const;
157 
158   /// The approximate size in bytes used by this instance,
159   /// including all the already decoded instructions.
160   size_t CalculateApproximateMemoryUsage() const;
161 
162 private:
163   /// When adding new members to this class, make sure
164   /// to update \a CalculateApproximateMemoryUsage() accordingly.
165   lldb::ThreadSP m_thread_sp;
166   std::vector<IntelPTInstruction> m_instructions;
167   size_t m_raw_trace_size;
168 };
169 
170 using DecodedThreadSP = std::shared_ptr<DecodedThread>;
171 
172 } // namespace trace_intel_pt
173 } // namespace lldb_private
174 
175 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
176