xref: /llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h (revision 44103c96fa6b00e7824319de1b10ce26781e3852)
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 DecodedThread
55 /// Class holding the instructions and function call hierarchy obtained from
56 /// decoding a trace, as well as a position cursor used when reverse debugging
57 /// the trace.
58 ///
59 /// Each decoded thread contains a cursor to the current position the user is
60 /// stopped at. See \a Trace::GetCursorPosition for more information.
61 class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
62 public:
63   /// \class TscRange
64   /// Class that represents the trace range associated with a given TSC.
65   /// It provides efficient iteration to the previous or next TSC range in the
66   /// decoded trace.
67   ///
68   /// TSC timestamps are emitted by the decoder infrequently, which means
69   /// that each TSC covers a range of instruction indices, which can be used to
70   /// speed up TSC lookups.
71   class TscRange {
72   public:
73     /// Check if this TSC range includes the given instruction index.
74     bool InRange(size_t insn_index) const;
75 
76     /// Get the next range chronologically.
77     llvm::Optional<TscRange> Next() const;
78 
79     /// Get the previous range chronologically.
80     llvm::Optional<TscRange> Prev() const;
81 
82     /// Get the TSC value.
83     size_t GetTsc() const;
84     /// Get the smallest instruction index that has this TSC.
85     size_t GetStartInstructionIndex() const;
86     /// Get the largest instruction index that has this TSC.
87     size_t GetEndInstructionIndex() const;
88 
89   private:
90     friend class DecodedThread;
91 
92     TscRange(std::map<size_t, uint64_t>::const_iterator it,
93              const DecodedThread &decoded_thread);
94 
95     /// The iterator pointing to the beginning of the range.
96     std::map<size_t, uint64_t>::const_iterator m_it;
97     /// The largest instruction index that has this TSC.
98     size_t m_end_index;
99 
100     const DecodedThread *m_decoded_thread;
101   };
102 
103   // Struct holding counts for libipts errors;
104   struct LibiptErrors {
105     // libipt error -> count
106     llvm::DenseMap<const char *, int> libipt_errors;
107     int total_count = 0;
108 
109     void RecordError(int libipt_error_code);
110   };
111 
112   DecodedThread(lldb::ThreadSP thread_sp);
113 
114   /// Utility constructor that initializes the trace with a provided error.
115   DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err);
116 
117   /// Append a successfully decoded instruction.
118   void AppendInstruction(const pt_insn &instruction);
119 
120   /// Append a sucessfully decoded instruction with an associated TSC timestamp.
121   void AppendInstruction(const pt_insn &instruction, uint64_t tsc);
122 
123   /// Append a decoding error (i.e. an instruction that failed to be decoded).
124   void AppendError(llvm::Error &&error);
125 
126   /// Append a decoding error with a corresponding TSC.
127   void AppendError(llvm::Error &&error, uint64_t tsc);
128 
129   /// Get the total number of instruction pointers from the decoded trace.
130   /// This will include instructions that indicate errors (or gaps) in the
131   /// trace. For an instruction error, you can access its underlying error
132   /// message with the \a GetErrorByInstructionIndex() method.
133   size_t GetInstructionsCount() const;
134 
135   /// \return
136   ///     The load address of the instruction at the given index, or \a
137   ///     LLDB_INVALID_ADDRESS if it is an error.
138   lldb::addr_t GetInstructionLoadAddress(size_t insn_index) const;
139 
140   /// Get the \a lldb::TraceInstructionControlFlowType categories of the
141   /// instruction.
142   ///
143   /// \return
144   ///     The control flow categories, or \b 0 if the instruction is an error.
145   lldb::TraceInstructionControlFlowType
146   GetInstructionControlFlowType(size_t insn_index) const;
147 
148   /// Construct the TSC range that covers the given instruction index.
149   /// This operation is O(logn) and should be used sparingly.
150   /// If the trace was collected with TSC support, all the instructions of
151   /// the trace will have associated TSCs. This means that this method will
152   /// only return \b llvm::None if there are no TSCs whatsoever in the trace.
153   ///
154   /// \param[in] insn_index
155   ///   The instruction index in question.
156   ///
157   /// \param[in] hint_range
158   ///   An optional range that might include the given index or might be a
159   ///   neighbor of it. It might help speed it traversals of the trace with
160   ///   short jumps.
161   llvm::Optional<TscRange> CalculateTscRange(
162       size_t insn_index,
163       const llvm::Optional<DecodedThread::TscRange> &hint_range) const;
164 
165   /// Check if an instruction given by its index is an error.
166   bool IsInstructionAnError(size_t insn_idx) const;
167 
168   /// Get the error associated with a given instruction index.
169   ///
170   /// \return
171   ///   The error message of \b nullptr if the given index
172   ///   points to a valid instruction.
173   const char *GetErrorByInstructionIndex(size_t ins_idx);
174 
175   /// Get a new cursor for the decoded thread.
176   lldb::TraceCursorUP GetCursor();
177 
178   /// Return the number of TSC decoding errors that happened. A TSC error
179   /// is not a fatal error and doesn't create gaps in the trace. Instead
180   /// we only keep track of them as a statistic.
181   ///
182   /// \return
183   ///   The number of TSC decoding errors.
184   const LibiptErrors &GetTscErrors() const;
185 
186   /// Record an error decoding a TSC timestamp.
187   ///
188   /// See \a GetTscErrors() for more documentation.
189   ///
190   /// \param[in] libipt_error_code
191   ///   An error returned by the libipt library.
192   void RecordTscError(int libipt_error_code);
193 
194   /// The approximate size in bytes used by this instance,
195   /// including all the already decoded instructions.
196   size_t CalculateApproximateMemoryUsage() const;
197 
198   lldb::ThreadSP GetThread();
199 
200 private:
201   /// Notify this class that the last added instruction or error has
202   /// an associated TSC.
203   void RecordTscForLastInstruction(uint64_t tsc);
204 
205   /// When adding new members to this class, make sure
206   /// to update \a CalculateApproximateMemoryUsage() accordingly.
207   lldb::ThreadSP m_thread_sp;
208   /// The low level storage of all instruction addresses. Each instruction has
209   /// an index in this vector and it will be used in other parts of the code.
210   std::vector<lldb::addr_t> m_instruction_ips;
211   /// The size in bytes of each instruction.
212   std::vector<uint8_t> m_instruction_sizes;
213   /// The libipt instruction class for each instruction.
214   std::vector<pt_insn_class> m_instruction_classes;
215 
216   /// This map contains the TSCs of the decoded instructions. It maps
217   /// `instruction index -> TSC`, where `instruction index` is the first index
218   /// at which the mapped TSC appears. We use this representation because TSCs
219   /// are sporadic and we can think of them as ranges. If TSCs are present in
220   /// the trace, all instructions will have an associated TSC, including the
221   /// first one. Otherwise, this map will be empty.
222   std::map<size_t, uint64_t> m_instruction_timestamps;
223   /// This is the chronologically last TSC that has been added.
224   llvm::Optional<uint64_t> m_last_tsc = llvm::None;
225   // This variables stores the messages of all the error instructions in the
226   // trace. It maps `instruction index -> error message`.
227   llvm::DenseMap<uint64_t, std::string> m_errors;
228   /// The size in bytes of the raw buffer before decoding. It might be None if
229   /// the decoding failed.
230   llvm::Optional<size_t> m_raw_trace_size;
231   /// All occurrences of libipt errors when decoding TSCs.
232   LibiptErrors m_tsc_errors;
233   /// Total amount of time spent decoding.
234   std::chrono::milliseconds m_total_decoding_time{0};
235 };
236 
237 using DecodedThreadSP = std::shared_ptr<DecodedThread>;
238 
239 } // namespace trace_intel_pt
240 } // namespace lldb_private
241 
242 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
243