wallace updated this revision to Diff 352605. wallace added a comment. - Simplified Trace.h by simply having lldb::TraceCursorUP GetCursor, as suggested. - Improved the documentation including a sample code. - Added methods to quickly move the trace to the beginning or the end. - Renamed TraceInstructionType to TraceInstructionControlFlowType. I'm not happy with the long name though. I didn't stick to the granularity name because it's useful to know the control flow information of the current instruction, e.g. you might be traversing the instructions one by one but you want to log whenever you see a call. - Also added a dummy "end of trace" invalid instruction. It helps iterating making sure that only the wanted instructions are seen. The other option, which I don't like, is to point to the last actual instruction of the trace, which might not be what the user wants and they would need to make a additional check for it before the loop.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D104422/new/ https://reviews.llvm.org/D104422 Files: lldb/include/lldb/Target/Trace.h lldb/include/lldb/Target/TraceCursor.h lldb/include/lldb/lldb-enumerations.h lldb/include/lldb/lldb-forward.h
Index: lldb/include/lldb/lldb-forward.h =================================================================== --- lldb/include/lldb/lldb-forward.h +++ 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<lldb_private::ThreadPlan> ThreadPlanWP; typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP; typedef std::shared_ptr<lldb_private::Trace> TraceSP; +typedef std::unique_ptr<lldb_private::TraceCursor> TraceCursorUP; typedef std::shared_ptr<lldb_private::Type> TypeSP; typedef std::weak_ptr<lldb_private::Type> TypeWP; typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP; Index: lldb/include/lldb/lldb-enumerations.h =================================================================== --- lldb/include/lldb/lldb-enumerations.h +++ lldb/include/lldb/lldb-enumerations.h @@ -958,6 +958,25 @@ eExpressionEvaluationComplete }; +/// Architecture-agnostic categorization of instructions for traversing the +/// control flow of a trace. +/// +/// A single instruction can match one or more of these categories. +FLAGS_ENUM(TraceCursorInstructionType){ + /// Any instruction. + eTraceCursorInstructionTypeInstruction = (1u << 1), + /// A conditional or unconditional branch/jump. + eTraceCursorInstructionTypeBranch = (1u << 2), + /// A conditional or unconditional branch/jump that changed + /// the control flow of the program. + eTraceCursorInstructionTypeTakenBranch = (1u << 3), + /// A next call to a function. + eTraceCursorInstructionTypeCall = (1u << 4), + /// A return from a function. + eTraceCursorInstructionTypeReturn = (1u << 5)} + +LLDB_MARK_AS_BITMASK_ENUM(TraceCursorInstructionType) + /// Watchpoint Kind. /// /// Indicates what types of events cause the watchpoint to fire. Used by Native Index: lldb/include/lldb/Target/TraceCursor.h =================================================================== --- /dev/null +++ lldb/include/lldb/Target/TraceCursor.h @@ -0,0 +1,137 @@ +//===-- 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::GetError() 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. +/// +/// The Trace initially points to a dummy invalid instruction error signaling +/// the end of a trace, similar to a C++ collections' end iterator. +/// +/// Sample usage: +/// +/// TraceCursorUP cursor = trace.GetTrace(thread); +/// +/// while(cursor->Prev(eTraceCursorInstructionTypeCall | +/// eTraceCursorInstructionTypeReturn)) { +/// if (llvm::Error error = cursor->GetError()) +/// cout << llvm::toString(error) << endl; +/// else if (cursor->GetInstructionType() & eTraceCursorInstructionTypeCall) +/// std::cout << "call found at " << cursor->GetLoadAddress() << +/// std::endl; +/// else +/// std::cout << "return found at " << cursor->GetLoadAddress() << +/// std::endl; +/// } +class TraceCursor { +public: + virtual ~TraceCursor() = default; + + /// Move the cursor to the next instruction in the trace given the provided + /// granularity. 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] granularity + /// Bitmask granularity filter. The cursor stops at the next + /// instruction that matches the specified granularity. + /// + /// \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. + virtual bool Next(lldb::TraceCursorInstructionType granularity = + lldb::eTraceCursorInstructionTypeInstruction, + bool ignore_errors = false) = 0; + + /// Similar to \a TraceCursor::Next(), but moves backwards chronologically. + virtual bool Prev(lldb::TraceCursorInstructionType granularity = + lldb::eTraceCursorInstructionTypeInstruction, + bool ignore_errors = false) = 0; + + /// Force the cursor to point to the end of the trace. + virtual void ResetToEnd() = 0; + + /// Force the cursor to point to the first (i.e. oldest) item of the trace. + virtual void ResetToBegin() = 0; + + /// \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() { return m_stop_id != m_trace_sp->GetStopID(); } + + /// Instruction or error information + /// \{ + + /// Get the corresponding error message if the cursor points to an error in + /// the trace. + /// + /// \return + /// \b llvm::Error::success if the cursor is not pointing to an error in + /// the trace. Otherwise return an \a llvm::Error describing the issue. + virtual llvm::Error GetError() = 0; + + /// \return + /// The load address of the instruction the cursor is pointing at. If the + /// cursor points to an error in the trace, return \b + /// LLDB_INVALID_ADDRESS. + virtual lldb::addr_t GetLoadAddress() = 0; + + /// \return + /// The size in bytes of the instruction opcode the cursor is pointing at. + /// If the cursor points to an error in the trace, return \b 0. + virtual size_t GetInstructionSize() = 0; + + /// \return + /// The \a lldb::TraceCursorInstructionType categories the instruction the + /// cursor is pointing at falls into. If the cursor points to an error in + /// the trace, the return value is undefined. + virtual lldb::TraceCursorInstructionType GetInstructionType() = 0; + + /// \} + +private: + /// The stop ID when the cursor was created. + ssize_t m_stop_id = -1; + /// The trace that owns this cursor. + lldb::TraceSP m_trace_sp; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_CURSOR_H Index: lldb/include/lldb/Target/Trace.h =================================================================== --- lldb/include/lldb/Target/Trace.h +++ 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,14 @@ std::function<bool(size_t index, llvm::Expected<lldb::addr_t> load_addr)> callback) = 0; + /// Get a \a TraceCursor for the given thread's trace. + /// + /// \return + /// A \a TraceCursorUP. If the thread is not traced or its trace + /// information failed to load, the corresponding error is embedded in the + /// trace. + virtual lldb::TraceCursorUP GetCursor(Thread &thread); + /// Get the number of available instructions in the trace of the given thread. /// /// \param[in] thread
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits