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 12bdd1243dSDimitry Andric #include "intel-pt.h" 13bdd1243dSDimitry Andric #include "lldb/Target/Trace.h" 14bdd1243dSDimitry Andric #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 15bdd1243dSDimitry Andric #include "llvm/Support/Errc.h" 16bdd1243dSDimitry Andric #include "llvm/Support/Error.h" 17*297eecfbSDimitry Andric #include <deque> 18bdd1243dSDimitry Andric #include <optional> 1981ad6265SDimitry Andric #include <utility> 20*297eecfbSDimitry Andric #include <variant> 21e8d8bef9SDimitry Andric 22e8d8bef9SDimitry Andric namespace lldb_private { 23e8d8bef9SDimitry Andric namespace trace_intel_pt { 24e8d8bef9SDimitry Andric 25e8d8bef9SDimitry Andric /// Class for representing a libipt decoding error. 26e8d8bef9SDimitry Andric class IntelPTError : public llvm::ErrorInfo<IntelPTError> { 27e8d8bef9SDimitry Andric public: 28e8d8bef9SDimitry Andric static char ID; 29e8d8bef9SDimitry Andric 30e8d8bef9SDimitry Andric /// \param[in] libipt_error_code 31e8d8bef9SDimitry Andric /// Negative number returned by libipt when decoding the trace and 32e8d8bef9SDimitry Andric /// signaling errors. 33e8d8bef9SDimitry Andric /// 34e8d8bef9SDimitry Andric /// \param[in] address 35e8d8bef9SDimitry Andric /// Optional instruction address. When decoding an individual instruction, 36e8d8bef9SDimitry Andric /// its address might be available in the \a pt_insn object, and should be 37e8d8bef9SDimitry Andric /// passed to this constructor. Other errors don't have an associated 38e8d8bef9SDimitry Andric /// address. 39e8d8bef9SDimitry Andric IntelPTError(int libipt_error_code, 40e8d8bef9SDimitry Andric lldb::addr_t address = LLDB_INVALID_ADDRESS); 41e8d8bef9SDimitry Andric convertToErrorCode()42e8d8bef9SDimitry Andric std::error_code convertToErrorCode() const override { 43e8d8bef9SDimitry Andric return llvm::errc::not_supported; 44e8d8bef9SDimitry Andric } 45e8d8bef9SDimitry Andric GetLibiptErrorCode()4681ad6265SDimitry Andric int GetLibiptErrorCode() const { return m_libipt_error_code; } 4781ad6265SDimitry Andric 48e8d8bef9SDimitry Andric void log(llvm::raw_ostream &OS) const override; 49e8d8bef9SDimitry Andric 50e8d8bef9SDimitry Andric private: 51e8d8bef9SDimitry Andric int m_libipt_error_code; 52e8d8bef9SDimitry Andric lldb::addr_t m_address; 53e8d8bef9SDimitry Andric }; 54e8d8bef9SDimitry Andric 55e8d8bef9SDimitry Andric /// \class DecodedThread 56e8d8bef9SDimitry Andric /// Class holding the instructions and function call hierarchy obtained from 57e8d8bef9SDimitry Andric /// decoding a trace, as well as a position cursor used when reverse debugging 58e8d8bef9SDimitry Andric /// the trace. 59e8d8bef9SDimitry Andric /// 60e8d8bef9SDimitry Andric /// Each decoded thread contains a cursor to the current position the user is 61e8d8bef9SDimitry Andric /// stopped at. See \a Trace::GetCursorPosition for more information. 62fe6060f1SDimitry Andric class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 63e8d8bef9SDimitry Andric public: 64972a253aSDimitry Andric using TSC = uint64_t; 6581ad6265SDimitry Andric 66972a253aSDimitry Andric /// A structure that represents a maximal range of trace items associated to 67972a253aSDimitry Andric /// the same TSC value. 68972a253aSDimitry Andric struct TSCRange { 69972a253aSDimitry Andric TSC tsc; 70972a253aSDimitry Andric /// Number of trace items in this range. 71972a253aSDimitry Andric uint64_t items_count; 72972a253aSDimitry Andric /// Index of the first trace item in this range. 73972a253aSDimitry Andric uint64_t first_item_index; 74972a253aSDimitry Andric 75972a253aSDimitry Andric /// \return 76972a253aSDimitry Andric /// \b true if and only if the given \p item_index is covered by this 77972a253aSDimitry Andric /// range. 78972a253aSDimitry Andric bool InRange(uint64_t item_index) const; 79972a253aSDimitry Andric }; 80972a253aSDimitry Andric 81972a253aSDimitry Andric /// A structure that represents a maximal range of trace items associated to 82972a253aSDimitry Andric /// the same non-interpolated timestamps in nanoseconds. 83972a253aSDimitry Andric struct NanosecondsRange { 84972a253aSDimitry Andric /// The nanoseconds value for this range. 85972a253aSDimitry Andric uint64_t nanos; 86972a253aSDimitry Andric /// The corresponding TSC value for this range. 87972a253aSDimitry Andric TSC tsc; 88972a253aSDimitry Andric /// A nullable pointer to the next range. 89972a253aSDimitry Andric NanosecondsRange *next_range; 90972a253aSDimitry Andric /// Number of trace items in this range. 91972a253aSDimitry Andric uint64_t items_count; 92972a253aSDimitry Andric /// Index of the first trace item in this range. 93972a253aSDimitry Andric uint64_t first_item_index; 94972a253aSDimitry Andric 95972a253aSDimitry Andric /// Calculate an interpolated timestamp in nanoseconds for the given item 96972a253aSDimitry Andric /// index. It's guaranteed that two different item indices will produce 97972a253aSDimitry Andric /// different interpolated values. 98972a253aSDimitry Andric /// 99972a253aSDimitry Andric /// \param[in] item_index 100972a253aSDimitry Andric /// The index of the item whose timestamp will be estimated. It has to be 101972a253aSDimitry Andric /// part of this range. 102972a253aSDimitry Andric /// 103972a253aSDimitry Andric /// \param[in] beginning_of_time_nanos 104972a253aSDimitry Andric /// The timestamp at which tracing started. 105972a253aSDimitry Andric /// 106972a253aSDimitry Andric /// \param[in] tsc_conversion 107972a253aSDimitry Andric /// The tsc -> nanos conversion utility 108972a253aSDimitry Andric /// 109972a253aSDimitry Andric /// \return 110972a253aSDimitry Andric /// An interpolated timestamp value for the given trace item. 111972a253aSDimitry Andric double 112972a253aSDimitry Andric GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos, 113972a253aSDimitry Andric const LinuxPerfZeroTscConversion &tsc_conversion) const; 114972a253aSDimitry Andric 115972a253aSDimitry Andric /// \return 116972a253aSDimitry Andric /// \b true if and only if the given \p item_index is covered by this 117972a253aSDimitry Andric /// range. 118972a253aSDimitry Andric bool InRange(uint64_t item_index) const; 119972a253aSDimitry Andric }; 120972a253aSDimitry Andric 121bdd1243dSDimitry Andric // Struct holding counts for events 12281ad6265SDimitry Andric struct EventsStats { 12381ad6265SDimitry Andric /// A count for each individual event kind. We use an unordered map instead 12481ad6265SDimitry Andric /// of a DenseMap because DenseMap can't understand enums. 125bdd1243dSDimitry Andric /// 126bdd1243dSDimitry Andric /// Note: We can't use DenseMap because lldb::TraceEvent is not 127bdd1243dSDimitry Andric /// automatically handled correctly by DenseMap. We'd need to implement a 128bdd1243dSDimitry Andric /// custom DenseMapInfo struct for TraceEvent and that's a bit too much for 129bdd1243dSDimitry Andric /// such a simple structure. 130bdd1243dSDimitry Andric std::unordered_map<lldb::TraceEvent, uint64_t> events_counts; 131bdd1243dSDimitry Andric uint64_t total_count = 0; 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric void RecordEvent(lldb::TraceEvent event); 13481ad6265SDimitry Andric }; 13581ad6265SDimitry Andric 136bdd1243dSDimitry Andric // Struct holding counts for errors 137bdd1243dSDimitry Andric struct ErrorStats { 138bdd1243dSDimitry Andric /// The following counters are mutually exclusive 139bdd1243dSDimitry Andric /// \{ 140bdd1243dSDimitry Andric uint64_t other_errors = 0; 141bdd1243dSDimitry Andric uint64_t fatal_errors = 0; 142bdd1243dSDimitry Andric // libipt error -> count 143bdd1243dSDimitry Andric llvm::DenseMap<const char *, uint64_t> libipt_errors; 144bdd1243dSDimitry Andric /// \} 145bdd1243dSDimitry Andric 146bdd1243dSDimitry Andric uint64_t GetTotalCount() const; 147bdd1243dSDimitry Andric 148bdd1243dSDimitry Andric void RecordError(int libipt_error_code); 149bdd1243dSDimitry Andric 150bdd1243dSDimitry Andric void RecordError(bool fatal); 151bdd1243dSDimitry Andric }; 152bdd1243dSDimitry Andric 153972a253aSDimitry Andric DecodedThread( 154972a253aSDimitry Andric lldb::ThreadSP thread_sp, 155bdd1243dSDimitry Andric const std::optional<LinuxPerfZeroTscConversion> &tsc_conversion); 15681ad6265SDimitry Andric 15781ad6265SDimitry Andric /// Get the total number of instruction, errors and events from the decoded 15881ad6265SDimitry Andric /// trace. 159972a253aSDimitry Andric uint64_t GetItemsCount() const; 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric /// \return 16281ad6265SDimitry Andric /// The error associated with a given trace item. 16306c3fb27SDimitry Andric llvm::StringRef GetErrorByIndex(uint64_t item_index) const; 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric /// \return 16681ad6265SDimitry Andric /// The trace item kind given an item index. 167972a253aSDimitry Andric lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const; 16881ad6265SDimitry Andric 16981ad6265SDimitry Andric /// \return 17081ad6265SDimitry Andric /// The underlying event type for the given trace item index. 17181ad6265SDimitry Andric lldb::TraceEvent GetEventByIndex(int item_index) const; 17281ad6265SDimitry Andric 173753f127fSDimitry Andric /// Get the most recent CPU id before or at the given trace item index. 174753f127fSDimitry Andric /// 175753f127fSDimitry Andric /// \param[in] item_index 176753f127fSDimitry Andric /// The trace item index to compare with. 177753f127fSDimitry Andric /// 178753f127fSDimitry Andric /// \return 179bdd1243dSDimitry Andric /// The requested cpu id, or \a LLDB_INVALID_CPU_ID if not available. 180bdd1243dSDimitry Andric lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const; 181bdd1243dSDimitry Andric 182bdd1243dSDimitry Andric /// \return 183bdd1243dSDimitry Andric /// The PSB offset associated with the given item index. 184bdd1243dSDimitry Andric lldb::addr_t GetSyncPointOffsetByIndex(uint64_t item_index) const; 185753f127fSDimitry Andric 186972a253aSDimitry Andric /// Get a maximal range of trace items that include the given \p item_index 187972a253aSDimitry Andric /// that have the same TSC value. 188972a253aSDimitry Andric /// 189972a253aSDimitry Andric /// \param[in] item_index 190972a253aSDimitry Andric /// The trace item index to compare with. 191972a253aSDimitry Andric /// 192972a253aSDimitry Andric /// \return 193bdd1243dSDimitry Andric /// The requested TSC range, or \a std::nullopt if not available. 194bdd1243dSDimitry Andric std::optional<DecodedThread::TSCRange> 195972a253aSDimitry Andric GetTSCRangeByIndex(uint64_t item_index) const; 196972a253aSDimitry Andric 197972a253aSDimitry Andric /// Get a maximal range of trace items that include the given \p item_index 198972a253aSDimitry Andric /// that have the same nanoseconds timestamp without interpolation. 199972a253aSDimitry Andric /// 200972a253aSDimitry Andric /// \param[in] item_index 201972a253aSDimitry Andric /// The trace item index to compare with. 202972a253aSDimitry Andric /// 203972a253aSDimitry Andric /// \return 204bdd1243dSDimitry Andric /// The requested nanoseconds range, or \a std::nullopt if not available. 205bdd1243dSDimitry Andric std::optional<DecodedThread::NanosecondsRange> 206972a253aSDimitry Andric GetNanosecondsRangeByIndex(uint64_t item_index); 207972a253aSDimitry Andric 20881ad6265SDimitry Andric /// \return 20981ad6265SDimitry Andric /// The load address of the instruction at the given index. 210972a253aSDimitry Andric lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const; 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric /// \return 213bdd1243dSDimitry Andric /// The number of instructions in this trace (not trace items). 214bdd1243dSDimitry Andric uint64_t GetTotalInstructionCount() const; 21581ad6265SDimitry Andric 21681ad6265SDimitry Andric /// Return an object with statistics of the trace events that happened. 21781ad6265SDimitry Andric /// 21881ad6265SDimitry Andric /// \return 21981ad6265SDimitry Andric /// The stats object of all the events. 22081ad6265SDimitry Andric const EventsStats &GetEventsStats() const; 22181ad6265SDimitry Andric 222bdd1243dSDimitry Andric /// Return an object with statistics of the trace errors that happened. 22381ad6265SDimitry Andric /// 224bdd1243dSDimitry Andric /// \return 225bdd1243dSDimitry Andric /// The stats object of all the events. 226bdd1243dSDimitry Andric const ErrorStats &GetErrorStats() const; 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric /// The approximate size in bytes used by this instance, 22981ad6265SDimitry Andric /// including all the already decoded instructions. 23081ad6265SDimitry Andric size_t CalculateApproximateMemoryUsage() const; 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric lldb::ThreadSP GetThread(); 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric /// Notify this object that a new tsc has been seen. 235753f127fSDimitry Andric /// If this a new TSC, an event will be created. 236972a253aSDimitry Andric void NotifyTsc(TSC tsc); 23781ad6265SDimitry Andric 238753f127fSDimitry Andric /// Notify this object that a CPU has been seen. 239753f127fSDimitry Andric /// If this a new CPU, an event will be created. 240753f127fSDimitry Andric void NotifyCPU(lldb::cpu_id_t cpu_id); 241753f127fSDimitry Andric 242bdd1243dSDimitry Andric /// Notify this object that a new PSB has been seen. 243bdd1243dSDimitry Andric void NotifySyncPoint(lldb::addr_t psb_offset); 244bdd1243dSDimitry Andric 24581ad6265SDimitry Andric /// Append a decoding error. 24681ad6265SDimitry Andric void AppendError(const IntelPTError &error); 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric /// Append a custom decoding. 249bdd1243dSDimitry Andric /// 250bdd1243dSDimitry Andric /// \param[in] error 251bdd1243dSDimitry Andric /// The error message. 252bdd1243dSDimitry Andric /// 253bdd1243dSDimitry Andric /// \param[in] fatal 254bdd1243dSDimitry Andric /// If \b true, then the whole decoded thread should be discarded because a 255bdd1243dSDimitry Andric /// fatal anomaly has been found. 256bdd1243dSDimitry Andric void AppendCustomError(llvm::StringRef error, bool fatal = false); 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric /// Append an event. 25981ad6265SDimitry Andric void AppendEvent(lldb::TraceEvent); 26081ad6265SDimitry Andric 26181ad6265SDimitry Andric /// Append an instruction. 26281ad6265SDimitry Andric void AppendInstruction(const pt_insn &insn); 26381ad6265SDimitry Andric 26481ad6265SDimitry Andric private: 26581ad6265SDimitry Andric /// When adding new members to this class, make sure 26681ad6265SDimitry Andric /// to update \a CalculateApproximateMemoryUsage() accordingly. 267fe6060f1SDimitry Andric lldb::ThreadSP m_thread_sp; 26881ad6265SDimitry Andric 269*297eecfbSDimitry Andric using TraceItemStorage = 270*297eecfbSDimitry Andric std::variant<std::string, lldb::TraceEvent, lldb::addr_t>; 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric /// Create a new trace item. 27381ad6265SDimitry Andric /// 27481ad6265SDimitry Andric /// \return 27581ad6265SDimitry Andric /// The index of the new item. 276*297eecfbSDimitry Andric template <typename Data> 277*297eecfbSDimitry Andric DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind, 278*297eecfbSDimitry Andric Data &&data); 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric /// Most of the trace data is stored here. 281*297eecfbSDimitry Andric std::deque<TraceItemStorage> m_item_data; 28281ad6265SDimitry Andric 283972a253aSDimitry Andric /// This map contains the TSCs of the decoded trace items. It maps 284972a253aSDimitry Andric /// `item index -> TSC`, where `item index` is the first index 285972a253aSDimitry Andric /// at which the mapped TSC first appears. We use this representation because 286972a253aSDimitry Andric /// TSCs are sporadic and we can think of them as ranges. 287972a253aSDimitry Andric std::map<uint64_t, TSCRange> m_tscs; 28881ad6265SDimitry Andric /// This is the chronologically last TSC that has been added. 289bdd1243dSDimitry Andric std::optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc = 290bdd1243dSDimitry Andric std::nullopt; 291972a253aSDimitry Andric /// This map contains the non-interpolated nanoseconds timestamps of the 292972a253aSDimitry Andric /// decoded trace items. It maps `item index -> nanoseconds`, where `item 293972a253aSDimitry Andric /// index` is the first index at which the mapped nanoseconds first appears. 294972a253aSDimitry Andric /// We use this representation because timestamps are sporadic and we think of 295972a253aSDimitry Andric /// them as ranges. 296972a253aSDimitry Andric std::map<uint64_t, NanosecondsRange> m_nanoseconds; 297bdd1243dSDimitry Andric std::optional<std::map<uint64_t, NanosecondsRange>::iterator> 298bdd1243dSDimitry Andric m_last_nanoseconds = std::nullopt; 29981ad6265SDimitry Andric 300bdd1243dSDimitry Andric // The cpu information is stored as a map. It maps `item index -> CPU`. 301753f127fSDimitry Andric // A CPU is associated with the next instructions that follow until the next 302753f127fSDimitry Andric // cpu is seen. 303753f127fSDimitry Andric std::map<uint64_t, lldb::cpu_id_t> m_cpus; 304753f127fSDimitry Andric /// This is the chronologically last CPU ID. 305bdd1243dSDimitry Andric std::optional<uint64_t> m_last_cpu; 306bdd1243dSDimitry Andric 307bdd1243dSDimitry Andric // The PSB offsets are stored as a map. It maps `item index -> psb offset`. 308bdd1243dSDimitry Andric llvm::DenseMap<uint64_t, lldb::addr_t> m_psb_offsets; 309753f127fSDimitry Andric 310972a253aSDimitry Andric /// TSC -> nanos conversion utility. 311bdd1243dSDimitry Andric std::optional<LinuxPerfZeroTscConversion> m_tsc_conversion; 312bdd1243dSDimitry Andric 313bdd1243dSDimitry Andric /// Statistics of all tracing errors. 314bdd1243dSDimitry Andric ErrorStats m_error_stats; 315972a253aSDimitry Andric 31681ad6265SDimitry Andric /// Statistics of all tracing events. 31781ad6265SDimitry Andric EventsStats m_events_stats; 31881ad6265SDimitry Andric /// Total amount of time spent decoding. 31981ad6265SDimitry Andric std::chrono::milliseconds m_total_decoding_time{0}; 320bdd1243dSDimitry Andric 321bdd1243dSDimitry Andric /// Total number of instructions in the trace. 322bdd1243dSDimitry Andric uint64_t m_insn_count = 0; 323e8d8bef9SDimitry Andric }; 324e8d8bef9SDimitry Andric 325fe6060f1SDimitry Andric using DecodedThreadSP = std::shared_ptr<DecodedThread>; 326fe6060f1SDimitry Andric 327e8d8bef9SDimitry Andric } // namespace trace_intel_pt 328e8d8bef9SDimitry Andric } // namespace lldb_private 329e8d8bef9SDimitry Andric 330e8d8bef9SDimitry Andric #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 331