xref: /llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h (revision a50ea2f76f993f65c8756067f7ad5a21e560b0c9)
1cfd96f05SWalter Erquinigo //===-- DecodedThread.h -----------------------------------------*- C++ -*-===//
2cfd96f05SWalter Erquinigo //
3cfd96f05SWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cfd96f05SWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
5cfd96f05SWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cfd96f05SWalter Erquinigo //
7cfd96f05SWalter Erquinigo //===----------------------------------------------------------------------===//
8cfd96f05SWalter Erquinigo 
9cfd96f05SWalter Erquinigo #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
10cfd96f05SWalter Erquinigo #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
11cfd96f05SWalter Erquinigo 
12c4fb631cSWalter Erquinigo #include "intel-pt.h"
13cfd96f05SWalter Erquinigo #include "lldb/Target/Trace.h"
140b697561SWalter Erquinigo #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
15c4fb631cSWalter Erquinigo #include "llvm/Support/Errc.h"
16c4fb631cSWalter Erquinigo #include "llvm/Support/Error.h"
17*a50ea2f7SNicholas Mosier #include <deque>
18f190ce62SKazu Hirata #include <optional>
19c4fb631cSWalter Erquinigo #include <utility>
20*a50ea2f7SNicholas Mosier #include <variant>
21cfd96f05SWalter Erquinigo 
22cfd96f05SWalter Erquinigo namespace lldb_private {
23cfd96f05SWalter Erquinigo namespace trace_intel_pt {
24cfd96f05SWalter Erquinigo 
25cfd96f05SWalter Erquinigo /// Class for representing a libipt decoding error.
26cfd96f05SWalter Erquinigo class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
27cfd96f05SWalter Erquinigo public:
28cfd96f05SWalter Erquinigo   static char ID;
29cfd96f05SWalter Erquinigo 
30cfd96f05SWalter Erquinigo   /// \param[in] libipt_error_code
31cfd96f05SWalter Erquinigo   ///     Negative number returned by libipt when decoding the trace and
32cfd96f05SWalter Erquinigo   ///     signaling errors.
33cfd96f05SWalter Erquinigo   ///
34cfd96f05SWalter Erquinigo   /// \param[in] address
35cfd96f05SWalter Erquinigo   ///     Optional instruction address. When decoding an individual instruction,
36cfd96f05SWalter Erquinigo   ///     its address might be available in the \a pt_insn object, and should be
37cfd96f05SWalter Erquinigo   ///     passed to this constructor. Other errors don't have an associated
38cfd96f05SWalter Erquinigo   ///     address.
39cfd96f05SWalter Erquinigo   IntelPTError(int libipt_error_code,
40cfd96f05SWalter Erquinigo                lldb::addr_t address = LLDB_INVALID_ADDRESS);
41cfd96f05SWalter Erquinigo 
convertToErrorCode()42cfd96f05SWalter Erquinigo   std::error_code convertToErrorCode() const override {
43cfd96f05SWalter Erquinigo     return llvm::errc::not_supported;
44cfd96f05SWalter Erquinigo   }
45cfd96f05SWalter Erquinigo 
GetLibiptErrorCode()46a7d6c3efSWalter Erquinigo   int GetLibiptErrorCode() const { return m_libipt_error_code; }
47a7d6c3efSWalter Erquinigo 
48cfd96f05SWalter Erquinigo   void log(llvm::raw_ostream &OS) const override;
49cfd96f05SWalter Erquinigo 
50cfd96f05SWalter Erquinigo private:
51cfd96f05SWalter Erquinigo   int m_libipt_error_code;
52cfd96f05SWalter Erquinigo   lldb::addr_t m_address;
53cfd96f05SWalter Erquinigo };
54cfd96f05SWalter Erquinigo 
55cfd96f05SWalter Erquinigo /// \class DecodedThread
56cfd96f05SWalter Erquinigo /// Class holding the instructions and function call hierarchy obtained from
57cfd96f05SWalter Erquinigo /// decoding a trace, as well as a position cursor used when reverse debugging
58cfd96f05SWalter Erquinigo /// the trace.
59cfd96f05SWalter Erquinigo ///
60cfd96f05SWalter Erquinigo /// Each decoded thread contains a cursor to the current position the user is
61cfd96f05SWalter Erquinigo /// stopped at. See \a Trace::GetCursorPosition for more information.
62b0aa7076SWalter Erquinigo class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
63cfd96f05SWalter Erquinigo public:
644f676c25SWalter Erquinigo   using TSC = uint64_t;
65ca922a35SAlisamar Husain 
664f676c25SWalter Erquinigo   /// A structure that represents a maximal range of trace items associated to
674f676c25SWalter Erquinigo   /// the same TSC value.
684f676c25SWalter Erquinigo   struct TSCRange {
694f676c25SWalter Erquinigo     TSC tsc;
704f676c25SWalter Erquinigo     /// Number of trace items in this range.
714f676c25SWalter Erquinigo     uint64_t items_count;
724f676c25SWalter Erquinigo     /// Index of the first trace item in this range.
734f676c25SWalter Erquinigo     uint64_t first_item_index;
744f676c25SWalter Erquinigo 
754f676c25SWalter Erquinigo     /// \return
764f676c25SWalter Erquinigo     ///   \b true if and only if the given \p item_index is covered by this
774f676c25SWalter Erquinigo     ///   range.
784f676c25SWalter Erquinigo     bool InRange(uint64_t item_index) const;
794f676c25SWalter Erquinigo   };
804f676c25SWalter Erquinigo 
814f676c25SWalter Erquinigo   /// A structure that represents a maximal range of trace items associated to
824f676c25SWalter Erquinigo   /// the same non-interpolated timestamps in nanoseconds.
834f676c25SWalter Erquinigo   struct NanosecondsRange {
844f676c25SWalter Erquinigo     /// The nanoseconds value for this range.
854f676c25SWalter Erquinigo     uint64_t nanos;
864f676c25SWalter Erquinigo     /// The corresponding TSC value for this range.
874f676c25SWalter Erquinigo     TSC tsc;
884f676c25SWalter Erquinigo     /// A nullable pointer to the next range.
894f676c25SWalter Erquinigo     NanosecondsRange *next_range;
904f676c25SWalter Erquinigo     /// Number of trace items in this range.
914f676c25SWalter Erquinigo     uint64_t items_count;
924f676c25SWalter Erquinigo     /// Index of the first trace item in this range.
934f676c25SWalter Erquinigo     uint64_t first_item_index;
944f676c25SWalter Erquinigo 
954f676c25SWalter Erquinigo     /// Calculate an interpolated timestamp in nanoseconds for the given item
964f676c25SWalter Erquinigo     /// index. It's guaranteed that two different item indices will produce
974f676c25SWalter Erquinigo     /// different interpolated values.
984f676c25SWalter Erquinigo     ///
994f676c25SWalter Erquinigo     /// \param[in] item_index
1004f676c25SWalter Erquinigo     ///   The index of the item whose timestamp will be estimated. It has to be
1014f676c25SWalter Erquinigo     ///   part of this range.
1024f676c25SWalter Erquinigo     ///
1034f676c25SWalter Erquinigo     /// \param[in] beginning_of_time_nanos
1044f676c25SWalter Erquinigo     ///   The timestamp at which tracing started.
1054f676c25SWalter Erquinigo     ///
1064f676c25SWalter Erquinigo     /// \param[in] tsc_conversion
1074f676c25SWalter Erquinigo     ///   The tsc -> nanos conversion utility
1084f676c25SWalter Erquinigo     ///
1094f676c25SWalter Erquinigo     /// \return
1104f676c25SWalter Erquinigo     ///   An interpolated timestamp value for the given trace item.
1114f676c25SWalter Erquinigo     double
1124f676c25SWalter Erquinigo     GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos,
1134f676c25SWalter Erquinigo                         const LinuxPerfZeroTscConversion &tsc_conversion) const;
1144f676c25SWalter Erquinigo 
1154f676c25SWalter Erquinigo     /// \return
1164f676c25SWalter Erquinigo     ///   \b true if and only if the given \p item_index is covered by this
1174f676c25SWalter Erquinigo     ///   range.
1184f676c25SWalter Erquinigo     bool InRange(uint64_t item_index) const;
1194f676c25SWalter Erquinigo   };
1204f676c25SWalter Erquinigo 
121c49d14acSWalter Erquinigo   // Struct holding counts for events
122059f39d2SWalter Erquinigo   struct EventsStats {
123059f39d2SWalter Erquinigo     /// A count for each individual event kind. We use an unordered map instead
124059f39d2SWalter Erquinigo     /// of a DenseMap because DenseMap can't understand enums.
125c49d14acSWalter Erquinigo     ///
126c49d14acSWalter Erquinigo     /// Note: We can't use DenseMap because lldb::TraceEvent is not
127c49d14acSWalter Erquinigo     /// automatically handled correctly by DenseMap. We'd need to implement a
128c49d14acSWalter Erquinigo     /// custom DenseMapInfo struct for TraceEvent and that's a bit too much for
129c49d14acSWalter Erquinigo     /// such a simple structure.
130c49d14acSWalter Erquinigo     std::unordered_map<lldb::TraceEvent, uint64_t> events_counts;
131c49d14acSWalter Erquinigo     uint64_t total_count = 0;
132059f39d2SWalter Erquinigo 
133a7d6c3efSWalter Erquinigo     void RecordEvent(lldb::TraceEvent event);
134059f39d2SWalter Erquinigo   };
135059f39d2SWalter Erquinigo 
136c49d14acSWalter Erquinigo   // Struct holding counts for errors
137c49d14acSWalter Erquinigo   struct ErrorStats {
138c49d14acSWalter Erquinigo     /// The following counters are mutually exclusive
139c49d14acSWalter Erquinigo     /// \{
140c49d14acSWalter Erquinigo     uint64_t other_errors = 0;
141c49d14acSWalter Erquinigo     uint64_t fatal_errors = 0;
142c49d14acSWalter Erquinigo     // libipt error -> count
143c49d14acSWalter Erquinigo     llvm::DenseMap<const char *, uint64_t> libipt_errors;
144c49d14acSWalter Erquinigo     /// \}
145c49d14acSWalter Erquinigo 
146c49d14acSWalter Erquinigo     uint64_t GetTotalCount() const;
147c49d14acSWalter Erquinigo 
148c49d14acSWalter Erquinigo     void RecordError(int libipt_error_code);
149c49d14acSWalter Erquinigo 
150c49d14acSWalter Erquinigo     void RecordError(bool fatal);
151c49d14acSWalter Erquinigo   };
152c49d14acSWalter Erquinigo 
1534f676c25SWalter Erquinigo   DecodedThread(
1544f676c25SWalter Erquinigo       lldb::ThreadSP thread_sp,
1552fe83274SKazu Hirata       const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion);
1560b697561SWalter Erquinigo 
157a7d6c3efSWalter Erquinigo   /// Get the total number of instruction, errors and events from the decoded
158a7d6c3efSWalter Erquinigo   /// trace.
1594f676c25SWalter Erquinigo   uint64_t GetItemsCount() const;
160ca922a35SAlisamar Husain 
161bcf1978aSAlisamar Husain   /// \return
162a7d6c3efSWalter Erquinigo   ///   The error associated with a given trace item.
1634bae7066SAlex Langford   llvm::StringRef GetErrorByIndex(uint64_t item_index) const;
164a7d6c3efSWalter Erquinigo 
165a7d6c3efSWalter Erquinigo   /// \return
166a7d6c3efSWalter Erquinigo   ///   The trace item kind given an item index.
1674f676c25SWalter Erquinigo   lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const;
168a7d6c3efSWalter Erquinigo 
169a7d6c3efSWalter Erquinigo   /// \return
170a7d6c3efSWalter Erquinigo   ///   The underlying event type for the given trace item index.
171a7d6c3efSWalter Erquinigo   lldb::TraceEvent GetEventByIndex(int item_index) const;
172a7d6c3efSWalter Erquinigo 
1734a843d92SWalter Erquinigo   /// Get the most recent CPU id before or at the given trace item index.
1744a843d92SWalter Erquinigo   ///
1754a843d92SWalter Erquinigo   /// \param[in] item_index
1764a843d92SWalter Erquinigo   ///   The trace item index to compare with.
1774a843d92SWalter Erquinigo   ///
1784a843d92SWalter Erquinigo   /// \return
179f9b4ea0cSJakob Johnson   ///   The requested cpu id, or \a LLDB_INVALID_CPU_ID if not available.
180f9b4ea0cSJakob Johnson   lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const;
1814a843d92SWalter Erquinigo 
182e17cae07SWalter Erquinigo   /// \return
183e17cae07SWalter Erquinigo   ///   The PSB offset associated with the given item index.
184e17cae07SWalter Erquinigo   lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const;
185e17cae07SWalter Erquinigo 
1864f676c25SWalter Erquinigo   /// Get a maximal range of trace items that include the given \p item_index
1874f676c25SWalter Erquinigo   /// that have the same TSC value.
1884f676c25SWalter Erquinigo   ///
1894f676c25SWalter Erquinigo   /// \param[in] item_index
1904f676c25SWalter Erquinigo   ///   The trace item index to compare with.
1914f676c25SWalter Erquinigo   ///
1924f676c25SWalter Erquinigo   /// \return
193768cae4aSKazu Hirata   ///   The requested TSC range, or \a std::nullopt if not available.
1942fe83274SKazu Hirata   std::optional<DecodedThread::TSCRange>
1954f676c25SWalter Erquinigo   GetTSCRangeByIndex(uint64_t item_index) const;
1964f676c25SWalter Erquinigo 
1974f676c25SWalter Erquinigo   /// Get a maximal range of trace items that include the given \p item_index
1984f676c25SWalter Erquinigo   /// that have the same nanoseconds timestamp without interpolation.
1994f676c25SWalter Erquinigo   ///
2004f676c25SWalter Erquinigo   /// \param[in] item_index
2014f676c25SWalter Erquinigo   ///   The trace item index to compare with.
2024f676c25SWalter Erquinigo   ///
2034f676c25SWalter Erquinigo   /// \return
204768cae4aSKazu Hirata   ///   The requested nanoseconds range, or \a std::nullopt if not available.
2052fe83274SKazu Hirata   std::optional<DecodedThread::NanosecondsRange>
2064f676c25SWalter Erquinigo   GetNanosecondsRangeByIndex(uint64_t item_index);
2074f676c25SWalter Erquinigo 
208a7d6c3efSWalter Erquinigo   /// \return
209a7d6c3efSWalter Erquinigo   ///     The load address of the instruction at the given index.
2104f676c25SWalter Erquinigo   lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const;
211cfd96f05SWalter Erquinigo 
212c49d14acSWalter Erquinigo   /// \return
213c49d14acSWalter Erquinigo   ///     The number of instructions in this trace (not trace items).
214c49d14acSWalter Erquinigo   uint64_t GetTotalInstructionCount() const;
215c49d14acSWalter Erquinigo 
216059f39d2SWalter Erquinigo   /// Return an object with statistics of the trace events that happened.
217059f39d2SWalter Erquinigo   ///
218059f39d2SWalter Erquinigo   /// \return
219059f39d2SWalter Erquinigo   ///   The stats object of all the events.
220059f39d2SWalter Erquinigo   const EventsStats &GetEventsStats() const;
2211e5083a5SWalter Erquinigo 
222c49d14acSWalter Erquinigo   /// Return an object with statistics of the trace errors that happened.
223c49d14acSWalter Erquinigo   ///
224c49d14acSWalter Erquinigo   /// \return
225c49d14acSWalter Erquinigo   ///   The stats object of all the events.
226c49d14acSWalter Erquinigo   const ErrorStats &GetErrorStats() const;
227c49d14acSWalter Erquinigo 
22837a466ddSAlisamar Husain   /// The approximate size in bytes used by this instance,
22937a466ddSAlisamar Husain   /// including all the already decoded instructions.
23037a466ddSAlisamar Husain   size_t CalculateApproximateMemoryUsage() const;
23137a466ddSAlisamar Husain 
232bcf1978aSAlisamar Husain   lldb::ThreadSP GetThread();
233bcf1978aSAlisamar Husain 
234a7d6c3efSWalter Erquinigo   /// Notify this object that a new tsc has been seen.
2354a843d92SWalter Erquinigo   /// If this a new TSC, an event will be created.
2364f676c25SWalter Erquinigo   void NotifyTsc(TSC tsc);
237a7d6c3efSWalter Erquinigo 
2384a843d92SWalter Erquinigo   /// Notify this object that a CPU has been seen.
2394a843d92SWalter Erquinigo   /// If this a new CPU, an event will be created.
2404a843d92SWalter Erquinigo   void NotifyCPU(lldb::cpu_id_t cpu_id);
2414a843d92SWalter Erquinigo 
242e17cae07SWalter Erquinigo   /// Notify this object that a new PSB has been seen.
243e17cae07SWalter Erquinigo   void NotifySyncPoint(lldb::addr_t psb_offset);
244e17cae07SWalter Erquinigo 
245a7d6c3efSWalter Erquinigo   /// Append a decoding error.
246a7d6c3efSWalter Erquinigo   void AppendError(const IntelPTError &error);
247a7d6c3efSWalter Erquinigo 
248a7d6c3efSWalter Erquinigo   /// Append a custom decoding.
249c49d14acSWalter Erquinigo   ///
250c49d14acSWalter Erquinigo   /// \param[in] error
251c49d14acSWalter Erquinigo   ///   The error message.
252c49d14acSWalter Erquinigo   ///
253c49d14acSWalter Erquinigo   /// \param[in] fatal
254c49d14acSWalter Erquinigo   ///   If \b true, then the whole decoded thread should be discarded because a
255c49d14acSWalter Erquinigo   ///   fatal anomaly has been found.
256c49d14acSWalter Erquinigo   void AppendCustomError(llvm::StringRef error, bool fatal = false);
257a7d6c3efSWalter Erquinigo 
258a7d6c3efSWalter Erquinigo   /// Append an event.
259a7d6c3efSWalter Erquinigo   void AppendEvent(lldb::TraceEvent);
260a7d6c3efSWalter Erquinigo 
261a7d6c3efSWalter Erquinigo   /// Append an instruction.
262a7d6c3efSWalter Erquinigo   void AppendInstruction(const pt_insn &insn);
263059f39d2SWalter Erquinigo 
264a19fcc2bSWalter Erquinigo private:
26537a466ddSAlisamar Husain   /// When adding new members to this class, make sure
26637a466ddSAlisamar Husain   /// to update \a CalculateApproximateMemoryUsage() accordingly.
267b0aa7076SWalter Erquinigo   lldb::ThreadSP m_thread_sp;
268a7d6c3efSWalter Erquinigo 
269*a50ea2f7SNicholas Mosier   using TraceItemStorage =
270*a50ea2f7SNicholas Mosier       std::variant<std::string, lldb::TraceEvent, lldb::addr_t>;
271a7d6c3efSWalter Erquinigo 
272a7d6c3efSWalter Erquinigo   /// Create a new trace item.
273a7d6c3efSWalter Erquinigo   ///
274a7d6c3efSWalter Erquinigo   /// \return
275a7d6c3efSWalter Erquinigo   ///   The index of the new item.
276*a50ea2f7SNicholas Mosier   template <typename Data>
277*a50ea2f7SNicholas Mosier   DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind,
278*a50ea2f7SNicholas Mosier                                                       Data &&data);
279a7d6c3efSWalter Erquinigo 
280a7d6c3efSWalter Erquinigo   /// Most of the trace data is stored here.
281*a50ea2f7SNicholas Mosier   std::deque<TraceItemStorage> m_item_data;
282d8499590SAlisamar Husain 
2834f676c25SWalter Erquinigo   /// This map contains the TSCs of the decoded trace items. It maps
2844f676c25SWalter Erquinigo   /// `item index -> TSC`, where `item index` is the first index
2854f676c25SWalter Erquinigo   /// at which the mapped TSC first appears. We use this representation because
2864f676c25SWalter Erquinigo   /// TSCs are sporadic and we can think of them as ranges.
2874f676c25SWalter Erquinigo   std::map<uint64_t, TSCRange> m_tscs;
288ca922a35SAlisamar Husain   /// This is the chronologically last TSC that has been added.
2892fe83274SKazu Hirata   std::optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc =
290529ca5adSKazu Hirata       std::nullopt;
2914f676c25SWalter Erquinigo   /// This map contains the non-interpolated nanoseconds timestamps of the
2924f676c25SWalter Erquinigo   /// decoded trace items. It maps `item index -> nanoseconds`, where `item
2934f676c25SWalter Erquinigo   /// index` is the first index at which the mapped nanoseconds first appears.
2944f676c25SWalter Erquinigo   /// We use this representation because timestamps are sporadic and we think of
2954f676c25SWalter Erquinigo   /// them as ranges.
2964f676c25SWalter Erquinigo   std::map<uint64_t, NanosecondsRange> m_nanoseconds;
2972fe83274SKazu Hirata   std::optional<std::map<uint64_t, NanosecondsRange>::iterator>
298529ca5adSKazu Hirata       m_last_nanoseconds = std::nullopt;
299059f39d2SWalter Erquinigo 
300e17cae07SWalter Erquinigo   // The cpu information is stored as a map. It maps `item index -> CPU`.
3014a843d92SWalter Erquinigo   // A CPU is associated with the next instructions that follow until the next
3024a843d92SWalter Erquinigo   // cpu is seen.
3034a843d92SWalter Erquinigo   std::map<uint64_t, lldb::cpu_id_t> m_cpus;
3044a843d92SWalter Erquinigo   /// This is the chronologically last CPU ID.
30591682b26SKazu Hirata   std::optional<uint64_t> m_last_cpu;
3064a843d92SWalter Erquinigo 
307e17cae07SWalter Erquinigo   // The PSB offsets are stored as a map. It maps `item index -> psb offset`.
308e17cae07SWalter Erquinigo   llvm::DenseMap<uint64_t, lldb::addr_t> m_psb_offsets;
309e17cae07SWalter Erquinigo 
3104f676c25SWalter Erquinigo   /// TSC -> nanos conversion utility.
3112fe83274SKazu Hirata   std::optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
3124f676c25SWalter Erquinigo 
313c49d14acSWalter Erquinigo   /// Statistics of all tracing errors.
314c49d14acSWalter Erquinigo   ErrorStats m_error_stats;
315c49d14acSWalter Erquinigo 
316059f39d2SWalter Erquinigo   /// Statistics of all tracing events.
317059f39d2SWalter Erquinigo   EventsStats m_events_stats;
318bdf3e7e5SWalter Erquinigo   /// Total amount of time spent decoding.
319bdf3e7e5SWalter Erquinigo   std::chrono::milliseconds m_total_decoding_time{0};
320c49d14acSWalter Erquinigo 
321c49d14acSWalter Erquinigo   /// Total number of instructions in the trace.
322c49d14acSWalter Erquinigo   uint64_t m_insn_count = 0;
323cfd96f05SWalter Erquinigo };
324cfd96f05SWalter Erquinigo 
325b0aa7076SWalter Erquinigo using DecodedThreadSP = std::shared_ptr<DecodedThread>;
326b0aa7076SWalter Erquinigo 
327cfd96f05SWalter Erquinigo } // namespace trace_intel_pt
328cfd96f05SWalter Erquinigo } // namespace lldb_private
329cfd96f05SWalter Erquinigo 
330cfd96f05SWalter Erquinigo #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H
331