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 <cmt...@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 <cmt...@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 <cmt...@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 <cmt...@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 <cmt...@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 <cmt...@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); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits