[Lldb-commits] [lldb] [LLDB] Add more helper functions to ValueObject class. (PR #87197)

via lldb-commits lldb-commits at lists.llvm.org
Wed May 22 07:26:28 PDT 2024


https://github.com/cmtice updated https://github.com/llvm/llvm-project/pull/87197

>From 68cb68d3f93aed6b3479fb305131b99ec599c9d8 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 31 Mar 2024 10:59:38 -0700
Subject: [PATCH 1/4] [LLDB] Add more helper functions to ValueObject class.

Create additional helper functions for the ValueObject class, for:
  - returning the value as an APSInt or APFloat
  - additional type casting options
  - additional ways to create ValueObjects from various types of data
  - dereferencing a ValueObject

These helper functions are needed for implementing the Data Inspection
Language, described in
https://discourse.llvm.org/t/rfc-data-inspection-language/69893
---
 lldb/include/lldb/Core/ValueObject.h |  61 ++++
 lldb/source/Core/ValueObject.cpp     | 405 +++++++++++++++++++++++++++
 2 files changed, 466 insertions(+)

diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index e7e35e2b2bffc..0c8dbf384a326 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,6 +441,19 @@ class ValueObject {
 
   virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
 
+  llvm::APSInt GetValueAsAPSInt();
+
+  llvm::APFloat GetValueAsFloat();
+
+  bool GetValueAsBool();
+
+  /// Update the value of the current object to be the integer in the 'value'
+  /// parameter.
+  void UpdateIntegerValue(const llvm::APInt &value);
+
+  /// Assign the integer value 'new_val_sp' to the current object.
+  void UpdateIntegerValue(lldb::ValueObjectSP new_val_sp);
+
   virtual bool SetValueFromCString(const char *value_str, Status &error);
 
   /// Return the module associated with this value object in case the value is
@@ -618,6 +631,24 @@ class ValueObject {
   virtual lldb::ValueObjectSP CastPointerType(const char *name,
                                               lldb::TypeSP &type_sp);
 
+  /// Return the target load address assocaited with this value object.
+  lldb::addr_t GetLoadAddress();
+
+  lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type,
+                                            const std::vector<uint32_t> &idx);
+
+  lldb::ValueObjectSP CastBaseToDerivedType(CompilerType type, uint64_t offset);
+
+  lldb::ValueObjectSP CastScalarToBasicType(CompilerType type, Status &error);
+
+  lldb::ValueObjectSP CastEnumToBasicType(CompilerType type);
+
+  lldb::ValueObjectSP CastPointerToBasicType(CompilerType type);
+
+  lldb::ValueObjectSP CastIntegerOrEnumToEnumType(CompilerType type);
+
+  lldb::ValueObjectSP CastFloatToEnumType(CompilerType type, Status &error);
+
   /// If this object represents a C++ class with a vtable, return an object
   /// that represents the virtual function table. If the object isn't a class
   /// with a vtable, return a valid ValueObject with the error set correctly.
@@ -668,6 +699,32 @@ class ValueObject {
   CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
                             const ExecutionContext &exe_ctx, CompilerType type);
 
+  static lldb::ValueObjectSP
+  CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes,
+                             CompilerType type);
+
+  static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target,
+                                                        const void *bytes,
+                                                        lldb::BasicType type);
+
+  static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
+                                                        const llvm::APInt &v,
+                                                        CompilerType type);
+
+  static lldb::ValueObjectSP
+  CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
+                               CompilerType type);
+
+  static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target,
+                                                          uintptr_t addr,
+                                                          CompilerType type);
+
+  static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
+                                                       bool value);
+
+  static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target,
+                                                          CompilerType type);
+
   lldb::ValueObjectSP Persist();
 
   /// Returns true if this is a char* or a char[] if it is a char* and
@@ -719,6 +776,10 @@ class ValueObject {
     ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
   }
 
+  void SetDerefValobj(ValueObject *deref) { m_deref_valobj = deref; }
+
+  ValueObject *GetDerefValobj() { return m_deref_valobj; }
+
   void SetValueFormat(lldb::TypeFormatImplSP format) {
     m_type_format_sp = std::move(format);
     ClearUserVisibleData(eClearUserVisibleDataItemsValue);
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index f39bd07a25536..70cd3bdece8a4 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1089,6 +1089,116 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
   return fail_value;
 }
 
+llvm::APSInt ValueObject::GetValueAsAPSInt() {
+  lldb::TargetSP target = GetTargetSP();
+  uint64_t byte_size = 0;
+  if (auto temp = GetCompilerType().GetByteSize(target.get()))
+    byte_size = temp.value();
+
+  unsigned bit_width = static_cast<unsigned>(byte_size * CHAR_BIT);
+  bool success = true;
+  uint64_t fail_value = 0;
+  uint64_t ret_val = GetValueAsUnsigned(fail_value, &success);
+  uint64_t new_value = fail_value;
+  if (success)
+    new_value = ret_val;
+  bool is_signed = GetCompilerType().IsSigned();
+
+  return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed);
+}
+
+llvm::APFloat ValueObject::GetValueAsFloat() {
+  lldb::BasicType basic_type =
+      GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration();
+  lldb::DataExtractorSP data_sp(new DataExtractor());
+  Status error;
+
+  switch (basic_type) {
+  case lldb::eBasicTypeFloat: {
+    float v = 0;
+    GetData(*data_sp, error);
+    assert(error.Success() && "Unable to read float data from value");
+
+    lldb::offset_t offset = 0;
+    uint32_t old_offset = offset;
+    void *ok = nullptr;
+    ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float));
+    assert(offset != old_offset && ok != nullptr && "unable to read data");
+
+    return llvm::APFloat(v);
+  }
+  case lldb::eBasicTypeDouble:
+    // No way to get more precision at the moment.
+  case lldb::eBasicTypeLongDouble: {
+    double v = 0;
+    GetData(*data_sp, error);
+    assert(error.Success() && "Unable to read long double data from value");
+
+    lldb::offset_t offset = 0;
+    uint32_t old_offset = offset;
+    void *ok = nullptr;
+    ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double));
+    assert(offset != old_offset && ok != nullptr && "unable to read data");
+
+    return llvm::APFloat(v);
+  }
+  default:
+    return llvm::APFloat(NAN);
+  }
+}
+
+bool ValueObject::GetValueAsBool() {
+  CompilerType val_type = GetCompilerType();
+  if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
+      val_type.IsPointerType()) {
+    return GetValueAsAPSInt().getBoolValue();
+  }
+  if (val_type.IsFloat()) {
+    return GetValueAsFloat().isNonZero();
+  }
+  if (val_type.IsArrayType()) {
+    lldb::ValueObjectSP new_val =
+        ValueObject::ValueObject::CreateValueObjectFromAddress(
+            GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(),
+            val_type);
+    return new_val->GetValueAsUnsigned(0) != 0;
+  }
+  return false;
+}
+
+void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
+  lldb::TargetSP target = GetTargetSP();
+  uint64_t byte_size = 0;
+  if (auto temp = GetCompilerType().GetByteSize(target.get()))
+    byte_size = temp.value();
+
+  assert(value.getBitWidth() == byte_size * CHAR_BIT &&
+         "illegal argument: new value should be of the same size");
+
+  lldb::DataExtractorSP data_sp;
+  Status error;
+  data_sp->SetData(value.getRawData(), byte_size,
+                   target->GetArchitecture().GetByteOrder());
+  data_sp->SetAddressByteSize(
+      static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize()));
+  SetData(*data_sp, error);
+}
+
+void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) {
+  CompilerType new_val_type = new_val_sp->GetCompilerType();
+  assert((new_val_type.IsInteger() || new_val_type.IsFloat() ||
+          new_val_type.IsPointerType()) &&
+         "illegal argument: new value should be of the same size");
+
+  if (new_val_type.IsInteger()) {
+    UpdateIntegerValue(new_val_sp->GetValueAsAPSInt());
+  } else if (new_val_type.IsFloat()) {
+    UpdateIntegerValue(new_val_sp->GetValueAsFloat().bitcastToAPInt());
+  } else if (new_val_type.IsPointerType()) {
+    UpdateIntegerValue(llvm::APInt(64, new_val_sp->GetValueAsUnsigned(0)));
+  }
+}
+
 // if any more "special cases" are added to
 // ValueObject::DumpPrintableRepresentation() please keep this call up to date
 // by returning true for your new special cases. We will eventually move to
