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