1*f6aab3d8Srobert //===-- LibiptDecoder.h --======---------------------------------*- C++ -*-===// 2*f6aab3d8Srobert // 3*f6aab3d8Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*f6aab3d8Srobert // See https://llvm.org/LICENSE.txt for license information. 5*f6aab3d8Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*f6aab3d8Srobert // 7*f6aab3d8Srobert //===----------------------------------------------------------------------===// 8*f6aab3d8Srobert 9*f6aab3d8Srobert #ifndef LLDB_SOURCE_PLUGINS_TRACE_LIBIPT_DECODER_H 10*f6aab3d8Srobert #define LLDB_SOURCE_PLUGINS_TRACE_LIBIPT_DECODER_H 11*f6aab3d8Srobert 12*f6aab3d8Srobert #include "DecodedThread.h" 13*f6aab3d8Srobert #include "PerfContextSwitchDecoder.h" 14*f6aab3d8Srobert #include "forward-declarations.h" 15*f6aab3d8Srobert #include "intel-pt.h" 16*f6aab3d8Srobert #include <optional> 17*f6aab3d8Srobert 18*f6aab3d8Srobert namespace lldb_private { 19*f6aab3d8Srobert namespace trace_intel_pt { 20*f6aab3d8Srobert 21*f6aab3d8Srobert /// This struct represents a contiguous section of a trace that starts at a PSB 22*f6aab3d8Srobert /// and ends right before the next PSB or the end of the trace. 23*f6aab3d8Srobert struct PSBBlock { 24*f6aab3d8Srobert /// The memory offset of a PSB packet that is a synchronization point for the 25*f6aab3d8Srobert /// decoder. A decoder normally looks first for a PSB packet and then it 26*f6aab3d8Srobert /// starts decoding. 27*f6aab3d8Srobert uint64_t psb_offset; 28*f6aab3d8Srobert /// The timestamp associated with the PSB packet above. 29*f6aab3d8Srobert std::optional<uint64_t> tsc; 30*f6aab3d8Srobert /// Size in bytes of this block 31*f6aab3d8Srobert uint64_t size; 32*f6aab3d8Srobert /// The first ip for this PSB block. 33*f6aab3d8Srobert /// This is \a std::nullopt if tracing was disabled when the PSB block was 34*f6aab3d8Srobert /// emitted. This means that eventually there's be an enablement event that 35*f6aab3d8Srobert /// will come with an ip. 36*f6aab3d8Srobert std::optional<lldb::addr_t> starting_ip; 37*f6aab3d8Srobert }; 38*f6aab3d8Srobert 39*f6aab3d8Srobert /// This struct represents a continuous execution of a thread in a cpu, 40*f6aab3d8Srobert /// delimited by a context switch in and out, and a list of Intel PT subtraces 41*f6aab3d8Srobert /// that belong to this execution. 42*f6aab3d8Srobert struct IntelPTThreadContinousExecution { 43*f6aab3d8Srobert ThreadContinuousExecution thread_execution; 44*f6aab3d8Srobert std::vector<PSBBlock> psb_blocks; 45*f6aab3d8Srobert IntelPTThreadContinousExecutionIntelPTThreadContinousExecution46*f6aab3d8Srobert IntelPTThreadContinousExecution( 47*f6aab3d8Srobert const ThreadContinuousExecution &thread_execution) 48*f6aab3d8Srobert : thread_execution(thread_execution) {} 49*f6aab3d8Srobert 50*f6aab3d8Srobert /// Comparator by time 51*f6aab3d8Srobert bool operator<(const IntelPTThreadContinousExecution &o) const; 52*f6aab3d8Srobert }; 53*f6aab3d8Srobert 54*f6aab3d8Srobert /// Decode a raw Intel PT trace for a single thread given in \p buffer and 55*f6aab3d8Srobert /// append the decoded instructions and errors in \p decoded_thread. It uses the 56*f6aab3d8Srobert /// low level libipt library underneath. 57*f6aab3d8Srobert /// 58*f6aab3d8Srobert /// \return 59*f6aab3d8Srobert /// An \a llvm::Error if the decoder couldn't be properly set up. 60*f6aab3d8Srobert llvm::Error DecodeSingleTraceForThread(DecodedThread &decoded_thread, 61*f6aab3d8Srobert TraceIntelPT &trace_intel_pt, 62*f6aab3d8Srobert llvm::ArrayRef<uint8_t> buffer); 63*f6aab3d8Srobert 64*f6aab3d8Srobert /// Decode a raw Intel PT trace for a single thread that was collected in a per 65*f6aab3d8Srobert /// cpu core basis. 66*f6aab3d8Srobert /// 67*f6aab3d8Srobert /// \param[out] decoded_thread 68*f6aab3d8Srobert /// All decoded instructions, errors and events will be appended to this 69*f6aab3d8Srobert /// object. 70*f6aab3d8Srobert /// 71*f6aab3d8Srobert /// \param[in] trace_intel_pt 72*f6aab3d8Srobert /// The main Trace object that contains all the information related to the 73*f6aab3d8Srobert /// trace session. 74*f6aab3d8Srobert /// 75*f6aab3d8Srobert /// \param[in] buffers 76*f6aab3d8Srobert /// A map from cpu core id to raw intel pt buffers. 77*f6aab3d8Srobert /// 78*f6aab3d8Srobert /// \param[in] executions 79*f6aab3d8Srobert /// A list of chunks of timed executions of the same given thread. It is used 80*f6aab3d8Srobert /// to identify if some executions have missing intel pt data and also to 81*f6aab3d8Srobert /// determine in which core a certain part of the execution ocurred. 82*f6aab3d8Srobert /// 83*f6aab3d8Srobert /// \return 84*f6aab3d8Srobert /// An \a llvm::Error if the decoder couldn't be properly set up, i.e. no 85*f6aab3d8Srobert /// instructions were attempted to be decoded. 86*f6aab3d8Srobert llvm::Error DecodeSystemWideTraceForThread( 87*f6aab3d8Srobert DecodedThread &decoded_thread, TraceIntelPT &trace_intel_pt, 88*f6aab3d8Srobert const llvm::DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> &buffers, 89*f6aab3d8Srobert const std::vector<IntelPTThreadContinousExecution> &executions); 90*f6aab3d8Srobert 91*f6aab3d8Srobert /// Given an intel pt trace, split it in chunks delimited by PSB packets. Each 92*f6aab3d8Srobert /// of these chunks is guaranteed to have been executed continuously. 93*f6aab3d8Srobert /// 94*f6aab3d8Srobert /// \param[in] trace_intel_pt 95*f6aab3d8Srobert /// The main Trace object that contains all the information related to the 96*f6aab3d8Srobert /// trace session. 97*f6aab3d8Srobert /// 98*f6aab3d8Srobert /// \param[in] buffer 99*f6aab3d8Srobert /// The intel pt buffer that belongs to a single thread or to a single cpu 100*f6aab3d8Srobert /// core. 101*f6aab3d8Srobert /// 102*f6aab3d8Srobert /// \param[in] expect_tscs 103*f6aab3d8Srobert /// If \b true, an error is return if a packet without TSC is found. 104*f6aab3d8Srobert /// 105*f6aab3d8Srobert /// \return 106*f6aab3d8Srobert /// A list of continuous executions sorted by time, or an \a llvm::Error in 107*f6aab3d8Srobert /// case of failures. 108*f6aab3d8Srobert llvm::Expected<std::vector<PSBBlock>> 109*f6aab3d8Srobert SplitTraceIntoPSBBlock(TraceIntelPT &trace_intel_pt, 110*f6aab3d8Srobert llvm::ArrayRef<uint8_t> buffer, bool expect_tscs); 111*f6aab3d8Srobert 112*f6aab3d8Srobert /// Find the lowest TSC in the given trace. 113*f6aab3d8Srobert /// 114*f6aab3d8Srobert /// \return 115*f6aab3d8Srobert /// The lowest TSC value in this trace if available, \a std::nullopt if the 116*f6aab3d8Srobert /// trace is empty or the trace contains no timing information, or an \a 117*f6aab3d8Srobert /// llvm::Error if it was not possible to set up the decoder. 118*f6aab3d8Srobert llvm::Expected<std::optional<uint64_t>> 119*f6aab3d8Srobert FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt, 120*f6aab3d8Srobert llvm::ArrayRef<uint8_t> buffer); 121*f6aab3d8Srobert 122*f6aab3d8Srobert } // namespace trace_intel_pt 123*f6aab3d8Srobert } // namespace lldb_private 124*f6aab3d8Srobert 125*f6aab3d8Srobert #endif // LLDB_SOURCE_PLUGINS_TRACE_LIBIPT_DECODER_H 126