@@ -2809,6 +2919,243 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
   return valobj_sp;
 }
 
+lldb::addr_t ValueObject::GetLoadAddress() {
+  lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
+  lldb::TargetSP target_sp = GetTargetSP();
+  if (target_sp) {
+    const bool scalar_is_load_address = true;
+    AddressType addr_type;
+    addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
+    if (addr_type == eAddressTypeFile) {
+      lldb::ModuleSP module_sp(GetModule());
+      if (!module_sp)
+        addr_value = LLDB_INVALID_ADDRESS;
+      else {
+        Address tmp_addr;
+        module_sp->ResolveFileAddress(addr_value, tmp_addr);
+        addr_value = tmp_addr.GetLoadAddress(target_sp.get());
+      }
+    } else if (addr_type == eAddressTypeHost || addr_type == eAddressTypeHost)
+      addr_value = LLDB_INVALID_ADDRESS;
+  }
+  return addr_value;
+}
+
+lldb::ValueObjectSP
+ValueObject::CastDerivedToBaseType(CompilerType type,
+                                   const std::vector<uint32_t> &idx) {
+
+  lldb::TargetSP target = GetTargetSP();
+  assert((type.IsPointerType() || type.IsReferenceType()) &&
+         "invalid ast: target type should be a pointer or a reference");
+  assert(!idx.empty() && "invalid ast: children sequence should be non-empty");
+
+  // The `value` can be a pointer, but GetChildAtIndex works for pointers too.
+  lldb::ValueObjectSP inner_value;
+
+  for (const uint32_t i : idx) {
+    // Force static value, otherwise we can end up with the "real" type.
+    inner_value = GetChildAtIndex(i, /*can_create_synthetic*/ false);
+  }
+
+  // At this point type of `inner_value` should be the dereferenced target type.
+  CompilerType inner_value_type = inner_value->GetCompilerType();
+  if (type.IsPointerType()) {
+    assert(inner_value_type.CompareTypes(type.GetPointeeType()) &&
+           "casted value doesn't match the desired type");
+
+    uintptr_t addr = inner_value->GetLoadAddress();
+    return ValueObject::CreateValueObjectFromPointer(target, addr, type);
+  }
+
+  // At this point the target type should be a reference.
+  assert(inner_value_type.CompareTypes(type.GetNonReferenceType()) &&
+         "casted value doesn't match the desired type");
+
+  return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType()));
+}
+
+lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
+                                                       uint64_t offset) {
+  lldb::TargetSP target = GetTargetSP();
+
+  assert((type.IsPointerType() || type.IsReferenceType()) &&
+         "invalid ast: target type should be a pointer or a reference");
+
+  auto pointer_type =
+      type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType();
+
+  uintptr_t addr =
+      type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
+
+  lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromPointer(
+      target, addr - offset, pointer_type);
+
+  if (type.IsPointerType()) {
+    return value;
+  }
+
+  // At this point the target type is a reference. Since `value` is a pointer,
+  // it has to be dereferenced.
+  Status error;
+  return value->Dereference(error);
+}
+
+lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
+                                                       Status &error) {
+  assert(type.IsScalarType() && "target type must be an scalar");
+  assert(GetCompilerType().IsScalarType() && "argument must be a scalar");
+
+  lldb::TargetSP target = GetTargetSP();
+  if (type.IsBoolean()) {
+    if (GetCompilerType().IsInteger()) {
+      return ValueObject::CreateValueObjectFromBool(target,
+                                                    GetValueAsUnsigned(0) != 0);
+    }
+    if (GetCompilerType().IsFloat()) {
+      return ValueObject::CreateValueObjectFromBool(
+          target, !GetValueAsFloat().isZero());
+    }
+  }
+  if (type.IsInteger()) {
+    if (GetCompilerType().IsInteger()) {
+      uint64_t byte_size = 0;
+      if (auto temp = type.GetByteSize(target.get()))
+        byte_size = temp.value();
+      llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+      return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+    }
+    if (GetCompilerType().IsFloat()) {
+      uint64_t byte_size = 0;
+      if (auto temp = type.GetByteSize(target.get()))
+        byte_size = temp.value();
+      llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+      bool is_exact;
+      llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
+          integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+      // Casting floating point values that are out of bounds of the target type
+      // is undefined behaviour.
+      if (status & llvm::APFloatBase::opInvalidOp) {
+        error.SetErrorString("invalid type cast detected");
+      }
+
+      return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+    }
+  }
+  if (type.IsFloat()) {
+    if (GetCompilerType().IsInteger()) {
+      Scalar scalar_int(GetValueAsAPSInt());
+      llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+          type.GetCanonicalType().GetBasicTypeEnumeration());
+      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+    }
+    if (GetCompilerType().IsFloat()) {
+      Scalar scalar_float(GetValueAsFloat());
+      llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+          type.GetCanonicalType().GetBasicTypeEnumeration());
+      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+    }
+  }
+  assert(false && "invalid target type: must be a scalar");
+  return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
+  lldb::TargetSP target = GetTargetSP();
+
+  assert(type.IsScalarType() && "target type must be a scalar");
+  assert(GetCompilerType().IsEnumerationType() && "argument must be an enum");
+
+  if (type.IsBoolean()) {
+    return ValueObject::CreateValueObjectFromBool(target,
+                                                  GetValueAsUnsigned(0) != 0);
+  }
+
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    byte_size = temp.value();
+  // Get the value as APSInt and extend or truncate it to the requested size.
+  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+
+  if (type.IsInteger()) {
+    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+  }
+  if (type.IsFloat()) {
+    Scalar scalar_int(ext);
+    llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+        type.GetCanonicalType().GetBasicTypeEnumeration());
+    return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+  }
+  assert(false && "invalid target type: must be a scalar");
+  return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
+  lldb::TargetSP target = GetTargetSP();
+
+  uint64_t type_byte_size = 0;
+  uint64_t val_byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    type_byte_size = temp.value();
+  if (auto temp = GetCompilerType().GetByteSize(target.get()))
+    val_byte_size = temp.value();
+  assert(type.IsInteger() && "target type must be an integer");
+  assert((type.IsBoolean() || type_byte_size >= val_byte_size) &&
+         "target type cannot be smaller than the pointer type");
+
+  if (type.IsBoolean()) {
+    return ValueObject::CreateValueObjectFromBool(target,
+                                                  GetValueAsUnsigned(0) != 0);
+  }
+
+  // Get the value as APSInt and extend or truncate it to the requested size.
+  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(type_byte_size * CHAR_BIT);
+  return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
+  lldb::TargetSP target = GetTargetSP();
+
+  assert(type.IsEnumerationType() && "target type must be an enum");
+  assert((GetCompilerType().IsInteger() ||
+          GetCompilerType().IsEnumerationType()) &&
+         "argument must be an integer or an enum");
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    byte_size = temp.value();
+
+  // Get the value as APSInt and extend or truncate it to the requested size.
+  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+  return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+}
+
+lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
+                                                     Status &error) {
+  lldb::TargetSP target = GetTargetSP();
+
+  assert(type.IsEnumerationType() && "target type must be an enum");
+  assert(GetCompilerType().IsFloat() && "argument must be a float");
+
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    byte_size = temp.value();
+  llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
+  bool is_exact;
+
+  llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
+      integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+  // Casting floating point values that are out of bounds of the target type
+  // is undefined behaviour.
+  if (status & llvm::APFloatBase::opInvalidOp) {
+    error.SetErrorString("invalid type cast detected");
+  }
+
+  return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+}
+
 ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
 
 ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
