157 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "LibCxx.h"10 11#include "lldb/DataFormatters/FormattersHelpers.h"12#include "lldb/Utility/ConstString.h"13#include "lldb/ValueObject/ValueObject.h"14#include "llvm/ADT/APSInt.h"15#include <optional>16 17using namespace lldb;18using namespace lldb_private;19using namespace lldb_private::formatters;20 21namespace lldb_private {22namespace formatters {23 24class LibcxxStdSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {25public: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 object35 //36 // std::span can either be instantiated with a compile-time known37 // extent or a std::dynamic_extent (this is the default if only the38 // type template argument is provided). The layout of std::span39 // depends on whether the extent is dynamic or not. For static40 // extents (e.g., std::span<int, 9>):41 //42 // (std::__1::span<const int, 9>) s = {43 // __data = 0x000000016fdff49444 // }45 //46 // For dynamic extents, e.g., std::span<int>, the layout is:47 //48 // (std::__1::span<const int, 18446744073709551615>) s = {49 // __data = 0x000000016fdff49450 // __size = 651 // }52 //53 // This function checks for a '__size' member to determine the number54 // of elements in the span. If no such member exists, we get the size55 // from the only other place it can be: the template argument.56 lldb::ChildCacheState Update() override;57 58 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;59 60private:61 ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.62 CompilerType m_element_type{}; ///< Type of span elements.63 size_t m_num_elements = 0; ///< Number of elements in span.64 uint32_t m_element_size = 0; ///< Size in bytes of each span element.65};66 67lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::68 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)69 : SyntheticChildrenFrontEnd(*valobj_sp) {70 if (valobj_sp)71 Update();72}73 74llvm::Expected<uint32_t> lldb_private::formatters::75 LibcxxStdSpanSyntheticFrontEnd::CalculateNumChildren() {76 return m_num_elements;77}78 79lldb::ValueObjectSP80lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex(81 uint32_t idx) {82 if (!m_start)83 return {};84 85 uint64_t offset = idx * m_element_size;86 offset = offset + m_start->GetValueAsUnsigned(0);87 StreamString name;88 name.Printf("[%" PRIu64 "]", (uint64_t)idx);89 return CreateValueObjectFromAddress(name.GetString(), offset,90 m_backend.GetExecutionContextRef(),91 m_element_type);92}93 94lldb::ChildCacheState95lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() {96 // Get element type.97 ValueObjectSP data_type_finder_sp = GetChildMemberWithName(98 m_backend, {ConstString("__data_"), ConstString("__data")});99 if (!data_type_finder_sp)100 return lldb::ChildCacheState::eRefetch;101 102 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();103 104 // Get element size.105 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);106 if (!size_or_err)107 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),108 "{0}");109 else {110 m_element_size = *size_or_err;111 112 // Get data.113 if (m_element_size > 0) {114 m_start = data_type_finder_sp.get();115 }116 117 // Get number of elements.118 if (auto size_sp = GetChildMemberWithName(119 m_backend, {ConstString("__size_"), ConstString("__size")})) {120 m_num_elements = size_sp->GetValueAsUnsigned(0);121 } else if (auto arg =122 m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {123 124 m_num_elements = arg->value.GetAPSInt().getLimitedValue();125 }126 }127 128 return lldb::ChildCacheState::eReuse;129}130 131llvm::Expected<size_t> lldb_private::formatters::132 LibcxxStdSpanSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {133 if (!m_start)134 return llvm::createStringError("Type has no child named '%s'",135 name.AsCString());136 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());137 if (!optional_idx) {138 return llvm::createStringError("Type has no child named '%s'",139 name.AsCString());140 }141 return *optional_idx;142}143 144lldb_private::SyntheticChildrenFrontEnd *145LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,146 lldb::ValueObjectSP valobj_sp) {147 if (!valobj_sp)148 return nullptr;149 CompilerType type = valobj_sp->GetCompilerType();150 if (!type.IsValid() || type.GetNumTemplateArguments() != 2)151 return nullptr;152 return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp);153}154 155} // namespace formatters156} // namespace lldb_private157