1*e8d8bef9SDimitry Andric //===-- Trace.h -------------------------------------------------*- C++ -*-===//
2*e8d8bef9SDimitry Andric //
3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*e8d8bef9SDimitry Andric //
7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8*e8d8bef9SDimitry Andric 
9*e8d8bef9SDimitry Andric #ifndef LLDB_TARGET_TRACE_H
10*e8d8bef9SDimitry Andric #define LLDB_TARGET_TRACE_H
11*e8d8bef9SDimitry Andric 
12*e8d8bef9SDimitry Andric #include "llvm/Support/JSON.h"
13*e8d8bef9SDimitry Andric 
14*e8d8bef9SDimitry Andric #include "lldb/Core/PluginInterface.h"
15*e8d8bef9SDimitry Andric #include "lldb/Utility/ArchSpec.h"
16*e8d8bef9SDimitry Andric #include "lldb/Utility/UnimplementedError.h"
17*e8d8bef9SDimitry Andric #include "lldb/lldb-private.h"
18*e8d8bef9SDimitry Andric 
19*e8d8bef9SDimitry Andric namespace lldb_private {
20*e8d8bef9SDimitry Andric 
21*e8d8bef9SDimitry Andric /// \class Trace Trace.h "lldb/Target/Trace.h"
22*e8d8bef9SDimitry Andric /// A plug-in interface definition class for trace information.
23*e8d8bef9SDimitry Andric ///
24*e8d8bef9SDimitry Andric /// Trace plug-ins allow processor trace information to be loaded into LLDB so
25*e8d8bef9SDimitry Andric /// that the data can be dumped, used for reverse and forward stepping to allow
26*e8d8bef9SDimitry Andric /// introspection into the reason your process crashed or found its way to its
27*e8d8bef9SDimitry Andric /// current state.
28*e8d8bef9SDimitry Andric ///
29*e8d8bef9SDimitry Andric /// Trace information can be loaded into a target without a process to allow
30*e8d8bef9SDimitry Andric /// introspection of the trace information during post mortem analysis, such as
31*e8d8bef9SDimitry Andric /// when loading core files.
32*e8d8bef9SDimitry Andric ///
33*e8d8bef9SDimitry Andric /// Processor trace information can also be fetched through the process
34*e8d8bef9SDimitry Andric /// interfaces during a live debug session if your process supports gathering
35*e8d8bef9SDimitry Andric /// this information.
36*e8d8bef9SDimitry Andric ///
37*e8d8bef9SDimitry Andric /// In order to support live tracing, the name of the plug-in should match the
38*e8d8bef9SDimitry Andric /// name of the tracing type returned by the gdb-remote packet
39*e8d8bef9SDimitry Andric /// \a jLLDBTraceSupportedType.
40*e8d8bef9SDimitry Andric class Trace : public PluginInterface,
41*e8d8bef9SDimitry Andric               public std::enable_shared_from_this<Trace> {
42*e8d8bef9SDimitry Andric public:
43*e8d8bef9SDimitry Andric   enum class TraceDirection {
44*e8d8bef9SDimitry Andric     Forwards = 0,
45*e8d8bef9SDimitry Andric     Backwards,
46*e8d8bef9SDimitry Andric   };
47*e8d8bef9SDimitry Andric 
48*e8d8bef9SDimitry Andric   /// Dump the trace data that this plug-in has access to.
49*e8d8bef9SDimitry Andric   ///
50*e8d8bef9SDimitry Andric   /// This function will dump all of the trace data for all threads in a user
51*e8d8bef9SDimitry Andric   /// readable format. Options for dumping can be added as this API is iterated
52*e8d8bef9SDimitry Andric   /// on.
53*e8d8bef9SDimitry Andric   ///
54*e8d8bef9SDimitry Andric   /// \param[in] s
55*e8d8bef9SDimitry Andric   ///     A stream object to dump the information to.
56*e8d8bef9SDimitry Andric   virtual void Dump(Stream *s) const = 0;
57*e8d8bef9SDimitry Andric 
58*e8d8bef9SDimitry Andric   /// Find a trace plug-in using JSON data.
59*e8d8bef9SDimitry Andric   ///
60*e8d8bef9SDimitry Andric   /// When loading trace data from disk, the information for the trace data
61*e8d8bef9SDimitry Andric   /// can be contained in multiple files and require plug-in specific
62*e8d8bef9SDimitry Andric   /// information about the CPU. Using data like JSON provides an
63*e8d8bef9SDimitry Andric   /// easy way to specify all of the settings and information that we will need
64*e8d8bef9SDimitry Andric   /// to load trace data into LLDB. This structured data can include:
65*e8d8bef9SDimitry Andric   ///   - The plug-in name (this allows a specific plug-in to be selected)
66*e8d8bef9SDimitry Andric   ///   - Architecture or target triple
67*e8d8bef9SDimitry Andric   ///   - one or more paths to the trace data file on disk
68*e8d8bef9SDimitry Andric   ///     - core trace data
69*e8d8bef9SDimitry Andric   ///     - thread events or related information
70*e8d8bef9SDimitry Andric   ///   - shared library load information to use for this trace data that
71*e8d8bef9SDimitry Andric   ///     allows a target to be created so the trace information can be
72*e8d8bef9SDimitry Andric   ///     symbolicated so that the trace information can be displayed to the
73*e8d8bef9SDimitry Andric   ///     user
74*e8d8bef9SDimitry Andric   ///     - shared library path
75*e8d8bef9SDimitry Andric   ///     - load address
76*e8d8bef9SDimitry Andric   ///     - information on how to fetch the shared library
77*e8d8bef9SDimitry Andric   ///       - path to locally cached file on disk
78*e8d8bef9SDimitry Andric   ///       - URL to download the file
79*e8d8bef9SDimitry Andric   ///   - Any information needed to load the trace file
80*e8d8bef9SDimitry Andric   ///     - CPU information
81*e8d8bef9SDimitry Andric   ///     - Custom plug-in information needed to decode the trace information
82*e8d8bef9SDimitry Andric   ///       correctly.
83*e8d8bef9SDimitry Andric   ///
84*e8d8bef9SDimitry Andric   /// \param[in] debugger
85*e8d8bef9SDimitry Andric   ///     The debugger instance where new Targets will be created as part of the
86*e8d8bef9SDimitry Andric   ///     JSON data parsing.
87*e8d8bef9SDimitry Andric   ///
88*e8d8bef9SDimitry Andric   /// \param[in] trace_session_file
89*e8d8bef9SDimitry Andric   ///     The contents of the trace session file describing the trace session.
90*e8d8bef9SDimitry Andric   ///     See \a TraceSessionFileParser::BuildSchema for more information about
91*e8d8bef9SDimitry Andric   ///     the schema of this JSON file.
92*e8d8bef9SDimitry Andric   ///
93*e8d8bef9SDimitry Andric   /// \param[in] session_file_dir
94*e8d8bef9SDimitry Andric   ///     The path to the directory that contains the session file. It's used to
95*e8d8bef9SDimitry Andric   ///     resolved relative paths in the session file.
96*e8d8bef9SDimitry Andric   static llvm::Expected<lldb::TraceSP>
97*e8d8bef9SDimitry Andric   FindPlugin(Debugger &debugger, const llvm::json::Value &trace_session_file,
98*e8d8bef9SDimitry Andric              llvm::StringRef session_file_dir);
99*e8d8bef9SDimitry Andric 
100*e8d8bef9SDimitry Andric   /// Get the schema of a Trace plug-in given its name.
101*e8d8bef9SDimitry Andric   ///
102*e8d8bef9SDimitry Andric   /// \param[in] plugin_name
103*e8d8bef9SDimitry Andric   ///     Name of the trace plugin.
104*e8d8bef9SDimitry Andric   static llvm::Expected<llvm::StringRef>
105*e8d8bef9SDimitry Andric   FindPluginSchema(llvm::StringRef plugin_name);
106*e8d8bef9SDimitry Andric 
107*e8d8bef9SDimitry Andric   /// \return
108*e8d8bef9SDimitry Andric   ///     The JSON schema of this Trace plug-in.
109*e8d8bef9SDimitry Andric   virtual llvm::StringRef GetSchema() = 0;
110*e8d8bef9SDimitry Andric 
111*e8d8bef9SDimitry Andric   /// Each decoded thread contains a cursor to the current position the user is
112*e8d8bef9SDimitry Andric   /// stopped at. When reverse debugging, each operation like reverse-next or
113*e8d8bef9SDimitry Andric   /// reverse-continue will move this cursor, which is then picked by any
114*e8d8bef9SDimitry Andric   /// subsequent dump or reverse operation.
115*e8d8bef9SDimitry Andric   ///
116*e8d8bef9SDimitry Andric   /// The initial position for this cursor is the last element of the thread,
117*e8d8bef9SDimitry Andric   /// which is the most recent chronologically.
118*e8d8bef9SDimitry Andric   ///
119*e8d8bef9SDimitry Andric   /// \return
120*e8d8bef9SDimitry Andric   ///     The current position of the thread's trace or \b 0 if empty.
121*e8d8bef9SDimitry Andric   virtual size_t GetCursorPosition(const Thread &thread) = 0;
122*e8d8bef9SDimitry Andric 
123*e8d8bef9SDimitry Andric   /// Dump \a count instructions of the given thread's trace ending at the
124*e8d8bef9SDimitry Andric   /// given \a end_position position.
125*e8d8bef9SDimitry Andric   ///
126*e8d8bef9SDimitry Andric   /// The instructions are printed along with their indices or positions, which
127*e8d8bef9SDimitry Andric   /// are increasing chronologically. This means that the \a index 0 represents
128*e8d8bef9SDimitry Andric   /// the oldest instruction of the trace chronologically.
129*e8d8bef9SDimitry Andric   ///
130*e8d8bef9SDimitry Andric   /// \param[in] thread
131*e8d8bef9SDimitry Andric   ///     The thread whose trace will be dumped.
132*e8d8bef9SDimitry Andric   ///
133*e8d8bef9SDimitry Andric   /// \param[in] s
134*e8d8bef9SDimitry Andric   ///     The stream object where the instructions are printed.
135*e8d8bef9SDimitry Andric   ///
136*e8d8bef9SDimitry Andric   /// \param[in] count
137*e8d8bef9SDimitry Andric   ///     The number of instructions to print.
138*e8d8bef9SDimitry Andric   ///
139*e8d8bef9SDimitry Andric   /// \param[in] end_position
140*e8d8bef9SDimitry Andric   ///     The position of the last instruction to print.
141*e8d8bef9SDimitry Andric   ///
142*e8d8bef9SDimitry Andric   /// \param[in] raw
143*e8d8bef9SDimitry Andric   ///     Dump only instruction addresses without disassembly nor symbol
144*e8d8bef9SDimitry Andric   ///     information.
145*e8d8bef9SDimitry Andric   void DumpTraceInstructions(Thread &thread, Stream &s, size_t count,
146*e8d8bef9SDimitry Andric                              size_t end_position, bool raw);
147*e8d8bef9SDimitry Andric 
148*e8d8bef9SDimitry Andric   /// Run the provided callback on the instructions of the trace of the given
149*e8d8bef9SDimitry Andric   /// thread.
150*e8d8bef9SDimitry Andric   ///
151*e8d8bef9SDimitry Andric   /// The instructions will be traversed starting at the given \a position
152*e8d8bef9SDimitry Andric   /// sequentially until the callback returns \b false, in which case no more
153*e8d8bef9SDimitry Andric   /// instructions are inspected.
154*e8d8bef9SDimitry Andric   ///
155*e8d8bef9SDimitry Andric   /// The purpose of this method is to allow inspecting traced instructions
156*e8d8bef9SDimitry Andric   /// without exposing the internal representation of how they are stored on
157*e8d8bef9SDimitry Andric   /// memory.
158*e8d8bef9SDimitry Andric   ///
159*e8d8bef9SDimitry Andric   /// \param[in] thread
160*e8d8bef9SDimitry Andric   ///     The thread whose trace will be traversed.
161*e8d8bef9SDimitry Andric   ///
162*e8d8bef9SDimitry Andric   /// \param[in] position
163*e8d8bef9SDimitry Andric   ///     The instruction position to start iterating on.
164*e8d8bef9SDimitry Andric   ///
165*e8d8bef9SDimitry Andric   /// \param[in] direction
166*e8d8bef9SDimitry Andric   ///     If \b TraceDirection::Forwards, then then instructions will be
167*e8d8bef9SDimitry Andric   ///     traversed forwards chronologically, i.e. with incrementing indices. If
168*e8d8bef9SDimitry Andric   ///     \b TraceDirection::Backwards, the traversal is done backwards
169*e8d8bef9SDimitry Andric   ///     chronologically, i.e. with decrementing indices.
170*e8d8bef9SDimitry Andric   ///
171*e8d8bef9SDimitry Andric   /// \param[in] callback
172*e8d8bef9SDimitry Andric   ///     The callback to execute on each instruction. If it returns \b false,
173*e8d8bef9SDimitry Andric   ///     the iteration stops.
174*e8d8bef9SDimitry Andric   virtual void TraverseInstructions(
175*e8d8bef9SDimitry Andric       const Thread &thread, size_t position, TraceDirection direction,
176*e8d8bef9SDimitry Andric       std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)>
177*e8d8bef9SDimitry Andric           callback) = 0;
178*e8d8bef9SDimitry Andric 
179*e8d8bef9SDimitry Andric   /// Stop tracing a live thread
180*e8d8bef9SDimitry Andric   ///
181*e8d8bef9SDimitry Andric   /// \param[in] thread
182*e8d8bef9SDimitry Andric   ///     The thread object to stop tracing.
183*e8d8bef9SDimitry Andric   ///
184*e8d8bef9SDimitry Andric   /// \return
185*e8d8bef9SDimitry Andric   ///     An \a llvm::Error if stopping tracing failed, or \b
186*e8d8bef9SDimitry Andric   ///     llvm::Error::success() otherwise.
187*e8d8bef9SDimitry Andric   virtual llvm::Error StopTracingThread(const Thread &thread) {
188*e8d8bef9SDimitry Andric     return llvm::make_error<UnimplementedError>();
189*e8d8bef9SDimitry Andric   }
190*e8d8bef9SDimitry Andric 
191*e8d8bef9SDimitry Andric   /// Get the number of available instructions in the trace of the given thread.
192*e8d8bef9SDimitry Andric   ///
193*e8d8bef9SDimitry Andric   /// \param[in] thread
194*e8d8bef9SDimitry Andric   ///     The thread whose trace will be inspected.
195*e8d8bef9SDimitry Andric   ///
196*e8d8bef9SDimitry Andric   /// \return
197*e8d8bef9SDimitry Andric   ///     The total number of instructions in the trace.
198*e8d8bef9SDimitry Andric   virtual size_t GetInstructionCount(const Thread &thread) = 0;
199*e8d8bef9SDimitry Andric };
200*e8d8bef9SDimitry Andric 
201*e8d8bef9SDimitry Andric } // namespace lldb_private
202*e8d8bef9SDimitry Andric 
203*e8d8bef9SDimitry Andric #endif // LLDB_TARGET_TRACE_H
204