| //===-- Variables.h -----------------------------------------------------*-===// |
| // |
| // 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_TOOLS_LLDB_DAP_VARIABLES_H |
| #define LLDB_TOOLS_LLDB_DAP_VARIABLES_H |
| |
| #include "DAPForward.h" |
| #include "DAPLog.h" |
| #include "Protocol/DAPTypes.h" |
| #include "Protocol/ProtocolRequests.h" |
| #include "Protocol/ProtocolTypes.h" |
| #include "lldb/API/SBFrame.h" |
| #include "lldb/API/SBValue.h" |
| #include "lldb/API/SBValueList.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| namespace lldb_dap { |
| struct VariableReferenceStorage; |
| |
| enum ScopeKind : unsigned { |
| eScopeKindLocals, |
| eScopeKindGlobals, |
| eScopeKindRegisters |
| }; |
| |
| /// An Interface to get or find specific variables by name. |
| class VariableStore { |
| public: |
| explicit VariableStore(VariableReferenceStorage &storage, bool is_permanent, |
| bool is_internal) |
| : m_storage(storage), m_is_permanent(is_permanent), |
| m_is_internal(is_internal) {} |
| virtual ~VariableStore() = default; |
| |
| virtual llvm::Expected<std::vector<protocol::Variable>> |
| GetVariables(const protocol::VariablesArguments &args) = 0; |
| virtual lldb::SBValue FindVariable(llvm::StringRef name) = 0; |
| virtual lldb::SBValue GetVariable() const { return {}; } |
| |
| // Not copyable. |
| VariableStore(const VariableStore &) = delete; |
| VariableStore &operator=(const VariableStore &) = delete; |
| VariableStore(VariableStore &&) = delete; |
| VariableStore &operator=(VariableStore &&) = delete; |
| |
| protected: |
| VariableReferenceStorage &m_storage; |
| bool m_is_permanent; |
| bool m_is_internal; |
| }; |
| |
| struct VariableReferenceStorage { |
| explicit VariableReferenceStorage(Log &log, protocol::Configuration &config) |
| : log(log), config(config) {} |
| /// \return a new variableReference. |
| /// Specify is_permanent as true for variable that should persist entire |
| /// debug session. |
| var_ref_t CreateVariableReference(bool is_permanent); |
| |
| /// \return the expandable variable corresponding with variableReference |
| /// value of \p value. |
| /// If \p var_ref is invalid an empty SBValue is returned. |
| lldb::SBValue GetVariable(var_ref_t var_ref); |
| |
| /// Insert a new \p variable. |
| /// \return variableReference assigned to this expandable variable. |
| var_ref_t Insert(const lldb::SBValue &variable, bool is_permanent, |
| bool is_internal); |
| |
| /// Insert a value list. Used to store references to lldb repl command |
| /// outputs. |
| var_ref_t Insert(const lldb::SBValueList &values); |
| |
| /// Insert a new frame into temporary storage. |
| std::vector<protocol::Scope> Insert(const lldb::SBFrame &frame); |
| |
| lldb::SBValue FindVariable(var_ref_t var_ref, llvm::StringRef name); |
| |
| void Clear() { m_temporary_kind_pool.Clear(); } |
| |
| VariableStore *GetVariableStore(var_ref_t var_ref); |
| Log &log; |
| protocol::Configuration &config; |
| |
| private: |
| /// Template class for managing pools of variable stores. |
| /// All references created starts from zero with the Reference kind mask |
| /// applied, the mask is then removed when fetching a variable store |
| /// |
| /// \tparam ReferenceKind |
| /// The reference kind created in this pool |
| template <protocol::ReferenceKind Kind> class ReferenceKindPool { |
| |
| public: |
| explicit ReferenceKindPool() = default; |
| |
| /// Resets the count to zero and clears the pool, |
| /// disabled for permanent reference kind. |
| template <protocol::ReferenceKind LHS = Kind, |
| protocol::ReferenceKind RHS = protocol::eReferenceKindPermanent> |
| std::enable_if_t<LHS != RHS, void> Clear() { |
| reference_count = 0; |
| m_pool.clear(); |
| } |
| |
| VariableStore *GetVariableStore(var_ref_t var_ref) { |
| const uint32_t raw_ref = var_ref.Reference(); |
| |
| if (raw_ref != 0 && raw_ref <= m_pool.size()) |
| return m_pool[raw_ref - 1].get(); |
| return nullptr; |
| } |
| |
| template <typename T, typename... Args> var_ref_t Add(Args &&...args) { |
| assert(reference_count == m_pool.size() && |
| "Current reference_count must be the size of the pool"); |
| |
| if (LLVM_UNLIKELY(reference_count >= |
| var_ref_t::k_max_variables_references)) { |
| // We cannot add new variables to the pool; |
| return var_ref_t(var_ref_t::k_invalid_var_ref); |
| } |
| |
| m_pool.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)); |
| const uint32_t raw_ref = NextRawReference(); |
| return var_ref_t(raw_ref, Kind); |
| } |
| |
| [[nodiscard]] size_t Size() const { return m_pool.size(); } |
| |
| // Non copyable and non movable. |
| ReferenceKindPool(const ReferenceKindPool &) = delete; |
| ReferenceKindPool &operator=(const ReferenceKindPool &) = delete; |
| ReferenceKindPool(ReferenceKindPool &&) = delete; |
| ReferenceKindPool &operator=(ReferenceKindPool &&) = delete; |
| ~ReferenceKindPool() = default; |
| |
| private: |
| uint32_t NextRawReference() { |
| reference_count++; |
| return reference_count; |
| } |
| |
| uint32_t reference_count = 0; |
| std::vector<std::unique_ptr<VariableStore>> m_pool; |
| }; |
| |
| /// Variables that are alive in this stop state. |
| /// Will be cleared when debuggee resumes. |
| ReferenceKindPool<protocol::eReferenceKindTemporary> m_temporary_kind_pool; |
| /// Variables that persist across entire debug session. |
| /// These are the variables evaluated from debug console REPL. |
| ReferenceKindPool<protocol::eReferenceKindPermanent> m_permanent_kind_pool; |
| }; |
| |
| } // namespace lldb_dap |
| |
| #endif |