1e8d8bef9SDimitry Andric //===-- Trace.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_TARGET_TRACE_H 10e8d8bef9SDimitry Andric #define LLDB_TARGET_TRACE_H 11e8d8bef9SDimitry Andric 12bdd1243dSDimitry Andric #include <optional> 13fe6060f1SDimitry Andric #include <unordered_map> 14fe6060f1SDimitry Andric 15e8d8bef9SDimitry Andric #include "llvm/Support/JSON.h" 16e8d8bef9SDimitry Andric 17e8d8bef9SDimitry Andric #include "lldb/Core/PluginInterface.h" 18fe6060f1SDimitry Andric #include "lldb/Target/Thread.h" 19fe6060f1SDimitry Andric #include "lldb/Target/TraceCursor.h" 20e8d8bef9SDimitry Andric #include "lldb/Utility/ArchSpec.h" 21fe6060f1SDimitry Andric #include "lldb/Utility/TraceGDBRemotePackets.h" 22e8d8bef9SDimitry Andric #include "lldb/Utility/UnimplementedError.h" 23e8d8bef9SDimitry Andric #include "lldb/lldb-private.h" 24349cc55cSDimitry Andric #include "lldb/lldb-types.h" 25e8d8bef9SDimitry Andric 26e8d8bef9SDimitry Andric namespace lldb_private { 27e8d8bef9SDimitry Andric 28e8d8bef9SDimitry Andric /// \class Trace Trace.h "lldb/Target/Trace.h" 29e8d8bef9SDimitry Andric /// A plug-in interface definition class for trace information. 30e8d8bef9SDimitry Andric /// 31e8d8bef9SDimitry Andric /// Trace plug-ins allow processor trace information to be loaded into LLDB so 32e8d8bef9SDimitry Andric /// that the data can be dumped, used for reverse and forward stepping to allow 33e8d8bef9SDimitry Andric /// introspection into the reason your process crashed or found its way to its 34e8d8bef9SDimitry Andric /// current state. 35e8d8bef9SDimitry Andric /// 36e8d8bef9SDimitry Andric /// Trace information can be loaded into a target without a process to allow 37e8d8bef9SDimitry Andric /// introspection of the trace information during post mortem analysis, such as 38e8d8bef9SDimitry Andric /// when loading core files. 39e8d8bef9SDimitry Andric /// 40e8d8bef9SDimitry Andric /// Processor trace information can also be fetched through the process 41e8d8bef9SDimitry Andric /// interfaces during a live debug session if your process supports gathering 42e8d8bef9SDimitry Andric /// this information. 43e8d8bef9SDimitry Andric /// 44e8d8bef9SDimitry Andric /// In order to support live tracing, the name of the plug-in should match the 45e8d8bef9SDimitry Andric /// name of the tracing type returned by the gdb-remote packet 46fe6060f1SDimitry Andric /// \a jLLDBTraceSupported. 47e8d8bef9SDimitry Andric class Trace : public PluginInterface, 48e8d8bef9SDimitry Andric public std::enable_shared_from_this<Trace> { 49e8d8bef9SDimitry Andric public: 50e8d8bef9SDimitry Andric /// Dump the trace data that this plug-in has access to. 51e8d8bef9SDimitry Andric /// 52e8d8bef9SDimitry Andric /// This function will dump all of the trace data for all threads in a user 53e8d8bef9SDimitry Andric /// readable format. Options for dumping can be added as this API is iterated 54e8d8bef9SDimitry Andric /// on. 55e8d8bef9SDimitry Andric /// 56e8d8bef9SDimitry Andric /// \param[in] s 57e8d8bef9SDimitry Andric /// A stream object to dump the information to. 58e8d8bef9SDimitry Andric virtual void Dump(Stream *s) const = 0; 59e8d8bef9SDimitry Andric 60753f127fSDimitry Andric /// Save the trace to the specified directory, which will be created if 61*5f757f3fSDimitry Andric /// needed. This will also create a file \a <directory>/trace.json with the 62753f127fSDimitry Andric /// main properties of the trace session, along with others files which 63753f127fSDimitry Andric /// contain the actual trace data. The trace.json file can be used later as 64753f127fSDimitry Andric /// input for the "trace load" command to load the trace in LLDB. 65349cc55cSDimitry Andric /// 66349cc55cSDimitry Andric /// \param[in] directory 67349cc55cSDimitry Andric /// The directory where the trace files will be saved. 68349cc55cSDimitry Andric /// 69753f127fSDimitry Andric /// \param[in] compact 70753f127fSDimitry Andric /// Try not to save to disk information irrelevant to the traced processes. 71753f127fSDimitry Andric /// Each trace plug-in implements this in a different fashion. 72753f127fSDimitry Andric /// 73349cc55cSDimitry Andric /// \return 74753f127fSDimitry Andric /// A \a FileSpec pointing to the bundle description file, or an \a 75753f127fSDimitry Andric /// llvm::Error otherwise. 76753f127fSDimitry Andric virtual llvm::Expected<FileSpec> SaveToDisk(FileSpec directory, 77753f127fSDimitry Andric bool compact) = 0; 78349cc55cSDimitry Andric 79e8d8bef9SDimitry Andric /// Find a trace plug-in using JSON data. 80e8d8bef9SDimitry Andric /// 81e8d8bef9SDimitry Andric /// When loading trace data from disk, the information for the trace data 82e8d8bef9SDimitry Andric /// can be contained in multiple files and require plug-in specific 83e8d8bef9SDimitry Andric /// information about the CPU. Using data like JSON provides an 84e8d8bef9SDimitry Andric /// easy way to specify all of the settings and information that we will need 85e8d8bef9SDimitry Andric /// to load trace data into LLDB. This structured data can include: 86e8d8bef9SDimitry Andric /// - The plug-in name (this allows a specific plug-in to be selected) 87e8d8bef9SDimitry Andric /// - Architecture or target triple 88e8d8bef9SDimitry Andric /// - one or more paths to the trace data file on disk 8981ad6265SDimitry Andric /// - cpu trace data 90e8d8bef9SDimitry Andric /// - thread events or related information 91e8d8bef9SDimitry Andric /// - shared library load information to use for this trace data that 92e8d8bef9SDimitry Andric /// allows a target to be created so the trace information can be 93e8d8bef9SDimitry Andric /// symbolicated so that the trace information can be displayed to the 94e8d8bef9SDimitry Andric /// user 95e8d8bef9SDimitry Andric /// - shared library path 96e8d8bef9SDimitry Andric /// - load address 97e8d8bef9SDimitry Andric /// - information on how to fetch the shared library 98e8d8bef9SDimitry Andric /// - path to locally cached file on disk 99e8d8bef9SDimitry Andric /// - URL to download the file 100e8d8bef9SDimitry Andric /// - Any information needed to load the trace file 101e8d8bef9SDimitry Andric /// - CPU information 102e8d8bef9SDimitry Andric /// - Custom plug-in information needed to decode the trace information 103e8d8bef9SDimitry Andric /// correctly. 104e8d8bef9SDimitry Andric /// 105e8d8bef9SDimitry Andric /// \param[in] debugger 106e8d8bef9SDimitry Andric /// The debugger instance where new Targets will be created as part of the 107e8d8bef9SDimitry Andric /// JSON data parsing. 108e8d8bef9SDimitry Andric /// 10981ad6265SDimitry Andric /// \param[in] bundle_description 11081ad6265SDimitry Andric /// The trace bundle description object describing the trace session. 111e8d8bef9SDimitry Andric /// 11281ad6265SDimitry Andric /// \param[in] bundle_dir 11381ad6265SDimitry Andric /// The path to the directory that contains the trace bundle. 114e8d8bef9SDimitry Andric static llvm::Expected<lldb::TraceSP> 115fe6060f1SDimitry Andric FindPluginForPostMortemProcess(Debugger &debugger, 11681ad6265SDimitry Andric const llvm::json::Value &bundle_description, 117e8d8bef9SDimitry Andric llvm::StringRef session_file_dir); 118e8d8bef9SDimitry Andric 119fe6060f1SDimitry Andric /// Find a trace plug-in to trace a live process. 120fe6060f1SDimitry Andric /// 121fe6060f1SDimitry Andric /// \param[in] plugin_name 122fe6060f1SDimitry Andric /// Plug-in name to search. 123fe6060f1SDimitry Andric /// 124fe6060f1SDimitry Andric /// \param[in] process 125fe6060f1SDimitry Andric /// Live process to trace. 126fe6060f1SDimitry Andric /// 127fe6060f1SDimitry Andric /// \return 128fe6060f1SDimitry Andric /// A \a TraceSP instance, or an \a llvm::Error if the plug-in name 129fe6060f1SDimitry Andric /// doesn't match any registered plug-ins or tracing couldn't be 130fe6060f1SDimitry Andric /// started. 131fe6060f1SDimitry Andric static llvm::Expected<lldb::TraceSP> 132fe6060f1SDimitry Andric FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process); 133fe6060f1SDimitry Andric 134e8d8bef9SDimitry Andric /// Get the schema of a Trace plug-in given its name. 135e8d8bef9SDimitry Andric /// 136e8d8bef9SDimitry Andric /// \param[in] plugin_name 137e8d8bef9SDimitry Andric /// Name of the trace plugin. 138e8d8bef9SDimitry Andric static llvm::Expected<llvm::StringRef> 139e8d8bef9SDimitry Andric FindPluginSchema(llvm::StringRef plugin_name); 140e8d8bef9SDimitry Andric 14181ad6265SDimitry Andric /// Load a trace from a trace description file and create Targets, 14281ad6265SDimitry Andric /// Processes and Threads based on the contents of such file. 14381ad6265SDimitry Andric /// 14481ad6265SDimitry Andric /// \param[in] debugger 14581ad6265SDimitry Andric /// The debugger instance where new Targets will be created as part of the 14681ad6265SDimitry Andric /// JSON data parsing. 14781ad6265SDimitry Andric /// 14881ad6265SDimitry Andric /// \param[in] trace_description_file 14981ad6265SDimitry Andric /// The file containing the necessary information to load the trace. 15081ad6265SDimitry Andric /// 15181ad6265SDimitry Andric /// \return 15281ad6265SDimitry Andric /// A \a TraceSP instance, or an \a llvm::Error if loading the trace 15381ad6265SDimitry Andric /// fails. 15481ad6265SDimitry Andric static llvm::Expected<lldb::TraceSP> 15581ad6265SDimitry Andric LoadPostMortemTraceFromFile(Debugger &debugger, 15681ad6265SDimitry Andric const FileSpec &trace_description_file); 15781ad6265SDimitry Andric 158fe6060f1SDimitry Andric /// Get the command handle for the "process trace start" command. 159fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 160fe6060f1SDimitry Andric GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0; 161fe6060f1SDimitry Andric 162fe6060f1SDimitry Andric /// Get the command handle for the "thread trace start" command. 163fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 164fe6060f1SDimitry Andric GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0; 165fe6060f1SDimitry Andric 166e8d8bef9SDimitry Andric /// \return 167e8d8bef9SDimitry Andric /// The JSON schema of this Trace plug-in. 168e8d8bef9SDimitry Andric virtual llvm::StringRef GetSchema() = 0; 169e8d8bef9SDimitry Andric 170fe6060f1SDimitry Andric /// Get a \a TraceCursor for the given thread's trace. 171e8d8bef9SDimitry Andric /// 172e8d8bef9SDimitry Andric /// \return 173bdd1243dSDimitry Andric /// A \a TraceCursorSP. If the thread is not traced or its trace 17481ad6265SDimitry Andric /// information failed to load, an \a llvm::Error is returned. 175bdd1243dSDimitry Andric virtual llvm::Expected<lldb::TraceCursorSP> 17681ad6265SDimitry Andric CreateNewCursor(Thread &thread) = 0; 177e8d8bef9SDimitry Andric 178fe6060f1SDimitry Andric /// Dump general info about a given thread's trace. Each Trace plug-in 179fe6060f1SDimitry Andric /// decides which data to show. 180e8d8bef9SDimitry Andric /// 181e8d8bef9SDimitry Andric /// \param[in] thread 182fe6060f1SDimitry Andric /// The thread that owns the trace in question. 183e8d8bef9SDimitry Andric /// 184e8d8bef9SDimitry Andric /// \param[in] s 185fe6060f1SDimitry Andric /// The stream object where the info will be printed printed. 186e8d8bef9SDimitry Andric /// 187fe6060f1SDimitry Andric /// \param[in] verbose 188fe6060f1SDimitry Andric /// If \b true, print detailed info 189fe6060f1SDimitry Andric /// If \b false, print compact info 190753f127fSDimitry Andric virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose, 191753f127fSDimitry Andric bool json) = 0; 192fe6060f1SDimitry Andric 193fe6060f1SDimitry Andric /// Check if a thread is currently traced by this object. 194e8d8bef9SDimitry Andric /// 195349cc55cSDimitry Andric /// \param[in] tid 196349cc55cSDimitry Andric /// The id of the thread in question. 197e8d8bef9SDimitry Andric /// 198fe6060f1SDimitry Andric /// \return 199fe6060f1SDimitry Andric /// \b true if the thread is traced by this instance, \b false otherwise. 200349cc55cSDimitry Andric virtual bool IsTraced(lldb::tid_t tid) = 0; 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric /// \return 203fe6060f1SDimitry Andric /// A description of the parameters to use for the \a Trace::Start method. 204fe6060f1SDimitry Andric virtual const char *GetStartConfigurationHelp() = 0; 205fe6060f1SDimitry Andric 206fe6060f1SDimitry Andric /// Start tracing a live process. 207fe6060f1SDimitry Andric /// 208fe6060f1SDimitry Andric /// \param[in] configuration 209fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBStructuredData &) for more 210e8d8bef9SDimitry Andric /// information. 211e8d8bef9SDimitry Andric /// 212e8d8bef9SDimitry Andric /// \return 213fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 214fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 215fe6060f1SDimitry Andric virtual llvm::Error Start( 216fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 217e8d8bef9SDimitry Andric 218fe6060f1SDimitry Andric /// Start tracing live threads. 219e8d8bef9SDimitry Andric /// 220fe6060f1SDimitry Andric /// \param[in] tids 221fe6060f1SDimitry Andric /// Threads to trace. This method tries to trace as many threads as 222fe6060f1SDimitry Andric /// possible. 223fe6060f1SDimitry Andric /// 224fe6060f1SDimitry Andric /// \param[in] configuration 225fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBThread &, const 226fe6060f1SDimitry Andric /// lldb::SBStructuredData &) for more information. 227e8d8bef9SDimitry Andric /// 228e8d8bef9SDimitry Andric /// \return 229fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 230fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 231fe6060f1SDimitry Andric virtual llvm::Error Start( 232fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids, 233fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 234fe6060f1SDimitry Andric 235fe6060f1SDimitry Andric /// Stop tracing live threads. 236fe6060f1SDimitry Andric /// 237fe6060f1SDimitry Andric /// \param[in] tids 238fe6060f1SDimitry Andric /// The threads to stop tracing on. 239fe6060f1SDimitry Andric /// 240fe6060f1SDimitry Andric /// \return 241fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 242fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 243fe6060f1SDimitry Andric llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids); 244fe6060f1SDimitry Andric 245fe6060f1SDimitry Andric /// Stop tracing all current and future threads of a live process. 246fe6060f1SDimitry Andric /// 247fe6060f1SDimitry Andric /// \param[in] request 248fe6060f1SDimitry Andric /// The information determining which threads or process to stop tracing. 249fe6060f1SDimitry Andric /// 250fe6060f1SDimitry Andric /// \return 251fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 252fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 253fe6060f1SDimitry Andric llvm::Error Stop(); 254fe6060f1SDimitry Andric 255fe6060f1SDimitry Andric /// \return 256fe6060f1SDimitry Andric /// The stop ID of the live process being traced, or an invalid stop ID 257fe6060f1SDimitry Andric /// if the trace is in an error or invalid state. 258fe6060f1SDimitry Andric uint32_t GetStopID(); 259fe6060f1SDimitry Andric 26081ad6265SDimitry Andric using OnBinaryDataReadCallback = 26181ad6265SDimitry Andric std::function<llvm::Error(llvm::ArrayRef<uint8_t> data)>; 26281ad6265SDimitry Andric using OnCpusBinaryDataReadCallback = std::function<llvm::Error( 26381ad6265SDimitry Andric const llvm::DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> 26481ad6265SDimitry Andric &cpu_to_data)>; 26581ad6265SDimitry Andric 26681ad6265SDimitry Andric /// Fetch binary data associated with a thread, either live or postmortem, and 26781ad6265SDimitry Andric /// pass it to the given callback. The reason of having a callback is to free 26881ad6265SDimitry Andric /// the caller from having to manage the life cycle of the data and to hide 26981ad6265SDimitry Andric /// the different data fetching procedures that exist for live and post mortem 27081ad6265SDimitry Andric /// threads. 27181ad6265SDimitry Andric /// 27281ad6265SDimitry Andric /// The fetched data is not persisted after the callback is invoked. 27381ad6265SDimitry Andric /// 27481ad6265SDimitry Andric /// \param[in] tid 27581ad6265SDimitry Andric /// The tid who owns the data. 27681ad6265SDimitry Andric /// 27781ad6265SDimitry Andric /// \param[in] kind 27881ad6265SDimitry Andric /// The kind of data to read. 27981ad6265SDimitry Andric /// 28081ad6265SDimitry Andric /// \param[in] callback 28181ad6265SDimitry Andric /// The callback to be invoked once the data was successfully read. Its 28281ad6265SDimitry Andric /// return value, which is an \a llvm::Error, is returned by this 28381ad6265SDimitry Andric /// function. 28481ad6265SDimitry Andric /// 28581ad6265SDimitry Andric /// \return 28681ad6265SDimitry Andric /// An \a llvm::Error if the data couldn't be fetched, or the return value 28781ad6265SDimitry Andric /// of the callback, otherwise. 28881ad6265SDimitry Andric llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 28981ad6265SDimitry Andric OnBinaryDataReadCallback callback); 29081ad6265SDimitry Andric 29181ad6265SDimitry Andric /// Fetch binary data associated with a cpu, either live or postmortem, and 29281ad6265SDimitry Andric /// pass it to the given callback. The reason of having a callback is to free 29381ad6265SDimitry Andric /// the caller from having to manage the life cycle of the data and to hide 29481ad6265SDimitry Andric /// the different data fetching procedures that exist for live and post mortem 29581ad6265SDimitry Andric /// cpus. 29681ad6265SDimitry Andric /// 29781ad6265SDimitry Andric /// The fetched data is not persisted after the callback is invoked. 29881ad6265SDimitry Andric /// 29981ad6265SDimitry Andric /// \param[in] cpu_id 30081ad6265SDimitry Andric /// The cpu who owns the data. 30181ad6265SDimitry Andric /// 30281ad6265SDimitry Andric /// \param[in] kind 30381ad6265SDimitry Andric /// The kind of data to read. 30481ad6265SDimitry Andric /// 30581ad6265SDimitry Andric /// \param[in] callback 30681ad6265SDimitry Andric /// The callback to be invoked once the data was successfully read. Its 30781ad6265SDimitry Andric /// return value, which is an \a llvm::Error, is returned by this 30881ad6265SDimitry Andric /// function. 30981ad6265SDimitry Andric /// 31081ad6265SDimitry Andric /// \return 31181ad6265SDimitry Andric /// An \a llvm::Error if the data couldn't be fetched, or the return value 31281ad6265SDimitry Andric /// of the callback, otherwise. 31381ad6265SDimitry Andric llvm::Error OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 31481ad6265SDimitry Andric OnBinaryDataReadCallback callback); 31581ad6265SDimitry Andric 31681ad6265SDimitry Andric /// Similar to \a OnCpuBinaryDataRead but this is able to fetch the same data 31781ad6265SDimitry Andric /// from all cpus at once. 31881ad6265SDimitry Andric llvm::Error OnAllCpusBinaryDataRead(llvm::StringRef kind, 31981ad6265SDimitry Andric OnCpusBinaryDataReadCallback callback); 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric /// \return 32281ad6265SDimitry Andric /// All the currently traced processes. 32381ad6265SDimitry Andric std::vector<Process *> GetAllProcesses(); 32481ad6265SDimitry Andric 32581ad6265SDimitry Andric /// \return 32681ad6265SDimitry Andric /// The list of cpus being traced. Might be empty depending on the 32781ad6265SDimitry Andric /// plugin. 32881ad6265SDimitry Andric llvm::ArrayRef<lldb::cpu_id_t> GetTracedCpus(); 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric /// Helper method for reading a data file and passing its data to the given 33181ad6265SDimitry Andric /// callback. 33281ad6265SDimitry Andric static llvm::Error OnDataFileRead(FileSpec file, 33381ad6265SDimitry Andric OnBinaryDataReadCallback callback); 33481ad6265SDimitry Andric 335fe6060f1SDimitry Andric protected: 33681ad6265SDimitry Andric /// Get the currently traced live process. 33781ad6265SDimitry Andric /// 33881ad6265SDimitry Andric /// \return 33981ad6265SDimitry Andric /// If it's not a live process, return \a nullptr. 34081ad6265SDimitry Andric Process *GetLiveProcess(); 34181ad6265SDimitry Andric 34281ad6265SDimitry Andric /// Get the currently traced postmortem processes. 34381ad6265SDimitry Andric /// 34481ad6265SDimitry Andric /// \return 34581ad6265SDimitry Andric /// If it's not a live process session, return an empty list. 34681ad6265SDimitry Andric llvm::ArrayRef<Process *> GetPostMortemProcesses(); 34781ad6265SDimitry Andric 34881ad6265SDimitry Andric /// Dispatcher for live trace data requests with some additional error 34981ad6265SDimitry Andric /// checking. 35081ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 35181ad6265SDimitry Andric GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request, 35281ad6265SDimitry Andric uint64_t expected_size); 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric /// Implementation of \a OnThreadBinaryDataRead() for live threads. 35581ad6265SDimitry Andric llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 35681ad6265SDimitry Andric OnBinaryDataReadCallback callback); 35781ad6265SDimitry Andric 35881ad6265SDimitry Andric /// Implementation of \a OnLiveBinaryDataRead() for live cpus. 35981ad6265SDimitry Andric llvm::Error OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu, llvm::StringRef kind, 36081ad6265SDimitry Andric OnBinaryDataReadCallback callback); 36181ad6265SDimitry Andric 36281ad6265SDimitry Andric /// Implementation of \a OnThreadBinaryDataRead() for post mortem threads. 36381ad6265SDimitry Andric llvm::Error 36481ad6265SDimitry Andric OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 36581ad6265SDimitry Andric OnBinaryDataReadCallback callback); 36681ad6265SDimitry Andric 36781ad6265SDimitry Andric /// Implementation of \a OnCpuBinaryDataRead() for post mortem cpus. 36881ad6265SDimitry Andric llvm::Error OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 36981ad6265SDimitry Andric llvm::StringRef kind, 37081ad6265SDimitry Andric OnBinaryDataReadCallback callback); 37181ad6265SDimitry Andric 37281ad6265SDimitry Andric /// Get the file path containing data of a postmortem thread given a data 37381ad6265SDimitry Andric /// identifier. 37481ad6265SDimitry Andric /// 37581ad6265SDimitry Andric /// \param[in] tid 37681ad6265SDimitry Andric /// The thread whose data is requested. 37781ad6265SDimitry Andric /// 37881ad6265SDimitry Andric /// \param[in] kind 37981ad6265SDimitry Andric /// The kind of data requested. 38081ad6265SDimitry Andric /// 38181ad6265SDimitry Andric /// \return 38281ad6265SDimitry Andric /// The file spec containing the requested data, or an \a llvm::Error in 38381ad6265SDimitry Andric /// case of failures. 38481ad6265SDimitry Andric llvm::Expected<FileSpec> GetPostMortemThreadDataFile(lldb::tid_t tid, 38581ad6265SDimitry Andric llvm::StringRef kind); 38681ad6265SDimitry Andric 38781ad6265SDimitry Andric /// Get the file path containing data of a postmortem cpu given a data 38881ad6265SDimitry Andric /// identifier. 38981ad6265SDimitry Andric /// 39081ad6265SDimitry Andric /// \param[in] cpu_id 39181ad6265SDimitry Andric /// The cpu whose data is requested. 39281ad6265SDimitry Andric /// 39381ad6265SDimitry Andric /// \param[in] kind 39481ad6265SDimitry Andric /// The kind of data requested. 39581ad6265SDimitry Andric /// 39681ad6265SDimitry Andric /// \return 39781ad6265SDimitry Andric /// The file spec containing the requested data, or an \a llvm::Error in 39881ad6265SDimitry Andric /// case of failures. 39981ad6265SDimitry Andric llvm::Expected<FileSpec> GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, 40081ad6265SDimitry Andric llvm::StringRef kind); 40181ad6265SDimitry Andric 40281ad6265SDimitry Andric /// Associate a given thread with a data file using a data identifier. 40381ad6265SDimitry Andric /// 40481ad6265SDimitry Andric /// \param[in] tid 40581ad6265SDimitry Andric /// The thread associated with the data file. 40681ad6265SDimitry Andric /// 40781ad6265SDimitry Andric /// \param[in] kind 40881ad6265SDimitry Andric /// The kind of data being registered. 40981ad6265SDimitry Andric /// 41081ad6265SDimitry Andric /// \param[in] file_spec 41181ad6265SDimitry Andric /// The path of the data file. 41281ad6265SDimitry Andric void SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, 41381ad6265SDimitry Andric FileSpec file_spec); 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric /// Associate a given cpu with a data file using a data identifier. 41681ad6265SDimitry Andric /// 41781ad6265SDimitry Andric /// \param[in] cpu_id 41881ad6265SDimitry Andric /// The cpu associated with the data file. 41981ad6265SDimitry Andric /// 42081ad6265SDimitry Andric /// \param[in] kind 42181ad6265SDimitry Andric /// The kind of data being registered. 42281ad6265SDimitry Andric /// 42381ad6265SDimitry Andric /// \param[in] file_spec 42481ad6265SDimitry Andric /// The path of the data file. 42581ad6265SDimitry Andric void SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 42681ad6265SDimitry Andric FileSpec file_spec); 42781ad6265SDimitry Andric 428fe6060f1SDimitry Andric /// Get binary data of a live thread given a data identifier. 429fe6060f1SDimitry Andric /// 430fe6060f1SDimitry Andric /// \param[in] tid 431fe6060f1SDimitry Andric /// The thread whose data is requested. 432fe6060f1SDimitry Andric /// 433fe6060f1SDimitry Andric /// \param[in] kind 434fe6060f1SDimitry Andric /// The kind of data requested. 435fe6060f1SDimitry Andric /// 436fe6060f1SDimitry Andric /// \return 437fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 438fe6060f1SDimitry Andric /// case of failures. 43981ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 440fe6060f1SDimitry Andric GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind); 441fe6060f1SDimitry Andric 44281ad6265SDimitry Andric /// Get binary data of a live cpu given a data identifier. 44381ad6265SDimitry Andric /// 44481ad6265SDimitry Andric /// \param[in] cpu_id 44581ad6265SDimitry Andric /// The cpu whose data is requested. 44681ad6265SDimitry Andric /// 44781ad6265SDimitry Andric /// \param[in] kind 44881ad6265SDimitry Andric /// The kind of data requested. 44981ad6265SDimitry Andric /// 45081ad6265SDimitry Andric /// \return 45181ad6265SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 45281ad6265SDimitry Andric /// case of failures. 45381ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 45481ad6265SDimitry Andric GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind); 45581ad6265SDimitry Andric 456fe6060f1SDimitry Andric /// Get binary data of the current process given a data identifier. 457fe6060f1SDimitry Andric /// 458fe6060f1SDimitry Andric /// \param[in] kind 459fe6060f1SDimitry Andric /// The kind of data requested. 460fe6060f1SDimitry Andric /// 461fe6060f1SDimitry Andric /// \return 462fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 463fe6060f1SDimitry Andric /// case of failures. 46481ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 465fe6060f1SDimitry Andric GetLiveProcessBinaryData(llvm::StringRef kind); 466fe6060f1SDimitry Andric 467fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveThreadBinaryData 468bdd1243dSDimitry Andric std::optional<uint64_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid, 46981ad6265SDimitry Andric llvm::StringRef kind); 47081ad6265SDimitry Andric 47181ad6265SDimitry Andric /// Get the size of the data returned by \a GetLiveCpuBinaryData 472bdd1243dSDimitry Andric std::optional<uint64_t> GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, 473fe6060f1SDimitry Andric llvm::StringRef kind); 474fe6060f1SDimitry Andric 475fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveProcessBinaryData 476bdd1243dSDimitry Andric std::optional<uint64_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind); 47781ad6265SDimitry Andric 478fe6060f1SDimitry Andric /// Constructor for post mortem processes 47981ad6265SDimitry Andric Trace(llvm::ArrayRef<lldb::ProcessSP> postmortem_processes, 480bdd1243dSDimitry Andric std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus); 481fe6060f1SDimitry Andric 482fe6060f1SDimitry Andric /// Constructor for a live process Trace(Process & live_process)483fe6060f1SDimitry Andric Trace(Process &live_process) : m_live_process(&live_process) {} 484fe6060f1SDimitry Andric 485fe6060f1SDimitry Andric /// Start tracing a live process or its threads. 486fe6060f1SDimitry Andric /// 487fe6060f1SDimitry Andric /// \param[in] request 488fe6060f1SDimitry Andric /// JSON object with the information necessary to start tracing. In the 489fe6060f1SDimitry Andric /// case of gdb-remote processes, this JSON object should conform to the 490fe6060f1SDimitry Andric /// jLLDBTraceStart packet. 491fe6060f1SDimitry Andric /// 492fe6060f1SDimitry Andric /// \return 493fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 494fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 495fe6060f1SDimitry Andric llvm::Error Start(const llvm::json::Value &request); 496fe6060f1SDimitry Andric 497fe6060f1SDimitry Andric /// Get the current tracing state of a live process and its threads. 498fe6060f1SDimitry Andric /// 499fe6060f1SDimitry Andric /// \return 500fe6060f1SDimitry Andric /// A JSON object string with custom data depending on the trace 501fe6060f1SDimitry Andric /// technology, or an \a llvm::Error in case of errors. 502fe6060f1SDimitry Andric llvm::Expected<std::string> GetLiveProcessState(); 503fe6060f1SDimitry Andric 504fe6060f1SDimitry Andric /// Method to be overriden by the plug-in to refresh its own state. 505fe6060f1SDimitry Andric /// 506fe6060f1SDimitry Andric /// This is invoked by RefreshLiveProcessState when a new state is found. 507fe6060f1SDimitry Andric /// 508fe6060f1SDimitry Andric /// \param[in] state 509fe6060f1SDimitry Andric /// The jLLDBTraceGetState response. 510fe6060f1SDimitry Andric /// 51181ad6265SDimitry Andric /// \param[in] json_response 51281ad6265SDimitry Andric /// The original JSON response as a string. It might be useful to redecode 51381ad6265SDimitry Andric /// it if it contains custom data for a specific trace plug-in. 51481ad6265SDimitry Andric /// 51581ad6265SDimitry Andric /// \return 51681ad6265SDimitry Andric /// \b Error::success() if this operation succeedes, or an actual error 51781ad6265SDimitry Andric /// otherwise. 51881ad6265SDimitry Andric virtual llvm::Error 51981ad6265SDimitry Andric DoRefreshLiveProcessState(TraceGetStateResponse state, 52081ad6265SDimitry Andric llvm::StringRef json_response) = 0; 521fe6060f1SDimitry Andric 52281ad6265SDimitry Andric /// Return the list of processes traced by this instance. None of the returned 52381ad6265SDimitry Andric /// pointers are invalid. 52481ad6265SDimitry Andric std::vector<Process *> GetTracedProcesses(); 52581ad6265SDimitry Andric 52681ad6265SDimitry Andric /// Method to be invoked by the plug-in to refresh the live process state. It 52781ad6265SDimitry Andric /// will invoked DoRefreshLiveProcessState at some point, which should be 52881ad6265SDimitry Andric /// implemented by the plug-in for custom state handling. 52981ad6265SDimitry Andric /// 53081ad6265SDimitry Andric /// The result is cached through the same process stop. Even in the case of 53181ad6265SDimitry Andric /// errors, it caches the error. 53281ad6265SDimitry Andric /// 53381ad6265SDimitry Andric /// \return 53481ad6265SDimitry Andric /// An error message if this operation failed, or \b nullptr otherwise. 53581ad6265SDimitry Andric const char *RefreshLiveProcessState(); 53681ad6265SDimitry Andric 53781ad6265SDimitry Andric private: 538fe6060f1SDimitry Andric uint32_t m_stop_id = LLDB_INVALID_STOP_ID; 53981ad6265SDimitry Andric 540fe6060f1SDimitry Andric /// Process traced by this object if doing live tracing. Otherwise it's null. 541fe6060f1SDimitry Andric Process *m_live_process = nullptr; 54281ad6265SDimitry Andric 54381ad6265SDimitry Andric /// We package all the data that can change upon process stops to make sure 54481ad6265SDimitry Andric /// this contract is very visible. 54581ad6265SDimitry Andric /// This variable should only be accessed directly by constructores or live 54681ad6265SDimitry Andric /// process data refreshers. 54781ad6265SDimitry Andric struct Storage { 54881ad6265SDimitry Andric /// Portmortem processes traced by this object if doing non-live tracing. 54981ad6265SDimitry Andric /// Otherwise it's empty. 55081ad6265SDimitry Andric std::vector<Process *> postmortem_processes; 55181ad6265SDimitry Andric 55281ad6265SDimitry Andric /// These data kinds are returned by lldb-server when fetching the state of 55381ad6265SDimitry Andric /// the tracing session. The size in bytes can be used later for fetching 55481ad6265SDimitry Andric /// the data in batches. 55581ad6265SDimitry Andric /// \{ 55681ad6265SDimitry Andric 557fe6060f1SDimitry Andric /// tid -> data kind -> size 55881ad6265SDimitry Andric llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, uint64_t>> 55981ad6265SDimitry Andric live_thread_data; 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric /// cpu id -> data kind -> size 56281ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, uint64_t>> 56381ad6265SDimitry Andric live_cpu_data_sizes; 56481ad6265SDimitry Andric /// cpu id -> data kind -> bytes 56581ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, 56681ad6265SDimitry Andric llvm::DenseMap<ConstString, std::vector<uint8_t>>> 56781ad6265SDimitry Andric live_cpu_data; 56881ad6265SDimitry Andric 569fe6060f1SDimitry Andric /// data kind -> size 57081ad6265SDimitry Andric llvm::DenseMap<ConstString, uint64_t> live_process_data; 57181ad6265SDimitry Andric /// \} 57281ad6265SDimitry Andric 57306c3fb27SDimitry Andric /// The list of cpus being traced. Might be \b std::nullopt depending on the 57481ad6265SDimitry Andric /// plug-in. 575bdd1243dSDimitry Andric std::optional<std::vector<lldb::cpu_id_t>> cpus; 57681ad6265SDimitry Andric 57781ad6265SDimitry Andric /// Postmortem traces can specific additional data files, which are 57881ad6265SDimitry Andric /// represented in this variable using a data kind identifier for each file. 57981ad6265SDimitry Andric /// \{ 58081ad6265SDimitry Andric 58181ad6265SDimitry Andric /// tid -> data kind -> file 58281ad6265SDimitry Andric llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, FileSpec>> 58381ad6265SDimitry Andric postmortem_thread_data; 58481ad6265SDimitry Andric 58581ad6265SDimitry Andric /// cpu id -> data kind -> file 58681ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, FileSpec>> 58781ad6265SDimitry Andric postmortem_cpu_data; 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric /// \} 59081ad6265SDimitry Andric 591bdd1243dSDimitry Andric std::optional<std::string> live_refresh_error; 59281ad6265SDimitry Andric } m_storage; 59381ad6265SDimitry Andric 59481ad6265SDimitry Andric /// Get the storage after refreshing the data in the case of a live process. 59581ad6265SDimitry Andric Storage &GetUpdatedStorage(); 596e8d8bef9SDimitry Andric }; 597e8d8bef9SDimitry Andric 598e8d8bef9SDimitry Andric } // namespace lldb_private 599e8d8bef9SDimitry Andric 600e8d8bef9SDimitry Andric #endif // LLDB_TARGET_TRACE_H 601