xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1e8d8bef9SDimitry Andric //===-- DecodedThread.h -----------------------------------------*- C++ -*-===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric 
9e8d8bef9SDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
10e8d8bef9SDimitry Andric #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
11e8d8bef9SDimitry Andric 
12*bdd1243dSDimitry Andric #include "intel-pt.h"
13*bdd1243dSDimitry Andric #include "lldb/Target/Trace.h"
14*bdd1243dSDimitry Andric #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
15*bdd1243dSDimitry Andric #include "llvm/Support/Errc.h"
16*bdd1243dSDimitry Andric #include "llvm/Support/Error.h"
17*bdd1243dSDimitry Andric #include <optional>
1881ad6265SDimitry Andric #include <utility>
19e8d8bef9SDimitry Andric #include <vector>
20e8d8bef9SDimitry Andric 
21e8d8bef9SDimitry Andric namespace lldb_private {
22e8d8bef9SDimitry Andric namespace trace_intel_pt {
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric /// Class for representing a libipt decoding error.
25e8d8bef9SDimitry Andric class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
26e8d8bef9SDimitry Andric public:
27e8d8bef9SDimitry Andric   static char ID;
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric   /// \param[in] libipt_error_code
30e8d8bef9SDimitry Andric   ///     Negative number returned by libipt when decoding the trace and
31e8d8bef9SDimitry Andric   ///     signaling errors.
32e8d8bef9SDimitry Andric   ///
33e8d8bef9SDimitry Andric   /// \param[in] address
34e8d8bef9SDimitry Andric   ///     Optional instruction address. When decoding an individual instruction,
35e8d8bef9SDimitry Andric   ///     its address might be available in the \a pt_insn object, and should be
36e8d8bef9SDimitry Andric   ///     passed to this constructor. Other errors don't have an associated
37e8d8bef9SDimitry Andric   ///     address.
38e8d8bef9SDimitry Andric   IntelPTError(int libipt_error_code,
39e8d8bef9SDimitry Andric                lldb::addr_t address = LLDB_INVALID_ADDRESS);
40e8d8bef9SDimitry Andric 
41e8d8bef9SDimitry Andric   std::error_code convertToErrorCode() const override {
42e8d8bef9SDimitry Andric     return llvm::errc::not_supported;
43e8d8bef9SDimitry Andric   }
44e8d8bef9SDimitry Andric 
4581ad6265SDimitry Andric   int GetLibiptErrorCode() const { return m_libipt_error_code; }
4681ad6265SDimitry Andric 
47e8d8bef9SDimitry Andric   void log(llvm::raw_ostream &OS) const override;
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric private:
50e8d8bef9SDimitry Andric   int m_libipt_error_code;
51e8d8bef9SDimitry Andric   lldb::addr_t m_address;
52e8d8bef9SDimitry Andric };
53e8d8bef9SDimitry Andric 
54e8d8bef9SDimitry Andric /// \class DecodedThread
55e8d8bef9SDimitry Andric /// Class holding the instructions and function call hierarchy obtained from
56e8d8bef9SDimitry Andric /// decoding a trace, as well as a position cursor used when reverse debugging
57e8d8bef9SDimitry Andric /// the trace.
58e8d8bef9SDimitry Andric ///
59e8d8bef9SDimitry Andric /// Each decoded thread contains a cursor to the current position the user is
60e8d8bef9SDimitry Andric /// stopped at. See \a Trace::GetCursorPosition for more information.
61fe6060f1SDimitry Andric class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
62e8d8bef9SDimitry Andric public:
63972a253aSDimitry Andric   using TSC = uint64_t;
6481ad6265SDimitry Andric 
65972a253aSDimitry Andric   /// A structure that represents a maximal range of trace items associated to
66972a253aSDimitry Andric   /// the same TSC value.
67972a253aSDimitry Andric   struct TSCRange {
68972a253aSDimitry Andric     TSC tsc;
69972a253aSDimitry Andric     /// Number of trace items in this range.
70972a253aSDimitry Andric     uint64_t items_count;
71972a253aSDimitry Andric     /// Index of the first trace item in this range.
72972a253aSDimitry Andric     uint64_t first_item_index;
73972a253aSDimitry Andric 
74972a253aSDimitry Andric     /// \return
75972a253aSDimitry Andric     ///   \b true if and only if the given \p item_index is covered by this
76972a253aSDimitry Andric     ///   range.
77972a253aSDimitry Andric     bool InRange(uint64_t item_index) const;
78972a253aSDimitry Andric   };
79972a253aSDimitry Andric 
80972a253aSDimitry Andric   /// A structure that represents a maximal range of trace items associated to
81972a253aSDimitry Andric   /// the same non-interpolated timestamps in nanoseconds.
82972a253aSDimitry Andric   struct NanosecondsRange {
83972a253aSDimitry Andric     /// The nanoseconds value for this range.
84972a253aSDimitry Andric     uint64_t nanos;
85972a253aSDimitry Andric     /// The corresponding TSC value for this range.
86972a253aSDimitry Andric     TSC tsc;
87972a253aSDimitry Andric     /// A nullable pointer to the next range.
88972a253aSDimitry Andric     NanosecondsRange *next_range;
89972a253aSDimitry Andric     /// Number of trace items in this range.
90972a253aSDimitry Andric     uint64_t items_count;
91972a253aSDimitry Andric     /// Index of the first trace item in this range.
92972a253aSDimitry Andric     uint64_t first_item_index;
93972a253aSDimitry Andric 
94972a253aSDimitry Andric     /// Calculate an interpolated timestamp in nanoseconds for the given item
95972a253aSDimitry Andric     /// index. It's guaranteed that two different item indices will produce
96972a253aSDimitry Andric     /// different interpolated values.
97972a253aSDimitry Andric     ///
98972a253aSDimitry Andric     /// \param[in] item_index
99972a253aSDimitry Andric     ///   The index of the item whose timestamp will be estimated. It has to be
100972a253aSDimitry Andric     ///   part of this range.
101972a253aSDimitry Andric     ///
102972a253aSDimitry Andric     /// \param[in] beginning_of_time_nanos
103972a253aSDimitry Andric     ///   The timestamp at which tracing started.
104972a253aSDimitry Andric     ///
105972a253aSDimitry Andric     /// \param[in] tsc_conversion
106972a253aSDimitry Andric     ///   The tsc -> nanos conversion utility
107972a253aSDimitry Andric     ///
108972a253aSDimitry Andric     /// \return
109972a253aSDimitry Andric     ///   An interpolated timestamp value for the given trace item.
110972a253aSDimitry Andric     double
111972a253aSDimitry Andric     GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
112972a253aSDimitry Andric                         const LinuxPerfZeroTscConversion &tsc_conversion) const;
113972a253aSDimitry Andric 
114972a253aSDimitry Andric     /// \return
115972a253aSDimitry Andric     ///   \b true if and only if the given \p item_index is covered by this
116972a253aSDimitry Andric     ///   range.
117972a253aSDimitry Andric     bool InRange(uint64_t item_index) const;
118972a253aSDimitry Andric   };
119972a253aSDimitry Andric 
120*bdd1243dSDimitry Andric   // Struct holding counts for events
12181ad6265SDimitry Andric   struct EventsStats {
12281ad6265SDimitry Andric     /// A count for each individual event kind. We use an unordered map instead
12381ad6265SDimitry Andric     /// of a DenseMap because DenseMap can't understand enums.
124*bdd1243dSDimitry Andric     ///
125*bdd1243dSDimitry Andric     /// Note: We can't use DenseMap because lldb::TraceEvent is not
126*bdd1243dSDimitry Andric     /// automatically handled correctly by DenseMap. We'd need to implement a
127*bdd1243dSDimitry Andric     /// custom DenseMapInfo struct for TraceEvent and that's a bit too much for
128*bdd1243dSDimitry Andric     /// such a simple structure.
129*bdd1243dSDimitry Andric     std::unordered_map<lldb::TraceEvent, uint64_t> events_counts;
130*bdd1243dSDimitry Andric     uint64_t total_count = 0;
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric     void RecordEvent(lldb::TraceEvent event);
13381ad6265SDimitry Andric   };
13481ad6265SDimitry Andric 
135*bdd1243dSDimitry Andric   // Struct holding counts for errors
136*bdd1243dSDimitry Andric   struct ErrorStats {
137*bdd1243dSDimitry Andric     /// The following counters are mutually exclusive
138*bdd1243dSDimitry Andric     /// \{
139*bdd1243dSDimitry Andric     uint64_t other_errors = 0;
140*bdd1243dSDimitry Andric     uint64_t fatal_errors = 0;
141*bdd1243dSDimitry Andric     // libipt error -> count
142*bdd1243dSDimitry Andric     llvm::DenseMap<const char *, uint64_t> libipt_errors;
143*bdd1243dSDimitry Andric     /// \}
144*bdd1243dSDimitry Andric 
145*bdd1243dSDimitry Andric     uint64_t GetTotalCount() const;
146*bdd1243dSDimitry Andric 
147*bdd1243dSDimitry Andric     void RecordError(int libipt_error_code);
148*bdd1243dSDimitry Andric 
149*bdd1243dSDimitry Andric     void RecordError(bool fatal);
150*bdd1243dSDimitry Andric   };
151*bdd1243dSDimitry Andric 
152972a253aSDimitry Andric   DecodedThread(
153972a253aSDimitry Andric       lldb::ThreadSP thread_sp,
154*bdd1243dSDimitry Andric       const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion);
15581ad6265SDimitry Andric 
15681ad6265SDimitry Andric   /// Get the total number of instruction, errors and events from the decoded
15781ad6265SDimitry Andric   /// trace.
158972a253aSDimitry Andric   uint64_t GetItemsCount() const;
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric   /// \return
16181ad6265SDimitry Andric   ///   The error associated with a given trace item.
162972a253aSDimitry Andric   const char *GetErrorByIndex(uint64_t item_index) const;
16381ad6265SDimitry Andric 
16481ad6265SDimitry Andric   /// \return
16581ad6265SDimitry Andric   ///   The trace item kind given an item index.
166972a253aSDimitry Andric   lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
16781ad6265SDimitry Andric 
16881ad6265SDimitry Andric   /// \return
16981ad6265SDimitry Andric   ///   The underlying event type for the given trace item index.
17081ad6265SDimitry Andric   lldb::TraceEvent GetEventByIndex(int item_index) const;
17181ad6265SDimitry Andric 
172753f127fSDimitry Andric   /// Get the most recent CPU id before or at the given trace item index.
173753f127fSDimitry Andric   ///
174753f127fSDimitry Andric   /// \param[in] item_index
175753f127fSDimitry Andric   ///   The trace item index to compare with.
176753f127fSDimitry Andric   ///
177753f127fSDimitry Andric   /// \return
178*bdd1243dSDimitry Andric   ///   The requested cpu id, or \a LLDB_INVALID_CPU_ID if not available.
179*bdd1243dSDimitry Andric   lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const;
180*bdd1243dSDimitry Andric 
181*bdd1243dSDimitry Andric   /// \return
182*bdd1243dSDimitry Andric   ///   The PSB offset associated with the given item index.
183*bdd1243dSDimitry Andric   lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const;
184753f127fSDimitry Andric 
185972a253aSDimitry Andric   /// Get a maximal range of trace items that include the given \p item_index
186972a253aSDimitry Andric   /// that have the same TSC value.
187972a253aSDimitry Andric   ///
188972a253aSDimitry Andric   /// \param[in] item_index
189972a253aSDimitry Andric   ///   The trace item index to compare with.
190972a253aSDimitry Andric   ///
191972a253aSDimitry Andric   /// \return
192*bdd1243dSDimitry Andric   ///   The requested TSC range, or \a std::nullopt if not available.
193*bdd1243dSDimitry Andric   std::optional<DecodedThread::TSCRange>
194972a253aSDimitry Andric   GetTSCRangeByIndex(uint64_t item_index) const;
195972a253aSDimitry Andric 
196972a253aSDimitry Andric   /// Get a maximal range of trace items that include the given \p item_index
197972a253aSDimitry Andric   /// that have the same nanoseconds timestamp without interpolation.
198972a253aSDimitry Andric   ///
199972a253aSDimitry Andric   /// \param[in] item_index
200972a253aSDimitry Andric   ///   The trace item index to compare with.
201972a253aSDimitry Andric   ///
202972a253aSDimitry Andric   /// \return
203*bdd1243dSDimitry Andric   ///   The requested nanoseconds range, or \a std::nullopt if not available.
204*bdd1243dSDimitry Andric   std::optional<DecodedThread::NanosecondsRange>
205972a253aSDimitry Andric   GetNanosecondsRangeByIndex(uint64_t item_index);
206972a253aSDimitry Andric 
20781ad6265SDimitry Andric   /// \return
20881ad6265SDimitry Andric   ///     The load address of the instruction at the given index.
209972a253aSDimitry Andric   lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
21081ad6265SDimitry Andric 
21181ad6265SDimitry Andric   /// \return
212*bdd1243dSDimitry Andric   ///     The number of instructions in this trace (not trace items).
213*bdd1243dSDimitry Andric   uint64_t GetTotalInstructionCount() const;
21481ad6265SDimitry Andric 
21581ad6265SDimitry Andric   /// Return an object with statistics of the trace events that happened.
21681ad6265SDimitry Andric   ///
21781ad6265SDimitry Andric   /// \return
21881ad6265SDimitry Andric   ///   The stats object of all the events.
21981ad6265SDimitry Andric   const EventsStats &GetEventsStats() const;
22081ad6265SDimitry Andric 
221*bdd1243dSDimitry Andric   /// Return an object with statistics of the trace errors that happened.
22281ad6265SDimitry Andric   ///
223*bdd1243dSDimitry Andric   /// \return
224*bdd1243dSDimitry Andric   ///   The stats object of all the events.
225*bdd1243dSDimitry Andric   const ErrorStats &GetErrorStats() const;
22681ad6265SDimitry Andric 
22781ad6265SDimitry Andric   /// The approximate size in bytes used by this instance,
22881ad6265SDimitry Andric   /// including all the already decoded instructions.
22981ad6265SDimitry Andric   size_t CalculateApproximateMemoryUsage() const;
23081ad6265SDimitry Andric 
23181ad6265SDimitry Andric   lldb::ThreadSP GetThread();
23281ad6265SDimitry Andric 
23381ad6265SDimitry Andric   /// Notify this object that a new tsc has been seen.
234753f127fSDimitry Andric   /// If this a new TSC, an event will be created.
235972a253aSDimitry Andric   void NotifyTsc(TSC tsc);
23681ad6265SDimitry Andric 
237753f127fSDimitry Andric   /// Notify this object that a CPU has been seen.
238753f127fSDimitry Andric   /// If this a new CPU, an event will be created.
239753f127fSDimitry Andric   void NotifyCPU(lldb::cpu_id_t cpu_id);
240753f127fSDimitry Andric 
241*bdd1243dSDimitry Andric   /// Notify this object that a new PSB has been seen.
242*bdd1243dSDimitry Andric   void NotifySyncPoint(lldb::addr_t psb_offset);
243*bdd1243dSDimitry Andric 
24481ad6265SDimitry Andric   /// Append a decoding error.
24581ad6265SDimitry Andric   void AppendError(const IntelPTError &error);
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric   /// Append a custom decoding.
248*bdd1243dSDimitry Andric   ///
249*bdd1243dSDimitry Andric   /// \param[in] error
250*bdd1243dSDimitry Andric   ///   The error message.
251*bdd1243dSDimitry Andric   ///
252*bdd1243dSDimitry Andric   /// \param[in] fatal
253*bdd1243dSDimitry Andric   ///   If \b true, then the whole decoded thread should be discarded because a
254*bdd1243dSDimitry Andric   ///   fatal anomaly has been found.
255*bdd1243dSDimitry Andric   void AppendCustomError(llvm::StringRef error, bool fatal = false);
25681ad6265SDimitry Andric 
25781ad6265SDimitry Andric   /// Append an event.
25881ad6265SDimitry Andric   void AppendEvent(lldb::TraceEvent);
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   /// Append an instruction.
26181ad6265SDimitry Andric   void AppendInstruction(const pt_insn &insn);
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric private:
26481ad6265SDimitry Andric   /// When adding new members to this class, make sure
26581ad6265SDimitry Andric   /// to update \a CalculateApproximateMemoryUsage() accordingly.
266fe6060f1SDimitry Andric   lldb::ThreadSP m_thread_sp;
26781ad6265SDimitry Andric 
26881ad6265SDimitry Andric   /// We use a union to optimize the memory usage for the different kinds of
26981ad6265SDimitry Andric   /// trace items.
27081ad6265SDimitry Andric   union TraceItemStorage {
27181ad6265SDimitry Andric     /// The load addresses of this item if it's an instruction.
27281ad6265SDimitry Andric     uint64_t load_address;
27381ad6265SDimitry Andric 
27481ad6265SDimitry Andric     /// The event kind of this item if it's an event
27581ad6265SDimitry Andric     lldb::TraceEvent event;
27681ad6265SDimitry Andric 
27781ad6265SDimitry Andric     /// The string message of this item if it's an error
27881ad6265SDimitry Andric     const char *error;
27981ad6265SDimitry Andric   };
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric   /// Create a new trace item.
28281ad6265SDimitry Andric   ///
28381ad6265SDimitry Andric   /// \return
28481ad6265SDimitry Andric   ///   The index of the new item.
28581ad6265SDimitry Andric   DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind);
28681ad6265SDimitry Andric 
28781ad6265SDimitry Andric   /// Most of the trace data is stored here.
28881ad6265SDimitry Andric   std::vector<TraceItemStorage> m_item_data;
28981ad6265SDimitry Andric   /// The TraceItemKind for each trace item encoded as uint8_t. We don't include
29081ad6265SDimitry Andric   /// it in TraceItemStorage to avoid padding.
29181ad6265SDimitry Andric   std::vector<uint8_t> m_item_kinds;
29281ad6265SDimitry Andric 
293972a253aSDimitry Andric   /// This map contains the TSCs of the decoded trace items. It maps
294972a253aSDimitry Andric   /// `item index -> TSC`, where `item index` is the first index
295972a253aSDimitry Andric   /// at which the mapped TSC first appears. We use this representation because
296972a253aSDimitry Andric   /// TSCs are sporadic and we can think of them as ranges.
297972a253aSDimitry Andric   std::map<uint64_t, TSCRange> m_tscs;
29881ad6265SDimitry Andric   /// This is the chronologically last TSC that has been added.
299*bdd1243dSDimitry Andric   std::optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
300*bdd1243dSDimitry Andric       std::nullopt;
301972a253aSDimitry Andric   /// This map contains the non-interpolated nanoseconds timestamps of the
302972a253aSDimitry Andric   /// decoded trace items. It maps `item index -> nanoseconds`, where `item
303972a253aSDimitry Andric   /// index` is the first index at which the mapped nanoseconds first appears.
304972a253aSDimitry Andric   /// We use this representation because timestamps are sporadic and we think of
305972a253aSDimitry Andric   /// them as ranges.
306972a253aSDimitry Andric   std::map<uint64_t, NanosecondsRange> m_nanoseconds;
307*bdd1243dSDimitry Andric   std::optional<std::map<uint64_t, NanosecondsRange>::iterator>
308*bdd1243dSDimitry Andric       m_last_nanoseconds = std::nullopt;
30981ad6265SDimitry Andric 
310*bdd1243dSDimitry Andric   // The cpu information is stored as a map. It maps `item index -> CPU`.
311753f127fSDimitry Andric   // A CPU is associated with the next instructions that follow until the next
312753f127fSDimitry Andric   // cpu is seen.
313753f127fSDimitry Andric   std::map<uint64_t, lldb::cpu_id_t> m_cpus;
314753f127fSDimitry Andric   /// This is the chronologically last CPU ID.
315*bdd1243dSDimitry Andric   std::optional<uint64_t> m_last_cpu;
316*bdd1243dSDimitry Andric 
317*bdd1243dSDimitry Andric   // The PSB offsets are stored as a map. It maps `item index -> psb offset`.
318*bdd1243dSDimitry Andric   llvm::DenseMap<uint64_t, lldb::addr_t> m_psb_offsets;
319753f127fSDimitry Andric 
320972a253aSDimitry Andric   /// TSC -> nanos conversion utility.
321*bdd1243dSDimitry Andric   std::optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
322*bdd1243dSDimitry Andric 
323*bdd1243dSDimitry Andric   /// Statistics of all tracing errors.
324*bdd1243dSDimitry Andric   ErrorStats m_error_stats;
325972a253aSDimitry Andric 
32681ad6265SDimitry Andric   /// Statistics of all tracing events.
32781ad6265SDimitry Andric   EventsStats m_events_stats;
32881ad6265SDimitry Andric   /// Total amount of time spent decoding.
32981ad6265SDimitry Andric   std::chrono::milliseconds m_total_decoding_time{0};
330*bdd1243dSDimitry Andric 
331*bdd1243dSDimitry Andric   /// Total number of instructions in the trace.
332*bdd1243dSDimitry Andric   uint64_t m_insn_count = 0;
333e8d8bef9SDimitry Andric };
334e8d8bef9SDimitry Andric 
335fe6060f1SDimitry Andric using DecodedThreadSP = std::shared_ptr<DecodedThread>;
336fe6060f1SDimitry Andric 
337e8d8bef9SDimitry Andric } // namespace trace_intel_pt
338e8d8bef9SDimitry Andric } // namespace lldb_private
339e8d8bef9SDimitry Andric 
340e8d8bef9SDimitry Andric #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
341