Skip to content
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

[lldb] Make ValueObjectDynamicValue::UpdateValue() point to a host b… #125143

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions lldb/include/lldb/Target/LanguageRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,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 @@ -865,6 +865,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 @@ -289,7 +289,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 @@ -770,7 +770,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 @@ -849,6 +849,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
43 changes: 33 additions & 10 deletions lldb/source/ValueObject/ValueObjectDynamicValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,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;

Expand All @@ -157,7 +158,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 @@ -166,20 +167,20 @@ bool ValueObjectDynamicValue::UpdateValue() {
// Fallback to the runtime for `known_type`.
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
value_type);
value_type, local_buffer);
} else {
runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);
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 @@ -239,11 +240,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 @@ -258,7 +277,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,6 +1,7 @@
add_lldb_unittest(LLDBValueObjectTests
DumpValueObjectOptionsTests.cpp
DILLexerTests.cpp
DynamicValueObjectLocalBuffer.cpp

LINK_LIBS
lldbValueObject
Expand Down
Loading