[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