1//===-- Trace.h -------------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_TARGET_TRACE_H
10#define LLDB_TARGET_TRACE_H
11
12#include <optional>
13#include <unordered_map>
14
15#include "llvm/Support/JSON.h"
16
17#include "lldb/Core/PluginInterface.h"
18#include "lldb/Target/Thread.h"
19#include "lldb/Target/TraceCursor.h"
20#include "lldb/Utility/ArchSpec.h"
21#include "lldb/Utility/TraceGDBRemotePackets.h"
22#include "lldb/Utility/UnimplementedError.h"
23#include "lldb/lldb-private.h"
24#include "lldb/lldb-types.h"
25
26namespace lldb_private {
27
28/// \class Trace Trace.h "lldb/Target/Trace.h"
29/// A plug-in interface definition class for trace information.
30///
31/// Trace plug-ins allow processor trace information to be loaded into LLDB so
32/// that the data can be dumped, used for reverse and forward stepping to allow
33/// introspection into the reason your process crashed or found its way to its
34/// current state.
35///
36/// Trace information can be loaded into a target without a process to allow
37/// introspection of the trace information during post mortem analysis, such as
38/// when loading core files.
39///
40/// Processor trace information can also be fetched through the process
41/// interfaces during a live debug session if your process supports gathering
42/// this information.
43///
44/// In order to support live tracing, the name of the plug-in should match the
45/// name of the tracing type returned by the gdb-remote packet
46/// \a jLLDBTraceSupported.
47class Trace : public PluginInterface,
48              public std::enable_shared_from_this<Trace> {
49public:
50  /// Dump the trace data that this plug-in has access to.
51  ///
52  /// This function will dump all of the trace data for all threads in a user
53  /// readable format. Options for dumping can be added as this API is iterated
54  /// on.
55  ///
56  /// \param[in] s
57  ///     A stream object to dump the information to.
58  virtual void Dump(Stream *s) const = 0;
59
60  /// Save the trace to the specified directory, which will be created if
61  /// needed. This will also create a file \a <directory>/trace.json with the
62  /// main properties of the trace session, along with others files which
63  /// contain the actual trace data. The trace.json file can be used later as
64  /// input for the "trace load" command to load the trace in LLDB.
65  ///
66  /// \param[in] directory
67  ///   The directory where the trace files will be saved.
68  ///
69  /// \param[in] compact
70  ///   Try not to save to disk information irrelevant to the traced processes.
71  ///   Each trace plug-in implements this in a different fashion.
72  ///
73  /// \return
74  ///   A \a FileSpec pointing to the bundle description file, or an \a
75  ///   llvm::Error otherwise.
76  virtual llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
77                                              bool compact) = 0;
78
79  /// Find a trace plug-in using JSON data.
80  ///
81  /// When loading trace data from disk, the information for the trace data
82  /// can be contained in multiple files and require plug-in specific
83  /// information about the CPU. Using data like JSON provides an
84  /// easy way to specify all of the settings and information that we will need
85  /// to load trace data into LLDB. This structured data can include:
86  ///   - The plug-in name (this allows a specific plug-in to be selected)
87  ///   - Architecture or target triple
88  ///   - one or more paths to the trace data file on disk
89  ///     - cpu trace data
90  ///     - thread events or related information
91  ///   - shared library load information to use for this trace data that
92  ///     allows a target to be created so the trace information can be
93  ///     symbolicated so that the trace information can be displayed to the
94  ///     user
95  ///     - shared library path
96  ///     - load address
97  ///     - information on how to fetch the shared library
98  ///       - path to locally cached file on disk
99  ///       - URL to download the file
100  ///   - Any information needed to load the trace file
101  ///     - CPU information
102  ///     - Custom plug-in information needed to decode the trace information
103  ///       correctly.
104  ///
105  /// \param[in] debugger
106  ///     The debugger instance where new Targets will be created as part of the
107  ///     JSON data parsing.
108  ///
109  /// \param[in] bundle_description
110  ///     The trace bundle description object describing the trace session.
111  ///
112  /// \param[in] bundle_dir
113  ///     The path to the directory that contains the trace bundle.
114  static llvm::Expected<lldb::TraceSP>
115  FindPluginForPostMortemProcess(Debugger &debugger,
116                                 const llvm::json::Value &bundle_description,
117                                 llvm::StringRef session_file_dir);
118
119  /// Find a trace plug-in to trace a live process.
120  ///
121  /// \param[in] plugin_name
122  ///     Plug-in name to search.
123  ///
124  /// \param[in] process
125  ///     Live process to trace.
126  ///
127  /// \return
128  ///     A \a TraceSP instance, or an \a llvm::Error if the plug-in name
129  ///     doesn't match any registered plug-ins or tracing couldn't be
130  ///     started.
131  static llvm::Expected<lldb::TraceSP>
132  FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process);
133
134  /// Get the schema of a Trace plug-in given its name.
135  ///
136  /// \param[in] plugin_name
137  ///     Name of the trace plugin.
138  static llvm::Expected<llvm::StringRef>
139  FindPluginSchema(llvm::StringRef plugin_name);
140
141  /// Load a trace from a trace description file and create Targets,
142  /// Processes and Threads based on the contents of such file.
143  ///
144  /// \param[in] debugger
145  ///     The debugger instance where new Targets will be created as part of the
146  ///     JSON data parsing.
147  ///
148  /// \param[in] trace_description_file
149  ///   The file containing the necessary information to load the trace.
150  ///
151  /// \return
152  ///     A \a TraceSP instance, or an \a llvm::Error if loading the trace
153  ///     fails.
154  static llvm::Expected<lldb::TraceSP>
155  LoadPostMortemTraceFromFile(Debugger &debugger,
156                              const FileSpec &trace_description_file);
157
158  /// Get the command handle for the "process trace start" command.
159  virtual lldb::CommandObjectSP
160  GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0;
161
162  /// Get the command handle for the "thread trace start" command.
163  virtual lldb::CommandObjectSP
164  GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0;
165
166  /// \return
167  ///     The JSON schema of this Trace plug-in.
168  virtual llvm::StringRef GetSchema() = 0;
169
170  /// Get a \a TraceCursor for the given thread's trace.
171  ///
172  /// \return
173  ///     A \a TraceCursorSP. If the thread is not traced or its trace
174  ///     information failed to load, an \a llvm::Error is returned.
175  virtual llvm::Expected<lldb::TraceCursorSP>
176  CreateNewCursor(Thread &thread) = 0;
177
178  /// Dump general info about a given thread's trace. Each Trace plug-in
179  /// decides which data to show.
180  ///
181  /// \param[in] thread
182  ///     The thread that owns the trace in question.
183  ///
184  /// \param[in] s
185  ///     The stream object where the info will be printed printed.
186  ///
187  /// \param[in] verbose
188  ///     If \b true, print detailed info
189  ///     If \b false, print compact info
190  virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
191                             bool json) = 0;
192
193  /// Check if a thread is currently traced by this object.
194  ///
195  /// \param[in] tid
196  ///     The id of the thread in question.
197  ///
198  /// \return
199  ///     \b true if the thread is traced by this instance, \b false otherwise.
200  virtual bool IsTraced(lldb::tid_t tid) = 0;
201
202  /// \return
203  ///     A description of the parameters to use for the \a Trace::Start method.
204  virtual const char *GetStartConfigurationHelp() = 0;
205
206  /// Start tracing a live process.
207  ///
208  /// \param[in] configuration
209  ///     See \a SBTrace::Start(const lldb::SBStructuredData &) for more
210  ///     information.
211  ///
212  /// \return
213  ///     \a llvm::Error::success if the operation was successful, or
214  ///     \a llvm::Error otherwise.
215  virtual llvm::Error Start(
216      StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0;
217
218  /// Start tracing live threads.
219  ///
220  /// \param[in] tids
221  ///     Threads to trace. This method tries to trace as many threads as
222  ///     possible.
223  ///
224  /// \param[in] configuration
225  ///     See \a SBTrace::Start(const lldb::SBThread &, const
226  ///     lldb::SBStructuredData &) for more information.
227  ///
228  /// \return
229  ///     \a llvm::Error::success if the operation was successful, or
230  ///     \a llvm::Error otherwise.
231  virtual llvm::Error Start(
232      llvm::ArrayRef<lldb::tid_t> tids,
233      StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0;
234
235  /// Stop tracing live threads.
236  ///
237  /// \param[in] tids
238  ///     The threads to stop tracing on.
239  ///
240  /// \return
241  ///     \a llvm::Error::success if the operation was successful, or
242  ///     \a llvm::Error otherwise.
243  llvm::Error Stop(llvm::ArrayRef<lldb::tid_t> tids);
244
245  /// Stop tracing all current and future threads of a live process.
246  ///
247  /// \param[in] request
248  ///     The information determining which threads or process to stop tracing.
249  ///
250  /// \return
251  ///     \a llvm::Error::success if the operation was successful, or
252  ///     \a llvm::Error otherwise.
253  llvm::Error Stop();
254
255  /// \return
256  ///     The stop ID of the live process being traced, or an invalid stop ID
257  ///     if the trace is in an error or invalid state.
258  uint32_t GetStopID();
259
260  using OnBinaryDataReadCallback =
261      std::function<llvm::Error(llvm::ArrayRef<uint8_t> data)>;
262  using OnCpusBinaryDataReadCallback = std::function<llvm::Error(
263      const llvm::DenseMap<lldb::cpu_id_t, llvm::ArrayRef<uint8_t>>
264          &cpu_to_data)>;
265
266  /// Fetch binary data associated with a thread, either live or postmortem, and
267  /// pass it to the given callback. The reason of having a callback is to free
268  /// the caller from having to manage the life cycle of the data and to hide
269  /// the different data fetching procedures that exist for live and post mortem
270  /// threads.
271  ///
272  /// The fetched data is not persisted after the callback is invoked.
273  ///
274  /// \param[in] tid
275  ///     The tid who owns the data.
276  ///
277  /// \param[in] kind
278  ///     The kind of data to read.
279  ///
280  /// \param[in] callback
281  ///     The callback to be invoked once the data was successfully read. Its
282  ///     return value, which is an \a llvm::Error, is returned by this
283  ///     function.
284  ///
285  /// \return
286  ///     An \a llvm::Error if the data couldn't be fetched, or the return value
287  ///     of the callback, otherwise.
288  llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
289                                     OnBinaryDataReadCallback callback);
290
291  /// Fetch binary data associated with a cpu, either live or postmortem, and
292  /// pass it to the given callback. The reason of having a callback is to free
293  /// the caller from having to manage the life cycle of the data and to hide
294  /// the different data fetching procedures that exist for live and post mortem
295  /// cpus.
296  ///
297  /// The fetched data is not persisted after the callback is invoked.
298  ///
299  /// \param[in] cpu_id
300  ///     The cpu who owns the data.
301  ///
302  /// \param[in] kind
303  ///     The kind of data to read.
304  ///
305  /// \param[in] callback
306  ///     The callback to be invoked once the data was successfully read. Its
307  ///     return value, which is an \a llvm::Error, is returned by this
308  ///     function.
309  ///
310  /// \return
311  ///     An \a llvm::Error if the data couldn't be fetched, or the return value
312  ///     of the callback, otherwise.
313  llvm::Error OnCpuBinaryDataRead(lldb::cpu_id_t cpu_id, llvm::StringRef kind,
314                                  OnBinaryDataReadCallback callback);
315
316  /// Similar to \a OnCpuBinaryDataRead but this is able to fetch the same data
317  /// from all cpus at once.
318  llvm::Error OnAllCpusBinaryDataRead(llvm::StringRef kind,
319                                      OnCpusBinaryDataReadCallback callback);
320
321  /// \return
322  ///     All the currently traced processes.
323  std::vector<Process *> GetAllProcesses();
324
325  /// \return
326  ///     The list of cpus being traced. Might be empty depending on the
327  ///     plugin.
328  llvm::ArrayRef<lldb::cpu_id_t> GetTracedCpus();
329
330  /// Helper method for reading a data file and passing its data to the given
331  /// callback.
332  static llvm::Error OnDataFileRead(FileSpec file,
333                                    OnBinaryDataReadCallback callback);
334
335protected:
336  /// Get the currently traced live process.
337  ///
338  /// \return
339  ///     If it's not a live process, return \a nullptr.
340  Process *GetLiveProcess();
341
342  /// Get the currently traced postmortem processes.
343  ///
344  /// \return
345  ///     If it's not a live process session, return an empty list.
346  llvm::ArrayRef<Process *> GetPostMortemProcesses();
347
348  /// Dispatcher for live trace data requests with some additional error
349  /// checking.
350  llvm::Expected<std::vector<uint8_t>>
351  GetLiveTraceBinaryData(const TraceGetBinaryDataRequest &request,
352                         uint64_t expected_size);
353
354  /// Implementation of \a OnThreadBinaryDataRead() for live threads.
355  llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
356                                         OnBinaryDataReadCallback callback);
357
358  /// Implementation of \a OnLiveBinaryDataRead() for live cpus.
359  llvm::Error OnLiveCpuBinaryDataRead(lldb::cpu_id_t cpu, llvm::StringRef kind,
360                                      OnBinaryDataReadCallback callback);
361
362  /// Implementation of \a OnThreadBinaryDataRead() for post mortem threads.
363  llvm::Error
364  OnPostMortemThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
365                                   OnBinaryDataReadCallback callback);
366
367  /// Implementation of \a OnCpuBinaryDataRead() for post mortem cpus.
368  llvm::Error OnPostMortemCpuBinaryDataRead(lldb::cpu_id_t cpu_id,
369                                            llvm::StringRef kind,
370                                            OnBinaryDataReadCallback callback);
371
372  /// Get the file path containing data of a postmortem thread given a data
373  /// identifier.
374  ///
375  /// \param[in] tid
376  ///     The thread whose data is requested.
377  ///
378  /// \param[in] kind
379  ///     The kind of data requested.
380  ///
381  /// \return
382  ///     The file spec containing the requested data, or an \a llvm::Error in
383  ///     case of failures.
384  llvm::Expected<FileSpec> GetPostMortemThreadDataFile(lldb::tid_t tid,
385                                                       llvm::StringRef kind);
386
387  /// Get the file path containing data of a postmortem cpu given a data
388  /// identifier.
389  ///
390  /// \param[in] cpu_id
391  ///     The cpu whose data is requested.
392  ///
393  /// \param[in] kind
394  ///     The kind of data requested.
395  ///
396  /// \return
397  ///     The file spec containing the requested data, or an \a llvm::Error in
398  ///     case of failures.
399  llvm::Expected<FileSpec> GetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id,
400                                                    llvm::StringRef kind);
401
402  /// Associate a given thread with a data file using a data identifier.
403  ///
404  /// \param[in] tid
405  ///     The thread associated with the data file.
406  ///
407  /// \param[in] kind
408  ///     The kind of data being registered.
409  ///
410  /// \param[in] file_spec
411  ///     The path of the data file.
412  void SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
413                                   FileSpec file_spec);
414
415  /// Associate a given cpu with a data file using a data identifier.
416  ///
417  /// \param[in] cpu_id
418  ///     The cpu associated with the data file.
419  ///
420  /// \param[in] kind
421  ///     The kind of data being registered.
422  ///
423  /// \param[in] file_spec
424  ///     The path of the data file.
425  void SetPostMortemCpuDataFile(lldb::cpu_id_t cpu_id, llvm::StringRef kind,
426                                FileSpec file_spec);
427
428  /// Get binary data of a live thread given a data identifier.
429  ///
430  /// \param[in] tid
431  ///     The thread whose data is requested.
432  ///
433  /// \param[in] kind
434  ///     The kind of data requested.
435  ///
436  /// \return
437  ///     A vector of bytes with the requested data, or an \a llvm::Error in
438  ///     case of failures.
439  llvm::Expected<std::vector<uint8_t>>
440  GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind);
441
442  /// Get binary data of a live cpu given a data identifier.
443  ///
444  /// \param[in] cpu_id
445  ///     The cpu whose data is requested.
446  ///
447  /// \param[in] kind
448  ///     The kind of data requested.
449  ///
450  /// \return
451  ///     A vector of bytes with the requested data, or an \a llvm::Error in
452  ///     case of failures.
453  llvm::Expected<std::vector<uint8_t>>
454  GetLiveCpuBinaryData(lldb::cpu_id_t cpu_id, llvm::StringRef kind);
455
456  /// Get binary data of the current process given a data identifier.
457  ///
458  /// \param[in] kind
459  ///     The kind of data requested.
460  ///
461  /// \return
462  ///     A vector of bytes with the requested data, or an \a llvm::Error in
463  ///     case of failures.
464  llvm::Expected<std::vector<uint8_t>>
465  GetLiveProcessBinaryData(llvm::StringRef kind);
466
467  /// Get the size of the data returned by \a GetLiveThreadBinaryData
468  std::optional<uint64_t> GetLiveThreadBinaryDataSize(lldb::tid_t tid,
469                                                      llvm::StringRef kind);
470
471  /// Get the size of the data returned by \a GetLiveCpuBinaryData
472  std::optional<uint64_t> GetLiveCpuBinaryDataSize(lldb::cpu_id_t cpu_id,
473                                                   llvm::StringRef kind);
474
475  /// Get the size of the data returned by \a GetLiveProcessBinaryData
476  std::optional<uint64_t> GetLiveProcessBinaryDataSize(llvm::StringRef kind);
477
478  /// Constructor for post mortem processes
479  Trace(llvm::ArrayRef<lldb::ProcessSP> postmortem_processes,
480        std::optional<std::vector<lldb::cpu_id_t>> postmortem_cpus);
481
482  /// Constructor for a live process
483  Trace(Process &live_process) : m_live_process(&live_process) {}
484
485  /// Start tracing a live process or its threads.
486  ///
487  /// \param[in] request
488  ///     JSON object with the information necessary to start tracing. In the
489  ///     case of gdb-remote processes, this JSON object should conform to the
490  ///     jLLDBTraceStart packet.
491  ///
492  /// \return
493  ///     \a llvm::Error::success if the operation was successful, or
494  ///     \a llvm::Error otherwise.
495  llvm::Error Start(const llvm::json::Value &request);
496
497  /// Get the current tracing state of a live process and its threads.
498  ///
499  /// \return
500  ///     A JSON object string with custom data depending on the trace
501  ///     technology, or an \a llvm::Error in case of errors.
502  llvm::Expected<std::string> GetLiveProcessState();
503
504  /// Method to be overriden by the plug-in to refresh its own state.
505  ///
506  /// This is invoked by RefreshLiveProcessState when a new state is found.
507  ///
508  /// \param[in] state
509  ///     The jLLDBTraceGetState response.
510  ///
511  /// \param[in] json_response
512  ///     The original JSON response as a string. It might be useful to redecode
513  ///     it if it contains custom data for a specific trace plug-in.
514  ///
515  /// \return
516  ///     \b Error::success() if this operation succeedes, or an actual error
517  ///     otherwise.
518  virtual llvm::Error
519  DoRefreshLiveProcessState(TraceGetStateResponse state,
520                            llvm::StringRef json_response) = 0;
521
522  /// Return the list of processes traced by this instance. None of the returned
523  /// pointers are invalid.
524  std::vector<Process *> GetTracedProcesses();
525
526  /// Method to be invoked by the plug-in to refresh the live process state. It
527  /// will invoked DoRefreshLiveProcessState at some point, which should be
528  /// implemented by the plug-in for custom state handling.
529  ///
530  /// The result is cached through the same process stop. Even in the case of
531  /// errors, it caches the error.
532  ///
533  /// \return
534  ///   An error message if this operation failed, or \b nullptr otherwise.
535  const char *RefreshLiveProcessState();
536
537private:
538  uint32_t m_stop_id = LLDB_INVALID_STOP_ID;
539
540  /// Process traced by this object if doing live tracing. Otherwise it's null.
541  Process *m_live_process = nullptr;
542
543  /// We package all the data that can change upon process stops to make sure
544  /// this contract is very visible.
545  /// This variable should only be accessed directly by constructores or live
546  /// process data refreshers.
547  struct Storage {
548    /// Portmortem processes traced by this object if doing non-live tracing.
549    /// Otherwise it's empty.
550    std::vector<Process *> postmortem_processes;
551
552    /// These data kinds are returned by lldb-server when fetching the state of
553    /// the tracing session. The size in bytes can be used later for fetching
554    /// the data in batches.
555    /// \{
556
557    /// tid -> data kind -> size
558    llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, uint64_t>>
559        live_thread_data;
560
561    /// cpu id -> data kind -> size
562    llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, uint64_t>>
563        live_cpu_data_sizes;
564    /// cpu id -> data kind -> bytes
565    llvm::DenseMap<lldb::cpu_id_t,
566                   llvm::DenseMap<ConstString, std::vector<uint8_t>>>
567        live_cpu_data;
568
569    /// data kind -> size
570    llvm::DenseMap<ConstString, uint64_t> live_process_data;
571    /// \}
572
573    /// The list of cpus being traced. Might be \b std::nullopt depending on the
574    /// plug-in.
575    std::optional<std::vector<lldb::cpu_id_t>> cpus;
576
577    /// Postmortem traces can specific additional data files, which are
578    /// represented in this variable using a data kind identifier for each file.
579    /// \{
580
581    /// tid -> data kind -> file
582    llvm::DenseMap<lldb::tid_t, llvm::DenseMap<ConstString, FileSpec>>
583        postmortem_thread_data;
584
585    /// cpu id -> data kind -> file
586    llvm::DenseMap<lldb::cpu_id_t, llvm::DenseMap<ConstString, FileSpec>>
587        postmortem_cpu_data;
588
589    /// \}
590
591    std::optional<std::string> live_refresh_error;
592  } m_storage;
593
594  /// Get the storage after refreshing the data in the case of a live process.
595  Storage &GetUpdatedStorage();
596};
597
598} // namespace lldb_private
599
600#endif // LLDB_TARGET_TRACE_H
601