[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 6 05:25:20 PDT 2024
https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/87197
>From 68cb68d3f93aed6b3479fb305131b99ec599c9d8 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 31 Mar 2024 10:59:38 -0700
Subject: [PATCH 1/6] [LLDB] Add more helper functions to ValueObject class.
Create additional helper functions for the ValueObject class, for:
- returning the value as an APSInt or APFloat
- additional type casting options
- additional ways to create ValueObjects from various types of data
- dereferencing a ValueObject
These helper functions are needed for implementing the Data Inspection
Language, described in
https://discourse.llvm.org/t/rfc-data-inspection-language/69893
---
lldb/include/lldb/Core/ValueObject.h | 61 ++++
lldb/source/Core/ValueObject.cpp | 405 +++++++++++++++++++++++++++
2 files changed, 466 insertions(+)
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index e7e35e2b2bffc..0c8dbf384a326 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,6 +441,19 @@ class ValueObject {
virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
+ llvm::APSInt GetValueAsAPSInt();
+
+ llvm::APFloat GetValueAsFloat();
+
+ bool GetValueAsBool();
+
+ /// Update the value of the current object to be the integer in the 'value'
+ /// parameter.
+ void UpdateIntegerValue(const llvm::APInt &value);
+
+ /// Assign the integer value 'new_val_sp' to the current object.
+ void UpdateIntegerValue(lldb::ValueObjectSP new_val_sp);
+
virtual bool SetValueFromCString(const char *value_str, Status &error);
/// Return the module associated with this value object in case the value is
@@ -618,6 +631,24 @@ class ValueObject {
virtual lldb::ValueObjectSP CastPointerType(const char *name,
lldb::TypeSP &type_sp);
+ /// Return the target load address assocaited with this value object.
+ lldb::addr_t GetLoadAddress();
+
+ lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type,
+ const std::vector<uint32_t> &idx);
+
+ lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset);
+
+ lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error);
+
+ lldb::ValueObjectSP CastEnumToBasicType(CompilerType type);
+
+ lldb::ValueObjectSP CastPointerToBasicType(CompilerType type);
+
+ lldb::ValueObjectSP CastIntegerOrEnumToEnumType(CompilerType type);
+
+ lldb::ValueObjectSP CastFloatToEnumType(CompilerType type, Status &error);
+
/// If this object represents a C++ class with a vtable, return an object
/// that represents the virtual function table. If the object isn't a class
/// with a vtable, return a valid ValueObject with the error set correctly.
@@ -668,6 +699,32 @@ class ValueObject {
CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
const ExecutionContext &exe_ctx, CompilerType type);
+ static lldb::ValueObjectSP
+ CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes,
+ CompilerType type);
+
+ static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target,
+ const void *bytes,
+ lldb::BasicType type);
+
+ static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
+ const llvm::APInt &v,
+ CompilerType type);
+
+ static lldb::ValueObjectSP
+ CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
+ CompilerType type);
+
+ static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target,
+ uintptr_t addr,
+ CompilerType type);
+
+ static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
+ bool value);
+
+ static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target,
+ CompilerType type);
+
lldb::ValueObjectSP Persist();
/// Returns true if this is a char* or a char[] if it is a char* and
@@ -719,6 +776,10 @@ class ValueObject {
ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
}
+ void SetDerefValobj(ValueObject *deref) { m_deref_valobj = deref; }
+
+ ValueObject *GetDerefValobj() { return m_deref_valobj; }
+
void SetValueFormat(lldb::TypeFormatImplSP format) {
m_type_format_sp = std::move(format);
ClearUserVisibleData(eClearUserVisibleDataItemsValue);
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index f39bd07a25536..70cd3bdece8a4 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
return fail_value;
}
+llvm::APSInt ValueObject::GetValueAsAPSInt() {
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ byte_size = temp.value();
+
+ unsigned bit_width = static_cast<unsigned>(byte_size * CHAR_BIT);
+ bool success = true;
+ uint64_t fail_value = 0;
+ uint64_t ret_val = GetValueAsUnsigned(fail_value, &success);
+ uint64_t new_value = fail_value;
+ if (success)
+ new_value = ret_val;
+ bool is_signed = GetCompilerType().IsSigned();
+
+ return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed);
+}
+
+llvm::APFloat ValueObject::GetValueAsFloat() {
+ lldb::BasicType basic_type =
+ GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration();
+ lldb::DataExtractorSP data_sp(new DataExtractor());
+ Status error;
+
+ switch (basic_type) {
+ case lldb::eBasicTypeFloat: {
+ float v = 0;
+ GetData(*data_sp, error);
+ assert(error.Success() && "Unable to read float data from value");
+
+ lldb::offset_t offset = 0;
+ uint32_t old_offset = offset;
+ void *ok = nullptr;
+ ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float));
+ assert(offset != old_offset && ok != nullptr && "unable to read data");
+
+ return llvm::APFloat(v);
+ }
+ case lldb::eBasicTypeDouble:
+ // No way to get more precision at the moment.
+ case lldb::eBasicTypeLongDouble: {
+ double v = 0;
+ GetData(*data_sp, error);
+ assert(error.Success() && "Unable to read long double data from value");
+
+ lldb::offset_t offset = 0;
+ uint32_t old_offset = offset;
+ void *ok = nullptr;
+ ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double));
+ assert(offset != old_offset && ok != nullptr && "unable to read data");
+
+ return llvm::APFloat(v);
+ }
+ default:
+ return llvm::APFloat(NAN);
+ }
+}
+
+bool ValueObject::GetValueAsBool() {
+ CompilerType val_type = GetCompilerType();
+ if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
+ val_type.IsPointerType()) {
+ return GetValueAsAPSInt().getBoolValue();
+ }
+ if (val_type.IsFloat()) {
+ return GetValueAsFloat().isNonZero();
+ }
+ if (val_type.IsArrayType()) {
+ lldb::ValueObjectSP new_val =
+ ValueObject::ValueObject::CreateValueObjectFromAddress(
+ GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(),
+ val_type);
+ return new_val->GetValueAsUnsigned(0) != 0;
+ }
+ return false;
+}
+
+void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t byte_size = 0;
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ byte_size = temp.value();
+
+ assert(value.getBitWidth() == byte_size * CHAR_BIT &&
+ "illegal argument: new value should be of the same size");
+
+ lldb::DataExtractorSP data_sp;
+ Status error;
+ data_sp->SetData(value.getRawData(), byte_size,
+ target->GetArchitecture().GetByteOrder());
+ data_sp->SetAddressByteSize(
+ static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize()));
+ SetData(*data_sp, error);
+}
+
+void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) {
+ CompilerType new_val_type = new_val_sp->GetCompilerType();
+ assert((new_val_type.IsInteger() || new_val_type.IsFloat() ||
+ new_val_type.IsPointerType()) &&
+ "illegal argument: new value should be of the same size");
+
+ if (new_val_type.IsInteger()) {
+ UpdateIntegerValue(new_val_sp->GetValueAsAPSInt());
+ } else if (new_val_type.IsFloat()) {
+ UpdateIntegerValue(new_val_sp->GetValueAsFloat().bitcastToAPInt());
+ } else if (new_val_type.IsPointerType()) {
+ UpdateIntegerValue(llvm::APInt(64, new_val_sp->GetValueAsUnsigned(0)));
+ }
+}
+
// if any more "special cases" are added to
// ValueObject::DumpPrintableRepresentation() please keep this call up to date
// by returning true for your new special cases. We will eventually move to
@@ -2809,6 +2919,243 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
return valobj_sp;
}
+lldb::addr_t ValueObject::GetLoadAddress() {
+ lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
+ lldb::TargetSP target_sp = GetTargetSP();
+ if (target_sp) {
+ const bool scalar_is_load_address = true;
+ AddressType addr_type;
+ addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
+ if (addr_type == eAddressTypeFile) {
+ lldb::ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ addr_value = LLDB_INVALID_ADDRESS;
+ else {
+ Address tmp_addr;
+ module_sp->ResolveFileAddress(addr_value, tmp_addr);
+ addr_value = tmp_addr.GetLoadAddress(target_sp.get());
+ }
+ } else if (addr_type == eAddressTypeHost || addr_type == eAddressTypeHost)
+ addr_value = LLDB_INVALID_ADDRESS;
+ }
+ return addr_value;
+}
+
+lldb::ValueObjectSP
+ValueObject::CastDerivedToBaseType(CompilerType type,
+ const std::vector<uint32_t> &idx) {
+
+ lldb::TargetSP target = GetTargetSP();
+ assert((type.IsPointerType() || type.IsReferenceType()) &&
+ "invalid ast: target type should be a pointer or a reference");
+ assert(!idx.empty() && "invalid ast: children sequence should be non-empty");
+
+ // The `value` can be a pointer, but GetChildAtIndex works for pointers too.
+ lldb::ValueObjectSP inner_value;
+
+ for (const uint32_t i : idx) {
+ // Force static value, otherwise we can end up with the "real" type.
+ inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false);
+ }
+
+ // At this point type of `inner_value` should be the dereferenced target type.
+ CompilerType inner_value_type = inner_value->GetCompilerType();
+ if (type.IsPointerType()) {
+ assert(inner_value_type.CompareTypes(type.GetPointeeType()) &&
+ "casted value doesn't match the desired type");
+
+ uintptr_t addr = inner_value->GetLoadAddress();
+ return ValueObject::CreateValueObjectFromPointer(target, addr, type);
+ }
+
+ // At this point the target type should be a reference.
+ assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) &&
+ "casted value doesn't match the desired type");
+
+ return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType()));
+}
+
+lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
+ uint64_t offset) {
+ lldb::TargetSP target = GetTargetSP();
+
+ assert((type.IsPointerType() || type.IsReferenceType()) &&
+ "invalid ast: target type should be a pointer or a reference");
+
+ auto pointer_type =
+ type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType();
+
+ uintptr_t addr =
+ type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
+
+ lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromPointer(
+ target, addr - offset, pointer_type);
+
+ if (type.IsPointerType()) {
+ return value;
+ }
+
+ // At this point the target type is a reference. Since `value` is a pointer,
+ // it has to be dereferenced.
+ Status error;
+ return value->Dereference(error);
+}
+
+lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
+ Status &error) {
+ assert(type.IsScalarType() && "target type must be an scalar");
+ assert(GetCompilerType().IsScalarType() && "argument must be a scalar");
+
+ lldb::TargetSP target = GetTargetSP();
+ if (type.IsBoolean()) {
+ if (GetCompilerType().IsInteger()) {
+ return ValueObject::CreateValueObjectFromBool(target,
+ GetValueAsUnsigned(0) != 0);
+ }
+ if (GetCompilerType().IsFloat()) {
+ return ValueObject::CreateValueObjectFromBool(
+ target, !GetValueAsFloat().isZero());
+ }
+ }
+ if (type.IsInteger()) {
+ if (GetCompilerType().IsInteger()) {
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ }
+ if (GetCompilerType().IsFloat()) {
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target type
+ // is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ error.SetErrorString("invalid type cast detected");
+ }
+
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ }
+ }
+ if (type.IsFloat()) {
+ if (GetCompilerType().IsInteger()) {
+ Scalar scalar_int(GetValueAsAPSInt());
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ }
+ if (GetCompilerType().IsFloat()) {
+ Scalar scalar_float(GetValueAsFloat());
+ llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ }
+ }
+ assert(false && "invalid target type: must be a scalar");
+ return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
+ lldb::TargetSP target = GetTargetSP();
+
+ assert(type.IsScalarType() && "target type must be a scalar");
+ assert(GetCompilerType().IsEnumerationType() && "argument must be an enum");
+
+ if (type.IsBoolean()) {
+ return ValueObject::CreateValueObjectFromBool(target,
+ GetValueAsUnsigned(0) != 0);
+ }
+
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+
+ if (type.IsInteger()) {
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ }
+ if (type.IsFloat()) {
+ Scalar scalar_int(ext);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ }
+ assert(false && "invalid target type: must be a scalar");
+ return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
+ lldb::TargetSP target = GetTargetSP();
+
+ uint64_t type_byte_size = 0;
+ uint64_t val_byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ type_byte_size = temp.value();
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ val_byte_size = temp.value();
+ assert(type.IsInteger() && "target type must be an integer");
+ assert((type.IsBoolean() || type_byte_size >= val_byte_size) &&
+ "target type cannot be smaller than the pointer type");
+
+ if (type.IsBoolean()) {
+ return ValueObject::CreateValueObjectFromBool(target,
+ GetValueAsUnsigned(0) != 0);
+ }
+
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(type_byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
+ lldb::TargetSP target = GetTargetSP();
+
+ assert(type.IsEnumerationType() && "target type must be an enum");
+ assert((GetCompilerType().IsInteger() ||
+ GetCompilerType().IsEnumerationType()) &&
+ "argument must be an integer or an enum");
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+}
+
+lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
+ Status &error) {
+ lldb::TargetSP target = GetTargetSP();
+
+ assert(type.IsEnumerationType() && "target type must be an enum");
+ assert(GetCompilerType().IsFloat() && "argument must be a float");
+
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+
+ llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target type
+ // is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ error.SetErrorString("invalid type cast detected");
+ }
+
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+}
+
ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
@@ -3031,6 +3378,64 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
return new_value_sp;
}
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBytes(lldb::TargetSP target_sp,
+ const void *bytes, CompilerType type) {
+ ExecutionContext exe_ctx(
+ ExecutionContextRef(ExecutionContext(target_sp.get(), false)));
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target_sp.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ bytes, byte_size, target_sp->GetArchitecture().GetByteOrder(),
+ static_cast<uint8_t>(target_sp->GetArchitecture().GetAddressByteSize()));
+ lldb::ValueObjectSP value =
+ ValueObject::CreateValueObjectFromData("result", *data_sp, exe_ctx, type);
+ return value;
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromBytes(
+ lldb::TargetSP target, const void *bytes, lldb::BasicType type) {
+ CompilerType target_type;
+ if (target) {
+ for (auto type_system_sp : target->GetScratchTypeSystems())
+ if (auto compiler_type = type_system_sp->GetBasicTypeFromAST(type)) {
+ target_type = compiler_type;
+ break;
+ }
+ }
+ return CreateValueObjectFromBytes(target, bytes, target_type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPInt(
+ lldb::TargetSP target, const llvm::APInt &v, CompilerType type) {
+ return CreateValueObjectFromBytes(target, v.getRawData(), type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+ lldb::TargetSP target, const llvm::APFloat &v, CompilerType type) {
+ return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromPointer(lldb::TargetSP target, uintptr_t addr,
+ CompilerType type) {
+ return CreateValueObjectFromBytes(target, &addr, type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value) {
+ return CreateValueObjectFromBytes(target, &value, lldb::eBasicTypeBool);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromNullptr(lldb::TargetSP target,
+ CompilerType type) {
+ assert(type.IsNullPtrType() && "target type must be nullptr");
+ uintptr_t zero = 0;
+ return CreateValueObjectFromBytes(target, &zero, type);
+}
+
ModuleSP ValueObject::GetModule() {
ValueObject *root(GetRoot());
if (root != this)
>From 145e74b6d4361b9749e49acc025cda45827c5d96 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 8 Apr 2024 09:46:32 -0700
Subject: [PATCH 2/6] [LLDB] Add more helper functions to ValueObject class.
Fix various issues in GetValueAsAPSInt, GetValueAsAPFloat,
GetValueAsBool, UpdateIntegerValue (renamed to SetValueFromInteger),
and GetLoadAddress:
- Added error checking & reporting.
- Removed asserts.
- Added doxygen comments.
- Renamed UpdateIntegerValue to SetValueFromInteger
- Renamed GetValueAsFloat to GetValueAsAPFloat
- Updated code in GetValue... functions to use existing Scalar values
where possibled.
- Updated SBValue::GetLoadAddress to call ValueObject::GetLoadAddress.
---
lldb/include/lldb/Core/ValueObject.h | 37 ++--
lldb/include/lldb/Utility/Scalar.h | 4 +
lldb/source/API/SBValue.cpp | 22 +-
lldb/source/Core/ValueObject.cpp | 312 +++++++++++++++++----------
4 files changed, 223 insertions(+), 152 deletions(-)
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 0c8dbf384a326..c81f57d2a174f 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,18 +441,29 @@ class ValueObject {
virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
- llvm::APSInt GetValueAsAPSInt();
-
- llvm::APFloat GetValueAsFloat();
-
- bool GetValueAsBool();
-
- /// Update the value of the current object to be the integer in the 'value'
- /// parameter.
- void UpdateIntegerValue(const llvm::APInt &value);
-
- /// Assign the integer value 'new_val_sp' to the current object.
- void UpdateIntegerValue(lldb::ValueObjectSP new_val_sp);
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to an APSInt and return that. Otherwise return an error.
+ llvm::Expected<llvm::APSInt> GetValueAsAPSInt();
+
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to an APFloat and return that. Otherwise return an error.
+ llvm::Expected<llvm::APFloat> GetValueAsAPFloat();
+
+ /// If the current ValueObject is of an appropriate type, convert the
+ /// value to a boolean and return that. Otherwise return an error.
+ llvm::Expected<bool> GetValueAsBool();
+
+ /// Update an existing integer ValueObject with a new integer value. This
+ /// is only intended to be used with 'temporary' ValueObjects, i.e. ones that
+ /// are not associated with program variables. It does not update program
+ /// memory, registers, stack, etc.
+ void SetValueFromInteger(const llvm::APInt &value, Status &error);
+
+ /// Update an existing integer ValueObject with an integer value created
+ /// frome 'new_val_sp'. This is only intended to be used with 'temporary'
+ /// ValueObjects, i.e. ones that are not associated with program variables.
+ /// It does not update program memory, registers, stack, etc.
+ void SetValueFromInteger(lldb::ValueObjectSP new_val_sp, Status &error);
virtual bool SetValueFromCString(const char *value_str, Status &error);
@@ -631,7 +642,7 @@ class ValueObject {
virtual lldb::ValueObjectSP CastPointerType(const char *name,
lldb::TypeSP &type_sp);
- /// Return the target load address assocaited with this value object.
+ /// Return the target load address associated with this value object.
lldb::addr_t GetLoadAddress();
lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type,
diff --git a/lldb/include/lldb/Utility/Scalar.h b/lldb/include/lldb/Utility/Scalar.h
index d7155884c6d1b..0d8eba3c9726d 100644
--- a/lldb/include/lldb/Utility/Scalar.h
+++ b/lldb/include/lldb/Utility/Scalar.h
@@ -181,6 +181,10 @@ class Scalar {
long double LongDouble(long double fail_value = 0.0) const;
+ llvm::APSInt GetAPSInt() const { return m_integer; }
+
+ llvm::APFloat GetAPFloat() const { return m_float; }
+
Status SetValueFromCString(const char *s, lldb::Encoding encoding,
size_t byte_size);
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 94a8f3ea319e8..9d1c720d9fc70 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1262,26 +1262,8 @@ lldb::addr_t SBValue::GetLoadAddress() {
lldb::addr_t value = LLDB_INVALID_ADDRESS;
ValueLocker locker;
lldb::ValueObjectSP value_sp(GetSP(locker));
- if (value_sp) {
- TargetSP target_sp(value_sp->GetTargetSP());
- if (target_sp) {
- const bool scalar_is_load_address = true;
- AddressType addr_type;
- value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
- if (addr_type == eAddressTypeFile) {
- ModuleSP module_sp(value_sp->GetModule());
- if (!module_sp)
- value = LLDB_INVALID_ADDRESS;
- else {
- Address addr;
- module_sp->ResolveFileAddress(value, addr);
- value = addr.GetLoadAddress(target_sp.get());
- }
- } else if (addr_type == eAddressTypeHost ||
- addr_type == eAddressTypeInvalid)
- value = LLDB_INVALID_ADDRESS;
- }
- }
+ if (value_sp)
+ return value_sp->GetLoadAddress();
return value;
}
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 70cd3bdece8a4..2fd7d100712b9 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1089,94 +1089,91 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
return fail_value;
}
-llvm::APSInt ValueObject::GetValueAsAPSInt() {
- lldb::TargetSP target = GetTargetSP();
- uint64_t byte_size = 0;
- if (auto temp = GetCompilerType().GetByteSize(target.get()))
- byte_size = temp.value();
+llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
+ // Make sure the type can be converted to an APSInt.
+ if (!GetCompilerType().IsInteger() &&
+ !GetCompilerType().IsScopedEnumerationType() &&
+ !GetCompilerType().IsPointerType() &&
+ !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
- unsigned bit_width = static_cast<unsigned>(byte_size * CHAR_BIT);
- bool success = true;
- uint64_t fail_value = 0;
- uint64_t ret_val = GetValueAsUnsigned(fail_value, &success);
- uint64_t new_value = fail_value;
- if (success)
- new_value = ret_val;
- bool is_signed = GetCompilerType().IsSigned();
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPSInt();
+ }
- return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed);
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APSInt",
+ llvm::inconvertibleErrorCode());
}
-llvm::APFloat ValueObject::GetValueAsFloat() {
- lldb::BasicType basic_type =
- GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration();
- lldb::DataExtractorSP data_sp(new DataExtractor());
- Status error;
-
- switch (basic_type) {
- case lldb::eBasicTypeFloat: {
- float v = 0;
- GetData(*data_sp, error);
- assert(error.Success() && "Unable to read float data from value");
-
- lldb::offset_t offset = 0;
- uint32_t old_offset = offset;
- void *ok = nullptr;
- ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float));
- assert(offset != old_offset && ok != nullptr && "unable to read data");
+llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() {
+ if (!GetCompilerType().IsFloat())
+ return llvm::make_error<llvm::StringError>(
+ "type cannot be converted to APFloat", llvm::inconvertibleErrorCode());
- return llvm::APFloat(v);
+ if (CanProvideValue()) {
+ Scalar scalar;
+ if (ResolveValue(scalar))
+ return scalar.GetAPFloat();
}
- case lldb::eBasicTypeDouble:
- // No way to get more precision at the moment.
- case lldb::eBasicTypeLongDouble: {
- double v = 0;
- GetData(*data_sp, error);
- assert(error.Success() && "Unable to read long double data from value");
-
- lldb::offset_t offset = 0;
- uint32_t old_offset = offset;
- void *ok = nullptr;
- ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double));
- assert(offset != old_offset && ok != nullptr && "unable to read data");
- return llvm::APFloat(v);
- }
- default:
- return llvm::APFloat(NAN);
- }
+ return llvm::make_error<llvm::StringError>(
+ "error occurred; unable to convert to APFloat",
+ llvm::inconvertibleErrorCode());
}
-bool ValueObject::GetValueAsBool() {
+llvm::Expected<bool> ValueObject::GetValueAsBool() {
CompilerType val_type = GetCompilerType();
if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
val_type.IsPointerType()) {
- return GetValueAsAPSInt().getBoolValue();
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err)
+ return value_or_err->getBoolValue();
}
if (val_type.IsFloat()) {
- return GetValueAsFloat().isNonZero();
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err)
+ return value_or_err->isNonZero();
}
if (val_type.IsArrayType()) {
- lldb::ValueObjectSP new_val =
- ValueObject::ValueObject::CreateValueObjectFromAddress(
- GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(),
- val_type);
- return new_val->GetValueAsUnsigned(0) != 0;
+ return GetAddressOf() != 0;
}
- return false;
+ return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
+ llvm::inconvertibleErrorCode());
}
-void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
+void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right size.
lldb::TargetSP target = GetTargetSP();
uint64_t byte_size = 0;
if (auto temp = GetCompilerType().GetByteSize(target.get()))
byte_size = temp.value();
-
- assert(value.getBitWidth() == byte_size * CHAR_BIT &&
- "illegal argument: new value should be of the same size");
+ if (value.getBitWidth() != byte_size * CHAR_BIT) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
lldb::DataExtractorSP data_sp;
- Status error;
data_sp->SetData(value.getRawData(), byte_size,
target->GetArchitecture().GetByteOrder());
data_sp->SetAddressByteSize(
@@ -1184,18 +1181,57 @@ void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
SetData(*data_sp, error);
}
-void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) {
+void ValueObject::SetValueFromInteger(lldb::ValueObjectSP new_val_sp,
+ Status &error) {
+ // Verify the current object is an integer object
+ CompilerType val_type = GetCompilerType();
+ if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+ !val_type.IsFloat() && !val_type.IsPointerType() &&
+ !val_type.IsScalarType()) {
+ error.SetErrorString("current value object is not an integer objet");
+ return;
+ }
+
+ // Verify the current object is not actually associated with any program
+ // variable.
+ if (GetVariable()) {
+ error.SetErrorString("current value object is not a temporary object");
+ return;
+ }
+
+ // Verify the proposed new value is the right type.
CompilerType new_val_type = new_val_sp->GetCompilerType();
- assert((new_val_type.IsInteger() || new_val_type.IsFloat() ||
- new_val_type.IsPointerType()) &&
- "illegal argument: new value should be of the same size");
+ if (!new_val_type.IsInteger() && !new_val_type.IsFloat() &&
+ !new_val_type.IsPointerType()) {
+ error.SetErrorString(
+ "illegal argument: new value should be of the same size");
+ return;
+ }
if (new_val_type.IsInteger()) {
- UpdateIntegerValue(new_val_sp->GetValueAsAPSInt());
+ auto value_or_err = new_val_sp->GetValueAsAPSInt();
+ if (value_or_err)
+ SetValueFromInteger(*value_or_err, error);
+ else
+ error.SetErrorString("error getting APSInt from new_val_sp");
} else if (new_val_type.IsFloat()) {
- UpdateIntegerValue(new_val_sp->GetValueAsFloat().bitcastToAPInt());
+ auto value_or_err = new_val_sp->GetValueAsAPFloat();
+ if (value_or_err)
+ SetValueFromInteger(value_or_err->bitcastToAPInt(), error);
+ else
+ error.SetErrorString("error getting APFloat from new_val_sp");
} else if (new_val_type.IsPointerType()) {
- UpdateIntegerValue(llvm::APInt(64, new_val_sp->GetValueAsUnsigned(0)));
+ bool success = true;
+ uint64_t int_val = new_val_sp->GetValueAsUnsigned(0, &success);
+ if (success) {
+ lldb::TargetSP target = GetTargetSP();
+ uint64_t num_bits = 0;
+ if (auto temp = new_val_sp->GetCompilerType().GetBitSize(target.get()))
+ num_bits = temp.value();
+ // SetValueFromInteger(llvm::APInt(64, int_val), error);
+ SetValueFromInteger(llvm::APInt(num_bits, int_val), error);
+ } else
+ error.SetErrorString("error converting new_val_sp to integer");
}
}
@@ -2921,8 +2957,7 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
lldb::addr_t ValueObject::GetLoadAddress() {
lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
- lldb::TargetSP target_sp = GetTargetSP();
- if (target_sp) {
+ if (auto target_sp = GetTargetSP()) {
const bool scalar_is_load_address = true;
AddressType addr_type;
addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
@@ -2935,7 +2970,8 @@ lldb::addr_t ValueObject::GetLoadAddress() {
module_sp->ResolveFileAddress(addr_value, tmp_addr);
addr_value = tmp_addr.GetLoadAddress(target_sp.get());
}
- } else if (addr_type == eAddressTypeHost || addr_type == eAddressTypeHost)
+ } else if (addr_type == eAddressTypeHost ||
+ addr_type == eAddressTypeInvalid)
addr_value = LLDB_INVALID_ADDRESS;
}
return addr_value;
@@ -3013,8 +3049,12 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
GetValueAsUnsigned(0) != 0);
}
if (GetCompilerType().IsFloat()) {
- return ValueObject::CreateValueObjectFromBool(
- target, !GetValueAsFloat().isZero());
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err)
+ return ValueObject::CreateValueObjectFromBool(target,
+ !value_or_err->isZero());
+ else // TODO: Figure out the right thing to do in error case..
+ return GetSP();
}
}
if (type.IsInteger()) {
@@ -3022,8 +3062,12 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
uint64_t byte_size = 0;
if (auto temp = type.GetByteSize(target.get()))
byte_size = temp.value();
- llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ } else // TODO: Figure out the right thing to do in error case..
+ return GetSP();
}
if (GetCompilerType().IsFloat()) {
uint64_t byte_size = 0;
@@ -3031,34 +3075,46 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
byte_size = temp.value();
llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
bool is_exact;
- llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
- integer, llvm::APFloat::rmTowardZero, &is_exact);
-
- // Casting floating point values that are out of bounds of the target type
- // is undefined behaviour.
- if (status & llvm::APFloatBase::opInvalidOp) {
- error.SetErrorString("invalid type cast detected");
- }
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ error.SetErrorString("invalid type cast detected");
+ }
- return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ } else // TODO: Figure out the right thing to do in error case..
+ return GetSP();
}
}
if (type.IsFloat()) {
if (GetCompilerType().IsInteger()) {
- Scalar scalar_int(GetValueAsAPSInt());
- llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
- type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ Scalar scalar_int(*value_or_err);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ } else // TODO: Figure out the right thing to do in error case..
+ return GetSP();
}
if (GetCompilerType().IsFloat()) {
- Scalar scalar_float(GetValueAsFloat());
- llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
- type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ Scalar scalar_float(*value_or_err);
+ llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ } else // TODO: Figure out the right thing to do in error case..
+ return GetSP();
}
}
- assert(false && "invalid target type: must be a scalar");
- return lldb::ValueObjectSP();
+ // TODO: Set error message.
+ return GetSP();
}
lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
@@ -3076,19 +3132,22 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
if (auto temp = type.GetByteSize(target.get()))
byte_size = temp.value();
// Get the value as APSInt and extend or truncate it to the requested size.
- llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
- if (type.IsInteger()) {
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
- }
- if (type.IsFloat()) {
- Scalar scalar_int(ext);
- llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
- type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ if (type.IsInteger()) {
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ }
+ if (type.IsFloat()) {
+ Scalar scalar_int(ext);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ }
}
- assert(false && "invalid target type: must be a scalar");
- return lldb::ValueObjectSP();
+ // TODO: Set error message.
+ return GetSP();
}
lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
@@ -3110,8 +3169,13 @@ lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
}
// Get the value as APSInt and extend or truncate it to the requested size.
- llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(type_byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ }
+ // TODO: Set error message.
+ return GetSP();
}
lldb::ValueObjectSP
@@ -3127,8 +3191,13 @@ ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
byte_size = temp.value();
// Get the value as APSInt and extend or truncate it to the requested size.
- llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ }
+ // TODO: Set error message.
+ return GetSP();
}
lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
@@ -3144,16 +3213,21 @@ lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
bool is_exact;
- llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
- integer, llvm::APFloat::rmTowardZero, &is_exact);
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
- // Casting floating point values that are out of bounds of the target type
- // is undefined behaviour.
- if (status & llvm::APFloatBase::opInvalidOp) {
- error.SetErrorString("invalid type cast detected");
- }
+ // Casting floating point values that are out of bounds of the target type
+ // is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ error.SetErrorString("invalid type cast detected");
+ }
- return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ }
+ // TODO: Set error message.
+ return GetSP();
}
ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
>From 22e1b0685eb3fcbc2d232ed981a6bcae99c0a00b Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 22 Apr 2024 21:33:56 -0700
Subject: [PATCH 3/6] [LLDB] Fix review comments for "CreateValueObjectFrom..."
functions.
- Update CreateValueObjectFromAddress to optionally not dereference the address
before creating the value (i.e. create a value object containing the addres
itself). This removes the need for CreateValueObjectFromPointer.
- Remove CreateValueObjectFromPointer
- Remove CreateValueObjectFromBytes functions, moving the DataExtractor into
the callers & having them call CreateValueObjectFromData directly.
- Add 'name' parameter to the next CreateValueObjectFrom... functions.
- Remove assert stetement.
- Add Doxygen comments.
---
lldb/include/lldb/Core/ValueObject.h | 34 +++----
lldb/source/Core/ValueObject.cpp | 146 +++++++++++++++------------
2 files changed, 99 insertions(+), 81 deletions(-)
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index c81f57d2a174f..9910fa7562175 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -701,40 +701,40 @@ class ValueObject {
const ExecutionContext &exe_ctx,
const EvaluateExpressionOptions &options);
+ /// Given an address either create a value object containing the value at
+ /// that address, or create a value object containing the address itself
+ /// (pointer value), depending on whether the parameter 'do_deref' is true or
+ /// false.
static lldb::ValueObjectSP
CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
const ExecutionContext &exe_ctx,
- CompilerType type);
+ CompilerType type, bool do_deref = true);
static lldb::ValueObjectSP
CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
const ExecutionContext &exe_ctx, CompilerType type);
- static lldb::ValueObjectSP
- CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes,
- CompilerType type);
-
- static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target,
- const void *bytes,
- lldb::BasicType type);
-
+ /// Create a value object containing the given APInt value.
static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
const llvm::APInt &v,
- CompilerType type);
+ CompilerType type,
+ llvm::StringRef name);
+ /// Create a value object containing the given APFloat value.
static lldb::ValueObjectSP
CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
- CompilerType type);
-
- static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target,
- uintptr_t addr,
- CompilerType type);
+ CompilerType type, llvm::StringRef name);
+ /// Create a value object containing the given boolean value.
static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
- bool value);
+ bool value,
+ llvm::StringRef name);
+ /// Create a nullptr value object with the specified type (must be a
+ /// nullptr type).
static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target,
- CompilerType type);
+ CompilerType type,
+ llvm::StringRef name);
lldb::ValueObjectSP Persist();
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 2fd7d100712b9..0c5740258e24d 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -3001,7 +3001,10 @@ ValueObject::CastDerivedToBaseType(CompilerType type,
"casted value doesn't match the desired type");
uintptr_t addr = inner_value->GetLoadAddress();
- return ValueObject::CreateValueObjectFromPointer(target, addr, type);
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, type,
+ /* do deref */ false);
}
// At this point the target type should be a reference.
@@ -3024,8 +3027,10 @@ lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
uintptr_t addr =
type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
- lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromPointer(
- target, addr - offset, pointer_type);
+ llvm::StringRef name = "";
+ ExecutionContext exe_ctx(target.get(), false);
+ lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
+ name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false);
if (type.IsPointerType()) {
return value;
@@ -3045,14 +3050,14 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
lldb::TargetSP target = GetTargetSP();
if (type.IsBoolean()) {
if (GetCompilerType().IsInteger()) {
- return ValueObject::CreateValueObjectFromBool(target,
- GetValueAsUnsigned(0) != 0);
+ return ValueObject::CreateValueObjectFromBool(
+ target, GetValueAsUnsigned(0) != 0, "result");
}
if (GetCompilerType().IsFloat()) {
auto value_or_err = GetValueAsAPFloat();
if (value_or_err)
- return ValueObject::CreateValueObjectFromBool(target,
- !value_or_err->isZero());
+ return ValueObject::CreateValueObjectFromBool(
+ target, !value_or_err->isZero(), "result");
else // TODO: Figure out the right thing to do in error case..
return GetSP();
}
@@ -3065,7 +3070,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
auto value_or_err = GetValueAsAPSInt();
if (value_or_err) {
llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
} else // TODO: Figure out the right thing to do in error case..
return GetSP();
}
@@ -3086,7 +3092,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
error.SetErrorString("invalid type cast detected");
}
- return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
} else // TODO: Figure out the right thing to do in error case..
return GetSP();
}
@@ -3098,7 +3105,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
Scalar scalar_int(*value_or_err);
llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
} else // TODO: Figure out the right thing to do in error case..
return GetSP();
}
@@ -3108,7 +3116,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
Scalar scalar_float(*value_or_err);
llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
} else // TODO: Figure out the right thing to do in error case..
return GetSP();
}
@@ -3124,8 +3133,8 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
assert(GetCompilerType().IsEnumerationType() && "argument must be an enum");
if (type.IsBoolean()) {
- return ValueObject::CreateValueObjectFromBool(target,
- GetValueAsUnsigned(0) != 0);
+ return ValueObject::CreateValueObjectFromBool(
+ target, GetValueAsUnsigned(0) != 0, "result");
}
uint64_t byte_size = 0;
@@ -3137,13 +3146,15 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
if (type.IsInteger()) {
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
}
if (type.IsFloat()) {
Scalar scalar_int(ext);
llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
}
}
// TODO: Set error message.
@@ -3164,15 +3175,15 @@ lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
"target type cannot be smaller than the pointer type");
if (type.IsBoolean()) {
- return ValueObject::CreateValueObjectFromBool(target,
- GetValueAsUnsigned(0) != 0);
+ return ValueObject::CreateValueObjectFromBool(
+ target, GetValueAsUnsigned(0) != 0, "result");
}
// Get the value as APSInt and extend or truncate it to the requested size.
auto value_or_err = GetValueAsAPSInt();
if (value_or_err) {
llvm::APSInt ext = value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
}
// TODO: Set error message.
return GetSP();
@@ -3194,7 +3205,7 @@ ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
auto value_or_err = GetValueAsAPSInt();
if (value_or_err) {
llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
}
// TODO: Set error message.
return GetSP();
@@ -3224,7 +3235,8 @@ lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
error.SetErrorString("invalid type cast detected");
}
- return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
}
// TODO: Set error message.
return GetSP();
@@ -3415,9 +3427,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
- CompilerType type) {
+ CompilerType type, bool do_deref) {
if (type) {
CompilerType pointer_type(type.GetPointerType());
+ if (!do_deref)
+ pointer_type = type;
if (pointer_type) {
lldb::DataBufferSP buffer(
new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
@@ -3426,10 +3440,12 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
ConstString(name), buffer, exe_ctx.GetByteOrder(),
exe_ctx.GetAddressByteSize()));
if (ptr_result_valobj_sp) {
- ptr_result_valobj_sp->GetValue().SetValueType(
- Value::ValueType::LoadAddress);
+ if (do_deref)
+ ptr_result_valobj_sp->GetValue().SetValueType(
+ Value::ValueType::LoadAddress);
Status err;
- ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+ if (do_deref)
+ ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
if (ptr_result_valobj_sp && !name.empty())
ptr_result_valobj_sp->SetName(ConstString(name));
}
@@ -3453,61 +3469,63 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
}
lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromBytes(lldb::TargetSP target_sp,
- const void *bytes, CompilerType type) {
- ExecutionContext exe_ctx(
- ExecutionContextRef(ExecutionContext(target_sp.get(), false)));
+ValueObject::CreateValueObjectFromAPInt(lldb::TargetSP target,
+ const llvm::APInt &v, CompilerType type,
+ llvm::StringRef name) {
+ ExecutionContext exe_ctx(target.get(), false);
uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(target_sp.get()))
+ if (auto temp = type.GetByteSize(target.get()))
byte_size = temp.value();
lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
- bytes, byte_size, target_sp->GetArchitecture().GetByteOrder(),
- static_cast<uint8_t>(target_sp->GetArchitecture().GetAddressByteSize()));
- lldb::ValueObjectSP value =
- ValueObject::CreateValueObjectFromData("result", *data_sp, exe_ctx, type);
- return value;
+ reinterpret_cast<const void *>(v.getRawData()), byte_size,
+ exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
}
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromBytes(
- lldb::TargetSP target, const void *bytes, lldb::BasicType type) {
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+ lldb::TargetSP target, const llvm::APFloat &v, CompilerType type,
+ llvm::StringRef name) {
+ return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value,
+ llvm::StringRef name) {
CompilerType target_type;
if (target) {
for (auto type_system_sp : target->GetScratchTypeSystems())
- if (auto compiler_type = type_system_sp->GetBasicTypeFromAST(type)) {
+ if (auto compiler_type =
+ type_system_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool)) {
target_type = compiler_type;
break;
}
}
- return CreateValueObjectFromBytes(target, bytes, target_type);
-}
-
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPInt(
- lldb::TargetSP target, const llvm::APInt &v, CompilerType type) {
- return CreateValueObjectFromBytes(target, v.getRawData(), type);
-}
-
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
- lldb::TargetSP target, const llvm::APFloat &v, CompilerType type) {
- return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type);
-}
-
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromPointer(lldb::TargetSP target, uintptr_t addr,
- CompilerType type) {
- return CreateValueObjectFromBytes(target, &addr, type);
-}
-
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value) {
- return CreateValueObjectFromBytes(target, &value, lldb::eBasicTypeBool);
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = target_type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx,
+ target_type);
}
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromNullptr(lldb::TargetSP target,
- CompilerType type) {
- assert(type.IsNullPtrType() && "target type must be nullptr");
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
+ lldb::TargetSP target, CompilerType type, llvm::StringRef name) {
+ if (!type.IsNullPtrType()) {
+ lldb::ValueObjectSP ret_val;
+ return ret_val;
+ }
uintptr_t zero = 0;
- return CreateValueObjectFromBytes(target, &zero, type);
+ ExecutionContext exe_ctx(target.get(), false);
+ uint64_t byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ byte_size = temp.value();
+ lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+ reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(),
+ exe_ctx.GetAddressByteSize());
+ return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
}
ModuleSP ValueObject::GetModule() {
>From 1e41bfa4e5db70cd157b1a5b1a12b21bfb226b1d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 22 May 2024 07:21:10 -0700
Subject: [PATCH 4/6] [LLDB] Add more helper functions to ValueObject class.
Add doxygen comments for cast functions; reduce number of cast functions
by combining some; fix error reporting in cast functions and remove all
assertions.
---
lldb/include/lldb/Core/ValueObject.h | 36 ++-
lldb/source/Core/ValueObject.cpp | 409 ++++++++++++++++-----------
2 files changed, 258 insertions(+), 187 deletions(-)
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 9910fa7562175..a68ab2da8bb90 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -645,20 +645,28 @@ class ValueObject {
/// Return the target load address associated with this value object.
lldb::addr_t GetLoadAddress();
- lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type,
- const std::vector<uint32_t> &idx);
-
- lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset);
-
- lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error);
-
- lldb::ValueObjectSP CastEnumToBasicType(CompilerType type);
-
- lldb::ValueObjectSP CastPointerToBasicType(CompilerType type);
-
- lldb::ValueObjectSP CastIntegerOrEnumToEnumType(CompilerType type);
-
- lldb::ValueObjectSP CastFloatToEnumType(CompilerType type, Status &error);
+ /// Take a ValueObject whose type is an inherited class, and cast it to
+ /// 'type', which should be one of its base classes. 'base_type_indices'
+ /// contains the indices of direct base classes on the path from the
+ /// ValueObject's current type to 'type'
+ llvm::Expected<lldb::ValueObjectSP>
+ CastDerivedToBaseType(CompilerType type,
+ const llvm::ArrayRef<uint32_t> &base_type_indices);
+
+ /// Take a ValueObject whose type is a base class, and cast it to 'type',
+ /// which should be one of its derived classes. 'base_type_indices'
+ /// contains the indices of direct base classes on the path from the
+ /// ValueObject's current type to 'type'
+ llvm::Expected<lldb::ValueObjectSP> CastBaseToDerivedType(CompilerType type,
+ uint64_t offset);
+
+ // Take a ValueObject that contains a scalar, enum or pointer type, and
+ // cast it to a "basic" type (integer, float or boolean).
+ lldb::ValueObjectSP CastToBasicType(CompilerType type);
+
+ // Take a ValueObject that contain an integer, float or enum, and cast it
+ // to an enum.
+ lldb::ValueObjectSP CastToEnumType(CompilerType type);
/// If this object represents a C++ class with a vtable, return an object
/// that represents the virtual function table. If the object isn't a class
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 0c5740258e24d..d421798e29f7e 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1138,9 +1138,9 @@ llvm::Expected<bool> ValueObject::GetValueAsBool() {
if (value_or_err)
return value_or_err->isNonZero();
}
- if (val_type.IsArrayType()) {
+ if (val_type.IsArrayType())
return GetAddressOf() != 0;
- }
+
return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
llvm::inconvertibleErrorCode());
}
@@ -2977,28 +2977,58 @@ lldb::addr_t ValueObject::GetLoadAddress() {
return addr_value;
}
-lldb::ValueObjectSP
-ValueObject::CastDerivedToBaseType(CompilerType type,
- const std::vector<uint32_t> &idx) {
+llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType(
+ CompilerType type, const llvm::ArrayRef<uint32_t> &base_type_indices) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
- lldb::TargetSP target = GetTargetSP();
- assert((type.IsPointerType() || type.IsReferenceType()) &&
- "invalid ast: target type should be a pointer or a reference");
- assert(!idx.empty() && "invalid ast: children sequence should be non-empty");
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ if (base_type_indices.empty())
+ return llvm::make_error<llvm::StringError>(
+ "Children sequence must be non-empty", llvm::inconvertibleErrorCode());
+
+ // Both the starting & target types are valid for the cast, and the list of
+ // base class indices is non-empty, so we can proceed with the cast.
+
+ lldb::TargetSP target = GetTargetSP();
// The `value` can be a pointer, but GetChildAtIndex works for pointers too.
lldb::ValueObjectSP inner_value;
- for (const uint32_t i : idx) {
+ for (const uint32_t i : base_type_indices)
// Force static value, otherwise we can end up with the "real" type.
inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false);
- }
- // At this point type of `inner_value` should be the dereferenced target type.
+ // At this point type of `inner_value` should be the dereferenced target
+ // type.
CompilerType inner_value_type = inner_value->GetCompilerType();
if (type.IsPointerType()) {
- assert(inner_value_type.CompareTypes(type.GetPointeeType()) &&
- "casted value doesn't match the desired type");
+ if (!inner_value_type.CompareTypes(type.GetPointeeType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
uintptr_t addr = inner_value->GetLoadAddress();
llvm::StringRef name = "";
@@ -3008,19 +3038,59 @@ ValueObject::CastDerivedToBaseType(CompilerType type,
}
// At this point the target type should be a reference.
- assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) &&
- "casted value doesn't match the desired type");
+ if (!inner_value_type.CompareTypes(type.GetNonReferenceType()))
+ return llvm::make_error<llvm::StringError>(
+ "casted value doesn't match the desired type",
+ llvm::inconvertibleErrorCode());
return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType()));
}
-lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
- uint64_t offset) {
- lldb::TargetSP target = GetTargetSP();
+llvm::Expected<lldb::ValueObjectSP>
+ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) {
+ // Make sure the starting type and the target type are both valid for this
+ // type of cast; otherwise return the shared pointer to the original
+ // (unchanged) ValueObject.
+ if (!type.IsPointerType() && !type.IsReferenceType())
+ return llvm::make_error<llvm::StringError>(
+ "Invalid target type: should be a pointer or a reference",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType start_type = GetCompilerType();
+ if (start_type.IsReferenceType())
+ start_type = start_type.GetNonReferenceType();
+
+ auto target_record_type =
+ type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType();
+ auto start_record_type =
+ start_type.IsPointerType() ? start_type.GetPointeeType() : start_type;
+
+ if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType())
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be record types",
+ llvm::inconvertibleErrorCode());
+
+ if (target_record_type.CompareTypes(start_record_type))
+ return llvm::make_error<llvm::StringError>(
+ "Underlying start & target types should be different",
+ llvm::inconvertibleErrorCode());
+
+ CompilerType virtual_base;
+ if (target_record_type.IsVirtualBase(start_record_type, &virtual_base)) {
+ if (!virtual_base.IsValid())
+ return llvm::make_error<llvm::StringError>(
+ "virtual base should be valid", llvm::inconvertibleErrorCode());
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("cannot cast " + start_type.TypeDescription() + " to " +
+ type.TypeDescription() + " via virtual base " +
+ virtual_base.TypeDescription()),
+ llvm::inconvertibleErrorCode());
+ }
- assert((type.IsPointerType() || type.IsReferenceType()) &&
- "invalid ast: target type should be a pointer or a reference");
+ // Both the starting & target types are valid for the cast, so we can
+ // proceed with the cast.
+ lldb::TargetSP target = GetTargetSP();
auto pointer_type =
type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType();
@@ -3032,9 +3102,8 @@ lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false);
- if (type.IsPointerType()) {
+ if (type.IsPointerType())
return value;
- }
// At this point the target type is a reference. Since `value` is a pointer,
// it has to be dereferenced.
@@ -3042,203 +3111,197 @@ lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
return value->Dereference(error);
}
-lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
- Status &error) {
- assert(type.IsScalarType() && "target type must be an scalar");
- assert(GetCompilerType().IsScalarType() && "argument must be a scalar");
+lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
+ bool is_scalar = GetCompilerType().IsScalarType();
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_pointer =
+ GetCompilerType().IsPointerType() || GetCompilerType().IsNullPtrType();
+ bool is_float = GetCompilerType().IsFloat();
+ bool is_integer = GetCompilerType().IsInteger();
+
+ if (!type.IsScalarType()) {
+ m_error.SetErrorString("target type must be a scalar");
+ return GetSP();
+ }
+
+ if (!is_scalar && !is_enum && !is_pointer) {
+ m_error.SetErrorString("argument must be a scalar, enum, or pointer");
+ return GetSP();
+ }
lldb::TargetSP target = GetTargetSP();
+ uint64_t type_byte_size = 0;
+ uint64_t val_byte_size = 0;
+ if (auto temp = type.GetByteSize(target.get()))
+ type_byte_size = temp.value();
+ if (auto temp = GetCompilerType().GetByteSize(target.get()))
+ val_byte_size = temp.value();
+
+ if (is_pointer) {
+ if (type.IsBoolean() && type_byte_size < val_byte_size) {
+ m_error.SetErrorString(
+ "target type cannot be smaller than the pointer type");
+ return GetSP();
+ }
+ if (!type.IsInteger()) {
+ m_error.SetErrorString("target tyep must be an integer");
+ return GetSP();
+ }
+ }
+
if (type.IsBoolean()) {
- if (GetCompilerType().IsInteger()) {
+ if (!is_scalar || is_integer)
return ValueObject::CreateValueObjectFromBool(
target, GetValueAsUnsigned(0) != 0, "result");
- }
- if (GetCompilerType().IsFloat()) {
- auto value_or_err = GetValueAsAPFloat();
- if (value_or_err)
+ else if (is_scalar && is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err)
return ValueObject::CreateValueObjectFromBool(
- target, !value_or_err->isZero(), "result");
- else // TODO: Figure out the right thing to do in error case..
+ target, !float_value_or_err->isZero(), "result");
+ else {
+ m_error.SetErrorString("cannot get value as APFloat");
return GetSP();
+ }
}
}
+
if (type.IsInteger()) {
- if (GetCompilerType().IsInteger()) {
- uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(target.get()))
- byte_size = temp.value();
- auto value_or_err = GetValueAsAPSInt();
- if (value_or_err) {
- llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ if (!is_scalar || is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ // Get the value as APSInt and extend or truncate it to the requested
+ // size.
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
"result");
- } else // TODO: Figure out the right thing to do in error case..
+ } else {
+ m_error.SetErrorString("cannot get value as APSInt");
return GetSP();
- }
- if (GetCompilerType().IsFloat()) {
- uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(target.get()))
- byte_size = temp.value();
- llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ }
+ } else if (is_scalar && is_float) {
+ llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned());
bool is_exact;
- auto value_or_err = GetValueAsAPFloat();
- if (value_or_err) {
- llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
- integer, llvm::APFloat::rmTowardZero, &is_exact);
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ llvm::APFloatBase::opStatus status =
+ float_value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
// Casting floating point values that are out of bounds of the target
// type is undefined behaviour.
if (status & llvm::APFloatBase::opInvalidOp) {
- error.SetErrorString("invalid type cast detected");
+ m_error.SetErrorString("invalid type cast detected");
+ return GetSP();
}
-
return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
"result");
- } else // TODO: Figure out the right thing to do in error case..
- return GetSP();
+ }
}
}
+
if (type.IsFloat()) {
- if (GetCompilerType().IsInteger()) {
- auto value_or_err = GetValueAsAPSInt();
- if (value_or_err) {
- Scalar scalar_int(*value_or_err);
+ if (!is_scalar) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ llvm::APSInt ext =
+ int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+ Scalar scalar_int(ext);
llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
type.GetCanonicalType().GetBasicTypeEnumeration());
return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
"result");
- } else // TODO: Figure out the right thing to do in error case..
- return GetSP();
- }
- if (GetCompilerType().IsFloat()) {
- auto value_or_err = GetValueAsAPFloat();
- if (value_or_err) {
- Scalar scalar_float(*value_or_err);
- llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
- type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
- "result");
- } else // TODO: Figure out the right thing to do in error case..
+ } else {
+ m_error.SetErrorString("cannot get value as APSInt");
return GetSP();
+ }
+ } else {
+ if (is_integer) {
+ auto int_value_or_err = GetValueAsAPSInt();
+ if (int_value_or_err) {
+ Scalar scalar_int(*int_value_or_err);
+ llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APSInt");
+ return GetSP();
+ }
+ }
+ if (is_float) {
+ auto float_value_or_err = GetValueAsAPFloat();
+ if (float_value_or_err) {
+ Scalar scalar_float(*float_value_or_err);
+ llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+ type.GetCanonicalType().GetBasicTypeEnumeration());
+ return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APFloat");
+ return GetSP();
+ }
+ }
}
}
- // TODO: Set error message.
- return GetSP();
-}
-
-lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
- lldb::TargetSP target = GetTargetSP();
-
- assert(type.IsScalarType() && "target type must be a scalar");
- assert(GetCompilerType().IsEnumerationType() && "argument must be an enum");
-
- if (type.IsBoolean()) {
- return ValueObject::CreateValueObjectFromBool(
- target, GetValueAsUnsigned(0) != 0, "result");
- }
- uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(target.get()))
- byte_size = temp.value();
- // Get the value as APSInt and extend or truncate it to the requested size.
- auto value_or_err = GetValueAsAPSInt();
- if (value_or_err) {
- llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
-
- if (type.IsInteger()) {
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
- "result");
- }
- if (type.IsFloat()) {
- Scalar scalar_int(ext);
- llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
- type.GetCanonicalType().GetBasicTypeEnumeration());
- return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
- "result");
- }
- }
- // TODO: Set error message.
+ m_error.SetErrorString("Unable to perform requested cast");
return GetSP();
}
-lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
- lldb::TargetSP target = GetTargetSP();
+lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
+ bool is_enum = GetCompilerType().IsEnumerationType();
+ bool is_integer = GetCompilerType().IsInteger();
+ bool is_float = GetCompilerType().IsFloat();
- uint64_t type_byte_size = 0;
- uint64_t val_byte_size = 0;
- if (auto temp = type.GetByteSize(target.get()))
- type_byte_size = temp.value();
- if (auto temp = GetCompilerType().GetByteSize(target.get()))
- val_byte_size = temp.value();
- assert(type.IsInteger() && "target type must be an integer");
- assert((type.IsBoolean() || type_byte_size >= val_byte_size) &&
- "target type cannot be smaller than the pointer type");
-
- if (type.IsBoolean()) {
- return ValueObject::CreateValueObjectFromBool(
- target, GetValueAsUnsigned(0) != 0, "result");
+ if (!is_enum && !is_integer && !is_float) {
+ m_error.SetErrorString("argument must be an integer, a float, or an enum");
+ return GetSP();
}
- // Get the value as APSInt and extend or truncate it to the requested size.
- auto value_or_err = GetValueAsAPSInt();
- if (value_or_err) {
- llvm::APSInt ext = value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
+ if (!type.IsEnumerationType()) {
+ m_error.SetErrorString("target type must be an enum");
+ return GetSP();
}
- // TODO: Set error message.
- return GetSP();
-}
-lldb::ValueObjectSP
-ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
lldb::TargetSP target = GetTargetSP();
-
- assert(type.IsEnumerationType() && "target type must be an enum");
- assert((GetCompilerType().IsInteger() ||
- GetCompilerType().IsEnumerationType()) &&
- "argument must be an integer or an enum");
uint64_t byte_size = 0;
if (auto temp = type.GetByteSize(target.get()))
byte_size = temp.value();
- // Get the value as APSInt and extend or truncate it to the requested size.
- auto value_or_err = GetValueAsAPSInt();
- if (value_or_err) {
- llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
- return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
- }
- // TODO: Set error message.
- return GetSP();
-}
-
-lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
- Status &error) {
- lldb::TargetSP target = GetTargetSP();
-
- assert(type.IsEnumerationType() && "target type must be an enum");
- assert(GetCompilerType().IsFloat() && "argument must be a float");
-
- uint64_t byte_size = 0;
- if (auto temp = type.GetByteSize(target.get()))
- byte_size = temp.value();
- llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
- bool is_exact;
-
- auto value_or_err = GetValueAsAPFloat();
- if (value_or_err) {
- llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
- integer, llvm::APFloat::rmTowardZero, &is_exact);
-
- // Casting floating point values that are out of bounds of the target type
- // is undefined behaviour.
- if (status & llvm::APFloatBase::opInvalidOp) {
- error.SetErrorString("invalid type cast detected");
+ if (is_float) {
+ llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+ bool is_exact;
+ auto value_or_err = GetValueAsAPFloat();
+ if (value_or_err) {
+ llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+ integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+ // Casting floating point values that are out of bounds of the target
+ // type is undefined behaviour.
+ if (status & llvm::APFloatBase::opInvalidOp) {
+ m_error.SetErrorString("invalid type cast detected");
+ return GetSP();
+ }
+ return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APFloat");
+ return GetSP();
+ }
+ } else {
+ // Get the value as APSInt and extend or truncate it to the requested size.
+ auto value_or_err = GetValueAsAPSInt();
+ if (value_or_err) {
+ llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+ return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+ "result");
+ } else {
+ m_error.SetErrorString("cannot get value as APSInt");
+ return GetSP();
}
-
- return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
- "result");
}
- // TODO: Set error message.
+ m_error.SetErrorString("Cannot perform requested cast");
return GetSP();
}
>From 28748a9db3f09c15de5beb7b126ac568aa78cddc Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 5 Jun 2024 05:01:26 -0700
Subject: [PATCH 5/6] [LLDB] Add more helper functions to ValueObject.
Fix remaining issues wit 'cast' functions:
- Update parameter type checking
- Update error messages & error status checking
- Correctly update 'inner_value' in 'CastDerivedToBaseType'
---
lldb/source/Core/ValueObject.cpp | 44 +++++++++++++++++++++++---------
1 file changed, 32 insertions(+), 12 deletions(-)
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index d421798e29f7e..0ab1e677b99ae 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1093,7 +1093,9 @@ llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
// Make sure the type can be converted to an APSInt.
if (!GetCompilerType().IsInteger() &&
!GetCompilerType().IsScopedEnumerationType() &&
+ !GetCompilerType().IsEnumerationType() &&
!GetCompilerType().IsPointerType() &&
+ !GetCompilerType().IsNullPtrType() &&
!GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
return llvm::make_error<llvm::StringError>(
"type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
@@ -3015,11 +3017,12 @@ llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType(
lldb::TargetSP target = GetTargetSP();
// The `value` can be a pointer, but GetChildAtIndex works for pointers too.
- lldb::ValueObjectSP inner_value;
+ lldb::ValueObjectSP inner_value = GetSP();
for (const uint32_t i : base_type_indices)
// Force static value, otherwise we can end up with the "real" type.
- inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false);
+ inner_value =
+ inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true);
// At this point type of `inner_value` should be the dereferenced target
// type.
@@ -3138,13 +3141,13 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
val_byte_size = temp.value();
if (is_pointer) {
- if (type.IsBoolean() && type_byte_size < val_byte_size) {
+ if (!type.IsBoolean() && type_byte_size < val_byte_size) {
m_error.SetErrorString(
"target type cannot be smaller than the pointer type");
return GetSP();
}
if (!type.IsInteger()) {
- m_error.SetErrorString("target tyep must be an integer");
+ m_error.SetErrorString("target type must be an integer");
return GetSP();
}
}
@@ -3159,7 +3162,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
return ValueObject::CreateValueObjectFromBool(
target, !float_value_or_err->isZero(), "result");
else {
- m_error.SetErrorString("cannot get value as APFloat");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
return GetSP();
}
}
@@ -3176,7 +3181,10 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
"result");
} else {
- m_error.SetErrorString("cannot get value as APSInt");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
+ ;
return GetSP();
}
} else if (is_scalar && is_float) {
@@ -3191,7 +3199,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
// Casting floating point values that are out of bounds of the target
// type is undefined behaviour.
if (status & llvm::APFloatBase::opInvalidOp) {
- m_error.SetErrorString("invalid type cast detected");
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
return GetSP();
}
return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
@@ -3212,7 +3222,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
"result");
} else {
- m_error.SetErrorString("cannot get value as APSInt");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
return GetSP();
}
} else {
@@ -3225,7 +3237,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
"result");
} else {
- m_error.SetErrorString("cannot get value as APSInt");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(int_value_or_err.takeError()).c_str());
return GetSP();
}
}
@@ -3238,7 +3252,9 @@ lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) {
return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
"result");
} else {
- m_error.SetErrorString("cannot get value as APFloat");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APFloat: %s",
+ llvm::toString(float_value_or_err.takeError()).c_str());
return GetSP();
}
}
@@ -3280,7 +3296,9 @@ lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
// Casting floating point values that are out of bounds of the target
// type is undefined behaviour.
if (status & llvm::APFloatBase::opInvalidOp) {
- m_error.SetErrorString("invalid type cast detected");
+ m_error.SetErrorStringWithFormat(
+ "invalid type cast detected: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
return GetSP();
}
return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
@@ -3297,7 +3315,9 @@ lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
"result");
} else {
- m_error.SetErrorString("cannot get value as APSInt");
+ m_error.SetErrorStringWithFormat(
+ "cannot get value as APSInt: %s",
+ llvm::toString(value_or_err.takeError()).c_str());
return GetSP();
}
}
>From 499a097e1832334956655980470405d58ae91ab9 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Thu, 6 Jun 2024 05:24:27 -0700
Subject: [PATCH 6/6] Fix comment.
---
lldb/source/Core/ValueObject.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 0ab1e677b99ae..221b1499c2c56 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -3020,7 +3020,7 @@ llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType(
lldb::ValueObjectSP inner_value = GetSP();
for (const uint32_t i : base_type_indices)
- // Force static value, otherwise we can end up with the "real" type.
+ // Create synthetic value if needed.
inner_value =
inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true);
More information about the lldb-commits
mailing list