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