1 //===-- LibCxxSpan.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "LibCxx.h" 10 11 #include "lldb/Core/ValueObject.h" 12 #include "lldb/DataFormatters/FormattersHelpers.h" 13 #include "lldb/Utility/ConstString.h" 14 #include "llvm/ADT/APSInt.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 using namespace lldb_private::formatters; 19 20 namespace lldb_private { 21 namespace formatters { 22 23 class LibcxxStdSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 24 public: 25 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 26 27 ~LibcxxStdSpanSyntheticFrontEnd() override = default; 28 29 size_t CalculateNumChildren() override; 30 31 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 32 33 /// Determines properties of the std::span<> associated with this object 34 // 35 // std::span can either be instantiated with a compile-time known 36 // extent or a std::dynamic_extent (this is the default if only the 37 // type template argument is provided). The layout of std::span 38 // depends on whether the extent is dynamic or not. For static 39 // extents (e.g., std::span<int, 9>): 40 // 41 // (std::__1::span<const int, 9>) s = { 42 // __data = 0x000000016fdff494 43 // } 44 // 45 // For dynamic extents, e.g., std::span<int>, the layout is: 46 // 47 // (std::__1::span<const int, 18446744073709551615>) s = { 48 // __data = 0x000000016fdff494 49 // __size = 6 50 // } 51 // 52 // This function checks for a '__size' member to determine the number 53 // of elements in the span. If no such member exists, we get the size 54 // from the only other place it can be: the template argument. 55 bool Update() override; 56 57 bool MightHaveChildren() override; 58 59 size_t GetIndexOfChildWithName(ConstString name) override; 60 61 private: 62 ValueObject *m_start = nullptr; ///< First element of span. Held, not owned. 63 CompilerType m_element_type{}; ///< Type of span elements. 64 size_t m_num_elements = 0; ///< Number of elements in span. 65 uint32_t m_element_size = 0; ///< Size in bytes of each span element. 66 }; 67 68 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 69 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 70 : SyntheticChildrenFrontEnd(*valobj_sp) { 71 if (valobj_sp) 72 Update(); 73 } 74 75 size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 76 CalculateNumChildren() { 77 return m_num_elements; 78 } 79 80 lldb::ValueObjectSP 81 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex( 82 size_t idx) { 83 if (!m_start) 84 return {}; 85 86 uint64_t offset = idx * m_element_size; 87 offset = offset + m_start->GetValueAsUnsigned(0); 88 StreamString name; 89 name.Printf("[%" PRIu64 "]", (uint64_t)idx); 90 return CreateValueObjectFromAddress(name.GetString(), offset, 91 m_backend.GetExecutionContextRef(), 92 m_element_type); 93 } 94 95 bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { 96 // Get element type. 97 ValueObjectSP data_type_finder_sp( 98 m_backend.GetChildMemberWithName(ConstString("__data"), true)); 99 if (!data_type_finder_sp) 100 return false; 101 102 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); 103 104 // Get element size. 105 if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { 106 m_element_size = *size; 107 108 // Get data. 109 if (m_element_size > 0) { 110 m_start = data_type_finder_sp.get(); 111 } 112 113 // Get number of elements. 114 if (auto size_sp = 115 m_backend.GetChildMemberWithName(ConstString("__size"), true)) { 116 m_num_elements = size_sp->GetValueAsUnsigned(0); 117 } else if (auto arg = 118 m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) { 119 120 m_num_elements = arg->value.getLimitedValue(); 121 } 122 } 123 124 return true; 125 } 126 127 bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 128 MightHaveChildren() { 129 return true; 130 } 131 132 size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 133 GetIndexOfChildWithName(ConstString name) { 134 if (!m_start) 135 return UINT32_MAX; 136 return ExtractIndexFromString(name.GetCString()); 137 } 138 139 lldb_private::SyntheticChildrenFrontEnd * 140 LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *, 141 lldb::ValueObjectSP valobj_sp) { 142 if (!valobj_sp) 143 return nullptr; 144 CompilerType type = valobj_sp->GetCompilerType(); 145 if (!type.IsValid() || type.GetNumTemplateArguments() != 2) 146 return nullptr; 147 return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp); 148 } 149 150 } // namespace formatters 151 } // namespace lldb_private 152