Skip to content

Commit

Permalink
[lldb] Make ValueObjectDynamicValue::UpdateValue() point to a host b… (
Browse files Browse the repository at this point in the history
…llvm#125143)

…uffer

ValueObjectDynamicValue::UpdateValue() assumes that the dynamic type
found by GetDynamicTypeAndAddress() would return an address in the
inferior. This commit makes it so it can deal with being passed a host
address instead.

This is needed downstream by the Swift fork.

rdar://143357274
(cherry picked from commit 0cbc498)
  • Loading branch information
augusto2112 committed Feb 7, 2025
1 parent 9fbb19c commit 674bc6f
Show file tree
Hide file tree
Showing 17 changed files with 341 additions and 40 deletions.
16 changes: 10 additions & 6 deletions lldb/include/lldb/Target/LanguageRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,16 @@ class LanguageRuntime : public Runtime, public PluginInterface {
"language doesn't support getting vtable information");
}

// this call should return true if it could set the name and/or the type
virtual bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) = 0;
/// This call should return true if it could set the name and/or the type
/// Sets address to the address of the dynamic type if value_type is set to
/// a file or load address. Sets local_buffer to a buffer containing the data
/// of the dynamic type if value_type is set to a host address. Callers should
/// copy local_buffer over into their own buffer if they want to keep the data
/// alive.
virtual bool GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) = 0;

// This call should return a CompilerType given a generic type name and an
// ExecutionContextScope in which one can actually fetch any specialization
Expand Down
12 changes: 12 additions & 0 deletions lldb/include/lldb/ValueObject/ValueObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,18 @@ class ValueObject {

virtual void SetLanguageFlags(uint64_t flags) { m_language_flags = flags; }

/// Returns the size of the local buffer if it's available.
/// \return
/// The size of the local buffer if this value object's value points to a
/// host address, and if that size can be determined. Otherwise, returns
/// LLDB_INVALID_ADDRESS.
///
/// TODO: Because a ValueObject's Value can point to any arbitrary memory
/// location, it is possible that the size of the local buffer can't be
/// determined at all. See the comment in Value::m_value for a more thorough
/// explanation of why that is.
uint64_t GetLocalBufferSize();

protected:
typedef ClusterManager<ValueObject> ValueObjectManager;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ llvm::Expected<LanguageRuntime::VTableInfo>
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &dynamic_address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
// For Itanium, if the type has a vtable pointer in the object, it will be at
// offset 0 in the object. That will point to the "address point" within the
// vtable (not the beginning of the vtable.) We can then look up the symbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class ItaniumABILanguageRuntime : public lldb_private::CPPLanguageRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ bool AppleObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
bool AppleObjCRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class AppleObjCRuntime : public lldb_private::ObjCLanguageRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)
bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
class_type_or_name.Clear();
value_type = Value::ValueType::Scalar;
if (CouldHaveDynamicValue(in_value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ class AppleObjCRuntimeV1 : public AppleObjCRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string, ExecutionContext &exe_ctx) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) {
bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
// We should never get here with a null process...
assert(m_process != nullptr);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ class GNUstepObjCRuntime : public lldb_private::ObjCLanguageRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
Expand Down
16 changes: 16 additions & 0 deletions lldb/source/ValueObject/ValueObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,22 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) {
return true;
}

uint64_t ValueObject::GetLocalBufferSize() {
if (m_value.GetValueType() != Value::ValueType::HostAddress)
return LLDB_INVALID_ADDRESS;
auto start = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
if (start == LLDB_INVALID_ADDRESS)
return LLDB_INVALID_ADDRESS;
// Does our pointer point to this value object's m_data buffer?
if ((uint64_t)m_data.GetDataStart() == start)
return m_data.GetByteSize();
// Does our pointer point to the value's buffer?
if ((uint64_t)m_value.GetBuffer().GetBytes() == start)
return m_value.GetBuffer().GetByteSize();
// Our pointer points to something else. We can't know what the size is.
return LLDB_INVALID_ADDRESS;
}

static bool CopyStringDataToBufferSP(const StreamString &source,
lldb::WritableDataBufferSP &destination) {
llvm::StringRef src = source.GetString();
Expand Down
41 changes: 32 additions & 9 deletions lldb/source/ValueObject/ValueObjectDynamicValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
Address dynamic_address;
bool found_dynamic_type = false;
Value::ValueType value_type;
llvm::ArrayRef<uint8_t> local_buffer;

LanguageRuntime *runtime = nullptr;
lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
Expand All @@ -183,7 +184,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
// Try the preferred runtime first.
found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
value_type);
value_type, local_buffer);
if (found_dynamic_type)
// Set the operative `runtime` for later use in this function.
runtime = preferred_runtime;
Expand All @@ -198,14 +199,14 @@ bool ValueObjectDynamicValue::UpdateValue() {
if (runtime)
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
value_type);
value_type, local_buffer);

