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   int GetLibiptErrorCode() const { return m_libipt_error_code; }
57 
58   void log(llvm::raw_ostream &OS) const override;
59 
60 private:
61   int m_libipt_error_code;
62   lldb::addr_t m_address;
63 };
64 
65 /// \class DecodedThread
66 /// Class holding the instructions and function call hierarchy obtained from
67 /// decoding a trace, as well as a position cursor used when reverse debugging
68 /// the trace.
69 ///
70 /// Each decoded thread contains a cursor to the current position the user is
71 /// stopped at. See \a Trace::GetCursorPosition for more information.
72 class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
73 public:
74   using TSC = uint64_t;
75 
76   // Struct holding counts for libipts errors;
77   struct LibiptErrorsStats {
78     // libipt error -> count
79     llvm::DenseMap<const char *, int> libipt_errors_counts;
80     size_t total_count = 0;
81 
82     void RecordError(int libipt_error_code);
83   };
84 
85   /// A structure that represents a maximal range of trace items associated to
86   /// the same TSC value.
87   struct TSCRange {
88     TSC tsc;
89     /// Number of trace items in this range.
90     uint64_t items_count;
91     /// Index of the first trace item in this range.
92     uint64_t first_item_index;
93 
94     /// \return
95     ///   \b true if and only if the given \p item_index is covered by this
96     ///   range.
97     bool InRange(uint64_t item_index) const;
98   };
99 
100   /// A structure that represents a maximal range of trace items associated to
101   /// the same non-interpolated timestamps in nanoseconds.
102   struct NanosecondsRange {
103     /// The nanoseconds value for this range.
104     uint64_t nanos;
105     /// The corresponding TSC value for this range.
106     TSC tsc;
107     /// A nullable pointer to the next range.
108     NanosecondsRange *next_range;
109     /// Number of trace items in this range.
110     uint64_t items_count;
111     /// Index of the first trace item in this range.
112     uint64_t first_item_index;
113 
114     /// Calculate an interpolated timestamp in nanoseconds for the given item
115     /// index. It's guaranteed that two different item indices will produce
116     /// different interpolated values.
117     ///
118     /// \param[in] item_index
119     ///   The index of the item whose timestamp will be estimated. It has to be
120     ///   part of this range.
121     ///
122     /// \param[in] beginning_of_time_nanos
123     ///   The timestamp at which tracing started.
124     ///
125     /// \param[in] tsc_conversion
126     ///   The tsc -> nanos conversion utility
127     ///
128     /// \return
129     ///   An interpolated timestamp value for the given trace item.
130     double
131     GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
132                         const LinuxPerfZeroTscConversion &tsc_conversion) const;
133 
134     /// \return
135     ///   \b true if and only if the given \p item_index is covered by this
136     ///   range.
137     bool InRange(uint64_t item_index) const;
138   };
139 
140   // Struct holding counts for events;
141   struct EventsStats {
142     /// A count for each individual event kind. We use an unordered map instead
143     /// of a DenseMap because DenseMap can't understand enums.
144     std::unordered_map<lldb::TraceEvent, size_t> events_counts;
145     size_t total_count = 0;
146 
147     void RecordEvent(lldb::TraceEvent event);
148   };
149 
150   DecodedThread(
151       lldb::ThreadSP thread_sp,
152       const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion);
153 
154   /// Get the total number of instruction, errors and events from the decoded
155   /// trace.
156   uint64_t GetItemsCount() const;
157 
158   /// \return
159   ///   The error associated with a given trace item.
160   const char *GetErrorByIndex(uint64_t item_index) const;
161 
162   /// \return
163   ///   The trace item kind given an item index.
164   lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
165 
166   /// \return
167   ///   The underlying event type for the given trace item index.
168   lldb::TraceEvent GetEventByIndex(int item_index) const;
169 
170   /// Get the most recent CPU id before or at the given trace item index.
171   ///
172   /// \param[in] item_index
173   ///   The trace item index to compare with.
174   ///
175   /// \return
176   ///   The requested cpu id, or \a llvm::None if not available.
177   llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const;
178 
179   /// Get a maximal range of trace items that include the given \p item_index
180   /// that have the same TSC value.
181   ///
182   /// \param[in] item_index
183   ///   The trace item index to compare with.
184   ///
185   /// \return
186   ///   The requested TSC range, or \a llvm::None if not available.
187   llvm::Optional<DecodedThread::TSCRange>
188   GetTSCRangeByIndex(uint64_t item_index) const;
189 
190   /// Get a maximal range of trace items that include the given \p item_index
191   /// that have the same nanoseconds timestamp without interpolation.
192   ///
193   /// \param[in] item_index
194   ///   The trace item index to compare with.
195   ///
196   /// \return
197   ///   The requested nanoseconds range, or \a llvm::None if not available.
198   llvm::Optional<DecodedThread::NanosecondsRange>
199   GetNanosecondsRangeByIndex(uint64_t item_index);
200 
201   /// \return
202   ///     The load address of the instruction at the given index.
203   lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
204 
205   /// Return an object with statistics of the TSC decoding errors that happened.
206   /// A TSC error is not a fatal error and doesn't create gaps in the trace.
207   /// Instead we only keep track of them as statistics.
208   ///
209   /// \return
210   ///   An object with the statistics of TSC decoding errors.
211   const LibiptErrorsStats &GetTscErrorsStats() const;
212 
213   /// Return an object with statistics of the trace events that happened.
214   ///
215   /// \return
216   ///   The stats object of all the events.
217   const EventsStats &GetEventsStats() const;
218 
219   /// Record an error decoding a TSC timestamp.
220   ///
221   /// See \a GetTscErrors() for more documentation.
222   ///
223   /// \param[in] libipt_error_code
224   ///   An error returned by the libipt library.
225   void RecordTscError(int libipt_error_code);
226 
227   /// The approximate size in bytes used by this instance,
228   /// including all the already decoded instructions.
229   size_t CalculateApproximateMemoryUsage() const;
230 
231   lldb::ThreadSP GetThread();
232 
233   /// Notify this object that a new tsc has been seen.
234   /// If this a new TSC, an event will be created.
235   void NotifyTsc(TSC tsc);
236 
237   /// Notify this object that a CPU has been seen.
238   /// If this a new CPU, an event will be created.
239   void NotifyCPU(lldb::cpu_id_t cpu_id);
240 
241   /// Append a decoding error.
242   void AppendError(const IntelPTError &error);
243 
244   /// Append a custom decoding.
245   void AppendCustomError(llvm::StringRef error);
246 
247   /// Append an event.
248   void AppendEvent(lldb::TraceEvent);
249 
250   /// Append an instruction.
251   void AppendInstruction(const pt_insn &insn);
252 
253 private:
254   /// When adding new members to this class, make sure
255   /// to update \a CalculateApproximateMemoryUsage() accordingly.
256   lldb::ThreadSP m_thread_sp;
257 
258   /// We use a union to optimize the memory usage for the different kinds of
259   /// trace items.
260   union TraceItemStorage {
261     /// The load addresses of this item if it's an instruction.
262     uint64_t load_address;
263 
264     /// The event kind of this item if it's an event
265     lldb::TraceEvent event;
266 
267     /// The string message of this item if it's an error
268     const char *error;
269   };
270 
271   /// Create a new trace item.
272   ///
273   /// \return
274   ///   The index of the new item.
275   DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind);
276 
277   /// Most of the trace data is stored here.
278   std::vector<TraceItemStorage> m_item_data;
279   /// The TraceItemKind for each trace item encoded as uint8_t. We don't include
280   /// it in TraceItemStorage to avoid padding.
281   std::vector<uint8_t> m_item_kinds;
282 
283   /// This map contains the TSCs of the decoded trace items. It maps
284   /// `item index -> TSC`, where `item index` is the first index
285   /// at which the mapped TSC first appears. We use this representation because
286   /// TSCs are sporadic and we can think of them as ranges.
287   std::map<uint64_t, TSCRange> m_tscs;
288   /// This is the chronologically last TSC that has been added.
289   llvm::Optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
290       llvm::None;
291   /// This map contains the non-interpolated nanoseconds timestamps of the
292   /// decoded trace items. It maps `item index -> nanoseconds`, where `item
293   /// index` is the first index at which the mapped nanoseconds first appears.
294   /// We use this representation because timestamps are sporadic and we think of
295   /// them as ranges.
296   std::map<uint64_t, NanosecondsRange> m_nanoseconds;
297   llvm::Optional<std::map<uint64_t, NanosecondsRange>::iterator>
298       m_last_nanoseconds = llvm::None;
299 
300   // The cpu information is stored as a map. It maps `instruction index -> CPU`
301   // A CPU is associated with the next instructions that follow until the next
302   // cpu is seen.
303   std::map<uint64_t, lldb::cpu_id_t> m_cpus;
304   /// This is the chronologically last CPU ID.
305   llvm::Optional<uint64_t> m_last_cpu = llvm::None;
306 
307   /// TSC -> nanos conversion utility.
308   llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
309 
310   /// Statistics of all tracing events.
311   EventsStats m_events_stats;
312   /// Statistics of libipt errors when decoding TSCs.
313   LibiptErrorsStats m_tsc_errors_stats;
314   /// Total amount of time spent decoding.
315   std::chrono::milliseconds m_total_decoding_time{0};
316 };
317 
318 using DecodedThreadSP = std::shared_ptr<DecodedThread>;
319 
320 } // namespace trace_intel_pt
321 } // namespace lldb_private
322 
323 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
324