//===-- VectorType.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/DataFormatters/VectorType.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/ValueObject/ValueObject.h" #include "lldb/ValueObject/ValueObjectConstResult.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; static CompilerType GetCompilerTypeForFormat(lldb::Format format, CompilerType element_type, TypeSystemSP type_system) { lldbassert(type_system && "type_system needs to be not NULL"); if (!type_system) return {}; switch (format) { case lldb::eFormatAddressInfo: case lldb::eFormatPointer: return type_system->GetBuiltinTypeForEncodingAndBitSize( eEncodingUint, 8 * type_system->GetPointerByteSize()); case lldb::eFormatBoolean: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeBool); case lldb::eFormatBytes: case lldb::eFormatBytesWithASCII: case lldb::eFormatChar: case lldb::eFormatCharArray: case lldb::eFormatCharPrintable: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar); case lldb::eFormatComplex /* lldb::eFormatComplexFloat */: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloatComplex); case lldb::eFormatCString: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar) .GetPointerType(); case lldb::eFormatFloat: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat); case lldb::eFormatFloat128: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat128); case lldb::eFormatHex: case lldb::eFormatHexUppercase: case lldb::eFormatOctal: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeInt); case lldb::eFormatHexFloat: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat); case lldb::eFormatUnicode16: case lldb::eFormatUnicode32: case lldb::eFormatUnsigned: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt); case lldb::eFormatVectorOfChar: return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar); case lldb::eFormatVectorOfFloat32: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754, 32); case lldb::eFormatVectorOfFloat64: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754, 64); case lldb::eFormatVectorOfSInt16: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 16); case lldb::eFormatVectorOfSInt32: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32); case lldb::eFormatVectorOfSInt64: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64); case lldb::eFormatVectorOfSInt8: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 8); case lldb::eFormatVectorOfUInt128: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 128); case lldb::eFormatVectorOfUInt16: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16); case lldb::eFormatVectorOfUInt32: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); case lldb::eFormatVectorOfUInt64: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64); case lldb::eFormatVectorOfUInt8: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8); case lldb::eFormatDefault: return element_type; case lldb::eFormatBinary: case lldb::eFormatComplexInteger: case lldb::eFormatDecimal: case lldb::eFormatEnum: case lldb::eFormatInstruction: case lldb::eFormatOSType: case lldb::eFormatVoid: default: return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8); } } static lldb::Format GetItemFormatForFormat(lldb::Format format, CompilerType element_type) { switch (format) { case lldb::eFormatVectorOfChar: return lldb::eFormatChar; case lldb::eFormatVectorOfFloat32: case lldb::eFormatVectorOfFloat64: return lldb::eFormatFloat; case lldb::eFormatVectorOfSInt16: case lldb::eFormatVectorOfSInt32: case lldb::eFormatVectorOfSInt64: case lldb::eFormatVectorOfSInt8: return lldb::eFormatDecimal; case lldb::eFormatVectorOfUInt128: case lldb::eFormatVectorOfUInt16: case lldb::eFormatVectorOfUInt32: case lldb::eFormatVectorOfUInt64: case lldb::eFormatVectorOfUInt8: return lldb::eFormatUnsigned; case lldb::eFormatBinary: case lldb::eFormatComplexInteger: case lldb::eFormatDecimal: case lldb::eFormatEnum: case lldb::eFormatInstruction: case lldb::eFormatOSType: case lldb::eFormatVoid: return eFormatHex; case lldb::eFormatDefault: { // special case the (default, char) combination to actually display as an // integer value most often, you won't want to see the ASCII characters... // (and if you do, eFormatChar is a keystroke away) bool is_char = element_type.IsCharType(); bool is_signed = false; element_type.IsIntegerType(is_signed); return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format; } break; default: return format; } } /// Calculates the number of elements stored in a container (with /// element type 'container_elem_type') as if it had elements of type /// 'element_type'. /// /// For example, a container of type /// `uint8_t __attribute__((vector_size(16)))` has 16 elements. /// But calling `CalculateNumChildren` with an 'element_type' /// of `float` (4-bytes) will return `4` because we are interpreting /// the byte-array as a `float32[]`. /// /// \param[in] container_elem_type The type of the elements stored /// in the container we are calculating the children of. /// /// \param[in] num_elements Number of 'container_elem_type's our /// container stores. /// /// \param[in] element_type The type of elements we interpret /// container_type to contain for the purposes of calculating /// the number of children. /// /// \returns The number of elements stored in a container of /// type 'element_type'. Returns a std::nullopt if the /// size of the container is not a multiple of 'element_type' /// or if an error occurs. static std::optional CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type) { std::optional container_elem_size = llvm::expectedToOptional( container_elem_type.GetByteSize(/* exe_scope */ nullptr)); if (!container_elem_size) return {}; auto container_size = *container_elem_size * num_elements; std::optional element_size = llvm::expectedToOptional( element_type.GetByteSize(/* exe_scope */ nullptr)); if (!element_size || !*element_size) return {}; if (container_size % *element_size) return {}; return container_size / *element_size; } namespace lldb_private { namespace formatters { class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: VectorTypeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp), m_child_type() {} ~VectorTypeSyntheticFrontEnd() override = default; llvm::Expected CalculateNumChildren() override { return m_num_children; } lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { auto num_children_or_err = CalculateNumChildren(); if (!num_children_or_err) return ValueObjectConstResult::Create( nullptr, Status::FromError(num_children_or_err.takeError())); if (idx >= *num_children_or_err) return {}; auto size_or_err = m_child_type.GetByteSize(nullptr); if (!size_or_err) return ValueObjectConstResult::Create( nullptr, Status::FromError(size_or_err.takeError())); auto offset = idx * *size_or_err; StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset( offset, m_child_type, true, ConstString(idx_name.GetString()))); if (!child_sp) return child_sp; child_sp->SetFormat(m_item_format); return child_sp; } lldb::ChildCacheState Update() override { m_parent_format = m_backend.GetFormat(); CompilerType parent_type(m_backend.GetCompilerType()); CompilerType element_type; uint64_t num_elements; parent_type.IsVectorType(&element_type, &num_elements); m_child_type = ::GetCompilerTypeForFormat( m_parent_format, element_type, parent_type.GetTypeSystem().GetSharedPointer()); m_num_children = ::CalculateNumChildren(element_type, num_elements, m_child_type) .value_or(0); m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type); return lldb::ChildCacheState::eRefetch; } llvm::Expected GetIndexOfChildWithName(ConstString name) override { auto optional_idx = ExtractIndexFromString(name.AsCString()); if (!optional_idx) { return llvm::createStringError("Type has no child named '%s'", name.AsCString()); } uint32_t idx = *optional_idx; if (idx >= CalculateNumChildrenIgnoringErrors()) return llvm::createStringError("Type has no child named '%s'", name.AsCString()); return idx; } private: lldb::Format m_parent_format = eFormatInvalid; lldb::Format m_item_format = eFormatInvalid; CompilerType m_child_type; size_t m_num_children = 0; }; } // namespace formatters } // namespace lldb_private bool lldb_private::formatters::VectorTypeSummaryProvider( ValueObject &valobj, Stream &s, const TypeSummaryOptions &) { auto synthetic_children = VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP()); if (!synthetic_children) return false; synthetic_children->Update(); s.PutChar('('); bool first = true; size_t idx = 0, len = synthetic_children->CalculateNumChildrenIgnoringErrors(); for (; idx < len; idx++) { auto child_sp = synthetic_children->GetChildAtIndex(idx); if (!child_sp) continue; child_sp = child_sp->GetQualifiedRepresentationIfAvailable( lldb::eDynamicDontRunTarget, true); const char *child_value = child_sp->GetValueAsCString(); if (child_value && *child_value) { if (first) { s.Printf("%s", child_value); first = false; } else { s.Printf(", %s", child_value); } } } s.PutChar(')'); return true; } lldb_private::SyntheticChildrenFrontEnd * lldb_private::formatters::VectorTypeSyntheticFrontEndCreator( CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { if (!valobj_sp) return nullptr; return new VectorTypeSyntheticFrontEnd(valobj_sp); }