blob: eda7103aaa7816f02eb434f7696c8d5fad2a454b [file] [edit]
//===-- 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