xref: /freebsd-src/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h (revision 681ce946f33e75c590e97c53076e86dff1fe8f4a)
1 //===-- TraceCursor.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_CURSOR_H
10 #define LLDB_TARGET_TRACE_CURSOR_H
11 
12 #include "lldb/lldb-private.h"
13 
14 #include "lldb/Target/ExecutionContext.h"
15 
16 namespace lldb_private {
17 
18 /// Class used for iterating over the instructions of a thread's trace.
19 ///
20 /// This class attempts to be a generic interface for accessing the instructions
21 /// of the trace so that each Trace plug-in can reconstruct, represent and store
22 /// the instruction data in an flexible way that is efficient for the given
23 /// technology.
24 ///
25 /// Live processes:
26 ///  In the case of a live process trace, an instance of a \a TraceCursor should
27 ///  point to the trace at the moment it was collected. If the process is later
28 ///  resumed and new trace data is collected, that should leave that old cursor
29 ///  unaffected.
30 ///
31 /// Errors in the trace:
32 ///  As there could be errors when reconstructing the instructions of a trace,
33 ///  these errors are represented as failed instructions, and the cursor can
34 ///  point at them. The consumer should invoke \a TraceCursor::GetError() to
35 ///  check if the cursor is pointing to either a valid instruction or an error.
36 ///
37 /// Instructions:
38 ///  A \a TraceCursor always points to a specific instruction or error in the
39 ///  trace.
40 ///
41 /// Defaults:
42 ///   By default, the cursor points at the end item of the trace, moves
43 ///   backwards, has a move granularity of \a
44 ///   eTraceInstructionControlFlowTypeInstruction (i.e. visit every instruction)
45 ///   and stops at every error (the "ignore errors" flag is \b false). See the
46 ///   \a TraceCursor::Next() method for more documentation.
47 ///
48 /// Sample usage:
49 ///
50 ///  TraceCursorUP cursor = trace.GetTrace(thread);
51 ///
52 ///  cursor->SetGranularity(eTraceInstructionControlFlowTypeCall |
53 ///    eTraceInstructionControlFlowTypeReturn);
54 ///
55 ///  do {
56 ///     if (llvm::Error error = cursor->GetError())
57 ///       cout << "error found at: " << llvm::toString(error) << endl;
58 ///     else if (cursor->GetInstructionControlFlowType() &
59 ///         eTraceInstructionControlFlowTypeCall)
60 ///       std::cout << "call found at " << cursor->GetLoadAddress() <<
61 ///       std::endl;
62 ///     else if (cursor->GetInstructionControlFlowType() &
63 ///         eTraceInstructionControlFlowTypeReturn)
64 ///       std::cout << "return found at " << cursor->GetLoadAddress() <<
65 ///       std::endl;
66 ///  } while(cursor->Next());
67 ///
68 /// Low level traversal:
69 ///   Unlike the \a TraceCursor::Next() API, which uses a given granularity and
70 ///   direction to advance the cursor, the \a TraceCursor::Seek() method can be
71 ///   used to reposition the cursor to an offset of the end, beginning, or
72 ///   current position of the trace.
73 class TraceCursor {
74 public:
75   /// Helper enum to indicate the reference point when invoking
76   /// \a TraceCursor::Seek().
77   enum class SeekType {
78     /// The beginning of the trace, i.e the oldest item.
79     Set = 0,
80     /// The current position in the trace.
81     Current,
82     /// The end of the trace, i.e the most recent item.
83     End
84   };
85 
86   /// Create a cursor that initially points to the end of the trace, i.e. the
87   /// most recent item.
88   TraceCursor(lldb::ThreadSP thread_sp);
89 
90   virtual ~TraceCursor() = default;
91 
92   /// Set the granularity to use in the \a TraceCursor::Next() method.
93   void SetGranularity(lldb::TraceInstructionControlFlowType granularity);
94 
95   /// Set the "ignore errors" flag to use in the \a TraceCursor::Next() method.
96   void SetIgnoreErrors(bool ignore_errors);
97 
98   /// Set the direction to use in the \a TraceCursor::Next() method.
99   ///
100   /// \param[in] forwards
101   ///     If \b true, then the traversal will be forwards, otherwise backwards.
102   void SetForwards(bool forwards);
103 
104   /// Check if the direction to use in the \a TraceCursor::Next() method is
105   /// forwards.
106   ///
107   /// \return
108   ///     \b true if the current direction is forwards, \b false if backwards.
109   bool IsForwards() const;
110 
111   /// Move the cursor to the next instruction that matches the current
112   /// granularity.
113   ///
114   /// Direction:
115   ///     The traversal is done following the current direction of the trace. If
116   ///     it is forwards, the instructions are visited forwards
117   ///     chronologically. Otherwise, the traversal is done in
118   ///     the opposite direction. By default, a cursor moves backwards unless
119   ///     changed with \a TraceCursor::SetForwards().
120   ///
121   /// Granularity:
122   ///     The cursor will traverse the trace looking for the first instruction
123   ///     that matches the current granularity. If there aren't any matching
124   ///     instructions, the cursor won't move, to give the opportunity of
125   ///     changing granularities.
126   ///
127   /// Ignore errors:
128   ///     If the "ignore errors" flags is \b false, the traversal will stop as
129   ///     soon as it finds an error in the trace and the cursor will point at
130   ///     it.
131   ///
132   /// \return
133   ///     \b true if the cursor effectively moved, \b false otherwise.
134   virtual bool Next() = 0;
135 
136   /// Make the cursor point to an item in the trace based on an origin point and
137   /// an offset. This API doesn't distinguishes instruction types nor errors in
138   /// the trace, unlike the \a TraceCursor::Next() method.
139   ///
140   /// The resulting position of the trace is
141   ///     origin + offset
142   ///
143   /// If this resulting position would be out of bounds, it will be adjusted to
144   /// the last or first item in the trace correspondingly.
145   ///
146   /// \param[in] offset
147   ///     How many items to move forwards (if positive) or backwards (if
148   ///     negative) from the given origin point.
149   ///
150   /// \param[in] origin
151   ///     The reference point to use when moving the cursor.
152   ///
153   /// \return
154   ///     The number of trace items moved from the origin.
155   virtual size_t Seek(ssize_t offset, SeekType origin) = 0;
156 
157   /// \return
158   ///   The \a ExecutionContextRef of the backing thread from the creation time
159   ///   of this cursor.
160   ExecutionContextRef &GetExecutionContextRef();
161 
162   /// Instruction or error information
163   /// \{
164 
165   /// \return
166   ///     Whether the cursor points to an error or not.
167   virtual bool IsError() = 0;
168 
169   /// Get the corresponding error message if the cursor points to an error in
170   /// the trace.
171   ///
172   /// \return
173   ///     \b llvm::Error::success if the cursor is not pointing to an error in
174   ///     the trace. Otherwise return an \a llvm::Error describing the issue.
175   virtual llvm::Error GetError() = 0;
176 
177   /// \return
178   ///     The load address of the instruction the cursor is pointing at. If the
179   ///     cursor points to an error in the trace, return \b
180   ///     LLDB_INVALID_ADDRESS.
181   virtual lldb::addr_t GetLoadAddress() = 0;
182 
183   /// Get the timestamp counter associated with the current instruction.
184   /// Modern Intel, ARM and AMD processors support this counter. However, a
185   /// trace plugin might decide to use a different time unit instead of an
186   /// actual TSC.
187   ///
188   /// \return
189   ///     The timestamp or \b llvm::None if not available.
190   virtual llvm::Optional<uint64_t> GetTimestampCounter() = 0;
191 
192   /// \return
193   ///     The \a lldb::TraceInstructionControlFlowType categories the
194   ///     instruction the cursor is pointing at falls into. If the cursor points
195   ///     to an error in the trace, return \b 0.
196   virtual lldb::TraceInstructionControlFlowType
197   GetInstructionControlFlowType() = 0;
198   /// \}
199 
200 protected:
201   ExecutionContextRef m_exe_ctx_ref;
202 
203   lldb::TraceInstructionControlFlowType m_granularity =
204       lldb::eTraceInstructionControlFlowTypeInstruction;
205   bool m_ignore_errors = false;
206   bool m_forwards = false;
207 };
208 
209 } // namespace lldb_private
210 
211 #endif // LLDB_TARGET_TRACE_CURSOR_H
212