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/2] [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 e7e35e2b2bffc0..0c8dbf384a326c 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 f39bd07a255366..70cd3bdece8a40 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/2] [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 0c8dbf384a326c..c81f57d2a174f2 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 d7155884c6d1b8..0d8eba3c9726d5 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 94a8f3ea319e89..9d1c720d9fc701 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 70cd3bdece8a40..2fd7d100712b9b 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() {} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits