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

via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 13 09:14:21 PDT 2024


Author: cmtice
Date: 2024-06-13T09:14:17-07:00
New Revision: 9f70cd83897b36e5628057dfef2855a0b9045766

URL: https://github.com/llvm/llvm-project/commit/9f70cd83897b36e5628057dfef2855a0b9045766
DIFF: https://github.com/llvm/llvm-project/commit/9f70cd83897b36e5628057dfef2855a0b9045766.diff

LOG: [LLDB] Add more helper functions to ValueObject class. (#87197)

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

Added: 
    

Modified: 
    lldb/include/lldb/Core/ValueObject.h
    lldb/include/lldb/Utility/Scalar.h
    lldb/source/API/SBValue.cpp
    lldb/source/Core/ValueObject.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 1e8c7c9c00536..db1fdae170ed0 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -441,6 +441,30 @@ class ValueObject {
 
   virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
 
+  /// 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);
 
   /// Return the module associated with this value object in case the value is
@@ -618,6 +642,32 @@ class ValueObject {
   virtual lldb::ValueObjectSP CastPointerType(const char *name,
                                               lldb::TypeSP &type_sp);
 
+  /// Return the target load address associated with this value object.
+  lldb::addr_t GetLoadAddress();
+
+  /// 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
   /// with a vtable, return a valid ValueObject with the error set correctly.
@@ -659,15 +709,41 @@ 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);
 
+  /// Create a value object containing the given APInt value.
+  static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target,
+                                                        const llvm::APInt &v,
+                                                        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, llvm::StringRef name);
+
+  /// Create a value object containing the given boolean value.
+  static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
+                                                       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,
+                                                          llvm::StringRef name);
+
   lldb::ValueObjectSP Persist();
 
   /// Returns true if this is a char* or a char[] if it is a char* and
@@ -719,6 +795,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/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 c53ec5a746482..9d7efba024d11 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1281,26 +1281,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 f32cb82faa006..1c69145560de2 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -1116,6 +1116,153 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
   return fail_value;
 }
 
+llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() {
+  // Make sure the type can be converted to an APSInt.
+  if (!GetCompilerType().IsInteger() &&
+      !GetCompilerType().IsScopedEnumerationType() &&
+      !GetCompilerType().IsEnumerationType() &&
+      !GetCompilerType().IsPointerType() &&
+      !GetCompilerType().IsNullPtrType() &&
+      !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean())
+    return llvm::make_error<llvm::StringError>(
+        "type cannot be converted to APSInt", llvm::inconvertibleErrorCode());
+
+  if (CanProvideValue()) {
+    Scalar scalar;
+    if (ResolveValue(scalar))
+      return scalar.GetAPSInt();
+  }
+
+  return llvm::make_error<llvm::StringError>(
+      "error occurred; unable to convert to APSInt",
+      llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() {
+  if (!GetCompilerType().IsFloat())
+    return llvm::make_error<llvm::StringError>(
+        "type cannot be converted to APFloat", llvm::inconvertibleErrorCode());
+
+  if (CanProvideValue()) {
+    Scalar scalar;
+    if (ResolveValue(scalar))
+      return scalar.GetAPFloat();
+  }
+
+  return llvm::make_error<llvm::StringError>(
+      "error occurred; unable to convert to APFloat",
+      llvm::inconvertibleErrorCode());
+}
+
+llvm::Expected<bool> ValueObject::GetValueAsBool() {
+  CompilerType val_type = GetCompilerType();
+  if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() ||
+      val_type.IsPointerType()) {
+    auto value_or_err = GetValueAsAPSInt();
+    if (value_or_err)
+      return value_or_err->getBoolValue();
+  }
+  if (val_type.IsFloat()) {
+    auto value_or_err = GetValueAsAPFloat();
+    if (value_or_err)
+      return value_or_err->isNonZero();
+  }
+  if (val_type.IsArrayType())
+    return GetAddressOf() != 0;
+
+  return llvm::make_error<llvm::StringError>("type cannot be converted to bool",
+                                             llvm::inconvertibleErrorCode());
+}
+
+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();
+  if (value.getBitWidth() != byte_size * CHAR_BIT) {
+    error.SetErrorString(
+        "illegal argument: new value should be of the same size");
+    return;
+  }
+
+  lldb::DataExtractorSP data_sp;
+  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::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();
+  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()) {
+    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()) {
+    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()) {
+    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(num_bits, int_val), error);
+    } else
+      error.SetErrorString("error converting new_val_sp to integer");
+  }
+}
+
 // 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
