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

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Wed Nov 20 16:36:17 PST 2024


================
@@ -2809,6 +2956,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 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 = 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 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());
+  }
+
+  // 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();
----------------
adrian-prantl wrote:

Hi @cmtice! I just came across this code and I don't think this API makes sense. Since `CastToBasicType` creates a new casted ValueObject I think this method should be `const` and not modify the error of the original value when the cast fails. I think it should return a ValueObjectConstResult with the error instead.

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


More information about the lldb-commits mailing list