@@ -3031,6 +3378,64 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
   return new_value_sp;
 }
 
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBytes(lldb::TargetSP target_sp,
+                                        const void *bytes, CompilerType type) {
+  ExecutionContext exe_ctx(
+      ExecutionContextRef(ExecutionContext(target_sp.get(), false)));
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target_sp.get()))
+    byte_size = temp.value();
+  lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+      bytes, byte_size, target_sp->GetArchitecture().GetByteOrder(),
+      static_cast<uint8_t>(target_sp->GetArchitecture().GetAddressByteSize()));
+  lldb::ValueObjectSP value =
+      ValueObject::CreateValueObjectFromData("result", *data_sp, exe_ctx, type);
+  return value;
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromBytes(
+    lldb::TargetSP target, const void *bytes, lldb::BasicType type) {
+  CompilerType target_type;
+  if (target) {
+    for (auto type_system_sp : target->GetScratchTypeSystems())
+      if (auto compiler_type = type_system_sp->GetBasicTypeFromAST(type)) {
+        target_type = compiler_type;
+        break;
+      }
+  }
+  return CreateValueObjectFromBytes(target, bytes, target_type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPInt(
+    lldb::TargetSP target, const llvm::APInt &v, CompilerType type) {
+  return CreateValueObjectFromBytes(target, v.getRawData(), type);
+}
+
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+    lldb::TargetSP target, const llvm::APFloat &v, CompilerType type) {
+  return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromPointer(lldb::TargetSP target, uintptr_t addr,
+                                          CompilerType type) {
+  return CreateValueObjectFromBytes(target, &addr, type);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value) {
+  return CreateValueObjectFromBytes(target, &value, lldb::eBasicTypeBool);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromNullptr(lldb::TargetSP target,
+                                          CompilerType type) {
+  assert(type.IsNullPtrType() && "target type must be nullptr");
+  uintptr_t zero = 0;
+  return CreateValueObjectFromBytes(target, &zero, type);
+}
+
 ModuleSP ValueObject::GetModule() {
   ValueObject *root(GetRoot());
   if (root != this)

>From 145e74b6d4361b9749e49acc025cda45827c5d96 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 8 Apr 2024 09:46:32 -0700
Subject: [PATCH 2/4] [LLDB] Add more helper functions to ValueObject class.

Fix various issues in  GetValueAsAPSInt, GetValueAsAPFloat,
GetValueAsBool, UpdateIntegerValue (renamed to SetValueFromInteger),
and GetLoadAddress:

- Added error checking & reporting.
- Removed asserts.
- Added doxygen comments.
- Renamed UpdateIntegerValue to SetValueFromInteger
- Renamed GetValueAsFloat to GetValueAsAPFloat
- Updated code in GetValue... functions to use existing Scalar values
  where possibled.
- Updated SBValue::GetLoadAddress to call ValueObject::GetLoadAddress.
---
 lldb/include/lldb/Core/ValueObject.h |  37 ++--
 lldb/include/lldb/Utility/Scalar.h   |   4 +
 lldb/source/API/SBValue.cpp          |  22 +-
 lldb/source/Core/ValueObject.cpp     | 312 +++++++++++++++++----------
 4 files changed, 223 insertions(+), 152 deletions(-)

diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 0c8dbf384a326..c81f57d2a174f 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,18 +441,29 @@ class ValueObject {
 
   virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
 
-  llvm::APSInt GetValueAsAPSInt();
-
-  llvm::APFloat GetValueAsFloat();
-
-  bool GetValueAsBool();
-
-  /// Update the value of the current object to be the integer in the 'value'
-  /// parameter.
-  void UpdateIntegerValue(const llvm::APInt &value);
-
-  /// Assign the integer value 'new_val_sp' to the current object.
-  void UpdateIntegerValue(lldb::ValueObjectSP new_val_sp);
+  /// If the current ValueObject is of an appropriate type, convert the
+  /// value to an APSInt and return that. Otherwise return an error.
+  llvm::Expected<llvm::APSInt> GetValueAsAPSInt();
+
+  /// If the current ValueObject is of an appropriate type, convert the
+  /// value to an APFloat and return that. Otherwise return an error.
+  llvm::Expected<llvm::APFloat> GetValueAsAPFloat();
+
+  /// If the current ValueObject is of an appropriate type, convert the
+  /// value to a boolean and return that. Otherwise return an error.
+  llvm::Expected<bool> GetValueAsBool();
+
+  /// Update an existing integer ValueObject with a new integer value. This
+  /// is only intended to be used with 'temporary' ValueObjects, i.e. ones that
+  /// are not associated with program variables. It does not update program
+  /// memory, registers, stack, etc.
+  void SetValueFromInteger(const llvm::APInt &value, Status &error);
+
+  /// Update an existing integer ValueObject with an integer value created
+  /// frome 'new_val_sp'.  This is only intended to be used with 'temporary'
+  /// ValueObjects, i.e. ones that are not associated with program variables.
+  /// It does not update program  memory, registers, stack, etc.
+  void SetValueFromInteger(lldb::ValueObjectSP new_val_sp, Status &error);
 
   virtual bool SetValueFromCString(const char *value_str, Status &error);
 
@@ -631,7 +642,7 @@ class ValueObject {
   virtual lldb::ValueObjectSP CastPointerType(const char *name,
                                               lldb::TypeSP &type_sp);
 
-  /// Return the target load address assocaited with this value object.
+  /// Return the target load address associated with this value object.
   lldb::addr_t GetLoadAddress();
 
   lldb::ValueObjectSP CastDerivedToBaseType(CompilerType type,
diff --git a/lldb/include/lldb/Utility/Scalar.h b/lldb/include/lldb/Utility/Scalar.h
index d7155884c6d1b..0d8eba3c9726d 100644
--- a/lldb/include/lldb/Utility/Scalar.h
+++ b/lldb/include/lldb/Utility/Scalar.h
@@ -181,6 +181,10 @@ class Scalar {
 
   long double LongDouble(long double fail_value = 0.0) const;
 
+  llvm::APSInt GetAPSInt() const { return m_integer; }
+
+  llvm::APFloat GetAPFloat() const { return m_float; }
+
   Status SetValueFromCString(const char *s, lldb::Encoding encoding,
                              size_t byte_size);
 
diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 94a8f3ea319e8..9d1c720d9fc70 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1262,26 +1262,8 @@ lldb::addr_t SBValue::GetLoadAddress() {
   lldb::addr_t value = LLDB_INVALID_ADDRESS;
   ValueLocker locker;
   lldb::ValueObjectSP value_sp(GetSP(locker));
-  if (value_sp) {
-    TargetSP target_sp(value_sp->GetTargetSP());
-    if (target_sp) {
-      const bool scalar_is_load_address = true;
-      AddressType addr_type;
-      value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
-      if (addr_type == eAddressTypeFile) {
-        ModuleSP module_sp(value_sp->GetModule());
-        if (!module_sp)
-          value = LLDB_INVALID_ADDRESS;
-        else {
-          Address addr;
-          module_sp->ResolveFileAddress(value, addr);
-          value = addr.GetLoadAddress(target_sp.get());
-        }
-      } else if (addr_type == eAddressTypeHost ||
-                 addr_type == eAddressTypeInvalid)
-        value = LLDB_INVALID_ADDRESS;
-    }
-  }
+  if (value_sp)
+    return value_sp->GetLoadAddress();
 
   return value;
 }
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 70cd3bdece8a4..2fd7d100712b9 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1089,94 +1089,91 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
   return fail_value;
 }
 
-llvm::APSInt ValueObject::GetValueAsAPSInt() {
-  lldb::TargetSP target = GetTargetSP();
-  uint64_t byte_size = 0;
-  if (auto temp = GetCompilerType().GetByteSize(target.get()))
-    byte_size = temp.value();
+llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
+  // Make sure the type can be converted to an APSInt.
+  if (!GetCompilerType().IsInteger() &&
+      !GetCompilerType().IsScopedEnumerationType() &&
+      !GetCompilerType().IsPointerType() &&
+      !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
+    return llvm::make_error<llvm::StringError>(
+        "type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
 
-  unsigned bit_width = static_cast<unsigned>(byte_size * CHAR_BIT);
-  bool success = true;
-  uint64_t fail_value = 0;
-  uint64_t ret_val = GetValueAsUnsigned(fail_value, &success);
-  uint64_t new_value = fail_value;
-  if (success)
-    new_value = ret_val;
-  bool is_signed = GetCompilerType().IsSigned();
+  if (CanProvideValue()) {
+    Scalar scalar;
+    if (ResolveValue(scalar))
+      return scalar.GetAPSInt();
+  }
 
-  return llvm::APSInt(llvm::APInt(bit_width, new_value, is_signed), !is_signed);
+  return llvm::make_error<llvm::StringError>(
+      "error occurred; unable to convert to APSInt",
+      llvm::inconvertibleErrorCode());
 }
 
-llvm::APFloat ValueObject::GetValueAsFloat() {
-  lldb::BasicType basic_type =
-      GetCompilerType().GetCanonicalType().GetBasicTypeEnumeration();
-  lldb::DataExtractorSP data_sp(new DataExtractor());
-  Status error;
-
-  switch (basic_type) {
-  case lldb::eBasicTypeFloat: {
-    float v = 0;
-    GetData(*data_sp, error);
-    assert(error.Success() && "Unable to read float data from value");
-
-    lldb::offset_t offset = 0;
-    uint32_t old_offset = offset;
-    void *ok = nullptr;
-    ok = data_sp->GetU8(&offset, (void *)&v, sizeof(float));
-    assert(offset != old_offset && ok != nullptr && "unable to read data");
+llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() {
+  if (!GetCompilerType().IsFloat())
+    return llvm::make_error<llvm::StringError>(
+        "type cannot be converted to APFloat", llvm::inconvertibleErrorCode());
 
-    return llvm::APFloat(v);
+  if (CanProvideValue()) {
+    Scalar scalar;
+    if (ResolveValue(scalar))
+      return scalar.GetAPFloat();
   }
-  case lldb::eBasicTypeDouble:
-    // No way to get more precision at the moment.
-  case lldb::eBasicTypeLongDouble: {
-    double v = 0;
-    GetData(*data_sp, error);
-    assert(error.Success() && "Unable to read long double data from value");
-
-    lldb::offset_t offset = 0;
-    uint32_t old_offset = offset;
-    void *ok = nullptr;
-    ok = data_sp->GetU8(&offset, (void *)&v, sizeof(double));
-    assert(offset != old_offset && ok != nullptr && "unable to read data");
 
-    return llvm::APFloat(v);
-  }
-  default:
-    return llvm::APFloat(NAN);
-  }
+  return llvm::make_error<llvm::StringError>(
+      "error occurred; unable to convert to APFloat",
+      llvm::inconvertibleErrorCode());
 }
 
-bool ValueObject::GetValueAsBool() {
+llvm::Expected<bool> ValueObject::GetValueAsBool() {
   CompilerType val_type = GetCompilerType();
   if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
       val_type.IsPointerType()) {
-    return GetValueAsAPSInt().getBoolValue();
+    auto value_or_err = GetValueAsAPSInt();
+    if (value_or_err)
+      return value_or_err->getBoolValue();
   }
   if (val_type.IsFloat()) {
-    return GetValueAsFloat().isNonZero();
+    auto value_or_err = GetValueAsAPFloat();
+    if (value_or_err)
+      return value_or_err->isNonZero();
   }
   if (val_type.IsArrayType()) {
-    lldb::ValueObjectSP new_val =
-        ValueObject::ValueObject::CreateValueObjectFromAddress(
-            GetName().GetStringRef(), GetAddressOf(), GetExecutionContextRef(),
-            val_type);
-    return new_val->GetValueAsUnsigned(0) != 0;
+    return GetAddressOf() != 0;
   }
-  return false;
+  return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
+                                             llvm::inconvertibleErrorCode());
 }
 
-void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
+void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) {
+  // Verify the current object is an integer object
+  CompilerType val_type = GetCompilerType();
+  if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+      !val_type.IsFloat() && !val_type.IsPointerType() &&
+      !val_type.IsScalarType()) {
+    error.SetErrorString("current value object is not an integer objet");
+    return;
+  }
+
+  // Verify the current object is not actually associated with any program
+  // variable.
+  if (GetVariable()) {
+    error.SetErrorString("current value object is not a temporary object");
+    return;
+  }
+
+  // Verify the proposed new value is the right size.
   lldb::TargetSP target = GetTargetSP();
   uint64_t byte_size = 0;
   if (auto temp = GetCompilerType().GetByteSize(target.get()))
     byte_size = temp.value();
-
-  assert(value.getBitWidth() == byte_size * CHAR_BIT &&
-         "illegal argument: new value should be of the same size");
+  if (value.getBitWidth() != byte_size * CHAR_BIT) {
+    error.SetErrorString(
+        "illegal argument: new value should be of the same size");
+    return;
+  }
 
   lldb::DataExtractorSP data_sp;
-  Status error;
   data_sp->SetData(value.getRawData(), byte_size,
                    target->GetArchitecture().GetByteOrder());
   data_sp->SetAddressByteSize(
@@ -1184,18 +1181,57 @@ void ValueObject::UpdateIntegerValue(const llvm::APInt &value) {
   SetData(*data_sp, error);
 }
 
-void ValueObject::UpdateIntegerValue(lldb::ValueObjectSP new_val_sp) {
+void ValueObject::SetValueFromInteger(lldb::ValueObjectSP new_val_sp,
+                                      Status &error) {
+  // Verify the current object is an integer object
+  CompilerType val_type = GetCompilerType();
+  if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() &&
+      !val_type.IsFloat() && !val_type.IsPointerType() &&
+      !val_type.IsScalarType()) {
+    error.SetErrorString("current value object is not an integer objet");
+    return;
+  }
+
+  // Verify the current object is not actually associated with any program
+  // variable.
+  if (GetVariable()) {
+    error.SetErrorString("current value object is not a temporary object");
+    return;
+  }
+
+  // Verify the proposed new value is the right type.
   CompilerType new_val_type = new_val_sp->GetCompilerType();
-  assert((new_val_type.IsInteger() || new_val_type.IsFloat() ||
-          new_val_type.IsPointerType()) &&
-         "illegal argument: new value should be of the same size");
+  if (!new_val_type.IsInteger() && !new_val_type.IsFloat() &&
+      !new_val_type.IsPointerType()) {
+    error.SetErrorString(
+        "illegal argument: new value should be of the same size");
+    return;
+  }
 
   if (new_val_type.IsInteger()) {
-    UpdateIntegerValue(new_val_sp->GetValueAsAPSInt());
+    auto value_or_err = new_val_sp->GetValueAsAPSInt();
+    if (value_or_err)
+      SetValueFromInteger(*value_or_err, error);
+    else
+      error.SetErrorString("error getting APSInt from new_val_sp");
   } else if (new_val_type.IsFloat()) {
-    UpdateIntegerValue(new_val_sp->GetValueAsFloat().bitcastToAPInt());
+    auto value_or_err = new_val_sp->GetValueAsAPFloat();
+    if (value_or_err)
+      SetValueFromInteger(value_or_err->bitcastToAPInt(), error);
+    else
+      error.SetErrorString("error getting APFloat from new_val_sp");
   } else if (new_val_type.IsPointerType()) {
-    UpdateIntegerValue(llvm::APInt(64, new_val_sp->GetValueAsUnsigned(0)));
+    bool success = true;
+    uint64_t int_val = new_val_sp->GetValueAsUnsigned(0, &success);
+    if (success) {
+      lldb::TargetSP target = GetTargetSP();
+      uint64_t num_bits = 0;
+      if (auto temp = new_val_sp->GetCompilerType().GetBitSize(target.get()))
+        num_bits = temp.value();
+      // SetValueFromInteger(llvm::APInt(64, int_val), error);
+      SetValueFromInteger(llvm::APInt(num_bits, int_val), error);
+    } else
+      error.SetErrorString("error converting new_val_sp to integer");
   }
 }
 
@@ -2921,8 +2957,7 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
 
 lldb::addr_t ValueObject::GetLoadAddress() {
   lldb::addr_t addr_value = LLDB_INVALID_ADDRESS;
-  lldb::TargetSP target_sp = GetTargetSP();
-  if (target_sp) {
+  if (auto target_sp = GetTargetSP()) {
     const bool scalar_is_load_address = true;
     AddressType addr_type;
     addr_value = GetAddressOf(scalar_is_load_address, &addr_type);
@@ -2935,7 +2970,8 @@ lldb::addr_t ValueObject::GetLoadAddress() {
         module_sp->ResolveFileAddress(addr_value, tmp_addr);
         addr_value = tmp_addr.GetLoadAddress(target_sp.get());
       }
-    } else if (addr_type == eAddressTypeHost || addr_type == eAddressTypeHost)
+    } else if (addr_type == eAddressTypeHost ||
+               addr_type == eAddressTypeInvalid)
       addr_value = LLDB_INVALID_ADDRESS;
   }
   return addr_value;
@@ -3013,8 +3049,12 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
                                                     GetValueAsUnsigned(0) != 0);
     }
     if (GetCompilerType().IsFloat()) {
-      return ValueObject::CreateValueObjectFromBool(
-          target, !GetValueAsFloat().isZero());
+      auto value_or_err = GetValueAsAPFloat();
+      if (value_or_err)
+        return ValueObject::CreateValueObjectFromBool(target,
+                                                      !value_or_err->isZero());
+      else // TODO: Figure out the right thing to do in error case..
+        return GetSP();
     }
   }
   if (type.IsInteger()) {
@@ -3022,8 +3062,12 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
       uint64_t byte_size = 0;
       if (auto temp = type.GetByteSize(target.get()))
         byte_size = temp.value();
-      llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
-      return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+      auto value_or_err = GetValueAsAPSInt();
+      if (value_or_err) {
+        llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+        return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+      } else // TODO: Figure out the right thing to do in error case..
+        return GetSP();
     }
     if (GetCompilerType().IsFloat()) {
       uint64_t byte_size = 0;
@@ -3031,34 +3075,46 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
         byte_size = temp.value();
       llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
       bool is_exact;
-      llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
-          integer, llvm::APFloat::rmTowardZero, &is_exact);
-
-      // Casting floating point values that are out of bounds of the target type
-      // is undefined behaviour.
-      if (status & llvm::APFloatBase::opInvalidOp) {
-        error.SetErrorString("invalid type cast detected");
-      }
+      auto value_or_err = GetValueAsAPFloat();
+      if (value_or_err) {
+        llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+            integer, llvm::APFloat::rmTowardZero, &is_exact);
+
+        // Casting floating point values that are out of bounds of the target
+        // type is undefined behaviour.
+        if (status & llvm::APFloatBase::opInvalidOp) {
+          error.SetErrorString("invalid type cast detected");
+        }
 
-      return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+        return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+      } else // TODO: Figure out the right thing to do in error case..
+        return GetSP();
     }
   }
   if (type.IsFloat()) {
     if (GetCompilerType().IsInteger()) {
-      Scalar scalar_int(GetValueAsAPSInt());
-      llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
-          type.GetCanonicalType().GetBasicTypeEnumeration());
-      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+      auto value_or_err = GetValueAsAPSInt();
+      if (value_or_err) {
+        Scalar scalar_int(*value_or_err);
+        llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+            type.GetCanonicalType().GetBasicTypeEnumeration());
+        return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+      } else // TODO: Figure out the right thing to do in error case..
+        return GetSP();
     }
     if (GetCompilerType().IsFloat()) {
-      Scalar scalar_float(GetValueAsFloat());
-      llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
-          type.GetCanonicalType().GetBasicTypeEnumeration());
-      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+      auto value_or_err = GetValueAsAPFloat();
+      if (value_or_err) {
+        Scalar scalar_float(*value_or_err);
+        llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
+            type.GetCanonicalType().GetBasicTypeEnumeration());
+        return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+      } else // TODO: Figure out the right thing to do in error case..
+        return GetSP();
     }
   }
