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" 23349cc55cSDimitry 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 59349cc55cSDimitry Andric /// Save the trace of a live process to the specified directory, which 60349cc55cSDimitry Andric /// will be created if needed. 61349cc55cSDimitry Andric /// This will also create a a file \a <directory>/trace.json with the main 62349cc55cSDimitry Andric /// properties of the trace session, along with others files which contain 63349cc55cSDimitry Andric /// the actual trace data. The trace.json file can be used later as input 64349cc55cSDimitry Andric /// for the "trace load" command to load the trace in LLDB. 65349cc55cSDimitry Andric /// The process being trace is not a live process, return an error. 66349cc55cSDimitry Andric /// 67349cc55cSDimitry Andric /// \param[in] directory 68349cc55cSDimitry Andric /// The directory where the trace files will be saved. 69349cc55cSDimitry Andric /// 70349cc55cSDimitry Andric /// \return 71349cc55cSDimitry Andric /// \a llvm::success if the operation was successful, or an \a llvm::Error 72349cc55cSDimitry Andric /// otherwise. 73349cc55cSDimitry Andric virtual llvm::Error SaveLiveTraceToDisk(FileSpec directory) = 0; 74349cc55cSDimitry 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 85*81ad6265SDimitry Andric /// - cpu 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 /// 105*81ad6265SDimitry Andric /// \param[in] bundle_description 106*81ad6265SDimitry Andric /// The trace bundle description object describing the trace session. 107e8d8bef9SDimitry Andric /// 108*81ad6265SDimitry Andric /// \param[in] bundle_dir 109*81ad6265SDimitry Andric /// The path to the directory that contains the trace bundle. 110e8d8bef9SDimitry Andric static llvm::Expected<lldb::TraceSP> 111fe6060f1SDimitry Andric FindPluginForPostMortemProcess(Debugger &debugger, 112*81ad6265SDimitry Andric const llvm::json::Value &bundle_description, 113e8d8bef9SDimitry Andric llvm::StringRef session_file_dir); 114e8d8bef9SDimitry Andric 115fe6060f1SDimitry Andric /// Find a trace plug-in to trace a live process. 116fe6060f1SDimitry Andric /// 117fe6060f1SDimitry Andric /// \param[in] plugin_name 118fe6060f1SDimitry Andric /// Plug-in name to search. 119fe6060f1SDimitry Andric /// 120fe6060f1SDimitry Andric /// \param[in] process 121fe6060f1SDimitry Andric /// Live process to trace. 122fe6060f1SDimitry Andric /// 123fe6060f1SDimitry Andric /// \return 124fe6060f1SDimitry Andric /// A \a TraceSP instance, or an \a llvm::Error if the plug-in name 125fe6060f1SDimitry Andric /// doesn't match any registered plug-ins or tracing couldn't be 126fe6060f1SDimitry Andric /// started. 127fe6060f1SDimitry Andric static llvm::Expected<lldb::TraceSP> 128fe6060f1SDimitry Andric FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process); 129fe6060f1SDimitry Andric 130e8d8bef9SDimitry Andric /// Get the schema of a Trace plug-in given its name. 131e8d8bef9SDimitry Andric /// 132e8d8bef9SDimitry Andric /// \param[in] plugin_name 133e8d8bef9SDimitry Andric /// Name of the trace plugin. 134e8d8bef9SDimitry Andric static llvm::Expected<llvm::StringRef> 135e8d8bef9SDimitry Andric FindPluginSchema(llvm::StringRef plugin_name); 136e8d8bef9SDimitry Andric 137*81ad6265SDimitry Andric /// Load a trace from a trace description file and create Targets, 138*81ad6265SDimitry Andric /// Processes and Threads based on the contents of such file. 139*81ad6265SDimitry Andric /// 140*81ad6265SDimitry Andric /// \param[in] debugger 141*81ad6265SDimitry Andric /// The debugger instance where new Targets will be created as part of the 142*81ad6265SDimitry Andric /// JSON data parsing. 143*81ad6265SDimitry Andric /// 144*81ad6265SDimitry Andric /// \param[in] trace_description_file 145*81ad6265SDimitry Andric /// The file containing the necessary information to load the trace. 146*81ad6265SDimitry Andric /// 147*81ad6265SDimitry Andric /// \return 148*81ad6265SDimitry Andric /// A \a TraceSP instance, or an \a llvm::Error if loading the trace 149*81ad6265SDimitry Andric /// fails. 150*81ad6265SDimitry Andric static llvm::Expected<lldb::TraceSP> 151*81ad6265SDimitry Andric LoadPostMortemTraceFromFile(Debugger &debugger, 152*81ad6265SDimitry Andric const FileSpec &trace_description_file); 153*81ad6265SDimitry Andric 154fe6060f1SDimitry Andric /// Get the command handle for the "process trace start" command. 155fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 156fe6060f1SDimitry Andric GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0; 157fe6060f1SDimitry Andric 158fe6060f1SDimitry Andric /// Get the command handle for the "thread trace start" command. 159fe6060f1SDimitry Andric virtual lldb::CommandObjectSP 160fe6060f1SDimitry Andric GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0; 161fe6060f1SDimitry Andric 162e8d8bef9SDimitry Andric /// \return 163e8d8bef9SDimitry Andric /// The JSON schema of this Trace plug-in. 164e8d8bef9SDimitry Andric virtual llvm::StringRef GetSchema() = 0; 165e8d8bef9SDimitry Andric 166fe6060f1SDimitry Andric /// Get a \a TraceCursor for the given thread's trace. 167e8d8bef9SDimitry Andric /// 168e8d8bef9SDimitry Andric /// \return 169fe6060f1SDimitry Andric /// A \a TraceCursorUP. If the thread is not traced or its trace 170*81ad6265SDimitry Andric /// information failed to load, an \a llvm::Error is returned. 171*81ad6265SDimitry Andric virtual llvm::Expected<lldb::TraceCursorUP> 172*81ad6265SDimitry Andric CreateNewCursor(Thread &thread) = 0; 173e8d8bef9SDimitry Andric 174fe6060f1SDimitry Andric /// Dump general info about a given thread's trace. Each Trace plug-in 175fe6060f1SDimitry Andric /// decides which data to show. 176e8d8bef9SDimitry Andric /// 177e8d8bef9SDimitry Andric /// \param[in] thread 178fe6060f1SDimitry Andric /// The thread that owns the trace in question. 179e8d8bef9SDimitry Andric /// 180e8d8bef9SDimitry Andric /// \param[in] s 181fe6060f1SDimitry Andric /// The stream object where the info will be printed printed. 182e8d8bef9SDimitry Andric /// 183fe6060f1SDimitry Andric /// \param[in] verbose 184fe6060f1SDimitry Andric /// If \b true, print detailed info 185fe6060f1SDimitry Andric /// If \b false, print compact info 186fe6060f1SDimitry Andric virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) = 0; 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric /// Check if a thread is currently traced by this object. 189e8d8bef9SDimitry Andric /// 190349cc55cSDimitry Andric /// \param[in] tid 191349cc55cSDimitry Andric /// The id of the thread in question. 192e8d8bef9SDimitry Andric /// 193fe6060f1SDimitry Andric /// \return 194fe6060f1SDimitry Andric /// \b true if the thread is traced by this instance, \b false otherwise. 195349cc55cSDimitry Andric virtual bool IsTraced(lldb::tid_t tid) = 0; 196fe6060f1SDimitry Andric 197fe6060f1SDimitry Andric /// \return 198fe6060f1SDimitry Andric /// A description of the parameters to use for the \a Trace::Start method. 199fe6060f1SDimitry Andric virtual const char *GetStartConfigurationHelp() = 0; 200fe6060f1SDimitry Andric 201fe6060f1SDimitry Andric /// Start tracing a live process. 202fe6060f1SDimitry Andric /// 203fe6060f1SDimitry Andric /// \param[in] configuration 204fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBStructuredData &) for more 205e8d8bef9SDimitry Andric /// information. 206e8d8bef9SDimitry Andric /// 207e8d8bef9SDimitry Andric /// \return 208fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 209fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 210fe6060f1SDimitry Andric virtual llvm::Error Start( 211fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 212e8d8bef9SDimitry Andric 213fe6060f1SDimitry Andric /// Start tracing live threads. 214e8d8bef9SDimitry Andric /// 215fe6060f1SDimitry Andric /// \param[in] tids 216fe6060f1SDimitry Andric /// Threads to trace. This method tries to trace as many threads as 217fe6060f1SDimitry Andric /// possible. 218fe6060f1SDimitry Andric /// 219fe6060f1SDimitry Andric /// \param[in] configuration 220fe6060f1SDimitry Andric /// See \a SBTrace::Start(const lldb::SBThread &, const 221fe6060f1SDimitry Andric /// lldb::SBStructuredData &) for more information. 222e8d8bef9SDimitry Andric /// 223e8d8bef9SDimitry Andric /// \return 224fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 225fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 226fe6060f1SDimitry Andric virtual llvm::Error Start( 227fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids, 228fe6060f1SDimitry Andric StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric /// Stop tracing live threads. 231fe6060f1SDimitry Andric /// 232fe6060f1SDimitry Andric /// \param[in] tids 233fe6060f1SDimitry Andric /// The threads to stop tracing on. 234fe6060f1SDimitry Andric /// 235fe6060f1SDimitry Andric /// \return 236fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 237fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 238fe6060f1SDimitry Andric llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids); 239fe6060f1SDimitry Andric 240fe6060f1SDimitry Andric /// Stop tracing all current and future threads of a live process. 241fe6060f1SDimitry Andric /// 242fe6060f1SDimitry Andric /// \param[in] request 243fe6060f1SDimitry Andric /// The information determining which threads or process to stop tracing. 244fe6060f1SDimitry Andric /// 245fe6060f1SDimitry Andric /// \return 246fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 247fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 248fe6060f1SDimitry Andric llvm::Error Stop(); 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric /// \return 251fe6060f1SDimitry Andric /// The stop ID of the live process being traced, or an invalid stop ID 252fe6060f1SDimitry Andric /// if the trace is in an error or invalid state. 253fe6060f1SDimitry Andric uint32_t GetStopID(); 254fe6060f1SDimitry Andric 255*81ad6265SDimitry Andric using OnBinaryDataReadCallback = 256*81ad6265SDimitry Andric std::function<llvm::Error(llvm::ArrayRef<uint8_t> data)>; 257*81ad6265SDimitry Andric using OnCpusBinaryDataReadCallback = std::function<llvm::Error( 258*81ad6265SDimitry Andric const llvm::DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>> 259*81ad6265SDimitry Andric &cpu_to_data)>; 260*81ad6265SDimitry Andric 261*81ad6265SDimitry Andric /// Fetch binary data associated with a thread, either live or postmortem, and 262*81ad6265SDimitry Andric /// pass it to the given callback. The reason of having a callback is to free 263*81ad6265SDimitry Andric /// the caller from having to manage the life cycle of the data and to hide 264*81ad6265SDimitry Andric /// the different data fetching procedures that exist for live and post mortem 265*81ad6265SDimitry Andric /// threads. 266*81ad6265SDimitry Andric /// 267*81ad6265SDimitry Andric /// The fetched data is not persisted after the callback is invoked. 268*81ad6265SDimitry Andric /// 269*81ad6265SDimitry Andric /// \param[in] tid 270*81ad6265SDimitry Andric /// The tid who owns the data. 271*81ad6265SDimitry Andric /// 272*81ad6265SDimitry Andric /// \param[in] kind 273*81ad6265SDimitry Andric /// The kind of data to read. 274*81ad6265SDimitry Andric /// 275*81ad6265SDimitry Andric /// \param[in] callback 276*81ad6265SDimitry Andric /// The callback to be invoked once the data was successfully read. Its 277*81ad6265SDimitry Andric /// return value, which is an \a llvm::Error, is returned by this 278*81ad6265SDimitry Andric /// function. 279*81ad6265SDimitry Andric /// 280*81ad6265SDimitry Andric /// \return 281*81ad6265SDimitry Andric /// An \a llvm::Error if the data couldn't be fetched, or the return value 282*81ad6265SDimitry Andric /// of the callback, otherwise. 283*81ad6265SDimitry Andric llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 284*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 285*81ad6265SDimitry Andric 286*81ad6265SDimitry Andric /// Fetch binary data associated with a cpu, either live or postmortem, and 287*81ad6265SDimitry Andric /// pass it to the given callback. The reason of having a callback is to free 288*81ad6265SDimitry Andric /// the caller from having to manage the life cycle of the data and to hide 289*81ad6265SDimitry Andric /// the different data fetching procedures that exist for live and post mortem 290*81ad6265SDimitry Andric /// cpus. 291*81ad6265SDimitry Andric /// 292*81ad6265SDimitry Andric /// The fetched data is not persisted after the callback is invoked. 293*81ad6265SDimitry Andric /// 294*81ad6265SDimitry Andric /// \param[in] cpu_id 295*81ad6265SDimitry Andric /// The cpu who owns the data. 296*81ad6265SDimitry Andric /// 297*81ad6265SDimitry Andric /// \param[in] kind 298*81ad6265SDimitry Andric /// The kind of data to read. 299*81ad6265SDimitry Andric /// 300*81ad6265SDimitry Andric /// \param[in] callback 301*81ad6265SDimitry Andric /// The callback to be invoked once the data was successfully read. Its 302*81ad6265SDimitry Andric /// return value, which is an \a llvm::Error, is returned by this 303*81ad6265SDimitry Andric /// function. 304*81ad6265SDimitry Andric /// 305*81ad6265SDimitry Andric /// \return 306*81ad6265SDimitry Andric /// An \a llvm::Error if the data couldn't be fetched, or the return value 307*81ad6265SDimitry Andric /// of the callback, otherwise. 308*81ad6265SDimitry Andric llvm::Error OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 309*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 310*81ad6265SDimitry Andric 311*81ad6265SDimitry Andric /// Similar to \a OnCpuBinaryDataRead but this is able to fetch the same data 312*81ad6265SDimitry Andric /// from all cpus at once. 313*81ad6265SDimitry Andric llvm::Error OnAllCpusBinaryDataRead(llvm::StringRef kind, 314*81ad6265SDimitry Andric OnCpusBinaryDataReadCallback callback); 315*81ad6265SDimitry Andric 316*81ad6265SDimitry Andric /// \return 317*81ad6265SDimitry Andric /// All the currently traced processes. 318*81ad6265SDimitry Andric std::vector<Process *> GetAllProcesses(); 319*81ad6265SDimitry Andric 320*81ad6265SDimitry Andric /// \return 321*81ad6265SDimitry Andric /// The list of cpus being traced. Might be empty depending on the 322*81ad6265SDimitry Andric /// plugin. 323*81ad6265SDimitry Andric llvm::ArrayRef<lldb::cpu_id_t> GetTracedCpus(); 324*81ad6265SDimitry Andric 325*81ad6265SDimitry Andric /// Helper method for reading a data file and passing its data to the given 326*81ad6265SDimitry Andric /// callback. 327*81ad6265SDimitry Andric static llvm::Error OnDataFileRead(FileSpec file, 328*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 329*81ad6265SDimitry Andric 330fe6060f1SDimitry Andric protected: 331*81ad6265SDimitry Andric /// Get the currently traced live process. 332*81ad6265SDimitry Andric /// 333*81ad6265SDimitry Andric /// \return 334*81ad6265SDimitry Andric /// If it's not a live process, return \a nullptr. 335*81ad6265SDimitry Andric Process *GetLiveProcess(); 336*81ad6265SDimitry Andric 337*81ad6265SDimitry Andric /// Get the currently traced postmortem processes. 338*81ad6265SDimitry Andric /// 339*81ad6265SDimitry Andric /// \return 340*81ad6265SDimitry Andric /// If it's not a live process session, return an empty list. 341*81ad6265SDimitry Andric llvm::ArrayRef<Process *> GetPostMortemProcesses(); 342*81ad6265SDimitry Andric 343*81ad6265SDimitry Andric /// Dispatcher for live trace data requests with some additional error 344*81ad6265SDimitry Andric /// checking. 345*81ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 346*81ad6265SDimitry Andric GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request, 347*81ad6265SDimitry Andric uint64_t expected_size); 348*81ad6265SDimitry Andric 349*81ad6265SDimitry Andric /// Implementation of \a OnThreadBinaryDataRead() for live threads. 350*81ad6265SDimitry Andric llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 351*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 352*81ad6265SDimitry Andric 353*81ad6265SDimitry Andric /// Implementation of \a OnLiveBinaryDataRead() for live cpus. 354*81ad6265SDimitry Andric llvm::Error OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu, llvm::StringRef kind, 355*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 356*81ad6265SDimitry Andric 357*81ad6265SDimitry Andric /// Implementation of \a OnThreadBinaryDataRead() for post mortem threads. 358*81ad6265SDimitry Andric llvm::Error 359*81ad6265SDimitry Andric OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, 360*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 361*81ad6265SDimitry Andric 362*81ad6265SDimitry Andric /// Implementation of \a OnCpuBinaryDataRead() for post mortem cpus. 363*81ad6265SDimitry Andric llvm::Error OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id, 364*81ad6265SDimitry Andric llvm::StringRef kind, 365*81ad6265SDimitry Andric OnBinaryDataReadCallback callback); 366*81ad6265SDimitry Andric 367*81ad6265SDimitry Andric /// Get the file path containing data of a postmortem thread given a data 368*81ad6265SDimitry Andric /// identifier. 369*81ad6265SDimitry Andric /// 370*81ad6265SDimitry Andric /// \param[in] tid 371*81ad6265SDimitry Andric /// The thread whose data is requested. 372*81ad6265SDimitry Andric /// 373*81ad6265SDimitry Andric /// \param[in] kind 374*81ad6265SDimitry Andric /// The kind of data requested. 375*81ad6265SDimitry Andric /// 376*81ad6265SDimitry Andric /// \return 377*81ad6265SDimitry Andric /// The file spec containing the requested data, or an \a llvm::Error in 378*81ad6265SDimitry Andric /// case of failures. 379*81ad6265SDimitry Andric llvm::Expected<FileSpec> GetPostMortemThreadDataFile(lldb::tid_t tid, 380*81ad6265SDimitry Andric llvm::StringRef kind); 381*81ad6265SDimitry Andric 382*81ad6265SDimitry Andric /// Get the file path containing data of a postmortem cpu given a data 383*81ad6265SDimitry Andric /// identifier. 384*81ad6265SDimitry Andric /// 385*81ad6265SDimitry Andric /// \param[in] cpu_id 386*81ad6265SDimitry Andric /// The cpu whose data is requested. 387*81ad6265SDimitry Andric /// 388*81ad6265SDimitry Andric /// \param[in] kind 389*81ad6265SDimitry Andric /// The kind of data requested. 390*81ad6265SDimitry Andric /// 391*81ad6265SDimitry Andric /// \return 392*81ad6265SDimitry Andric /// The file spec containing the requested data, or an \a llvm::Error in 393*81ad6265SDimitry Andric /// case of failures. 394*81ad6265SDimitry Andric llvm::Expected<FileSpec> GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, 395*81ad6265SDimitry Andric llvm::StringRef kind); 396*81ad6265SDimitry Andric 397*81ad6265SDimitry Andric /// Associate a given thread with a data file using a data identifier. 398*81ad6265SDimitry Andric /// 399*81ad6265SDimitry Andric /// \param[in] tid 400*81ad6265SDimitry Andric /// The thread associated with the data file. 401*81ad6265SDimitry Andric /// 402*81ad6265SDimitry Andric /// \param[in] kind 403*81ad6265SDimitry Andric /// The kind of data being registered. 404*81ad6265SDimitry Andric /// 405*81ad6265SDimitry Andric /// \param[in] file_spec 406*81ad6265SDimitry Andric /// The path of the data file. 407*81ad6265SDimitry Andric void SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind, 408*81ad6265SDimitry Andric FileSpec file_spec); 409*81ad6265SDimitry Andric 410*81ad6265SDimitry Andric /// Associate a given cpu with a data file using a data identifier. 411*81ad6265SDimitry Andric /// 412*81ad6265SDimitry Andric /// \param[in] cpu_id 413*81ad6265SDimitry Andric /// The cpu associated with the data file. 414*81ad6265SDimitry Andric /// 415*81ad6265SDimitry Andric /// \param[in] kind 416*81ad6265SDimitry Andric /// The kind of data being registered. 417*81ad6265SDimitry Andric /// 418*81ad6265SDimitry Andric /// \param[in] file_spec 419*81ad6265SDimitry Andric /// The path of the data file. 420*81ad6265SDimitry Andric void SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, llvm::StringRef kind, 421*81ad6265SDimitry Andric FileSpec file_spec); 422*81ad6265SDimitry Andric 423fe6060f1SDimitry Andric /// Get binary data of a live thread given a data identifier. 424fe6060f1SDimitry Andric /// 425fe6060f1SDimitry Andric /// \param[in] tid 426fe6060f1SDimitry Andric /// The thread whose data is requested. 427fe6060f1SDimitry Andric /// 428fe6060f1SDimitry Andric /// \param[in] kind 429fe6060f1SDimitry Andric /// The kind of data requested. 430fe6060f1SDimitry Andric /// 431fe6060f1SDimitry Andric /// \return 432fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 433fe6060f1SDimitry Andric /// case of failures. 434*81ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 435fe6060f1SDimitry Andric GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind); 436fe6060f1SDimitry Andric 437*81ad6265SDimitry Andric /// Get binary data of a live cpu given a data identifier. 438*81ad6265SDimitry Andric /// 439*81ad6265SDimitry Andric /// \param[in] cpu_id 440*81ad6265SDimitry Andric /// The cpu whose data is requested. 441*81ad6265SDimitry Andric /// 442*81ad6265SDimitry Andric /// \param[in] kind 443*81ad6265SDimitry Andric /// The kind of data requested. 444*81ad6265SDimitry Andric /// 445*81ad6265SDimitry Andric /// \return 446*81ad6265SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 447*81ad6265SDimitry Andric /// case of failures. 448*81ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 449*81ad6265SDimitry Andric GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind); 450*81ad6265SDimitry Andric 451fe6060f1SDimitry Andric /// Get binary data of the current process given a data identifier. 452fe6060f1SDimitry Andric /// 453fe6060f1SDimitry Andric /// \param[in] kind 454fe6060f1SDimitry Andric /// The kind of data requested. 455fe6060f1SDimitry Andric /// 456fe6060f1SDimitry Andric /// \return 457fe6060f1SDimitry Andric /// A vector of bytes with the requested data, or an \a llvm::Error in 458fe6060f1SDimitry Andric /// case of failures. 459*81ad6265SDimitry Andric llvm::Expected<std::vector<uint8_t>> 460fe6060f1SDimitry Andric GetLiveProcessBinaryData(llvm::StringRef kind); 461fe6060f1SDimitry Andric 462fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveThreadBinaryData 463*81ad6265SDimitry Andric llvm::Optional<uint64_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid, 464*81ad6265SDimitry Andric llvm::StringRef kind); 465*81ad6265SDimitry Andric 466*81ad6265SDimitry Andric /// Get the size of the data returned by \a GetLiveCpuBinaryData 467*81ad6265SDimitry Andric llvm::Optional<uint64_t> GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id, 468fe6060f1SDimitry Andric llvm::StringRef kind); 469fe6060f1SDimitry Andric 470fe6060f1SDimitry Andric /// Get the size of the data returned by \a GetLiveProcessBinaryData 471*81ad6265SDimitry Andric llvm::Optional<uint64_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind); 472*81ad6265SDimitry Andric 473fe6060f1SDimitry Andric /// Constructor for post mortem processes 474*81ad6265SDimitry Andric Trace(llvm::ArrayRef<lldb::ProcessSP> postmortem_processes, 475*81ad6265SDimitry Andric llvm::Optional<std::vector<lldb::cpu_id_t>> postmortem_cpus); 476fe6060f1SDimitry Andric 477fe6060f1SDimitry Andric /// Constructor for a live process 478fe6060f1SDimitry Andric Trace(Process &live_process) : m_live_process(&live_process) {} 479fe6060f1SDimitry Andric 480fe6060f1SDimitry Andric /// Start tracing a live process or its threads. 481fe6060f1SDimitry Andric /// 482fe6060f1SDimitry Andric /// \param[in] request 483fe6060f1SDimitry Andric /// JSON object with the information necessary to start tracing. In the 484fe6060f1SDimitry Andric /// case of gdb-remote processes, this JSON object should conform to the 485fe6060f1SDimitry Andric /// jLLDBTraceStart packet. 486fe6060f1SDimitry Andric /// 487fe6060f1SDimitry Andric /// \return 488fe6060f1SDimitry Andric /// \a llvm::Error::success if the operation was successful, or 489fe6060f1SDimitry Andric /// \a llvm::Error otherwise. 490fe6060f1SDimitry Andric llvm::Error Start(const llvm::json::Value &request); 491fe6060f1SDimitry Andric 492fe6060f1SDimitry Andric /// Get the current tracing state of a live process and its threads. 493fe6060f1SDimitry Andric /// 494fe6060f1SDimitry Andric /// \return 495fe6060f1SDimitry Andric /// A JSON object string with custom data depending on the trace 496fe6060f1SDimitry Andric /// technology, or an \a llvm::Error in case of errors. 497fe6060f1SDimitry Andric llvm::Expected<std::string> GetLiveProcessState(); 498fe6060f1SDimitry Andric 499fe6060f1SDimitry Andric /// Method to be overriden by the plug-in to refresh its own state. 500fe6060f1SDimitry Andric /// 501fe6060f1SDimitry Andric /// This is invoked by RefreshLiveProcessState when a new state is found. 502fe6060f1SDimitry Andric /// 503fe6060f1SDimitry Andric /// \param[in] state 504fe6060f1SDimitry Andric /// The jLLDBTraceGetState response. 505fe6060f1SDimitry Andric /// 506*81ad6265SDimitry Andric /// \param[in] json_response 507*81ad6265SDimitry Andric /// The original JSON response as a string. It might be useful to redecode 508*81ad6265SDimitry Andric /// it if it contains custom data for a specific trace plug-in. 509*81ad6265SDimitry Andric /// 510*81ad6265SDimitry Andric /// \return 511*81ad6265SDimitry Andric /// \b Error::success() if this operation succeedes, or an actual error 512*81ad6265SDimitry Andric /// otherwise. 513*81ad6265SDimitry Andric virtual llvm::Error 514*81ad6265SDimitry Andric DoRefreshLiveProcessState(TraceGetStateResponse state, 515*81ad6265SDimitry Andric llvm::StringRef json_response) = 0; 516fe6060f1SDimitry Andric 517*81ad6265SDimitry Andric /// Return the list of processes traced by this instance. None of the returned 518*81ad6265SDimitry Andric /// pointers are invalid. 519*81ad6265SDimitry Andric std::vector<Process *> GetTracedProcesses(); 520*81ad6265SDimitry Andric 521*81ad6265SDimitry Andric /// Method to be invoked by the plug-in to refresh the live process state. It 522*81ad6265SDimitry Andric /// will invoked DoRefreshLiveProcessState at some point, which should be 523*81ad6265SDimitry Andric /// implemented by the plug-in for custom state handling. 524*81ad6265SDimitry Andric /// 525*81ad6265SDimitry Andric /// The result is cached through the same process stop. Even in the case of 526*81ad6265SDimitry Andric /// errors, it caches the error. 527*81ad6265SDimitry Andric /// 528*81ad6265SDimitry Andric /// \return 529*81ad6265SDimitry Andric /// An error message if this operation failed, or \b nullptr otherwise. 530*81ad6265SDimitry Andric const char *RefreshLiveProcessState(); 531*81ad6265SDimitry Andric 532*81ad6265SDimitry Andric private: 533fe6060f1SDimitry Andric uint32_t m_stop_id = LLDB_INVALID_STOP_ID; 534*81ad6265SDimitry Andric 535fe6060f1SDimitry Andric /// Process traced by this object if doing live tracing. Otherwise it's null. 536fe6060f1SDimitry Andric Process *m_live_process = nullptr; 537*81ad6265SDimitry Andric 538*81ad6265SDimitry Andric /// We package all the data that can change upon process stops to make sure 539*81ad6265SDimitry Andric /// this contract is very visible. 540*81ad6265SDimitry Andric /// This variable should only be accessed directly by constructores or live 541*81ad6265SDimitry Andric /// process data refreshers. 542*81ad6265SDimitry Andric struct Storage { 543*81ad6265SDimitry Andric /// Portmortem processes traced by this object if doing non-live tracing. 544*81ad6265SDimitry Andric /// Otherwise it's empty. 545*81ad6265SDimitry Andric std::vector<Process *> postmortem_processes; 546*81ad6265SDimitry Andric 547*81ad6265SDimitry Andric /// These data kinds are returned by lldb-server when fetching the state of 548*81ad6265SDimitry Andric /// the tracing session. The size in bytes can be used later for fetching 549*81ad6265SDimitry Andric /// the data in batches. 550*81ad6265SDimitry Andric /// \{ 551*81ad6265SDimitry Andric 552fe6060f1SDimitry Andric /// tid -> data kind -> size 553*81ad6265SDimitry Andric llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, uint64_t>> 554*81ad6265SDimitry Andric live_thread_data; 555*81ad6265SDimitry Andric 556*81ad6265SDimitry Andric /// cpu id -> data kind -> size 557*81ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, uint64_t>> 558*81ad6265SDimitry Andric live_cpu_data_sizes; 559*81ad6265SDimitry Andric /// cpu id -> data kind -> bytes 560*81ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, 561*81ad6265SDimitry Andric llvm::DenseMap<ConstString, std::vector<uint8_t>>> 562*81ad6265SDimitry Andric live_cpu_data; 563*81ad6265SDimitry Andric 564fe6060f1SDimitry Andric /// data kind -> size 565*81ad6265SDimitry Andric llvm::DenseMap<ConstString, uint64_t> live_process_data; 566*81ad6265SDimitry Andric /// \} 567*81ad6265SDimitry Andric 568*81ad6265SDimitry Andric /// The list of cpus being traced. Might be \b None depending on the 569*81ad6265SDimitry Andric /// plug-in. 570*81ad6265SDimitry Andric llvm::Optional<std::vector<lldb::cpu_id_t>> cpus; 571*81ad6265SDimitry Andric 572*81ad6265SDimitry Andric /// Postmortem traces can specific additional data files, which are 573*81ad6265SDimitry Andric /// represented in this variable using a data kind identifier for each file. 574*81ad6265SDimitry Andric /// \{ 575*81ad6265SDimitry Andric 576*81ad6265SDimitry Andric /// tid -> data kind -> file 577*81ad6265SDimitry Andric llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, FileSpec>> 578*81ad6265SDimitry Andric postmortem_thread_data; 579*81ad6265SDimitry Andric 580*81ad6265SDimitry Andric /// cpu id -> data kind -> file 581*81ad6265SDimitry Andric llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, FileSpec>> 582*81ad6265SDimitry Andric postmortem_cpu_data; 583*81ad6265SDimitry Andric 584*81ad6265SDimitry Andric /// \} 585*81ad6265SDimitry Andric 586*81ad6265SDimitry Andric llvm::Optional<std::string> live_refresh_error; 587*81ad6265SDimitry Andric } m_storage; 588*81ad6265SDimitry Andric 589*81ad6265SDimitry Andric /// Get the storage after refreshing the data in the case of a live process. 590*81ad6265SDimitry Andric Storage &GetUpdatedStorage(); 591e8d8bef9SDimitry Andric }; 592e8d8bef9SDimitry Andric 593e8d8bef9SDimitry Andric } // namespace lldb_private 594e8d8bef9SDimitry Andric 595e8d8bef9SDimitry Andric #endif // LLDB_TARGET_TRACE_H 596