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 1281ad6265SDimitry Andric #include <utility> 13e8d8bef9SDimitry Andric #include <vector> 14e8d8bef9SDimitry Andric 15e8d8bef9SDimitry Andric #include "llvm/Support/Errc.h" 16e8d8bef9SDimitry Andric #include "llvm/Support/Error.h" 17e8d8bef9SDimitry Andric 18e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h" 19fe6060f1SDimitry Andric #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 20e8d8bef9SDimitry Andric 21e8d8bef9SDimitry Andric #include "intel-pt.h" 22e8d8bef9SDimitry Andric 23e8d8bef9SDimitry Andric namespace lldb_private { 24e8d8bef9SDimitry Andric namespace trace_intel_pt { 25e8d8bef9SDimitry Andric 2681ad6265SDimitry Andric /// libipt status utils 2781ad6265SDimitry Andric /// \{ 2881ad6265SDimitry Andric bool IsLibiptError(int libipt_status); 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric bool IsEndOfStream(int libipt_status); 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric bool IsTscUnavailable(int libipt_status); 3381ad6265SDimitry Andric /// \} 3481ad6265SDimitry Andric 35e8d8bef9SDimitry Andric /// Class for representing a libipt decoding error. 36e8d8bef9SDimitry Andric class IntelPTError : public llvm::ErrorInfo<IntelPTError> { 37e8d8bef9SDimitry Andric public: 38e8d8bef9SDimitry Andric static char ID; 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric /// \param[in] libipt_error_code 41e8d8bef9SDimitry Andric /// Negative number returned by libipt when decoding the trace and 42e8d8bef9SDimitry Andric /// signaling errors. 43e8d8bef9SDimitry Andric /// 44e8d8bef9SDimitry Andric /// \param[in] address 45e8d8bef9SDimitry Andric /// Optional instruction address. When decoding an individual instruction, 46e8d8bef9SDimitry Andric /// its address might be available in the \a pt_insn object, and should be 47e8d8bef9SDimitry Andric /// passed to this constructor. Other errors don't have an associated 48e8d8bef9SDimitry Andric /// address. 49e8d8bef9SDimitry Andric IntelPTError(int libipt_error_code, 50e8d8bef9SDimitry Andric lldb::addr_t address = LLDB_INVALID_ADDRESS); 51e8d8bef9SDimitry Andric 52e8d8bef9SDimitry Andric std::error_code convertToErrorCode() const override { 53e8d8bef9SDimitry Andric return llvm::errc::not_supported; 54e8d8bef9SDimitry Andric } 55e8d8bef9SDimitry Andric 5681ad6265SDimitry Andric int GetLibiptErrorCode() const { return m_libipt_error_code; } 5781ad6265SDimitry Andric 58e8d8bef9SDimitry Andric void log(llvm::raw_ostream &OS) const override; 59e8d8bef9SDimitry Andric 60e8d8bef9SDimitry Andric private: 61e8d8bef9SDimitry Andric int m_libipt_error_code; 62e8d8bef9SDimitry Andric lldb::addr_t m_address; 63e8d8bef9SDimitry Andric }; 64e8d8bef9SDimitry Andric 65e8d8bef9SDimitry Andric /// \class DecodedThread 66e8d8bef9SDimitry Andric /// Class holding the instructions and function call hierarchy obtained from 67e8d8bef9SDimitry Andric /// decoding a trace, as well as a position cursor used when reverse debugging 68e8d8bef9SDimitry Andric /// the trace. 69e8d8bef9SDimitry Andric /// 70e8d8bef9SDimitry Andric /// Each decoded thread contains a cursor to the current position the user is 71e8d8bef9SDimitry Andric /// stopped at. See \a Trace::GetCursorPosition for more information. 72fe6060f1SDimitry Andric class DecodedThread : public std::enable_shared_from_this<DecodedThread> { 73e8d8bef9SDimitry Andric public: 74*972a253aSDimitry Andric using TSC = uint64_t; 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric // Struct holding counts for libipts errors; 7781ad6265SDimitry Andric struct LibiptErrorsStats { 7881ad6265SDimitry Andric // libipt error -> count 7981ad6265SDimitry Andric llvm::DenseMap<const char *, int> libipt_errors_counts; 8081ad6265SDimitry Andric size_t total_count = 0; 8181ad6265SDimitry Andric 8281ad6265SDimitry Andric void RecordError(int libipt_error_code); 8381ad6265SDimitry Andric }; 8481ad6265SDimitry Andric 85*972a253aSDimitry Andric /// A structure that represents a maximal range of trace items associated to 86*972a253aSDimitry Andric /// the same TSC value. 87*972a253aSDimitry Andric struct TSCRange { 88*972a253aSDimitry Andric TSC tsc; 89*972a253aSDimitry Andric /// Number of trace items in this range. 90*972a253aSDimitry Andric uint64_t items_count; 91*972a253aSDimitry Andric /// Index of the first trace item in this range. 92*972a253aSDimitry Andric uint64_t first_item_index; 93*972a253aSDimitry Andric 94*972a253aSDimitry Andric /// \return 95*972a253aSDimitry Andric /// \b true if and only if the given \p item_index is covered by this 96*972a253aSDimitry Andric /// range. 97*972a253aSDimitry Andric bool InRange(uint64_t item_index) const; 98*972a253aSDimitry Andric }; 99*972a253aSDimitry Andric 100*972a253aSDimitry Andric /// A structure that represents a maximal range of trace items associated to 101*972a253aSDimitry Andric /// the same non-interpolated timestamps in nanoseconds. 102*972a253aSDimitry Andric struct NanosecondsRange { 103*972a253aSDimitry Andric /// The nanoseconds value for this range. 104*972a253aSDimitry Andric uint64_t nanos; 105*972a253aSDimitry Andric /// The corresponding TSC value for this range. 106*972a253aSDimitry Andric TSC tsc; 107*972a253aSDimitry Andric /// A nullable pointer to the next range. 108*972a253aSDimitry Andric NanosecondsRange *next_range; 109*972a253aSDimitry Andric /// Number of trace items in this range. 110*972a253aSDimitry Andric uint64_t items_count; 111*972a253aSDimitry Andric /// Index of the first trace item in this range. 112*972a253aSDimitry Andric uint64_t first_item_index; 113*972a253aSDimitry Andric 114*972a253aSDimitry Andric /// Calculate an interpolated timestamp in nanoseconds for the given item 115*972a253aSDimitry Andric /// index. It's guaranteed that two different item indices will produce 116*972a253aSDimitry Andric /// different interpolated values. 117*972a253aSDimitry Andric /// 118*972a253aSDimitry Andric /// \param[in] item_index 119*972a253aSDimitry Andric /// The index of the item whose timestamp will be estimated. It has to be 120*972a253aSDimitry Andric /// part of this range. 121*972a253aSDimitry Andric /// 122*972a253aSDimitry Andric /// \param[in] beginning_of_time_nanos 123*972a253aSDimitry Andric /// The timestamp at which tracing started. 124*972a253aSDimitry Andric /// 125*972a253aSDimitry Andric /// \param[in] tsc_conversion 126*972a253aSDimitry Andric /// The tsc -> nanos conversion utility 127*972a253aSDimitry Andric /// 128*972a253aSDimitry Andric /// \return 129*972a253aSDimitry Andric /// An interpolated timestamp value for the given trace item. 130*972a253aSDimitry Andric double 131*972a253aSDimitry Andric GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos, 132*972a253aSDimitry Andric const LinuxPerfZeroTscConversion &tsc_conversion) const; 133*972a253aSDimitry Andric 134*972a253aSDimitry Andric /// \return 135*972a253aSDimitry Andric /// \b true if and only if the given \p item_index is covered by this 136*972a253aSDimitry Andric /// range. 137*972a253aSDimitry Andric bool InRange(uint64_t item_index) const; 138*972a253aSDimitry Andric }; 139*972a253aSDimitry Andric 14081ad6265SDimitry Andric // Struct holding counts for events; 14181ad6265SDimitry Andric struct EventsStats { 14281ad6265SDimitry Andric /// A count for each individual event kind. We use an unordered map instead 14381ad6265SDimitry Andric /// of a DenseMap because DenseMap can't understand enums. 14481ad6265SDimitry Andric std::unordered_map<lldb::TraceEvent, size_t> events_counts; 14581ad6265SDimitry Andric size_t total_count = 0; 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric void RecordEvent(lldb::TraceEvent event); 14881ad6265SDimitry Andric }; 14981ad6265SDimitry Andric 150*972a253aSDimitry Andric DecodedThread( 151*972a253aSDimitry Andric lldb::ThreadSP thread_sp, 152*972a253aSDimitry Andric const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion); 15381ad6265SDimitry Andric 15481ad6265SDimitry Andric /// Get the total number of instruction, errors and events from the decoded 15581ad6265SDimitry Andric /// trace. 156*972a253aSDimitry Andric uint64_t GetItemsCount() const; 15781ad6265SDimitry Andric 15881ad6265SDimitry Andric /// \return 15981ad6265SDimitry Andric /// The error associated with a given trace item. 160*972a253aSDimitry Andric const char *GetErrorByIndex(uint64_t item_index) const; 16181ad6265SDimitry Andric 16281ad6265SDimitry Andric /// \return 16381ad6265SDimitry Andric /// The trace item kind given an item index. 164*972a253aSDimitry Andric lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const; 16581ad6265SDimitry Andric 16681ad6265SDimitry Andric /// \return 16781ad6265SDimitry Andric /// The underlying event type for the given trace item index. 16881ad6265SDimitry Andric lldb::TraceEvent GetEventByIndex(int item_index) const; 16981ad6265SDimitry Andric 170753f127fSDimitry Andric /// Get the most recent CPU id before or at the given trace item index. 171753f127fSDimitry Andric /// 172753f127fSDimitry Andric /// \param[in] item_index 173753f127fSDimitry Andric /// The trace item index to compare with. 174753f127fSDimitry Andric /// 175753f127fSDimitry Andric /// \return 176753f127fSDimitry Andric /// The requested cpu id, or \a llvm::None if not available. 177753f127fSDimitry Andric llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const; 178753f127fSDimitry Andric 179*972a253aSDimitry Andric /// Get a maximal range of trace items that include the given \p item_index 180*972a253aSDimitry Andric /// that have the same TSC value. 181*972a253aSDimitry Andric /// 182*972a253aSDimitry Andric /// \param[in] item_index 183*972a253aSDimitry Andric /// The trace item index to compare with. 184*972a253aSDimitry Andric /// 185*972a253aSDimitry Andric /// \return 186*972a253aSDimitry Andric /// The requested TSC range, or \a llvm::None if not available. 187*972a253aSDimitry Andric llvm::Optional<DecodedThread::TSCRange> 188*972a253aSDimitry Andric GetTSCRangeByIndex(uint64_t item_index) const; 189*972a253aSDimitry Andric 190*972a253aSDimitry Andric /// Get a maximal range of trace items that include the given \p item_index 191*972a253aSDimitry Andric /// that have the same nanoseconds timestamp without interpolation. 192*972a253aSDimitry Andric /// 193*972a253aSDimitry Andric /// \param[in] item_index 194*972a253aSDimitry Andric /// The trace item index to compare with. 195*972a253aSDimitry Andric /// 196*972a253aSDimitry Andric /// \return 197*972a253aSDimitry Andric /// The requested nanoseconds range, or \a llvm::None if not available. 198*972a253aSDimitry Andric llvm::Optional<DecodedThread::NanosecondsRange> 199*972a253aSDimitry Andric GetNanosecondsRangeByIndex(uint64_t item_index); 200*972a253aSDimitry Andric 20181ad6265SDimitry Andric /// \return 20281ad6265SDimitry Andric /// The load address of the instruction at the given index. 203*972a253aSDimitry Andric lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const; 20481ad6265SDimitry Andric 20581ad6265SDimitry Andric /// Return an object with statistics of the TSC decoding errors that happened. 20681ad6265SDimitry Andric /// A TSC error is not a fatal error and doesn't create gaps in the trace. 20781ad6265SDimitry Andric /// Instead we only keep track of them as statistics. 20881ad6265SDimitry Andric /// 20981ad6265SDimitry Andric /// \return 21081ad6265SDimitry Andric /// An object with the statistics of TSC decoding errors. 21181ad6265SDimitry Andric const LibiptErrorsStats &GetTscErrorsStats() const; 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric /// Return an object with statistics of the trace events that happened. 21481ad6265SDimitry Andric /// 21581ad6265SDimitry Andric /// \return 21681ad6265SDimitry Andric /// The stats object of all the events. 21781ad6265SDimitry Andric const EventsStats &GetEventsStats() const; 21881ad6265SDimitry Andric 21981ad6265SDimitry Andric /// Record an error decoding a TSC timestamp. 22081ad6265SDimitry Andric /// 22181ad6265SDimitry Andric /// See \a GetTscErrors() for more documentation. 22281ad6265SDimitry Andric /// 22381ad6265SDimitry Andric /// \param[in] libipt_error_code 22481ad6265SDimitry Andric /// An error returned by the libipt library. 22581ad6265SDimitry Andric void RecordTscError(int libipt_error_code); 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. 235*972a253aSDimitry 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 24181ad6265SDimitry Andric /// Append a decoding error. 24281ad6265SDimitry Andric void AppendError(const IntelPTError &error); 24381ad6265SDimitry Andric 24481ad6265SDimitry Andric /// Append a custom decoding. 24581ad6265SDimitry Andric void AppendCustomError(llvm::StringRef error); 24681ad6265SDimitry Andric 24781ad6265SDimitry Andric /// Append an event. 24881ad6265SDimitry Andric void AppendEvent(lldb::TraceEvent); 24981ad6265SDimitry Andric 25081ad6265SDimitry Andric /// Append an instruction. 25181ad6265SDimitry Andric void AppendInstruction(const pt_insn &insn); 25281ad6265SDimitry Andric 25381ad6265SDimitry Andric private: 25481ad6265SDimitry Andric /// When adding new members to this class, make sure 25581ad6265SDimitry Andric /// to update \a CalculateApproximateMemoryUsage() accordingly. 256fe6060f1SDimitry Andric lldb::ThreadSP m_thread_sp; 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric /// We use a union to optimize the memory usage for the different kinds of 25981ad6265SDimitry Andric /// trace items. 26081ad6265SDimitry Andric union TraceItemStorage { 26181ad6265SDimitry Andric /// The load addresses of this item if it's an instruction. 26281ad6265SDimitry Andric uint64_t load_address; 26381ad6265SDimitry Andric 26481ad6265SDimitry Andric /// The event kind of this item if it's an event 26581ad6265SDimitry Andric lldb::TraceEvent event; 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric /// The string message of this item if it's an error 26881ad6265SDimitry Andric const char *error; 26981ad6265SDimitry Andric }; 27081ad6265SDimitry Andric 27181ad6265SDimitry Andric /// Create a new trace item. 27281ad6265SDimitry Andric /// 27381ad6265SDimitry Andric /// \return 27481ad6265SDimitry Andric /// The index of the new item. 27581ad6265SDimitry Andric DecodedThread::TraceItemStorage &CreateNewTraceItem(lldb::TraceItemKind kind); 27681ad6265SDimitry Andric 27781ad6265SDimitry Andric /// Most of the trace data is stored here. 27881ad6265SDimitry Andric std::vector<TraceItemStorage> m_item_data; 27981ad6265SDimitry Andric /// The TraceItemKind for each trace item encoded as uint8_t. We don't include 28081ad6265SDimitry Andric /// it in TraceItemStorage to avoid padding. 28181ad6265SDimitry Andric std::vector<uint8_t> m_item_kinds; 28281ad6265SDimitry Andric 283*972a253aSDimitry Andric /// This map contains the TSCs of the decoded trace items. It maps 284*972a253aSDimitry Andric /// `item index -> TSC`, where `item index` is the first index 285*972a253aSDimitry Andric /// at which the mapped TSC first appears. We use this representation because 286*972a253aSDimitry Andric /// TSCs are sporadic and we can think of them as ranges. 287*972a253aSDimitry Andric std::map<uint64_t, TSCRange> m_tscs; 28881ad6265SDimitry Andric /// This is the chronologically last TSC that has been added. 289*972a253aSDimitry Andric llvm::Optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc = 290*972a253aSDimitry Andric llvm::None; 291*972a253aSDimitry Andric /// This map contains the non-interpolated nanoseconds timestamps of the 292*972a253aSDimitry Andric /// decoded trace items. It maps `item index -> nanoseconds`, where `item 293*972a253aSDimitry Andric /// index` is the first index at which the mapped nanoseconds first appears. 294*972a253aSDimitry Andric /// We use this representation because timestamps are sporadic and we think of 295*972a253aSDimitry Andric /// them as ranges. 296*972a253aSDimitry Andric std::map<uint64_t, NanosecondsRange> m_nanoseconds; 297*972a253aSDimitry Andric llvm::Optional<std::map<uint64_t, NanosecondsRange>::iterator> 298*972a253aSDimitry Andric m_last_nanoseconds = llvm::None; 29981ad6265SDimitry Andric 300753f127fSDimitry Andric // The cpu information is stored as a map. It maps `instruction 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. 305753f127fSDimitry Andric llvm::Optional<uint64_t> m_last_cpu = llvm::None; 306753f127fSDimitry Andric 307*972a253aSDimitry Andric /// TSC -> nanos conversion utility. 308*972a253aSDimitry Andric llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion; 309*972a253aSDimitry Andric 31081ad6265SDimitry Andric /// Statistics of all tracing events. 31181ad6265SDimitry Andric EventsStats m_events_stats; 31281ad6265SDimitry Andric /// Statistics of libipt errors when decoding TSCs. 31381ad6265SDimitry Andric LibiptErrorsStats m_tsc_errors_stats; 31481ad6265SDimitry Andric /// Total amount of time spent decoding. 31581ad6265SDimitry Andric std::chrono::milliseconds m_total_decoding_time{0}; 316e8d8bef9SDimitry Andric }; 317e8d8bef9SDimitry Andric 318fe6060f1SDimitry Andric using DecodedThreadSP = std::shared_ptr<DecodedThread>; 319fe6060f1SDimitry Andric 320e8d8bef9SDimitry Andric } // namespace trace_intel_pt 321e8d8bef9SDimitry Andric } // namespace lldb_private 322e8d8bef9SDimitry Andric 323e8d8bef9SDimitry Andric #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H 324