-  assert(false && "invalid target type: must be a scalar");
-  return lldb::ValueObjectSP();
+  // TODO: Set error message.
+  return GetSP();
 }
 
 lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
@@ -3076,19 +3132,22 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
   if (auto temp = type.GetByteSize(target.get()))
     byte_size = temp.value();
   // Get the value as APSInt and extend or truncate it to the requested size.
-  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
+  auto value_or_err = GetValueAsAPSInt();
+  if (value_or_err) {
+    llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
 
-  if (type.IsInteger()) {
-    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
-  }
-  if (type.IsFloat()) {
-    Scalar scalar_int(ext);
-    llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
-        type.GetCanonicalType().GetBasicTypeEnumeration());
-    return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+    if (type.IsInteger()) {
+      return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+    }
+    if (type.IsFloat()) {
+      Scalar scalar_int(ext);
+      llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
+          type.GetCanonicalType().GetBasicTypeEnumeration());
+      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+    }
   }
-  assert(false && "invalid target type: must be a scalar");
-  return lldb::ValueObjectSP();
+  // TODO: Set error message.
+  return GetSP();
 }
 
 lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
@@ -3110,8 +3169,13 @@ lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
   }
 
   // Get the value as APSInt and extend or truncate it to the requested size.
-  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(type_byte_size * CHAR_BIT);
-  return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+  auto value_or_err = GetValueAsAPSInt();
+  if (value_or_err) {
+    llvm::APSInt ext = value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
+    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+  }
+  // TODO: Set error message.
+  return GetSP();
 }
 
 lldb::ValueObjectSP
