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 12fe6060f1SDimitry Andric #include <unordered_map> 13fe6060f1SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/Support/JSON.h" 15e8d8bef9SDimitry Andric 16e8d8bef9SDimitry Andric #include "lldb/Core/PluginInterface.h" 17fe6060f1SDimitry Andric #include "lldb/Target/Thread.h" 18fe6060f1SDimitry Andric #include "lldb/Target/TraceCursor.h" 19e8d8bef9SDimitry Andric #include "lldb/Utility/ArchSpec.h" 20fe6060f1SDimitry Andric #include "lldb/Utility/TraceGDBRemotePackets.h" 21e8d8bef9SDimitry Andric #include "lldb/Utility/UnimplementedError.h" 22e8d8bef9SDimitry Andric #include "lldb/lldb-private.h" 23*349cc55cSDimitry Andric #include "lldb/lldb-types.h" 24e8d8bef9SDimitry Andric 25e8d8bef9SDimitry Andric namespace lldb_private { 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric /// \class Trace Trace.h "lldb/Target/Trace.h" 28e8d8bef9SDimitry Andric /// A plug-in interface definition class for trace information. 29e8d8bef9SDimitry Andric /// 30e8d8bef9SDimitry Andric /// Trace plug-ins allow processor trace information to be loaded into LLDB so 31e8d8bef9SDimitry Andric /// that the data can be dumped, used for reverse and forward stepping to allow 32e8d8bef9SDimitry Andric /// introspection into the reason your process crashed or found its way to its 33e8d8bef9SDimitry Andric /// current state. 34e8d8bef9SDimitry Andric /// 35e8d8bef9SDimitry Andric /// Trace information can be loaded into a target without a process to allow 36e8d8bef9SDimitry Andric /// introspection of the trace information during post mortem analysis, such as 37e8d8bef9SDimitry Andric /// when loading core files. 38e8d8bef9SDimitry Andric /// 39e8d8bef9SDimitry Andric /// Processor trace information can also be fetched through the process 40e8d8bef9SDimitry Andric /// interfaces during a live debug session if your process supports gathering 41e8d8bef9SDimitry Andric /// this information. 42e8d8bef9SDimitry Andric /// 43e8d8bef9SDimitry Andric /// In order to support live tracing, the name of the plug-in should match the 44e8d8bef9SDimitry Andric /// name of the tracing type returned by the gdb-remote packet 45fe6060f1SDimitry Andric /// \a jLLDBTraceSupported. 46e8d8bef9SDimitry Andric class Trace : public PluginInterface, 47e8d8bef9SDimitry Andric public std::enable_shared_from_this<Trace> { 48e8d8bef9SDimitry Andric public: 49e8d8bef9SDimitry Andric /// Dump the trace data that this plug-in has access to. 50e8d8bef9SDimitry Andric /// 51e8d8bef9SDimitry Andric /// This function will dump all of the trace data for all threads in a user 52e8d8bef9SDimitry Andric /// readable format. Options for dumping can be added as this API is iterated 53e8d8bef9SDimitry Andric /// on. 54e8d8bef9SDimitry Andric /// 55e8d8bef9SDimitry Andric /// \param[in] s 56e8d8bef9SDimitry Andric /// A stream object to dump the information to. 57e8d8bef9SDimitry Andric virtual void Dump(Stream *s) const = 0; 58e8d8bef9SDimitry Andric 59*349cc55cSDimitry Andric /// Save the trace of a live process to the specified directory, which 60*349cc55cSDimitry Andric /// will be created if needed. 61*349cc55cSDimitry Andric /// This will also create a a file \a <directory>/trace.json with the main 62*349cc55cSDimitry Andric /// properties of the trace session, along with others files which contain 63*349cc55cSDimitry Andric /// the actual trace data. The trace.json file can be used later as input 64*349cc55cSDimitry Andric /// for the "trace load" command to load the trace in LLDB. 65*349cc55cSDimitry Andric /// The process being trace is not a live process, return an error. 66*349cc55cSDimitry Andric /// 67*349cc55cSDimitry Andric /// \param[in] directory 68*349cc55cSDimitry Andric /// The directory where the trace files will be saved. 69*349cc55cSDimitry Andric /// 70*349cc55cSDimitry Andric /// \return 71*349cc55cSDimitry Andric /// \a llvm::success if the operation was successful, or an \a llvm::Error 72*349cc55cSDimitry Andric /// otherwise. 73*349cc55cSDimitry Andric virtual llvm::Error SaveLiveTraceToDisk(FileSpec directory) = 0; 74*349cc55cSDimitry Andric 75e8d8bef9SDimitry Andric /// Find a trace plug-in using JSON data. 76e8d8bef9SDimitry Andric /// 77e8d8bef9SDimitry Andric /// When loading trace data from disk, the information for the trace data 78e8d8bef9SDimitry Andric /// can be contained in multiple files and require plug-in specific 79e8d8bef9SDimitry Andric /// information about the CPU. Using data like JSON provides an 80e8d8bef9SDimitry Andric /// easy way to specify all of the settings and information that we will need 81e8d8bef9SDimitry Andric /// to load trace data into LLDB. This structured data can include: 82e8d8bef9SDimitry Andric /// - The plug-in name (this allows a specific plug-in to be selected) 83e8d8bef9SDimitry Andric /// - Architecture or target triple 84e8d8bef9SDimitry Andric /// - one or more paths to the trace data file on disk 85e8d8bef9SDimitry Andric /// - core trace data 86e8d8bef9SDimitry Andric /// - thread events or related information 87e8d8bef9SDimitry Andric /// - shared library load information to use for this trace data that 88e8d8bef9SDimitry Andric /// allows a target to be created so the trace information can be 89e8d8bef9SDimitry Andric /// symbolicated so that the trace information can be displayed to the 90e8d8bef9SDimitry Andric /// user 91e8d8bef9SDimitry Andric /// - shared library path 92e8d8bef9SDimitry Andric /// - load address 93e8d8bef9SDimitry Andric /// - information on how to fetch the shared library 94e8d8bef9SDimitry Andric /// - path to locally cached file on disk 95e8d8bef9SDimitry Andric /// - URL to download the file 96e8d8bef9SDimitry Andric /// - Any information needed to load the trace file 97e8d8bef9SDimitry Andric /// - CPU information 98e8d8bef9SDimitry Andric /// - Custom plug-in information needed to decode the trace information 99e8d8bef9SDimitry Andric /// correctly. 100e8d8bef9SDimitry Andric /// 101e8d8bef9SDimitry Andric /// \param[in] debugger 102e8d8bef9SDimitry Andric /// The debugger instance where new Targets will be created as part of the 103e8d8bef9SDimitry Andric /// JSON data parsing. 104e8d8bef9SDimitry Andric /// 105e8d8bef9SDimitry Andric /// \param[in] trace_session_file 106e8d8bef9SDimitry Andric /// The contents of the trace session file describing the trace session. 107e8d8bef9SDimitry Andric /// See \a TraceSessionFileParser::BuildSchema for more information about 108e8d8bef9SDimitry Andric /// the schema of this JSON file. 109e8d8bef9SDimitry Andric /// 110e8d8bef9SDimitry Andric /// \param[in] session_file_dir 111e8d8bef9SDimitry Andric /// The path to the directory that contains the session file. It's used to 112e8d8bef9SDimitry Andric /// resolved relative paths in the session file. 113e8d8bef9SDimitry Andric static llvm::Expected<lldb::TraceSP> 114fe6060f1SDimitry Andric FindPluginForPostMortemProcess(Debugger &debugger, 115fe6060f1SDimitry Andric const llvm::json::Value &trace_session_file, 116e8d8bef9SDimitry Andric llvm::StringRef session_file_dir); 117e8d8bef9SDimitry Andric 118fe6060f1SDimitry Andric /// Find a trace plug-in to trace a live process. 119fe6060f1SDimitry Andric /// 120fe6060f1SDimitry Andric /// \param[in] plugin_name 121fe6060f1SDimitry Andric /// Plug-in name to search. 122fe6060f1SDimitry Andric /// 123fe6060f1SDimitry Andric /// \param[in] process 124fe6060f1SDimitry Andric /// Live process to trace. 125fe6060f1SDimitry Andric /// 126fe6060f1SDimitry Andric /// \return 127fe6060f1SDimitry Andric /// A \a TraceSP instance, or an \a llvm::Error if the plug-in name 128fe6060f1SDimitry Andric /// doesn't match any registered plug-ins or tracing couldn't be 129fe6060f1SDimitry Andric /// started. 130fe6060f1SDimitry Andric static llvm::Expected<lldb::TraceSP> 131fe6060f1SDimitry Andric FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process); 132fe6060f1SDimitry Andric 133e8d8bef9SDimitry Andric /// Get the schema of a Trace plug-in given its name. 134e8d8bef9SDimitry Andric /// 135e8d8bef9SDimitry Andric /// \param[in] plugin_name 136e8d8bef9SDimitry Andric /// Name of the trace plugin. 137e8d8bef9SDimitry Andric static llvm::Expected<llvm::StringRef> 138e8d8bef9SDimitry Andric FindPluginSchema(llvm::StringRef plugin_name); 139e8d8bef9SDimitry Andric 140fe6060f1SDimitry Andric /// Get the command handle for the "process trace start" command. 141fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 142fe6060f1SDimitry Andric GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0; 143fe6060f1SDimitry Andric 144fe6060f1SDimitry Andric /// Get the command handle for the "thread trace start" command. 145fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 146fe6060f1SDimitry Andric GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0; 147fe6060f1SDimitry Andric 148e8d8bef9SDimitry Andric /// \return 149e8d8bef9SDimitry Andric /// The JSON schema of this Trace plug-in. 150e8d8bef9SDimitry Andric virtual llvm::StringRef GetSchema() = 0; 151e8d8bef9SDimitry Andric 152fe6060f1SDimitry Andric /// Get a \a TraceCursor for the given thread's trace. 153e8d8bef9SDimitry Andric /// 154e8d8bef9SDimitry Andric /// \return 155fe6060f1SDimitry Andric /// A \a TraceCursorUP. If the thread is not traced or its trace 156fe6060f1SDimitry Andric /// information failed to load, the corresponding error is embedded in the 157fe6060f1SDimitry Andric /// trace. 158fe6060f1SDimitry Andric virtual lldb::TraceCursorUP GetCursor(Thread &thread) = 0; 159e8d8bef9SDimitry Andric 160fe6060f1SDimitry Andric /// Dump general info about a given thread's trace. Each Trace plug-in 161fe6060f1SDimitry Andric /// decides which data to show. 162e8d8bef9SDimitry Andric /// 163e8d8bef9SDimitry Andric /// \param[in] thread 164fe6060f1SDimitry Andric /// The thread that owns the trace in question. 165e8d8bef9SDimitry Andric /// 166e8d8bef9SDimitry Andric /// \param[in] s 167fe6060f1SDimitry Andric /// The stream object where the info will be printed printed. 168e8d8bef9SDimitry Andric /// 169fe6060f1SDimitry Andric /// \param[in] verbose 170fe6060f1SDimitry Andric /// If \b true, print detailed info 171fe6060f1SDimitry Andric /// If \b false, print compact info 172fe6060f1SDimitry Andric virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) = 0; 173fe6060f1SDimitry Andric 174fe6060f1SDimitry Andric /// Check if a thread is currently traced by this object. 175e8d8bef9SDimitry Andric /// 176*349cc55cSDimitry Andric /// \param[in] tid 177*349cc55cSDimitry Andric /// The id of the thread in question. 178e8d8bef9SDimitry Andric /// 179fe6060f1SDimitry Andric /// \return 180fe6060f1SDimitry Andric /// \b true if the thread is traced by this instance, \b false otherwise. 181*349cc55cSDimitry Andric virtual bool IsTraced(lldb::tid_t tid) = 0; 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric /// \return 184fe6060f1SDimitry Andric /// A description of the parameters to use for the \a Trace::Start method. 185fe6060f1SDimitry Andric virtual const char *GetStartConfigurationHelp() = 0; 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric /// Start tracing a live process. 188fe6060f1SDimitry Andric /// 189fe6060f1SDimitry Andric /// \param[in] configuration 190fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBStructuredData &) for more 191e8d8bef9SDimitry Andric /// information. 192e8d8bef9SDimitry Andric /// 193e8d8bef9SDimitry Andric /// \return 194fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 195fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 196fe6060f1SDimitry Andric virtual llvm::Error Start( 197fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 198e8d8bef9SDimitry Andric 199fe6060f1SDimitry Andric /// Start tracing live threads. 200e8d8bef9SDimitry Andric /// 201fe6060f1SDimitry Andric /// \param[in] tids 202fe6060f1SDimitry Andric /// Threads to trace. This method tries to trace as many threads as 203fe6060f1SDimitry Andric /// possible. 204fe6060f1SDimitry Andric /// 205fe6060f1SDimitry Andric /// \param[in] configuration 206fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBThread &, const 207fe6060f1SDimitry Andric /// lldb::SBStructuredData &) for more information. 208e8d8bef9SDimitry Andric /// 209e8d8bef9SDimitry Andric /// \return 210fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 211fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 212fe6060f1SDimitry Andric virtual llvm::Error Start( 213fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids, 214fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 215fe6060f1SDimitry Andric 216fe6060f1SDimitry Andric /// Stop tracing live threads. 217fe6060f1SDimitry Andric /// 218fe6060f1SDimitry Andric /// \param[in] tids 219fe6060f1SDimitry Andric /// The threads to stop tracing on. 220fe6060f1SDimitry Andric /// 221fe6060f1SDimitry Andric /// \return 222fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 223fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 224fe6060f1SDimitry Andric llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids); 225fe6060f1SDimitry Andric 226fe6060f1SDimitry Andric /// Stop tracing all current and future threads of a live process. 227fe6060f1SDimitry Andric /// 228fe6060f1SDimitry Andric /// \param[in] request 229fe6060f1SDimitry Andric /// The information determining which threads or process to stop tracing. 230fe6060f1SDimitry Andric /// 231fe6060f1SDimitry Andric /// \return 232fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 233fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 234fe6060f1SDimitry Andric llvm::Error Stop(); 235fe6060f1SDimitry Andric 236fe6060f1SDimitry Andric /// Get the trace file of the given post mortem thread. 237fe6060f1SDimitry Andric llvm::Expected<const FileSpec &> GetPostMortemTraceFile(lldb::tid_t tid); 238fe6060f1SDimitry Andric 239fe6060f1SDimitry Andric /// \return 240fe6060f1SDimitry Andric /// The stop ID of the live process being traced, or an invalid stop ID 241fe6060f1SDimitry Andric /// if the trace is in an error or invalid state. 242fe6060f1SDimitry Andric uint32_t GetStopID(); 243fe6060f1SDimitry Andric 244fe6060f1SDimitry Andric protected: 245fe6060f1SDimitry Andric /// Get binary data of a live thread given a data identifier. 246fe6060f1SDimitry Andric /// 247fe6060f1SDimitry Andric /// \param[in] tid 248fe6060f1SDimitry Andric /// The thread whose data is requested. 249fe6060f1SDimitry Andric /// 250fe6060f1SDimitry Andric /// \param[in] kind 251fe6060f1SDimitry Andric /// The kind of data requested. 252fe6060f1SDimitry Andric /// 253fe6060f1SDimitry Andric /// \return 254fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 255fe6060f1SDimitry Andric /// case of failures. 256fe6060f1SDimitry Andric llvm::Expected<llvm::ArrayRef<uint8_t>> 257fe6060f1SDimitry Andric GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind); 258fe6060f1SDimitry Andric 259fe6060f1SDimitry Andric /// Get binary data of the current process given a data identifier. 260fe6060f1SDimitry Andric /// 261fe6060f1SDimitry Andric /// \param[in] kind 262fe6060f1SDimitry Andric /// The kind of data requested. 263fe6060f1SDimitry Andric /// 264fe6060f1SDimitry Andric /// \return 265fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 266fe6060f1SDimitry Andric /// case of failures. 267fe6060f1SDimitry Andric llvm::Expected<llvm::ArrayRef<uint8_t>> 268fe6060f1SDimitry Andric GetLiveProcessBinaryData(llvm::StringRef kind); 269fe6060f1SDimitry Andric 270fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveThreadBinaryData 271fe6060f1SDimitry Andric llvm::Optional<size_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid, 272fe6060f1SDimitry Andric llvm::StringRef kind); 273fe6060f1SDimitry Andric 274fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveProcessBinaryData 275fe6060f1SDimitry Andric llvm::Optional<size_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind); 276fe6060f1SDimitry Andric /// Constructor for post mortem processes 277fe6060f1SDimitry Andric Trace() = default; 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric /// Constructor for a live process 280fe6060f1SDimitry Andric Trace(Process &live_process) : m_live_process(&live_process) {} 281fe6060f1SDimitry Andric 282fe6060f1SDimitry Andric /// Start tracing a live process or its threads. 283fe6060f1SDimitry Andric /// 284fe6060f1SDimitry Andric /// \param[in] request 285fe6060f1SDimitry Andric /// JSON object with the information necessary to start tracing. In the 286fe6060f1SDimitry Andric /// case of gdb-remote processes, this JSON object should conform to the 287fe6060f1SDimitry Andric /// jLLDBTraceStart packet. 288fe6060f1SDimitry Andric /// 289fe6060f1SDimitry Andric /// \return 290fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 291fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 292fe6060f1SDimitry Andric llvm::Error Start(const llvm::json::Value &request); 293fe6060f1SDimitry Andric 294fe6060f1SDimitry Andric /// Get the current tracing state of a live process and its threads. 295fe6060f1SDimitry Andric /// 296fe6060f1SDimitry Andric /// \return 297fe6060f1SDimitry Andric /// A JSON object string with custom data depending on the trace 298fe6060f1SDimitry Andric /// technology, or an \a llvm::Error in case of errors. 299fe6060f1SDimitry Andric llvm::Expected<std::string> GetLiveProcessState(); 300fe6060f1SDimitry Andric 301fe6060f1SDimitry Andric /// Method to be overriden by the plug-in to refresh its own state. 302fe6060f1SDimitry Andric /// 303fe6060f1SDimitry Andric /// This is invoked by RefreshLiveProcessState when a new state is found. 304fe6060f1SDimitry Andric /// 305fe6060f1SDimitry Andric /// \param[in] state 306fe6060f1SDimitry Andric /// The jLLDBTraceGetState response. 307fe6060f1SDimitry Andric virtual void 308fe6060f1SDimitry Andric DoRefreshLiveProcessState(llvm::Expected<TraceGetStateResponse> state) = 0; 309fe6060f1SDimitry Andric 310fe6060f1SDimitry Andric /// Method to be invoked by the plug-in to refresh the live process state. 311fe6060f1SDimitry Andric /// 312fe6060f1SDimitry Andric /// The result is cached through the same process stop. 313fe6060f1SDimitry Andric void RefreshLiveProcessState(); 314fe6060f1SDimitry Andric 315fe6060f1SDimitry Andric uint32_t m_stop_id = LLDB_INVALID_STOP_ID; 316fe6060f1SDimitry Andric /// Process traced by this object if doing live tracing. Otherwise it's null. 317fe6060f1SDimitry Andric Process *m_live_process = nullptr; 318fe6060f1SDimitry Andric /// tid -> data kind -> size 319fe6060f1SDimitry Andric std::map<lldb::tid_t, std::unordered_map<std::string, size_t>> 320fe6060f1SDimitry Andric m_live_thread_data; 321fe6060f1SDimitry Andric /// data kind -> size 322fe6060f1SDimitry Andric std::unordered_map<std::string, size_t> m_live_process_data; 323e8d8bef9SDimitry Andric }; 324e8d8bef9SDimitry Andric 325e8d8bef9SDimitry Andric } // namespace lldb_private 326e8d8bef9SDimitry Andric 327e8d8bef9SDimitry Andric #endif // LLDB_TARGET_TRACE_H 328