@@ -2843,6 +2990,374 @@ 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;
+  if (auto target_sp = GetTargetSP()) {
+    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 == eAddressTypeInvalid)
+      addr_value = LLDB_INVALID_ADDRESS;
+  }
+  return addr_value;
+}
+
+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());
+
+  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 
diff erent",
+        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 = GetSP();
+
+  for (const uint32_t i : base_type_indices)
+    // Create synthetic value if needed.
+    inner_value =
+        inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true);
+
+  // At this point type of `inner_value` should be the dereferenced target
+  // type.
+  CompilerType inner_value_type = inner_value->GetCompilerType();
+  if (type.IsPointerType()) {
+    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 = "";
+    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.
+  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()));
+}
+
+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 
diff erent",
+        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());
+  }
+
+  // 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();
+
+  uintptr_t addr =
+      type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress();
+
+  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;
+
+  // 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::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.IsInteger() && !type.IsBoolean()) {
+      m_error.SetErrorString("target type must be an integer or boolean");
+      return GetSP();
+    }
+    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.IsBoolean()) {
+    if (!is_scalar || is_integer)
+      return ValueObject::CreateValueObjectFromBool(
+          target, GetValueAsUnsigned(0) != 0, "result");
+    else if (is_scalar && is_float) {
+      auto float_value_or_err = GetValueAsAPFloat();
+      if (float_value_or_err)
+        return ValueObject::CreateValueObjectFromBool(
+            target, !float_value_or_err->isZero(), "result");
+      else {
+        m_error.SetErrorStringWithFormat(
+            "cannot get value as APFloat: %s",
+            llvm::toString(float_value_or_err.takeError()).c_str());
+        return GetSP();
+      }
+    }
+  }
+
+  if (type.IsInteger()) {
+    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 {
+        m_error.SetErrorStringWithFormat(
+            "cannot get value as APSInt: %s",
+            llvm::toString(int_value_or_err.takeError()).c_str());
+        ;
+        return GetSP();
+      }
+    } else if (is_scalar && is_float) {
+      llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned());
+      bool 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) {
+          m_error.SetErrorStringWithFormat(
+              "invalid type cast detected: %s",
+              llvm::toString(float_value_or_err.takeError()).c_str());
+          return GetSP();
+        }
+        return ValueObject::CreateValueObjectFromAPInt(target, integer, type,
+                                                       "result");
+      }
+    }
+  }
+
+  if (type.IsFloat()) {
+    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 {
+        m_error.SetErrorStringWithFormat(
+            "cannot get value as APSInt: %s",
+            llvm::toString(int_value_or_err.takeError()).c_str());
+        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.SetErrorStringWithFormat(
+              "cannot get value as APSInt: %s",
+              llvm::toString(int_value_or_err.takeError()).c_str());
+          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.SetErrorStringWithFormat(
+              "cannot get value as APFloat: %s",
+              llvm::toString(float_value_or_err.takeError()).c_str());
+          return GetSP();
+        }
+      }
+    }
+  }
+
+  m_error.SetErrorString("Unable to perform requested cast");
+  return GetSP();
+}
+
+lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) {
+  bool is_enum = GetCompilerType().IsEnumerationType();
+  bool is_integer = GetCompilerType().IsInteger();
+  bool is_float = GetCompilerType().IsFloat();
+
+  if (!is_enum && !is_integer && !is_float) {
+    m_error.SetErrorString("argument must be an integer, a float, or an enum");
+    return GetSP();
+  }
+
+  if (!type.IsEnumerationType()) {
+    m_error.SetErrorString("target type must be an enum");
+    return GetSP();
+  }
+
+  lldb::TargetSP target = GetTargetSP();
+  uint64_t byte_size = 0;
+  if (auto temp = type.GetByteSize(target.get()))
+    byte_size = temp.value();
+
+  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.SetErrorStringWithFormat(
+            "invalid type cast detected: %s",
+            llvm::toString(value_or_err.takeError()).c_str());
+        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.SetErrorStringWithFormat(
+          "cannot get value as APSInt: %s",
+          llvm::toString(value_or_err.takeError()).c_str());
+      return GetSP();
+    }
+  }
+  m_error.SetErrorString("Cannot perform requested cast");
+  return GetSP();
+}
+
 ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
 
 ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
@@ -3028,9 +3543,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)));
@@ -3039,10 +3556,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));
       }
@@ -3065,6 +3584,66 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
   return new_value_sp;
 }
 
+lldb::ValueObjectSP
+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.get()))
+    byte_size = temp.value();
+  lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>(
+      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::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(lldb::eBasicTypeBool)) {
+        target_type = compiler_type;
+        break;
+      }
+  }
+  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, llvm::StringRef name) {
+  if (!type.IsNullPtrType()) {
+    lldb::ValueObjectSP ret_val;
+    return ret_val;
+  }
+  uintptr_t zero = 0;
+  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() {
   ValueObject *root(GetRoot());
   if (root != this)


        


More information about the lldb-commits mailing list