@@ -3127,8 +3191,13 @@ ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
     byte_size = temp.value();
 
   // Get the value as APSInt and extend or truncate it to the requested size.
-  llvm::APSInt ext = GetValueAsAPSInt().extOrTrunc(byte_size * CHAR_BIT);
-  return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+  auto value_or_err = GetValueAsAPSInt();
+  if (value_or_err) {
+    llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
+    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+  }
+  // TODO: Set error message.
+  return GetSP();
 }
 
 lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
@@ -3144,16 +3213,21 @@ lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
   llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned());
   bool is_exact;
 
-  llvm::APFloatBase::opStatus status = GetValueAsFloat().convertToInteger(
-      integer, llvm::APFloat::rmTowardZero, &is_exact);
+  auto value_or_err = GetValueAsAPFloat();
+  if (value_or_err) {
+    llvm::APFloatBase::opStatus status = value_or_err->convertToInteger(
+        integer, llvm::APFloat::rmTowardZero, &is_exact);
 
-  // Casting floating point values that are out of bounds of the target type
-  // is undefined behaviour.
-  if (status & llvm::APFloatBase::opInvalidOp) {
-    error.SetErrorString("invalid type cast detected");
-  }
+    // Casting floating point values that are out of bounds of the target type
+    // is undefined behaviour.
+    if (status & llvm::APFloatBase::opInvalidOp) {
+      error.SetErrorString("invalid type cast detected");
+    }
 
-  return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+    return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+  }
+  // TODO: Set error message.
+  return GetSP();
 }
 
 ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}

