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 llvm::Expected<uint32_t> CalculateNumChildren() override; 31 32 lldb::ValueObjectSP GetChildAtIndex(uint32_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 lldb::ChildCacheState 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 llvm::Expected<uint32_t> lldb_private::formatters:: 77 LibcxxStdSpanSyntheticFrontEnd::CalculateNumChildren() { 78 return m_num_elements; 79 } 80 81 lldb::ValueObjectSP 82 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex( 83 uint32_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 lldb::ChildCacheState 97 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { 98 // Get element type. 99 ValueObjectSP data_type_finder_sp = GetChildMemberWithName( 100 m_backend, {ConstString("__data_"), ConstString("__data")}); 101 if (!data_type_finder_sp) 102 return lldb::ChildCacheState::eRefetch; 103 104 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); 105 106 // Get element size. 107 if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { 108 m_element_size = *size; 109 110 // Get data. 111 if (m_element_size > 0) { 112 m_start = data_type_finder_sp.get(); 113 } 114 115 // Get number of elements. 116 if (auto size_sp = GetChildMemberWithName( 117 m_backend, {ConstString("__size_"), ConstString("__size")})) { 118 m_num_elements = size_sp->GetValueAsUnsigned(0); 119 } else if (auto arg = 120 m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) { 121 122 m_num_elements = arg->value.getLimitedValue(); 123 } 124 } 125 126 return lldb::ChildCacheState::eReuse; 127 } 128 129 bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 130 MightHaveChildren() { 131 return true; 132 } 133 134 size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: 135 GetIndexOfChildWithName(ConstString name) { 136 if (!m_start) 137 return UINT32_MAX; 138 return ExtractIndexFromString(name.GetCString()); 139 } 140 141 lldb_private::SyntheticChildrenFrontEnd * 142 LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *, 143 lldb::ValueObjectSP valobj_sp) { 144 if (!valobj_sp) 145 return nullptr; 146 CompilerType type = valobj_sp->GetCompilerType(); 147 if (!type.IsValid() || type.GetNumTemplateArguments() != 2) 148 return nullptr; 149 return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp); 150 } 151 152 } // namespace formatters 153 } // namespace lldb_private 154