#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
+#include "lldb/lldb-forward.h"
#include <memory>
return ret;
}
-class EntityVariable : public Materializer::Entity {
+/// Base class for materialization of Variables and ValueObjects.
+///
+/// Subclasses specify how to obtain the Value which is to be
+/// materialized.
+class EntityVariableBase : public Materializer::Entity {
public:
- EntityVariable(lldb::VariableSP &variable_sp)
- : Entity(), m_variable_sp(variable_sp) {
+ virtual ~EntityVariableBase() = default;
+
+ EntityVariableBase() {
// Hard-coding to maximum size of a pointer since all variables are
// materialized by reference
m_size = g_default_var_byte_size;
m_alignment = g_default_var_alignment;
- m_is_reference =
- m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
}
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
LLDB_LOGF(log,
"EntityVariable::Materialize [address = 0x%" PRIx64
", m_variable_sp = %s]",
- (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
+ (uint64_t)load_addr, GetName().GetCString());
}
ExecutionContextScope *scope = frame_sp.get();
if (!scope)
scope = map.GetBestExecutionContextScope();
- lldb::ValueObjectSP valobj_sp =
- ValueObjectVariable::Create(scope, m_variable_sp);
+ lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
if (!valobj_sp) {
err.SetErrorStringWithFormat(
- "couldn't get a value object for variable %s",
- m_variable_sp->GetName().AsCString());
+ "couldn't get a value object for variable %s", GetName().AsCString());
return;
}
if (valobj_error.Fail()) {
err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
- m_variable_sp->GetName().AsCString(),
+ GetName().AsCString(),
valobj_error.AsCString());
return;
}
if (!extract_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't read contents of reference variable %s: %s",
- m_variable_sp->GetName().AsCString(), extract_error.AsCString());
+ GetName().AsCString(), extract_error.AsCString());
return;
}
if (!write_error.Success()) {
err.SetErrorStringWithFormat("couldn't write the contents of reference "
"variable %s to memory: %s",
- m_variable_sp->GetName().AsCString(),
+ GetName().AsCString(),
write_error.AsCString());
return;
}
if (!write_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't write the address of variable %s to memory: %s",
- m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ GetName().AsCString(), write_error.AsCString());
return;
}
} else {
valobj_sp->GetData(data, extract_error);
if (!extract_error.Success()) {
err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
- m_variable_sp->GetName().AsCString(),
+ GetName().AsCString(),
extract_error.AsCString());
return;
}
if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
err.SetErrorStringWithFormat(
"trying to create a temporary region for %s but one exists",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
return;
}
- if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize(scope)) {
- if (data.GetByteSize() == 0 &&
- !m_variable_sp->LocationExpressionList().IsValid()) {
+ if (data.GetByteSize() < GetByteSize(scope)) {
+ if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
err.SetErrorStringWithFormat("the variable '%s' has no location, "
"it may have been optimized out",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
} else {
err.SetErrorStringWithFormat(
"size of variable %s (%" PRIu64
") is larger than the ValueObject's size (%" PRIu64 ")",
- m_variable_sp->GetName().AsCString(),
- m_variable_sp->GetType()->GetByteSize(scope).value_or(0),
+ GetName().AsCString(), GetByteSize(scope).value_or(0),
data.GetByteSize());
}
return;
}
- llvm::Optional<size_t> opt_bit_align =
- m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
+ llvm::Optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
if (!opt_bit_align) {
err.SetErrorStringWithFormat("can't get the type alignment for %s",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
return;
}
if (!alloc_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't allocate a temporary region for %s: %s",
- m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
+ GetName().AsCString(), alloc_error.AsCString());
return;
}
if (!write_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't write to the temporary region for %s: %s",
- m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ GetName().AsCString(), write_error.AsCString());
return;
}
if (!pointer_write_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't write the address of the temporary region for %s: %s",
- m_variable_sp->GetName().AsCString(),
- pointer_write_error.AsCString());
+ GetName().AsCString(), pointer_write_error.AsCString());
}
}
}
LLDB_LOGF(log,
"EntityVariable::Dematerialize [address = 0x%" PRIx64
", m_variable_sp = %s]",
- (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
+ (uint64_t)load_addr, GetName().AsCString());
}
if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
if (!scope)
scope = map.GetBestExecutionContextScope();
- lldb::ValueObjectSP valobj_sp =
- ValueObjectVariable::Create(scope, m_variable_sp);
+ lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
if (!valobj_sp) {
err.SetErrorStringWithFormat(
"couldn't get a value object for variable %s",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
return;
}
if (!extract_error.Success()) {
err.SetErrorStringWithFormat("couldn't get the data for variable %s",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
return;
}
if (!set_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't write the new contents of %s back into the variable",
- m_variable_sp->GetName().AsCString());
+ GetName().AsCString());
return;
}
}
if (!free_error.Success()) {
err.SetErrorStringWithFormat(
"couldn't free the temporary region for %s: %s",
- m_variable_sp->GetName().AsCString(), free_error.AsCString());
+ GetName().AsCString(), free_error.AsCString());
return;
}
}
private:
- lldb::VariableSP m_variable_sp;
+ virtual ConstString GetName() const = 0;
+
+ /// Creates and returns ValueObject tied to this variable
+ /// and prepares Entity for materialization.
+ ///
+ /// Called each time the Materializer (de)materializes a
+ /// variable. We re-create the ValueObject based on the
+ /// current ExecutionContextScope since clients such as
+ /// conditional breakpoints may materialize the same
+ /// EntityVariable multiple times with different frames.
+ ///
+ /// Each subsequent use of the EntityVariableBase interface
+ /// will query the newly created ValueObject until this
+ /// function is called again.
+ virtual lldb::ValueObjectSP
+ SetupValueObject(ExecutionContextScope *scope) = 0;
+
+ /// Returns size in bytes of the type associated with this variable
+ ///
+ /// \returns On success, returns byte size of the type associated
+ /// with this variable. Returns NoneType otherwise.
+ virtual llvm::Optional<uint64_t>
+ GetByteSize(ExecutionContextScope *scope) const = 0;
+
+ /// Returns 'true' if the location expression associated with this variable
+ /// is valid.
+ virtual bool LocationExpressionIsValid() const = 0;
+
+ /// Returns alignment of the type associated with this variable in bits.
+ ///
+ /// \returns On success, returns alignment in bits for the type associated
+ /// with this variable. Returns NoneType otherwise.
+ virtual llvm::Optional<size_t>
+ GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
+
+protected:
bool m_is_reference = false;
lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
size_t m_temporary_allocation_size = 0;
lldb::DataBufferSP m_original_data;
};
+/// Represents an Entity constructed from a VariableSP.
+///
+/// This class is used for materialization of variables for which
+/// the user has a VariableSP on hand. The ValueObject is then
+/// derived from the associated DWARF location expression when needed
+/// by the Materializer.
+class EntityVariable : public EntityVariableBase {
+public:
+ EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
+ m_is_reference =
+ m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
+ }
+
+ ConstString GetName() const override { return m_variable_sp->GetName(); }
+
+ lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
+ assert(m_variable_sp != nullptr);
+ return ValueObjectVariable::Create(scope, m_variable_sp);
+ }
+
+ llvm::Optional<uint64_t>
+ GetByteSize(ExecutionContextScope *scope) const override {
+ return m_variable_sp->GetType()->GetByteSize(scope);
+ }
+
+ bool LocationExpressionIsValid() const override {
+ return m_variable_sp->LocationExpressionList().IsValid();
+ }
+
+ llvm::Optional<size_t>
+ GetTypeBitAlign(ExecutionContextScope *scope) const override {
+ return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
+ scope);
+ }
+
+private:
+ lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
+};
+
+/// Represents an Entity constructed from a VariableSP.
+///
+/// This class is used for materialization of variables for
+/// which the user does not have a VariableSP available (e.g.,
+/// when materializing ivars).
+class EntityValueObject : public EntityVariableBase {
+public:
+ EntityValueObject(ConstString name, ValueObjectProviderTy provider)
+ : m_name(name), m_valobj_provider(std::move(provider)) {
+ assert(m_valobj_provider);
+ }
+
+ ConstString GetName() const override { return m_name; }
+
+ lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
+ m_valobj_sp =
+ m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
+
+ if (m_valobj_sp)
+ m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
+
+ return m_valobj_sp;
+ }
+
+ llvm::Optional<uint64_t>
+ GetByteSize(ExecutionContextScope *scope) const override {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetCompilerType().GetByteSize(scope);
+
+ return {};
+ }
+
+ bool LocationExpressionIsValid() const override {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetError().Success();
+
+ return false;
+ }
+
+ llvm::Optional<size_t>
+ GetTypeBitAlign(ExecutionContextScope *scope) const override {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
+
+ return {};
+ }
+
+private:
+ ConstString m_name;
+ lldb::ValueObjectSP m_valobj_sp;
+ ValueObjectProviderTy m_valobj_provider;
+};
+
uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
*iter = std::make_unique<EntityVariable>(variable_sp);
return ret;
}
+uint32_t Materializer::AddValueObject(ConstString name,
+ ValueObjectProviderTy valobj_provider,
+ Status &err) {
+ assert(valobj_provider);
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
class EntityResultVariable : public Materializer::Entity {
public:
EntityResultVariable(const CompilerType &type, bool is_program_reference,