>From 22e1b0685eb3fcbc2d232ed981a6bcae99c0a00b Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 22 Apr 2024 21:33:56 -0700
Subject: [PATCH 3/4] [LLDB] Fix review comments for "CreateValueObjectFrom..."
 functions.

- Update CreateValueObjectFromAddress to optionally not dereference the address
  before creating the value (i.e. create a value object containing the addres
  itself). This removes the need for CreateValueObjectFromPointer.
- Remove CreateValueObjectFromPointer
- Remove CreateValueObjectFromBytes functions, moving the DataExtractor into
  the callers & having them call CreateValueObjectFromData directly.
- Add 'name' parameter to the next CreateValueObjectFrom... functions.
- Remove assert stetement.
- Add Doxygen comments.
---
 lldb/include/lldb/Core/ValueObject.h |  34 +++----
 lldb/source/Core/ValueObject.cpp     | 146 +++++++++++++++------------
 2 files changed, 99 insertions(+), 81 deletions(-)

diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index c81f57d2a174f..9910fa7562175 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -701,40 +701,40 @@ class ValueObject {
                                   const ExecutionContext &exe_ctx,
                                   const EvaluateExpressionOptions &options);
 
+  /// Given an address either create a value object containing the value at
+  /// that address, or create a value object containing the address itself
+  /// (pointer value), depending on whether the parameter 'do_deref' is true or
+  /// false.
   static lldb::ValueObjectSP
   CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
                                const ExecutionContext &exe_ctx,
