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