if (!found_dynamic_type) {
runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);
if (runtime)
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
value_type);
value_type, local_buffer);
}
}

Expand Down Expand Up @@ -277,11 +278,29 @@ bool ValueObjectDynamicValue::UpdateValue() {
if (m_address.IsValid())
SetValueDidChange(true);

// We've moved, so we should be fine...
m_address = dynamic_address;
lldb::TargetSP target_sp(GetTargetSP());
lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
m_value.GetScalar() = load_address;
// If we found a host address, and the dynamic type fits in the local buffer
// that was found, point to thar buffer. Later on this function will copy
// the buffer over.
if (value_type == Value::ValueType::HostAddress && !local_buffer.empty()) {
auto *exe_scope = exe_ctx.GetBestExecutionContextScope();
// If we found a host address but it doesn't fit in the buffer, there's
// nothing we can do.
if (local_buffer.size() <
m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
SetValueIsValid(false);
return false;
}

m_value.GetScalar() = (uint64_t)local_buffer.data();
m_address = LLDB_INVALID_ADDRESS;
} else {
// Otherwise we have a legitimate address on the target. Point to the load
// address.
m_address = dynamic_address;
lldb::TargetSP target_sp(GetTargetSP());
lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
m_value.GetScalar() = load_address;
}
}

if (runtime)
Expand All @@ -296,7 +315,11 @@ bool ValueObjectDynamicValue::UpdateValue() {
LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),
static_cast<void *>(this), GetTypeName().GetCString());

if (m_address.IsValid() && m_dynamic_type_info) {
// m_address could be invalid but we could still have a local buffer
// containing the dynamic value.
if ((m_address.IsValid() ||
m_value.GetValueType() == Value::ValueType::HostAddress) &&
m_dynamic_type_info) {
// The variable value is in the Scalar value inside the m_value. We can
// point our m_data right to it.
m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
Expand Down
22 changes: 12 additions & 10 deletions lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,21 @@ inline clang::DeclarationName getDeclarationName(TypeSystemClang &ast,
return ast.getASTContext().DeclarationNames.getIdentifier(&II);
}

inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) {
inline CompilerType
createRecord(TypeSystemClang &ast, llvm::StringRef name,
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(),
OptionalClangModuleID(),
lldb::AccessType::eAccessPublic, name, 0,
lldb::LanguageType::eLanguageTypeC);
lldb::AccessType::eAccessPublic, name, 0, lang);
}

/// Create a record with the given name and a field with the given type
/// and name.
inline CompilerType createRecordWithField(TypeSystemClang &ast,
llvm::StringRef record_name,
CompilerType field_type,
llvm::StringRef field_name) {
CompilerType t = createRecord(ast, record_name);
inline CompilerType createRecordWithField(
TypeSystemClang &ast, llvm::StringRef record_name, CompilerType field_type,
llvm::StringRef field_name,
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
CompilerType t = createRecord(ast, record_name, lang);

TypeSystemClang::StartTagDeclarationDefinition(t);
ast.AddFieldToRecordType(t, field_name, field_type,
Expand Down Expand Up @@ -63,12 +64,13 @@ struct SourceASTWithRecord {
CompilerType record_type;
clang::RecordDecl *record_decl = nullptr;
clang::FieldDecl *field_decl = nullptr;
SourceASTWithRecord() {
SourceASTWithRecord(
lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
holder = std::make_unique<TypeSystemClangHolder>("test ASTContext");
ast = holder->GetAST();
record_type = createRecordWithField(
*ast, "Source", ast->GetBasicType(lldb::BasicType::eBasicTypeChar),
"a_field");
"a_field", lang);
record_decl =
llvm::cast<clang::RecordDecl>(ClangUtil::GetAsTagDecl(record_type));
field_decl = *record_decl->fields().begin();
Expand Down
1 change: 1 addition & 0 deletions lldb/unittests/ValueObject/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_lldb_unittest(LLDBValueObjectTests
DumpValueObjectOptionsTests.cpp
DynamicValueObjectLocalBuffer.cpp

LINK_LIBS
lldbValueObject
Expand Down
Loading

0 comments on commit 674bc6f

Please sign in to comment.