-                               CompilerType type);
+                               CompilerType type, bool do_deref = true);
 
   static lldb::ValueObjectSP
   CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
                             const ExecutionContext &exe_ctx, CompilerType type);
 
-  static lldb::ValueObjectSP
-  CreateValueObjectFromBytes(lldb::TargetSP target_sp, const void *bytes,
-                             CompilerType type);
-
-  static lldb::ValueObjectSP CreateValueObjectFromBytes(lldb::TargetSP target,
-                                                        const void *bytes,
-                                                        lldb::BasicType type);
-
+  /// Create a value object containing the given APInt value.
   static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
                                                         const llvm::APInt &v,
-                                                        CompilerType type);
+                                                        CompilerType type,
+                                                        llvm::StringRef name);
 
+  /// Create a value object containing the given APFloat value.
   static lldb::ValueObjectSP
   CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
-                               CompilerType type);
-
-  static lldb::ValueObjectSP CreateValueObjectFromPointer(lldb::TargetSP target,
-                                                          uintptr_t addr,
-                                                          CompilerType type);
+                               CompilerType type, llvm::StringRef name);
 
+  /// Create a value object containing the given boolean value.
   static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
-                                                       bool value);
+                                                       bool value,
+                                                       llvm::StringRef name);
 
+  /// Create a nullptr value object with the specified type (must be a
+  /// nullptr type).
   static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target,
-                                                          CompilerType type);
+                                                          CompilerType type,
+                                                          llvm::StringRef name);
 
   lldb::ValueObjectSP Persist();
 
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 2fd7d100712b9..0c5740258e24d 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -3001,7 +3001,10 @@ ValueObject::CastDerivedToBaseType(CompilerType type,
            "casted value doesn't match the desired type");
 
     uintptr_t addr = inner_value->GetLoadAddress();
-    return ValueObject::CreateValueObjectFromPointer(target, addr, type);
+    llvm::StringRef name = "";
+    ExecutionContext exe_ctx(target.get(), false);
+    return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, type,
+                                                     /* do deref */ false);
   }
 
   // At this point the target type should be a reference.
@@ -3024,8 +3027,10 @@ lldb::ValueObjectSP ValueObject::CastBaseToDerivedType(CompilerType type,
   uintptr_t addr =
       type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
 
-  lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromPointer(
-      target, addr - offset, pointer_type);
+  llvm::StringRef name = "";
+  ExecutionContext exe_ctx(target.get(), false);
+  lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
+      name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false);
 
   if (type.IsPointerType()) {
     return value;
@@ -3045,14 +3050,14 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
   lldb::TargetSP target = GetTargetSP();
   if (type.IsBoolean()) {
     if (GetCompilerType().IsInteger()) {
-      return ValueObject::CreateValueObjectFromBool(target,
-                                                    GetValueAsUnsigned(0) != 0);
+      return ValueObject::CreateValueObjectFromBool(
+          target, GetValueAsUnsigned(0) != 0, "result");
     }
     if (GetCompilerType().IsFloat()) {
       auto value_or_err = GetValueAsAPFloat();
       if (value_or_err)
-        return ValueObject::CreateValueObjectFromBool(target,
-                                                      !value_or_err->isZero());
+        return ValueObject::CreateValueObjectFromBool(
+            target, !value_or_err->isZero(), "result");
       else // TODO: Figure out the right thing to do in error case..
         return GetSP();
     }
@@ -3065,7 +3070,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
       auto value_or_err = GetValueAsAPSInt();
       if (value_or_err) {
         llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
-        return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+        return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+                                                       "result");
       } else // TODO: Figure out the right thing to do in error case..
         return GetSP();
     }
@@ -3086,7 +3092,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
           error.SetErrorString("invalid type cast detected");
         }
 
-        return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+        return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+                                                       "result");
       } else // TODO: Figure out the right thing to do in error case..
         return GetSP();
     }
@@ -3098,7 +3105,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
         Scalar scalar_int(*value_or_err);
         llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
             type.GetCanonicalType().GetBasicTypeEnumeration());
-        return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+        return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+                                                         "result");
       } else // TODO: Figure out the right thing to do in error case..
         return GetSP();
     }
@@ -3108,7 +3116,8 @@ lldb::ValueObjectSP ValueObject::CastScalarToBasicType(CompilerType type,
         Scalar scalar_float(*value_or_err);
         llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat(
             type.GetCanonicalType().GetBasicTypeEnumeration());
-        return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+        return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+                                                         "result");
       } else // TODO: Figure out the right thing to do in error case..
         return GetSP();
     }
@@ -3124,8 +3133,8 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
   assert(GetCompilerType().IsEnumerationType() && "argument must be an enum");
 
   if (type.IsBoolean()) {
-    return ValueObject::CreateValueObjectFromBool(target,
-                                                  GetValueAsUnsigned(0) != 0);
+    return ValueObject::CreateValueObjectFromBool(
+        target, GetValueAsUnsigned(0) != 0, "result");
   }
 
   uint64_t byte_size = 0;
@@ -3137,13 +3146,15 @@ lldb::ValueObjectSP ValueObject::CastEnumToBasicType(CompilerType type) {
     llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
 
     if (type.IsInteger()) {
-      return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+      return ValueObject::CreateValueObjectFromAPInt(target, ext, type,
+                                                     "result");
     }
     if (type.IsFloat()) {
       Scalar scalar_int(ext);
       llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt(
           type.GetCanonicalType().GetBasicTypeEnumeration());
-      return ValueObject::CreateValueObjectFromAPFloat(target, f, type);
+      return ValueObject::CreateValueObjectFromAPFloat(target, f, type,
+                                                       "result");
     }
   }
   // TODO: Set error message.
