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, among
19 /// other kinds of information.
20 ///
21 /// This class attempts to be a generic interface for accessing the instructions
22 /// of the trace so that each Trace plug-in can reconstruct, represent and store
23 /// the instruction data in an flexible way that is efficient for the given
24 /// technology.
25 ///
26 /// Live processes:
27 ///   In the case of a live process trace, an instance of a \a TraceCursor
28 ///   should point to the trace at the moment it was collected. If the process
29 ///   is later resumed and new trace data is collected, then it's up to each
30 ///   trace plug-in to decide whether to leave the old cursor unaffected or not.
31 ///
32 /// Cursor items:
33 ///   A \a TraceCursor can point at one of the following items:
34 ///
35 ///   Errors:
36 ///     As there could be errors when reconstructing the instructions of a
37 ///     trace, these errors are represented as failed instructions, and the
38 ///     cursor can point at them.
39 ///
40 ///   Events:
41 ///     The cursor can also point at events in the trace, which aren't errors
42 ///     nor instructions. An example of an event could be a context switch in
43 ///     between two instructions.
44 ///
45 ///   Instruction:
46 ///     An actual instruction with a memory address.
47 ///
48 /// Defaults:
49 ///   By default, the cursor points at the most recent item in the trace and is
50 ///   set up to iterate backwards. See the \a TraceCursor::Next() method for
51 ///   more documentation.
52 ///
53 /// Sample usage:
54 ///
55 ///  TraceCursorUP cursor = trace.GetTrace(thread);
56 ///
57 ///  for (; cursor->HasValue(); cursor->Next()) {
58 ///     TraceItemKind kind = cursor->GetItemKind();
59 ///     switch (cursor->GetItemKind()):
60 ///       case eTraceItemKindError:
61 ///         cout << "error found: " << cursor->GetError() << endl;
62 ///         break;
63 ///       case eTraceItemKindEvent:
64 ///         cout << "event found: " << cursor->GetEventTypeAsString() << endl;
65 ///         break;
66 ///       case eTraceItemKindInstruction:
67 ///         std::cout << "instructions found at " << cursor->GetLoadAddress() <<
68 ///         std::endl; break;
69 ///     }
70 ///  }
71 ///
72 ///  As the trace might be empty or the cursor might have reached the end of the
73 ///  trace, you should always invoke \a HasValue() to make sure you don't access
74 ///  invalid memory.
75 ///
76 /// Random accesses:
77 ///
78 ///   The Trace Cursor offer random acesses in the trace via two APIs:
79 ///
80 ///     TraceCursor::Seek():
81 ///       Unlike the \a TraceCursor::Next() API, which moves instruction by
82 ///       instruction, the \a TraceCursor::Seek() method can be used to
83 ///       reposition the cursor to an offset of the end, beginning, or current
84 ///       position of the trace.
85 ///
86 ///     TraceCursor::GetId() / TraceCursor::SetId(id):
87 ///       Each item (error or instruction) in the trace has a numeric identifier
88 ///       which is defined by the trace plug-in. It's possible to access the id
89 ///       of the current item using GetId(), and to reposition the cursor to a
90 ///       given id using SetId(id).
91 ///
92 ///   You can read more in the documentation of these methods.
93 class TraceCursor {
94 public:
95   /// Helper enum to indicate the reference point when invoking
96   /// \a TraceCursor::Seek().
97   /// The following values are inspired by \a std::istream::seekg.
98   enum class SeekType {
99     /// The beginning of the trace, i.e the oldest item.
100     Beginning = 0,
101     /// The current position in the trace.
102     Current,
103     /// The end of the trace, i.e the most recent item.
104     End
105   };
106 
107   /// Create a cursor that initially points to the end of the trace, i.e. the
108   /// most recent item.
109   TraceCursor(lldb::ThreadSP thread_sp);
110 
111   virtual ~TraceCursor() = default;
112 
113   /// Set the direction to use in the \a TraceCursor::Next() method.
114   ///
115   /// \param[in] forwards
116   ///     If \b true, then the traversal will be forwards, otherwise backwards.
117   void SetForwards(bool forwards);
118 
119   /// Check if the direction to use in the \a TraceCursor::Next() method is
120   /// forwards.
121   ///
122   /// \return
123   ///     \b true if the current direction is forwards, \b false if backwards.
124   bool IsForwards() const;
125 
126   /// Move the cursor to the next item (instruction or error).
127   ///
128   /// Direction:
129   ///     The traversal is done following the current direction of the trace. If
130   ///     it is forwards, the instructions are visited forwards
131   ///     chronologically. Otherwise, the traversal is done in
132   ///     the opposite direction. By default, a cursor moves backwards unless
133   ///     changed with \a TraceCursor::SetForwards().
134   virtual void Next() = 0;
135 
136   /// \return
137   ///     \b true if the cursor is pointing to a valid item. \b false if the
138   ///     cursor has reached the end of the trace.
139   virtual bool HasValue() const = 0;
140 
141   /// Instruction identifiers:
142   ///
143   /// When building complex higher level tools, fast random accesses in the
144   /// trace might be needed, for which each instruction requires a unique
145   /// identifier within its thread trace. For example, a tool might want to
146   /// repeatedly inspect random consecutive portions of a trace. This means that
147   /// it will need to first move quickly to the beginning of each section and
148   /// then start its iteration. Given that the number of instructions can be in
149   /// the order of hundreds of millions, fast random access is necessary.
150   ///
151   /// An example of such a tool could be an inspector of the call graph of a
152   /// trace, where each call is represented with its start and end instructions.
153   /// Inspecting all the instructions of a call requires moving to its first
154   /// instruction and then iterating until the last instruction, which following
155   /// the pattern explained above.
156   ///
157   /// Instead of using 0-based indices as identifiers, each Trace plug-in can
158   /// decide the nature of these identifiers and thus no assumptions can be made
159   /// regarding their ordering and sequentiality. The reason is that an
160   /// instruction might be encoded by the plug-in in a way that hides its actual
161   /// 0-based index in the trace, but it's still possible to efficiently find
162   /// it.
163   ///
164   /// Requirements:
165   /// - For a given thread, no two instructions have the same id.
166   /// - In terms of efficiency, moving the cursor to a given id should be as
167   ///   fast as possible, but not necessarily O(1). That's why the recommended
168   ///   way to traverse sequential instructions is to use the \a
169   ///   TraceCursor::Next() method and only use \a TraceCursor::GoToId(id)
170   ///   sparingly.
171 
172   /// Make the cursor point to the item whose identifier is \p id.
173   ///
174   /// \return
175   ///     \b true if the given identifier exists and the cursor effectively
176   ///     moved to it. Otherwise, \b false is returned and the cursor now points
177   ///     to an invalid item, i.e. calling \a HasValue() will return \b false.
178   virtual bool GoToId(lldb::user_id_t id) = 0;
179 
180   /// \return
181   ///     \b true if and only if there's an instruction item with the given \p
182   ///     id.
183   virtual bool HasId(lldb::user_id_t id) const = 0;
184 
185   /// \return
186   ///     A unique identifier for the instruction or error this cursor is
187   ///     pointing to.
188   virtual lldb::user_id_t GetId() const = 0;
189   /// \}
190 
191   /// Make the cursor point to an item in the trace based on an origin point and
192   /// an offset.
193   ///
194   /// The resulting position of the trace is
195   ///     origin + offset
196   ///
197   /// If this resulting position would be out of bounds, the trace then points
198   /// to an invalid item, i.e. calling \a HasValue() returns \b false.
199   ///
200   /// \param[in] offset
201   ///     How many items to move forwards (if positive) or backwards (if
202   ///     negative) from the given origin point. For example, if origin is \b
203   ///     End, then a negative offset would move backward in the trace, but a
204   ///     positive offset would move past the trace to an invalid item.
205   ///
206   /// \param[in] origin
207   ///     The reference point to use when moving the cursor.
208   ///
209   /// \return
210   ///     \b true if and only if the cursor ends up pointing to a valid item.
211   virtual bool Seek(int64_t offset, SeekType origin) = 0;
212 
213   /// \return
214   ///   The \a ExecutionContextRef of the backing thread from the creation time
215   ///   of this cursor.
216   ExecutionContextRef &GetExecutionContextRef();
217 
218   /// Trace item information (instructions, errors and events)
219   /// \{
220 
221   /// \return
222   ///     The kind of item the cursor is pointing at.
223   virtual lldb::TraceItemKind GetItemKind() const = 0;
224 
225   /// \return
226   ///     Whether the cursor points to an error or not.
227   bool IsError() const;
228 
229   /// \return
230   ///     The error message the cursor is pointing at.
231   virtual const char *GetError() const = 0;
232 
233   /// \return
234   ///     Whether the cursor points to an event or not.
235   bool IsEvent() const;
236 
237   /// \return
238   ///     The specific kind of event the cursor is pointing at, or \b
239   ///     TraceEvent::eTraceEventNone if the cursor not pointing to an event.
240   virtual lldb::TraceEvent GetEventType() const = 0;
241 
242   /// \return
243   ///     A human-readable description of the event this cursor is pointing at.
244   const char *GetEventTypeAsString() const;
245 
246   /// \return
247   ///     A human-readable description of the given event.
248   static const char *EventKindToString(lldb::TraceEvent event_kind);
249 
250   /// \return
251   ///     Whether the cursor points to an instruction.
252   bool IsInstruction() const;
253 
254   /// \return
255   ///     The load address of the instruction the cursor is pointing at.
256   virtual lldb::addr_t GetLoadAddress() const = 0;
257 
258   /// Get the CPU associated with the current trace item.
259   ///
260   /// This call might not be O(1), so it's suggested to invoke this method
261   /// whenever an eTraceEventCPUChanged event is fired.
262   ///
263   /// \return
264   ///    The requested CPU id, or \a llvm::None if this information is
265   ///    not available for the current item.
266   virtual llvm::Optional<lldb::cpu_id_t> GetCPU() const = 0;
267 
268   /// Get the last hardware clock value that was emitted before the current
269   /// trace item.
270   ///
271   /// This call might not be O(1), so it's suggested to invoke this method
272   /// whenever an eTraceEventHWClockTick event is fired.
273   ///
274   /// \return
275   ///     The requested HW clock value, or \a llvm::None if this information is
276   ///     not available for the current item.
277   virtual llvm::Optional<uint64_t> GetHWClock() const = 0;
278 
279   /// Get the approximate wall clock time in nanoseconds at which the current
280   /// trace item was executed. Each trace plug-in has a different definition for
281   /// what time 0 means.
282   ///
283   /// \return
284   ///     The approximate wall clock time for the trace item, or \a llvm::None
285   ///     if not available.
286   virtual llvm::Optional<double> GetWallClockTime() const = 0;
287   /// \}
288 
289 protected:
290   ExecutionContextRef m_exe_ctx_ref;
291   bool m_forwards = false;
292 };
293 } // namespace lldb_private
294 
295 #endif // LLDB_TARGET_TRACE_CURSOR_H
296