diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h --- a/lldb/include/lldb/Target/Trace.h +++ b/lldb/include/lldb/Target/Trace.h @@ -15,6 +15,7 @@ #include "lldb/Core/PluginInterface.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/TraceCursor.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/TraceGDBRemotePackets.h" #include "lldb/Utility/UnimplementedError.h" @@ -204,6 +205,34 @@ std::function load_addr)> callback) = 0; + /// Get a cursor pointing to the most recent instruction of a given thread's + /// trace that passes the provided filter rules. + /// + /// \param[in] filter + /// Bitmask filter used to define which instruction type the cursor will + /// start pointing to. + /// + /// \param[in] ignore_errors + /// If \b false and there are errors in the trace more recent than the + /// requested instruction, the cursor will point at the most recent error + /// instead. + /// + /// \return + /// A \a TraceCursorSP if the cursor points to a valid instruction or an + /// error. Otherwise, if the thread is not traced or its trace information + /// failed to load, an \a llvm::Error is returned. + virtual llvm::Expected GetThreadEndCursor( + Thread &thread, + lldb::TraceInstructionType filter = lldb::eTraceInstructionTypeAny, + bool ignore_errors = false) = 0; + + /// Similar to \a Trace::GetThreadEndCursor() but it gets the oldest + /// instruction instead. + virtual llvm::Expected GetThreadBeginCursor( + Thread &thread, + lldb::TraceInstructionType filter = lldb::eTraceInstructionTypeAny, + bool ignore_errors = false) = 0; + /// Get the number of available instructions in the trace of the given thread. /// /// \param[in] thread diff --git a/lldb/include/lldb/Target/TraceCursor.h b/lldb/include/lldb/Target/TraceCursor.h new file mode 100644 --- /dev/null +++ b/lldb/include/lldb/Target/TraceCursor.h @@ -0,0 +1,102 @@ +//===-- TraceCursor.h -------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TARGET_TRACE_CURSOR_H +#define LLDB_TARGET_TRACE_CURSOR_H + +#include "lldb/lldb-private.h" + +namespace lldb_private { + +/// Class used for iterating over the instructions of a thread's trace. +/// +/// This class attempts to be a generic interface for accessing the instructions +/// of the trace so that each Trace plug-in can reconstruct, represent and store +/// the instruction data in an flexible way that is efficient for the given +/// technology. +/// +/// Live processes: +/// In the case of a live process trace, an instance of a \a TraceCursor should +/// point to the trace at the moment it was collected. If the process is later +/// resumed and new trace data is collected, that should leave that old cursor +/// unaffected. +/// +/// Errors in the trace: +/// As there could be errors when reconstructing the instructions of a trace, +/// these errors are represented as failed instructions, and the cursor can +/// point at them. The consumer should invoke \a TraceCursor::IsError() to +/// check if the cursor is pointing to either a valid instruction or an error. +/// +/// Instructions: +/// A \a TraceCursor always points to a specific instruction or error in the +/// trace. An empty trace can't have a cursor. +/// +class TraceCursor { +public: + /// Move the cursor to the next instruction in the trace given the provided + /// filter rules. If such instruction is not found, the cursor doesn't move. + /// + /// The instructions are traversed chronologically, and a "next" instruction + /// is newer than the current one. + /// + /// \param[in] filter + /// Bitmask filter. The cursor stops at the next + /// instruction whose type is included in the filter. + /// + /// \param[in] ignore_errors + /// If \b false, the cursor stops as soon as it finds a failure in the + /// trace and points at it. + /// + /// \return + /// \b true if the cursor moved, \b false otherwise. + bool Next(lldb::TraceInstructionType filter = lldb::eTraceInstructionTypeAny, + bool ignore_errors = false); + + /// Similar to \a TraceCursor::Next(), but moves backwards chronologically. + bool Prev(); + + /// \return + /// \b true if the trace corresponds to a live process who has resumed after + /// the trace cursor was created. Otherwise, including the case in which the + /// process is a post-mortem one, return \b false. + bool IsStale(); + + /// Instruction or error information + /// \{ + + /// \return + /// \b true if the cursor is pointing to an error in the trace. The actual + /// error message can be gotten by calling \a TraceCursor::GetError(). + bool IsError(); + + /// \return + /// \b nullptr if the cursor is not pointing to an error in the trace. + /// Otherwise return an error message describing the issue. + const char *GetError(); + + /// \return + /// The load address of the instruction. If the cursor points to an error + /// in the trace, return \b LLDB_INVALID_ADDRESS. + lldb::addr_t GetLoadAddress(); + + /// \return + /// The size in bytes of the instruction. If the cursor points to an error + /// in the trace, return \b 0. + size_t GetInstructionSize(); + + /// \return + /// The type of the instruction. If the cursor points to an error in the + /// trace, the return value is undefined. + lldb::TraceInstructionType GetInstructionType(); + + /// \} +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_H diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -958,6 +958,22 @@ eExpressionEvaluationComplete }; +/// Architecture-agnostic categorization of instructions. Useful for doing +/// analysis on traces. +FLAGS_ENUM(TraceInstructionType){ + /// Any instruction not listed below. + eTraceInstructionTypeNormal = (1u << 1), + /// This includes both conditional and unconditional jumps. + eTraceInstructionTypeJump = (1u << 2), + /// This represents a call to a function. + eTraceInstructionTypeCall = (1u << 3), + /// This represents a return from a function. + eTraceInstructionTypeReturn = (1u << 4), + /// Helper mask to include anything above. + eTraceInstructionTypeAny = (0xffffffffu)}; + +LLDB_MARK_AS_BITMASK_ENUM(TraceInstructionType) + /// Watchpoint Kind. /// /// Indicates what types of events cause the watchpoint to fire. Used by Native diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -229,6 +229,7 @@ class ThreadSpec; class ThreadPostMortemTrace; class Trace; +class TraceCursor; class TraceSessionFileParser; class Type; class TypeAndOrName; @@ -441,6 +442,7 @@ typedef std::weak_ptr ThreadPlanWP; typedef std::shared_ptr ThreadPlanTracerSP; typedef std::shared_ptr TraceSP; +typedef std::shared_ptr TraceCursorSP; typedef std::shared_ptr TypeSP; typedef std::weak_ptr TypeWP; typedef std::shared_ptr TypeCategoryImplSP;