@@ -3164,15 +3175,15 @@ lldb::ValueObjectSP ValueObject::CastPointerToBasicType(CompilerType type) {
          "target type cannot be smaller than the pointer type");
 
   if (type.IsBoolean()) {
-    return ValueObject::CreateValueObjectFromBool(target,
-                                                  GetValueAsUnsigned(0) != 0);
+    return ValueObject::CreateValueObjectFromBool(
+        target, GetValueAsUnsigned(0) != 0, "result");
   }
 
   // Get the value as APSInt and extend or truncate it to the requested size.
   auto value_or_err = GetValueAsAPSInt();
   if (value_or_err) {
     llvm::APSInt ext = value_or_err->extOrTrunc(type_byte_size * CHAR_BIT);
-    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+    return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
   }
   // TODO: Set error message.
   return GetSP();
@@ -3194,7 +3205,7 @@ ValueObject::CastIntegerOrEnumToEnumType(CompilerType type) {
   auto value_or_err = GetValueAsAPSInt();
   if (value_or_err) {
     llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT);
-    return ValueObject::CreateValueObjectFromAPInt(target, ext, type);
+    return ValueObject::CreateValueObjectFromAPInt(target, ext, type, "result");
   }
   // TODO: Set error message.
   return GetSP();
@@ -3224,7 +3235,8 @@ lldb::ValueObjectSP ValueObject::CastFloatToEnumType(CompilerType type,
       error.SetErrorString("invalid type cast detected");
     }
 
-    return ValueObject::CreateValueObjectFromAPInt(target, integer, type);
+    return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+                                                   "result");
   }
   // TODO: Set error message.
   return GetSP();
@@ -3415,9 +3427,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
 
 lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
     llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
-    CompilerType type) {
+    CompilerType type, bool do_deref) {
   if (type) {
     CompilerType pointer_type(type.GetPointerType());
+    if (!do_deref)
+      pointer_type = type;
     if (pointer_type) {
       lldb::DataBufferSP buffer(
           new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
@@ -3426,10 +3440,12 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
           ConstString(name), buffer, exe_ctx.GetByteOrder(),
           exe_ctx.GetAddressByteSize()));
       if (ptr_result_valobj_sp) {
-        ptr_result_valobj_sp->GetValue().SetValueType(
-            Value::ValueType::LoadAddress);
+        if (do_deref)
+          ptr_result_valobj_sp->GetValue().SetValueType(
+              Value::ValueType::LoadAddress);
         Status err;
-        ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+        if (do_deref)
+          ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
         if (ptr_result_valobj_sp && !name.empty())
           ptr_result_valobj_sp->SetName(ConstString(name));
       }
@@ -3453,61 +3469,63 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
 }
 
 lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromBytes(lldb::TargetSP target_sp,
-                                        const void *bytes, CompilerType type) {
-  ExecutionContext exe_ctx(
-      ExecutionContextRef(ExecutionContext(target_sp.get(), false)));
+ValueObject::CreateValueObjectFromAPInt(lldb::TargetSP target,
+                                        const llvm::APInt &v, CompilerType type,
+                                        llvm::StringRef name) {
+  ExecutionContext exe_ctx(target.get(), false);
   uint64_t byte_size = 0;
-  if (auto temp = type.GetByteSize(target_sp.get()))
+  if (auto temp = type.GetByteSize(target.get()))
     byte_size = temp.value();
   lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
-      bytes, byte_size, target_sp->GetArchitecture().GetByteOrder(),
-      static_cast<uint8_t>(target_sp->GetArchitecture().GetAddressByteSize()));
-  lldb::ValueObjectSP value =
-      ValueObject::CreateValueObjectFromData("result", *data_sp, exe_ctx, type);
-  return value;
+      reinterpret_cast<const void *>(v.getRawData()), byte_size,
+      exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize());
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
 }
 
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromBytes(
-    lldb::TargetSP target, const void *bytes, lldb::BasicType type) {
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
+    lldb::TargetSP target, const llvm::APFloat &v, CompilerType type,
+    llvm::StringRef name) {
+  return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name);
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value,
+                                       llvm::StringRef name) {
   CompilerType target_type;
   if (target) {
     for (auto type_system_sp : target->GetScratchTypeSystems())
-      if (auto compiler_type = type_system_sp->GetBasicTypeFromAST(type)) {
+      if (auto compiler_type =
+              type_system_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool)) {
         target_type = compiler_type;
         break;
       }
   }
-  return CreateValueObjectFromBytes(target, bytes, target_type);
-}
-
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPInt(
-    lldb::TargetSP target, const llvm::APInt &v, CompilerType type) {
-  return CreateValueObjectFromBytes(target, v.getRawData(), type);
-}
-
-lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
-    lldb::TargetSP target, const llvm::APFloat &v, CompilerType type) {
-  return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type);
-}
-
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromPointer(lldb::TargetSP target, uintptr_t addr,
-                                          CompilerType type) {
-  return CreateValueObjectFromBytes(target, &addr, type);
-}
-
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value) {
-  return CreateValueObjectFromBytes(target, &value, lldb::eBasicTypeBool);
+  ExecutionContext exe_ctx(target.get(), false);
+  uint64_t byte_size = 0;
+  if (auto temp = target_type.GetByteSize(target.get()))
+    byte_size = temp.value();
+  lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+      reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(),
+      exe_ctx.GetAddressByteSize());
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx,
+                                                target_type);
 }
 
-lldb::ValueObjectSP
-ValueObject::CreateValueObjectFromNullptr(lldb::TargetSP target,
-                                          CompilerType type) {
-  assert(type.IsNullPtrType() && "target type must be nullptr");
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr(
+    lldb::TargetSP target, CompilerType type, llvm::StringRef name) {
+  if (!type.IsNullPtrType()) {
+    lldb::ValueObjectSP ret_val;
+    return ret_val;
+  }
   uintptr_t zero = 0;
-  return CreateValueObjectFromBytes(target, &zero, type);
+  ExecutionContext exe_ctx(target.get(), false);
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    byte_size = temp.value();
+  lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+      reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(),
+      exe_ctx.GetAddressByteSize());
+  return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type);
 }
 
 ModuleSP ValueObject::GetModule() {

>From 1e41bfa4e5db70cd157b1a5b1a12b21bfb226b1d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 22 May 2024 07:21:10 -0700
Subject: [PATCH 4/4] [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();
 }
 



More information about the lldb-commits mailing list