-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[lldb/Target] Add BorrowedStackFrame and make StackFrame methods virtual #170191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-lldb Author: Med Ismail Bennani (medismailben) ChangesThis change makes StackFrame methods virtual to enable subclass overrides and introduces BorrowedStackFrame, a wrapper that presents an existing StackFrame with a different frame index. This enables creating synthetic frame views or renumbering frames without copying the underlying frame data, which is useful for frame manipulation scenarios. This also adds a new borrowed-info format entity to show what was the original frame index of the borrowed frame. Patch is 29.56 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170191.diff 10 Files Affected:
diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h
index 40916dc48a70b..107c30a000979 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -81,6 +81,7 @@ struct Entry {
FrameRegisterByName,
FrameIsArtificial,
FrameKind,
+ FrameBorrowedInfo,
ScriptFrame,
FunctionID,
FunctionDidChange,
diff --git a/lldb/include/lldb/Target/BorrowedStackFrame.h b/lldb/include/lldb/Target/BorrowedStackFrame.h
new file mode 100644
index 0000000000000..58c4e66d4f573
--- /dev/null
+++ b/lldb/include/lldb/Target/BorrowedStackFrame.h
@@ -0,0 +1,193 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_BORROWEDSTACKFRAME_H
+#define LLDB_TARGET_BORROWEDSTACKFRAME_H
+
+#include "lldb/Target/StackFrame.h"
+
+namespace lldb_private {
+
+/// \class BorrowedStackFrame BorrowedStackFrame.h
+/// "lldb/Target/BorrowedStackFrame.h"
+///
+/// A wrapper around an existing StackFrame that supersedes its frame index.
+///
+/// This class is useful when you need to present an existing stack frame
+/// with a different index, such as when creating synthetic frame views or
+/// renumbering frames without copying all the underlying data.
+///
+/// All methods delegate to the borrowed frame except for GetFrameIndex()
+/// which uses the overridden index.
+
+class BorrowedStackFrame : public StackFrame {
+public:
+ /// Construct a BorrowedStackFrame that wraps an existing frame.
+ ///
+ /// \param [in] borrowed_frame_sp
+ /// The existing StackFrame to borrow from. This frame's data will be
+ /// used for all operations except frame index queries.
+ ///
+ /// \param [in] override_frame_index
+ /// The frame index to report instead of the borrowed frame's index.
+ BorrowedStackFrame(const lldb::StackFrameSP &borrowed_frame_sp,
+ uint32_t override_frame_index);
+
+ ~BorrowedStackFrame() override = default;
+
+ // Override frame index methods
+ uint32_t GetFrameIndex() const override { return m_override_frame_index; }
+ void SetFrameIndex(uint32_t index) { m_override_frame_index = index; }
+
+ uint32_t GetConcreteFrameIndex() const override {
+ return m_borrowed_frame_sp->GetConcreteFrameIndex();
+ }
+
+ // Delegate all other virtual methods to the borrowed frame
+ StackID &GetStackID() override { return m_borrowed_frame_sp->GetStackID(); }
+
+ const Address &GetFrameCodeAddress() override {
+ return m_borrowed_frame_sp->GetFrameCodeAddress();
+ }
+
+ Address GetFrameCodeAddressForSymbolication() override {
+ return m_borrowed_frame_sp->GetFrameCodeAddressForSymbolication();
+ }
+
+ bool ChangePC(lldb::addr_t pc) override {
+ return m_borrowed_frame_sp->ChangePC(pc);
+ }
+
+ const SymbolContext &
+ GetSymbolContext(lldb::SymbolContextItem resolve_scope) override {
+ return m_borrowed_frame_sp->GetSymbolContext(resolve_scope);
+ }
+
+ llvm::Error GetFrameBaseValue(Scalar &value) override {
+ return m_borrowed_frame_sp->GetFrameBaseValue(value);
+ }
+
+ DWARFExpressionList *GetFrameBaseExpression(Status *error_ptr) override {
+ return m_borrowed_frame_sp->GetFrameBaseExpression(error_ptr);
+ }
+
+ Block *GetFrameBlock() override {
+ return m_borrowed_frame_sp->GetFrameBlock();
+ }
+
+ lldb::RegisterContextSP GetRegisterContext() override {
+ return m_borrowed_frame_sp->GetRegisterContext();
+ }
+
+ VariableList *GetVariableList(bool get_file_globals,
+ Status *error_ptr) override {
+ return m_borrowed_frame_sp->GetVariableList(get_file_globals, error_ptr);
+ }
+
+ lldb::VariableListSP
+ GetInScopeVariableList(bool get_file_globals,
+ bool must_have_valid_location = false) override {
+ return m_borrowed_frame_sp->GetInScopeVariableList(
+ get_file_globals, must_have_valid_location);
+ }
+
+ lldb::ValueObjectSP GetValueForVariableExpressionPath(
+ llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
+ uint32_t options, lldb::VariableSP &var_sp, Status &error) override {
+ return m_borrowed_frame_sp->GetValueForVariableExpressionPath(
+ var_expr, use_dynamic, options, var_sp, error);
+ }
+
+ bool HasDebugInformation() override {
+ return m_borrowed_frame_sp->HasDebugInformation();
+ }
+
+ const char *Disassemble() override {
+ return m_borrowed_frame_sp->Disassemble();
+ }
+
+ lldb::ValueObjectSP
+ GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp,
+ lldb::DynamicValueType use_dynamic) override {
+ return m_borrowed_frame_sp->GetValueObjectForFrameVariable(variable_sp,
+ use_dynamic);
+ }
+
+ bool IsInlined() override { return m_borrowed_frame_sp->IsInlined(); }
+
+ bool IsSynthetic() const override {
+ return m_borrowed_frame_sp->IsSynthetic();
+ }
+
+ bool IsHistorical() const override {
+ return m_borrowed_frame_sp->IsHistorical();
+ }
+
+ bool IsArtificial() const override {
+ return m_borrowed_frame_sp->IsArtificial();
+ }
+
+ bool IsHidden() override { return m_borrowed_frame_sp->IsHidden(); }
+
+ const char *GetFunctionName() override {
+ return m_borrowed_frame_sp->GetFunctionName();
+ }
+
+ const char *GetDisplayFunctionName() override {
+ return m_borrowed_frame_sp->GetDisplayFunctionName();
+ }
+
+ lldb::ValueObjectSP FindVariable(ConstString name) override {
+ return m_borrowed_frame_sp->FindVariable(name);
+ }
+
+ SourceLanguage GetLanguage() override {
+ return m_borrowed_frame_sp->GetLanguage();
+ }
+
+ SourceLanguage GuessLanguage() override {
+ return m_borrowed_frame_sp->GuessLanguage();
+ }
+
+ lldb::ValueObjectSP GuessValueForAddress(lldb::addr_t addr) override {
+ return m_borrowed_frame_sp->GuessValueForAddress(addr);
+ }
+
+ lldb::ValueObjectSP GuessValueForRegisterAndOffset(ConstString reg,
+ int64_t offset) override {
+ return m_borrowed_frame_sp->GuessValueForRegisterAndOffset(reg, offset);
+ }
+
+ StructuredData::ObjectSP GetLanguageSpecificData() override {
+ return m_borrowed_frame_sp->GetLanguageSpecificData();
+ }
+
+ lldb::RecognizedStackFrameSP GetRecognizedFrame() override {
+ return m_borrowed_frame_sp->GetRecognizedFrame();
+ }
+
+ /// Get the underlying borrowed frame.
+ lldb::StackFrameSP GetBorrowedFrame() const { return m_borrowed_frame_sp; }
+
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || StackFrame::isA(ClassID);
+ }
+ static bool classof(const StackFrame *obj) { return obj->isA(&ID); }
+
+private:
+ lldb::StackFrameSP m_borrowed_frame_sp;
+ uint32_t m_override_frame_index;
+ static char ID;
+
+ BorrowedStackFrame(const BorrowedStackFrame &) = delete;
+ const BorrowedStackFrame &operator=(const BorrowedStackFrame &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_BORROWEDSTACKFRAME_H
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index cdbe8ae3c6779..b7f657b06ae86 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -43,6 +43,13 @@ namespace lldb_private {
class StackFrame : public ExecutionContextScope,
public std::enable_shared_from_this<StackFrame> {
public:
+ /// LLVM RTTI support.
+ /// \{
+ static char ID;
+ virtual bool isA(const void *ClassID) const { return ClassID == &ID; }
+ static bool classof(const StackFrame *obj) { return obj->isA(&ID); }
+ /// \}
+
enum ExpressionPathOption {
eExpressionPathOptionCheckPtrVsMember = (1u << 0),
eExpressionPathOptionsNoFragileObjcIvar = (1u << 1),
@@ -127,7 +134,7 @@ class StackFrame : public ExecutionContextScope,
lldb::ThreadSP GetThread() const { return m_thread_wp.lock(); }
- StackID &GetStackID();
+ virtual StackID &GetStackID();
/// Get an Address for the current pc value in this StackFrame.
///
@@ -135,7 +142,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The Address object set to the current PC value.
- const Address &GetFrameCodeAddress();
+ virtual const Address &GetFrameCodeAddress();
/// Get the current code Address suitable for symbolication,
/// may not be the same as GetFrameCodeAddress().
@@ -153,7 +160,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The Address object set to the current PC value.
- Address GetFrameCodeAddressForSymbolication();
+ virtual Address GetFrameCodeAddressForSymbolication();
/// Change the pc value for a given thread.
///
@@ -165,7 +172,7 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// true if the pc was changed. false if this failed -- possibly
/// because this frame is not a live StackFrame.
- bool ChangePC(lldb::addr_t pc);
+ virtual bool ChangePC(lldb::addr_t pc);
/// Provide a SymbolContext for this StackFrame's current pc value.
///
@@ -181,7 +188,8 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// A SymbolContext reference which includes the types of information
/// requested by resolve_scope, if they are available.
- const SymbolContext &GetSymbolContext(lldb::SymbolContextItem resolve_scope);
+ virtual const SymbolContext &
+ GetSymbolContext(lldb::SymbolContextItem resolve_scope);
/// Return the Canonical Frame Address (DWARF term) for this frame.
///
@@ -199,7 +207,7 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// If there is an error determining the CFA address, return an error
/// explaining the failure. Success otherwise.
- llvm::Error GetFrameBaseValue(Scalar &value);
+ virtual llvm::Error GetFrameBaseValue(Scalar &value);
/// Get the DWARFExpressionList corresponding to the Canonical Frame Address.
///
@@ -211,7 +219,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// Returns the corresponding DWARF expression, or NULL.
- DWARFExpressionList *GetFrameBaseExpression(Status *error_ptr);
+ virtual DWARFExpressionList *GetFrameBaseExpression(Status *error_ptr);
/// Get the current lexical scope block for this StackFrame, if possible.
///
@@ -221,7 +229,7 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// A pointer to the current Block. nullptr is returned if this can
/// not be provided.
- Block *GetFrameBlock();
+ virtual Block *GetFrameBlock();
/// Get the RegisterContext for this frame, if possible.
///
@@ -235,7 +243,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The RegisterContext shared point for this frame.
- lldb::RegisterContextSP GetRegisterContext();
+ virtual lldb::RegisterContextSP GetRegisterContext();
const lldb::RegisterContextSP &GetRegisterContextSP() const {
return m_reg_context_sp;
@@ -261,7 +269,8 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// A pointer to a list of variables.
- VariableList *GetVariableList(bool get_file_globals, Status *error_ptr);
+ virtual VariableList *GetVariableList(bool get_file_globals,
+ Status *error_ptr);
/// Retrieve the list of variables that are in scope at this StackFrame's
/// pc.
@@ -280,7 +289,7 @@ class StackFrame : public ExecutionContextScope,
/// StackFrame's pc.
/// \return
/// A pointer to a list of variables.
- lldb::VariableListSP
+ virtual lldb::VariableListSP
GetInScopeVariableList(bool get_file_globals,
bool must_have_valid_location = false);
@@ -309,7 +318,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// A shared pointer to the ValueObject described by var_expr.
- lldb::ValueObjectSP GetValueForVariableExpressionPath(
+ virtual lldb::ValueObjectSP GetValueForVariableExpressionPath(
llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
uint32_t options, lldb::VariableSP &var_sp, Status &error);
@@ -318,14 +327,14 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// true if debug information is available for this frame (function,
/// compilation unit, block, etc.)
- bool HasDebugInformation();
+ virtual bool HasDebugInformation();
/// Return the disassembly for the instructions of this StackFrame's
/// function as a single C string.
///
/// \return
/// C string with the assembly instructions for this function.
- const char *Disassemble();
+ virtual const char *Disassemble();
/// Print a description of this frame using the provided frame format.
///
@@ -337,9 +346,9 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// \b true if and only if dumping with the given \p format worked.
- bool DumpUsingFormat(Stream &strm,
- const lldb_private::FormatEntity::Entry *format,
- llvm::StringRef frame_marker = {});
+ virtual bool DumpUsingFormat(Stream &strm,
+ const lldb_private::FormatEntity::Entry *format,
+ llvm::StringRef frame_marker = {});
/// Print a description for this frame using the frame-format formatter
/// settings. If the current frame-format settings are invalid, then the
@@ -353,8 +362,8 @@ class StackFrame : public ExecutionContextScope,
///
/// \param [in] frame_marker
/// Optional string that will be prepended to the frame output description.
- void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false,
- const char *frame_marker = nullptr);
+ virtual void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false,
+ const char *frame_marker = nullptr);
/// Print a description for this frame using a default format.
///
@@ -366,7 +375,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \param [in] show_fullpaths
/// Whether to print the full source paths or just the file base name.
- void Dump(Stream *strm, bool show_frame_index, bool show_fullpaths);
+ virtual void Dump(Stream *strm, bool show_frame_index, bool show_fullpaths);
/// Print a description of this stack frame and/or the source
/// context/assembly for this stack frame.
@@ -389,8 +398,9 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// Returns true if successful.
- bool GetStatus(Stream &strm, bool show_frame_info, bool show_source,
- bool show_unique = false, const char *frame_marker = nullptr);
+ virtual bool GetStatus(Stream &strm, bool show_frame_info, bool show_source,
+ bool show_unique = false,
+ const char *frame_marker = nullptr);
/// Query whether this frame is a concrete frame on the call stack, or if it
/// is an inlined frame derived from the debug information and presented by
@@ -401,10 +411,10 @@ class StackFrame : public ExecutionContextScope,
virtual bool IsInlined();
/// Query whether this frame is synthetic.
- bool IsSynthetic() const;
+ virtual bool IsSynthetic() const;
/// Query whether this frame is part of a historical backtrace.
- bool IsHistorical() const;
+ virtual bool IsHistorical() const;
/// Query whether this frame is artificial (e.g a synthesized result of
/// inferring missing tail call frames from a backtrace). Artificial frames
@@ -419,7 +429,7 @@ class StackFrame : public ExecutionContextScope,
/// Language plugins can use this API to report language-specific
/// runtime information about this compile unit, such as additional
/// language version details or feature flags.
- StructuredData::ObjectSP GetLanguageSpecificData();
+ virtual StructuredData::ObjectSP GetLanguageSpecificData();
/// Get the frame's demangled name.
///
@@ -439,7 +449,7 @@ class StackFrame : public ExecutionContextScope,
/// \return
/// StackFrame index 0 indicates the currently-executing function. Inline
/// frames are included in this frame index count.
- uint32_t GetFrameIndex() const;
+ virtual uint32_t GetFrameIndex() const;
/// Set this frame's synthetic frame index.
void SetFrameIndex(uint32_t index) { m_frame_index = index; }
@@ -452,7 +462,9 @@ class StackFrame : public ExecutionContextScope,
/// frames are not included in this frame index count; their concrete
/// frame index will be the same as the concrete frame that they are
/// derived from.
- uint32_t GetConcreteFrameIndex() const { return m_concrete_frame_index; }
+ virtual uint32_t GetConcreteFrameIndex() const {
+ return m_concrete_frame_index;
+ }
/// Create a ValueObject for a given Variable in this StackFrame.
///
@@ -466,7 +478,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// A ValueObject for this variable.
- lldb::ValueObjectSP
+ virtual lldb::ValueObjectSP
GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp,
lldb::DynamicValueType use_dynamic);
@@ -474,11 +486,11 @@ class StackFrame : public ExecutionContextScope,
/// parsing expressions given the execution context.
///
/// \return The language of the frame if known.
- SourceLanguage GetLanguage();
+ virtual SourceLanguage GetLanguage();
/// Similar to GetLanguage(), but is allowed to take a potentially incorrect
/// guess if exact information is not available.
- SourceLanguage GuessLanguage();
+ virtual SourceLanguage GuessLanguage();
/// Attempt to econstruct the ValueObject for a given raw address touched by
/// the current instruction. The ExpressionPath should indicate how to get
@@ -489,7 +501,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The ValueObject if found. If valid, it has a valid ExpressionPath.
- lldb::ValueObjectSP GuessValueForAddress(lldb::addr_t addr);
+ virtual lldb::ValueObjectSP GuessValueForAddress(lldb::addr_t addr);
/// Attempt to reconstruct the ValueObject for the address contained in a
/// given register plus an offset. The ExpressionPath should indicate how
@@ -503,8 +515,8 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The ValueObject if found. If valid, it has a valid ExpressionPath.
- lldb::ValueObjectSP GuessValueForRegisterAndOffset(ConstString reg,
- int64_t offset);
+ virtual lldb::ValueObjectSP GuessValueForRegisterAndOffset(ConstString reg,
+ int64_t offset);
/// Attempt to reconstruct the ValueObject for a variable with a given \a name
/// from within the current StackFrame, within the current block. The search
@@ -517,7 +529,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// The ValueObject if found.
- lldb::ValueObjectSP FindVariable(ConstString name);
+ virtual lldb::ValueObjectSP FindVariable(ConstString name);
// lldb::ExecutionContextScope pure virtual functions
lldb::TargetSP CalculateTarget() override;
@@ -530,9 +542,10 @@ class StackFrame : public ExecutionContextScope,
void CalculateExecutionContext(ExecutionContext &exe_ctx) override;
- lldb::RecognizedStackFrameSP GetRecognizedFrame();
+ virtual lldb::RecognizedStackFrameSP GetRecognizedFrame();
protected:
+ friend class BorrowedStackFrame;
friend class StackFrameList;
void SetSymbolContextScope(SymbolContextScope *symbol_scope);
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index 1be911c291703..101fbdd01f1a3 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -57,10 +57,20 @@ let Definition = "debugger" in {
Global,
DefaultStringValue<"{${function.initial-function}{${module...
[truncated]
|
|
LGTM except we need to think about what the concrete vrs. inlined index for a borrowed frame. This is supposed to be the frame index w/o inlining - and inlined frames from a concrete frame should all have the same concrete frame index. If you just look at the degenerate case of an original stack with no inlining -> scripted stack where I leave out the 0th frame, it's clear that all the frames concrete indexes in the scripted stack should shift down by one, i.e. reflect the I'm not sure what should happen if you borrow an inlined frame but not its concrete frame? |
Makes sense. I've changes the concrete index of the borrowed frame to match the new frame index. |
ef8b00c to
d59ae99
Compare
8eaf9d7 to
ad50667
Compare
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
c756760 to
deaa83e
Compare
JDevlieghere
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if Jim's happy.
This change makes StackFrame methods virtual to enable subclass overrides and introduces BorrowedStackFrame, a wrapper that presents an existing StackFrame with a different frame index. This enables creating synthetic frame views or renumbering frames without copying the underlying frame data, which is useful for frame manipulation scenarios. This also adds a new borrowed-info format entity to show what was the original frame index of the borrowed frame. Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
deaa83e to
048f2c5
Compare
This change makes StackFrame methods virtual to enable subclass overrides and introduces BorrowedStackFrame, a wrapper that presents an existing StackFrame with a different frame index.
This enables creating synthetic frame views or renumbering frames without copying the underlying frame data, which is useful for frame manipulation scenarios.
This also adds a new borrowed-info format entity to show what was the original frame index of the borrowed frame.