1 //===-- LibCxxSliceArray.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/DataFormatters/FormattersHelpers.h" 12 #include "lldb/ValueObject/ValueObject.h" 13 #include <optional> 14 15 using namespace lldb; 16 using namespace lldb_private; 17 using namespace lldb_private::formatters; 18 19 namespace lldb_private { 20 namespace formatters { 21 22 bool LibcxxStdSliceArraySummaryProvider(ValueObject &valobj, Stream &stream, 23 const TypeSummaryOptions &options) { 24 ValueObjectSP obj = valobj.GetNonSyntheticValue(); 25 if (!obj) 26 return false; 27 28 ValueObjectSP ptr_sp = obj->GetChildMemberWithName("__size_"); 29 if (!ptr_sp) 30 return false; 31 const size_t size = ptr_sp->GetValueAsUnsigned(0); 32 33 ptr_sp = obj->GetChildMemberWithName("__stride_"); 34 if (!ptr_sp) 35 return false; 36 const size_t stride = ptr_sp->GetValueAsUnsigned(0); 37 38 stream.Printf("stride=%zu size=%zu", stride, size); 39 40 return true; 41 } 42 43 /// Data formatter for libc++'s std::slice_array. 44 /// 45 /// A slice_array is created by using: 46 /// operator[](std::slice slicearr); 47 /// and std::slice is created by: 48 /// slice(std::size_t start, std::size_t size, std::size_t stride); 49 /// The std::slice_array has the following members: 50 /// - __vp_ points to std::valarray::__begin_ + @a start 51 /// - __size_ is @a size 52 /// - __stride_is @a stride 53 class LibcxxStdSliceArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { 54 public: 55 LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 56 57 ~LibcxxStdSliceArraySyntheticFrontEnd() override; 58 59 llvm::Expected<uint32_t> CalculateNumChildren() override; 60 61 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 62 63 lldb::ChildCacheState Update() override; 64 65 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; 66 67 private: 68 /// A non-owning pointer to slice_array.__vp_. 69 ValueObject *m_start = nullptr; 70 /// slice_array.__size_. 71 size_t m_size = 0; 72 /// slice_array.__stride_. 73 size_t m_stride = 0; 74 /// The type of slice_array's template argument T. 75 CompilerType m_element_type; 76 /// The sizeof slice_array's template argument T. 77 uint32_t m_element_size = 0; 78 }; 79 80 } // namespace formatters 81 } // namespace lldb_private 82 83 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: 84 LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 85 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { 86 if (valobj_sp) 87 Update(); 88 } 89 90 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: 91 ~LibcxxStdSliceArraySyntheticFrontEnd() { 92 // these need to stay around because they are child objects who will follow 93 // their parent's life cycle 94 // delete m_start; 95 } 96 97 llvm::Expected<uint32_t> lldb_private::formatters:: 98 LibcxxStdSliceArraySyntheticFrontEnd::CalculateNumChildren() { 99 return m_size; 100 } 101 102 lldb::ValueObjectSP 103 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::GetChildAtIndex( 104 uint32_t idx) { 105 if (!m_start) 106 return lldb::ValueObjectSP(); 107 108 uint64_t offset = idx * m_stride * m_element_size; 109 offset = offset + m_start->GetValueAsUnsigned(0); 110 StreamString name; 111 name.Printf("[%" PRIu64 "]", (uint64_t)idx); 112 return CreateValueObjectFromAddress(name.GetString(), offset, 113 m_backend.GetExecutionContextRef(), 114 m_element_type); 115 } 116 117 lldb::ChildCacheState 118 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::Update() { 119 m_start = nullptr; 120 121 CompilerType type = m_backend.GetCompilerType(); 122 if (type.GetNumTemplateArguments() == 0) 123 return ChildCacheState::eRefetch; 124 125 m_element_type = type.GetTypeTemplateArgument(0); 126 if (std::optional<uint64_t> size = 127 llvm::expectedToOptional(m_element_type.GetByteSize(nullptr))) 128 m_element_size = *size; 129 130 if (m_element_size == 0) 131 return ChildCacheState::eRefetch; 132 133 ValueObjectSP start = m_backend.GetChildMemberWithName("__vp_"); 134 ValueObjectSP size = m_backend.GetChildMemberWithName("__size_"); 135 ValueObjectSP stride = m_backend.GetChildMemberWithName("__stride_"); 136 137 if (!start || !size || !stride) 138 return ChildCacheState::eRefetch; 139 140 m_start = start.get(); 141 m_size = size->GetValueAsUnsigned(0); 142 m_stride = stride->GetValueAsUnsigned(0); 143 144 return ChildCacheState::eRefetch; 145 } 146 147 llvm::Expected<size_t> 148 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: 149 GetIndexOfChildWithName(ConstString name) { 150 if (!m_start) 151 return llvm::createStringError("Type has no child named '%s'", 152 name.AsCString()); 153 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString()); 154 if (!optional_idx) { 155 return llvm::createStringError("Type has no child named '%s'", 156 name.AsCString()); 157 } 158 return *optional_idx; 159 } 160 161 lldb_private::SyntheticChildrenFrontEnd * 162 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator( 163 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 164 if (!valobj_sp) 165 return nullptr; 166 return new LibcxxStdSliceArraySyntheticFrontEnd(valobj_sp); 167 } 168