1be691f3bSpatrick //===-- TraceIntelPT.h ------------------------------------------*- C++ -*-===// 2be691f3bSpatrick // 3be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information. 5be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6be691f3bSpatrick // 7be691f3bSpatrick //===----------------------------------------------------------------------===// 8be691f3bSpatrick 9be691f3bSpatrick #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H 10be691f3bSpatrick #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H 11be691f3bSpatrick 12*f6aab3d8Srobert #include "TaskTimer.h" 13*f6aab3d8Srobert #include "ThreadDecoder.h" 14*f6aab3d8Srobert #include "TraceIntelPTBundleLoader.h" 15*f6aab3d8Srobert #include "TraceIntelPTMultiCpuDecoder.h" 16*f6aab3d8Srobert #include "lldb/Utility/FileSpec.h" 17*f6aab3d8Srobert #include "lldb/lldb-types.h" 18*f6aab3d8Srobert #include "llvm/Support/raw_ostream.h" 19*f6aab3d8Srobert #include <optional> 20be691f3bSpatrick 21be691f3bSpatrick namespace lldb_private { 22be691f3bSpatrick namespace trace_intel_pt { 23be691f3bSpatrick 24be691f3bSpatrick class TraceIntelPT : public Trace { 25be691f3bSpatrick public: 26*f6aab3d8Srobert /// Properties to be used with the `settings` command. 27*f6aab3d8Srobert class PluginProperties : public Properties { 28*f6aab3d8Srobert public: 29*f6aab3d8Srobert static ConstString GetSettingName(); 30*f6aab3d8Srobert 31*f6aab3d8Srobert PluginProperties(); 32*f6aab3d8Srobert 33*f6aab3d8Srobert ~PluginProperties() override = default; 34*f6aab3d8Srobert 35*f6aab3d8Srobert uint64_t GetInfiniteDecodingLoopVerificationThreshold(); 36*f6aab3d8Srobert 37*f6aab3d8Srobert uint64_t GetExtremelyLargeDecodingThreshold(); 38*f6aab3d8Srobert }; 39*f6aab3d8Srobert 40*f6aab3d8Srobert /// Return the global properties for this trace plug-in. 41*f6aab3d8Srobert static PluginProperties &GetGlobalProperties(); 42*f6aab3d8Srobert 43be691f3bSpatrick void Dump(Stream *s) const override; 44be691f3bSpatrick 45*f6aab3d8Srobert llvm::Expected<FileSpec> SaveToDisk(FileSpec directory, 46*f6aab3d8Srobert bool compact) override; 47*f6aab3d8Srobert 48be691f3bSpatrick ~TraceIntelPT() override = default; 49be691f3bSpatrick 50be691f3bSpatrick /// PluginInterface protocol 51be691f3bSpatrick /// \{ GetPluginName()52*f6aab3d8Srobert llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } 53be691f3bSpatrick 54be691f3bSpatrick static void Initialize(); 55be691f3bSpatrick 56be691f3bSpatrick static void Terminate(); 57be691f3bSpatrick 58*f6aab3d8Srobert /// Create an instance of this class from a trace bundle. 59be691f3bSpatrick /// 60*f6aab3d8Srobert /// \param[in] trace_bundle_description 61*f6aab3d8Srobert /// The description of the trace bundle. See \a Trace::FindPlugin. 62be691f3bSpatrick /// 63*f6aab3d8Srobert /// \param[in] bundle_dir 64*f6aab3d8Srobert /// The path to the directory that contains the trace bundle. 65be691f3bSpatrick /// 66be691f3bSpatrick /// \param[in] debugger 67be691f3bSpatrick /// The debugger instance where new Targets will be created as part of the 68be691f3bSpatrick /// JSON data parsing. 69be691f3bSpatrick /// 70be691f3bSpatrick /// \return 71be691f3bSpatrick /// A trace instance or an error in case of failures. 72*f6aab3d8Srobert static llvm::Expected<lldb::TraceSP> CreateInstanceForTraceBundle( 73*f6aab3d8Srobert const llvm::json::Value &trace_bundle_description, 74*f6aab3d8Srobert llvm::StringRef bundle_dir, Debugger &debugger); 75be691f3bSpatrick 76be691f3bSpatrick static llvm::Expected<lldb::TraceSP> 77be691f3bSpatrick CreateInstanceForLiveProcess(Process &process); 78be691f3bSpatrick GetPluginNameStatic()79*f6aab3d8Srobert static llvm::StringRef GetPluginNameStatic() { return "intel-pt"; } 80be691f3bSpatrick 81*f6aab3d8Srobert static void DebuggerInitialize(Debugger &debugger); 82be691f3bSpatrick /// \} 83be691f3bSpatrick 84be691f3bSpatrick lldb::CommandObjectSP 85be691f3bSpatrick GetProcessTraceStartCommand(CommandInterpreter &interpreter) override; 86be691f3bSpatrick 87be691f3bSpatrick lldb::CommandObjectSP 88be691f3bSpatrick GetThreadTraceStartCommand(CommandInterpreter &interpreter) override; 89be691f3bSpatrick 90be691f3bSpatrick llvm::StringRef GetSchema() override; 91be691f3bSpatrick 92*f6aab3d8Srobert llvm::Expected<lldb::TraceCursorSP> CreateNewCursor(Thread &thread) override; 93be691f3bSpatrick 94*f6aab3d8Srobert void DumpTraceInfo(Thread &thread, Stream &s, bool verbose, 95*f6aab3d8Srobert bool json) override; 96be691f3bSpatrick 97*f6aab3d8Srobert llvm::Expected<std::optional<uint64_t>> GetRawTraceSize(Thread &thread); 98be691f3bSpatrick 99*f6aab3d8Srobert llvm::Error DoRefreshLiveProcessState(TraceGetStateResponse state, 100*f6aab3d8Srobert llvm::StringRef json_response) override; 101be691f3bSpatrick 102*f6aab3d8Srobert bool IsTraced(lldb::tid_t tid) override; 103be691f3bSpatrick 104be691f3bSpatrick const char *GetStartConfigurationHelp() override; 105be691f3bSpatrick 106be691f3bSpatrick /// Start tracing a live process. 107be691f3bSpatrick /// 108*f6aab3d8Srobert /// More information on the parameters below can be found in the 109*f6aab3d8Srobert /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt. 110*f6aab3d8Srobert /// 111*f6aab3d8Srobert /// \param[in] ipt_trace_size 112be691f3bSpatrick /// Trace size per thread in bytes. 113be691f3bSpatrick /// 114be691f3bSpatrick /// \param[in] total_buffer_size_limit 115be691f3bSpatrick /// Maximum total trace size per process in bytes. 116be691f3bSpatrick /// 117be691f3bSpatrick /// \param[in] enable_tsc 118be691f3bSpatrick /// Whether to use enable TSC timestamps or not. 119be691f3bSpatrick /// 120be691f3bSpatrick /// \param[in] psb_period 121be691f3bSpatrick /// This value defines the period in which PSB packets will be generated. 122*f6aab3d8Srobert /// 123*f6aab3d8Srobert /// \param[in] per_cpu_tracing 124*f6aab3d8Srobert /// This value defines whether to have an intel pt trace buffer per thread 125*f6aab3d8Srobert /// or per cpu core. 126*f6aab3d8Srobert /// 127*f6aab3d8Srobert /// \param[in] disable_cgroup_filtering 128*f6aab3d8Srobert /// Disable the cgroup filtering that is automatically applied when doing 129*f6aab3d8Srobert /// per cpu tracing. 130be691f3bSpatrick /// 131be691f3bSpatrick /// \return 132be691f3bSpatrick /// \a llvm::Error::success if the operation was successful, or 133be691f3bSpatrick /// \a llvm::Error otherwise. 134*f6aab3d8Srobert llvm::Error Start(uint64_t ipt_trace_size, uint64_t total_buffer_size_limit, 135*f6aab3d8Srobert bool enable_tsc, std::optional<uint64_t> psb_period, 136*f6aab3d8Srobert bool m_per_cpu_tracing, bool disable_cgroup_filtering); 137be691f3bSpatrick 138be691f3bSpatrick /// \copydoc Trace::Start 139be691f3bSpatrick llvm::Error Start(StructuredData::ObjectSP configuration = 140be691f3bSpatrick StructuredData::ObjectSP()) override; 141be691f3bSpatrick 142be691f3bSpatrick /// Start tracing live threads. 143be691f3bSpatrick /// 144*f6aab3d8Srobert /// More information on the parameters below can be found in the 145*f6aab3d8Srobert /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt. 146*f6aab3d8Srobert /// 147be691f3bSpatrick /// \param[in] tids 148be691f3bSpatrick /// Threads to trace. 149be691f3bSpatrick /// 150*f6aab3d8Srobert /// \param[in] ipt_trace_size 151*f6aab3d8Srobert /// Trace size per thread or per cpu core in bytes. 152be691f3bSpatrick /// 153be691f3bSpatrick /// \param[in] enable_tsc 154be691f3bSpatrick /// Whether to use enable TSC timestamps or not. 155be691f3bSpatrick /// 156be691f3bSpatrick /// \param[in] psb_period 157be691f3bSpatrick /// This value defines the period in which PSB packets will be generated. 158be691f3bSpatrick /// 159be691f3bSpatrick /// \return 160be691f3bSpatrick /// \a llvm::Error::success if the operation was successful, or 161be691f3bSpatrick /// \a llvm::Error otherwise. 162*f6aab3d8Srobert llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, uint64_t ipt_trace_size, 163*f6aab3d8Srobert bool enable_tsc, std::optional<uint64_t> psb_period); 164be691f3bSpatrick 165be691f3bSpatrick /// \copydoc Trace::Start 166be691f3bSpatrick llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, 167be691f3bSpatrick StructuredData::ObjectSP configuration = 168be691f3bSpatrick StructuredData::ObjectSP()) override; 169be691f3bSpatrick 170*f6aab3d8Srobert /// See \a Trace::OnThreadBinaryDataRead(). 171*f6aab3d8Srobert llvm::Error OnThreadBufferRead(lldb::tid_t tid, 172*f6aab3d8Srobert OnBinaryDataReadCallback callback); 173be691f3bSpatrick 174*f6aab3d8Srobert /// Get or fetch the cpu information from, for example, /proc/cpuinfo. 175be691f3bSpatrick llvm::Expected<pt_cpu> GetCPUInfo(); 176be691f3bSpatrick 177*f6aab3d8Srobert /// Get or fetch the values used to convert to and from TSCs and nanos. 178*f6aab3d8Srobert std::optional<LinuxPerfZeroTscConversion> GetPerfZeroTscConversion(); 179*f6aab3d8Srobert 180*f6aab3d8Srobert /// \return 181*f6aab3d8Srobert /// The timer object for this trace. 182*f6aab3d8Srobert TaskTimer &GetTimer(); 183*f6aab3d8Srobert 184*f6aab3d8Srobert /// \return 185*f6aab3d8Srobert /// The ScopedTaskTimer object for the given thread in this trace. 186*f6aab3d8Srobert ScopedTaskTimer &GetThreadTimer(lldb::tid_t tid); 187*f6aab3d8Srobert 188*f6aab3d8Srobert /// \return 189*f6aab3d8Srobert /// The global copedTaskTimer object for this trace. 190*f6aab3d8Srobert ScopedTaskTimer &GetGlobalTimer(); 191*f6aab3d8Srobert 192*f6aab3d8Srobert TraceIntelPTSP GetSharedPtr(); 193*f6aab3d8Srobert 194*f6aab3d8Srobert enum class TraceMode { UserMode, KernelMode }; 195*f6aab3d8Srobert 196*f6aab3d8Srobert TraceMode GetTraceMode(); 197*f6aab3d8Srobert 198be691f3bSpatrick private: 199*f6aab3d8Srobert friend class TraceIntelPTBundleLoader; 200be691f3bSpatrick 201be691f3bSpatrick llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess(); 202be691f3bSpatrick 203*f6aab3d8Srobert /// Postmortem trace constructor 204*f6aab3d8Srobert /// 205*f6aab3d8Srobert /// \param[in] bundle_description 206*f6aab3d8Srobert /// The definition file for the postmortem bundle. 207*f6aab3d8Srobert /// 208*f6aab3d8Srobert /// \param[in] traced_processes 209*f6aab3d8Srobert /// The processes traced in the postmortem session. 210*f6aab3d8Srobert /// 211be691f3bSpatrick /// \param[in] trace_threads 212*f6aab3d8Srobert /// The threads traced in the postmortem session. They must belong to the 213*f6aab3d8Srobert /// processes mentioned above. 214*f6aab3d8Srobert /// 215*f6aab3d8Srobert /// \param[in] trace_mode 216*f6aab3d8Srobert /// The tracing mode of the postmortem session. 217*f6aab3d8Srobert /// 218*f6aab3d8Srobert /// \return 219*f6aab3d8Srobert /// A TraceIntelPT shared pointer instance. 220*f6aab3d8Srobert /// \{ 221*f6aab3d8Srobert static TraceIntelPTSP CreateInstanceForPostmortemTrace( 222*f6aab3d8Srobert JSONTraceBundleDescription &bundle_description, 223*f6aab3d8Srobert llvm::ArrayRef<lldb::ProcessSP> traced_processes, 224*f6aab3d8Srobert llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads, 225*f6aab3d8Srobert TraceMode trace_mode); 226*f6aab3d8Srobert 227*f6aab3d8Srobert /// This constructor is used by CreateInstanceForPostmortemTrace to get the 228*f6aab3d8Srobert /// instance ready before using shared pointers, which is a limitation of C++. 229*f6aab3d8Srobert TraceIntelPT(JSONTraceBundleDescription &bundle_description, 230*f6aab3d8Srobert llvm::ArrayRef<lldb::ProcessSP> traced_processes, 231*f6aab3d8Srobert TraceMode trace_mode); 232*f6aab3d8Srobert /// \} 233be691f3bSpatrick 234be691f3bSpatrick /// Constructor for live processes TraceIntelPT(Process & live_process)235be691f3bSpatrick TraceIntelPT(Process &live_process) 236*f6aab3d8Srobert : Trace(live_process), trace_mode(TraceMode::UserMode){}; 237be691f3bSpatrick 238be691f3bSpatrick /// Decode the trace of the given thread that, i.e. recontruct the traced 239be691f3bSpatrick /// instructions. 240be691f3bSpatrick /// 241be691f3bSpatrick /// \param[in] thread 242be691f3bSpatrick /// If \a thread is a \a ThreadTrace, then its internal trace file will be 243be691f3bSpatrick /// decoded. Live threads are not currently supported. 244be691f3bSpatrick /// 245be691f3bSpatrick /// \return 246be691f3bSpatrick /// A \a DecodedThread shared pointer with the decoded instructions. Any 247*f6aab3d8Srobert /// errors are embedded in the instruction list. An \a llvm::Error is 248*f6aab3d8Srobert /// returned if the decoder couldn't be properly set up. 249*f6aab3d8Srobert llvm::Expected<DecodedThreadSP> Decode(Thread &thread); 250be691f3bSpatrick 251*f6aab3d8Srobert /// \return 252*f6aab3d8Srobert /// The lowest timestamp in nanoseconds in all traces if available, \a 253*f6aab3d8Srobert /// std::nullopt if all the traces were empty or no trace contained no 254*f6aab3d8Srobert /// timing information, or an \a llvm::Error if it was not possible to set 255*f6aab3d8Srobert /// up the decoder for some trace. 256*f6aab3d8Srobert llvm::Expected<std::optional<uint64_t>> FindBeginningOfTimeNanos(); 257*f6aab3d8Srobert 258*f6aab3d8Srobert // Dump out trace info in JSON format 259*f6aab3d8Srobert void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose); 260*f6aab3d8Srobert 261*f6aab3d8Srobert /// We package all the data that can change upon process stops to make sure 262*f6aab3d8Srobert /// this contract is very visible. 263*f6aab3d8Srobert /// This variable should only be accessed directly by constructores or live 264*f6aab3d8Srobert /// process data refreshers. 265*f6aab3d8Srobert struct Storage { 266*f6aab3d8Srobert std::optional<TraceIntelPTMultiCpuDecoder> multicpu_decoder; 267*f6aab3d8Srobert /// These decoders are used for the non-per-cpu case 268*f6aab3d8Srobert llvm::DenseMap<lldb::tid_t, std::unique_ptr<ThreadDecoder>> thread_decoders; 269*f6aab3d8Srobert /// Helper variable used to track long running operations for telemetry. 270*f6aab3d8Srobert TaskTimer task_timer; 271*f6aab3d8Srobert /// It is provided by either a trace bundle or a live process to convert TSC 272*f6aab3d8Srobert /// counters to and from nanos. It might not be available on all hosts. 273*f6aab3d8Srobert std::optional<LinuxPerfZeroTscConversion> tsc_conversion; 274*f6aab3d8Srobert std::optional<uint64_t> beginning_of_time_nanos; 275*f6aab3d8Srobert bool beginning_of_time_nanos_calculated = false; 276*f6aab3d8Srobert } m_storage; 277*f6aab3d8Srobert 278*f6aab3d8Srobert /// It is provided by either a trace bundle or a live process' "cpuInfo" 279*f6aab3d8Srobert /// binary data. We don't put it in the Storage because this variable doesn't 280*f6aab3d8Srobert /// change. 281*f6aab3d8Srobert std::optional<pt_cpu> m_cpu_info; 282*f6aab3d8Srobert 283*f6aab3d8Srobert /// Get the storage after refreshing the data in the case of a live process. 284*f6aab3d8Srobert Storage &GetUpdatedStorage(); 285*f6aab3d8Srobert 286*f6aab3d8Srobert /// The tracing mode of post mortem trace. 287*f6aab3d8Srobert TraceMode trace_mode; 288be691f3bSpatrick }; 289be691f3bSpatrick 290be691f3bSpatrick } // namespace trace_intel_pt 291be691f3bSpatrick } // namespace lldb_private 292be691f3bSpatrick 293be691f3bSpatrick #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H 294