brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · 30fec4e Raw
289 lines · cpp
1//===-- LibCxxVariant.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 "LibCxxVariant.h"10#include "LibCxx.h"11#include "lldb/DataFormatters/FormattersHelpers.h"12#include "lldb/Symbol/CompilerType.h"13#include "lldb/Utility/LLDBAssert.h"14 15#include "llvm/ADT/ScopeExit.h"16#include <optional>17 18using namespace lldb;19using namespace lldb_private;20 21// libc++ variant implementation contains two members that we care about both22// are contained in the __impl member.23// - __index which tells us which of the variadic template types is the active24//   type for the variant25// - __data is a variadic union which recursively contains itself as member26//   which refers to the tailing variadic types.27//   - __head which refers to the leading non pack type28//     - __value refers to the actual value contained29//   - __tail which refers to the remaining pack types30//31// e.g. given std::variant<int,double,char> v132//33// (lldb) frame var -R v1.__impl.__data34//(... __union<... 0, int, double, char>) v1.__impl.__data = {35// ...36//  __head = {37//    __value = ...38//  }39//  __tail = {40//  ...41//    __head = {42//      __value = ...43//    }44//    __tail = {45//    ...46//      __head = {47//        __value = ...48//  ...49//50// So given51// - __index equal to 0 the active value is contained in52//53//     __data.__head.__value54//55// - __index equal to 1 the active value is contained in56//57//     __data.__tail.__head.__value58//59// - __index equal to 2 the active value is contained in60//61//      __data.__tail.__tail.__head.__value62//63 64namespace {65// libc++ std::variant index could have one of three states66// 1) Valid, we can obtain it and its not variant_npos67// 2) Invalid, we can't obtain it or it is not a type we expect68// 3) NPos, its value is variant_npos which means the variant has no value69enum class LibcxxVariantIndexValidity { Valid, Invalid, NPos };70 71uint64_t VariantNposValue(uint64_t index_byte_size) {72  switch (index_byte_size) {73  case 1:74    return static_cast<uint8_t>(-1);75  case 2:76    return static_cast<uint16_t>(-1);77  case 4:78    return static_cast<uint32_t>(-1);79  }80  lldbassert(false && "Unknown index type size");81  return static_cast<uint32_t>(-1); // Fallback to stable ABI type.82}83 84LibcxxVariantIndexValidity85LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {86  ValueObjectSP index_sp(impl_sp->GetChildMemberWithName("__index"));87 88  if (!index_sp)89    return LibcxxVariantIndexValidity::Invalid;90 91  // In the stable ABI, the type of __index is just int.92  // In the unstable ABI, where _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION is93  // enabled, the type can either be unsigned char/short/int depending on94  // how many variant types there are.95  // We only need to do this here when comparing against npos, because npos is96  // just `-1`, but that translates to different unsigned values depending on97  // the byte size.98  CompilerType index_type = index_sp->GetCompilerType();99 100  llvm::Expected<uint64_t> index_type_bytes = index_type.GetByteSize(nullptr);101  if (!index_type_bytes) {102    LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters),103                    index_type_bytes.takeError(), "{0}");104    if (!index_type_bytes)105      return LibcxxVariantIndexValidity::Invalid;106  }107  uint64_t npos_value = VariantNposValue(*index_type_bytes);108  uint64_t index_value = index_sp->GetValueAsUnsigned(0);109 110  if (index_value == npos_value)111    return LibcxxVariantIndexValidity::NPos;112 113  return LibcxxVariantIndexValidity::Valid;114}115 116std::optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {117  ValueObjectSP index_sp(impl_sp->GetChildMemberWithName("__index"));118 119  if (!index_sp)120    return {};121 122  return {index_sp->GetValueAsUnsigned(0)};123}124 125ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {126  ValueObjectSP data_sp(impl_sp->GetChildMemberWithName("__data"));127 128  if (!data_sp)129    return ValueObjectSP{};130 131  ValueObjectSP current_level = data_sp;132  for (uint64_t n = index; n != 0; --n) {133    ValueObjectSP tail_sp(current_level->GetChildMemberWithName("__tail"));134 135    if (!tail_sp)136      return ValueObjectSP{};137 138    current_level = tail_sp;139  }140 141  return current_level->GetChildMemberWithName("__head");142}143} // namespace144 145namespace lldb_private {146namespace formatters {147bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,148                                  const TypeSummaryOptions &options) {149  ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());150  if (!valobj_sp)151    return false;152 153  ValueObjectSP impl_sp = GetChildMemberWithName(154      *valobj_sp, {ConstString("__impl_"), ConstString("__impl")});155 156  if (!impl_sp)157    return false;158 159  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);160 161  if (validity == LibcxxVariantIndexValidity::Invalid)162    return false;163 164  if (validity == LibcxxVariantIndexValidity::NPos) {165    stream.Printf(" No Value");166    return true;167  }168 169  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);170 171  if (!optional_index_value)172    return false;173 174  uint64_t index_value = *optional_index_value;175 176  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);177 178  if (!nth_head)179    return false;180 181  CompilerType head_type = nth_head->GetCompilerType();182 183  if (!head_type)184    return false;185 186  CompilerType template_type = head_type.GetTypeTemplateArgument(1);187 188  if (!template_type)189    return false;190 191  stream << " Active Type = " << template_type.GetDisplayTypeName() << " ";192 193  return true;194}195} // namespace formatters196} // namespace lldb_private197 198namespace {199class VariantFrontEnd : public SyntheticChildrenFrontEnd {200public:201  VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {202    Update();203  }204 205  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {206    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());207    if (!optional_idx) {208      return llvm::createStringError("Type has no child named '%s'",209                                     name.AsCString());210    }211    return *optional_idx;212  }213 214  lldb::ChildCacheState Update() override;215  llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }216  ValueObjectSP GetChildAtIndex(uint32_t idx) override;217 218private:219  size_t m_size = 0;220};221} // namespace222 223lldb::ChildCacheState VariantFrontEnd::Update() {224  m_size = 0;225  ValueObjectSP impl_sp = formatters::GetChildMemberWithName(226      m_backend, {ConstString("__impl_"), ConstString("__impl")});227  if (!impl_sp)228    return lldb::ChildCacheState::eRefetch;229 230  LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);231 232  if (validity == LibcxxVariantIndexValidity::Invalid)233    return lldb::ChildCacheState::eRefetch;234 235  if (validity == LibcxxVariantIndexValidity::NPos)236    return lldb::ChildCacheState::eReuse;237 238  m_size = 1;239 240  return lldb::ChildCacheState::eRefetch;241}242 243ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) {244  if (idx >= m_size)245    return {};246 247  ValueObjectSP impl_sp = formatters::GetChildMemberWithName(248      m_backend, {ConstString("__impl_"), ConstString("__impl")});249  if (!impl_sp)250    return {};251 252  auto optional_index_value = LibcxxVariantIndexValue(impl_sp);253 254  if (!optional_index_value)255    return {};256 257  uint64_t index_value = *optional_index_value;258 259  ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);260 261  if (!nth_head)262    return {};263 264  CompilerType head_type = nth_head->GetCompilerType();265 266  if (!head_type)267    return {};268 269  CompilerType template_type = head_type.GetTypeTemplateArgument(1);270 271  if (!template_type)272    return {};273 274  ValueObjectSP head_value(nth_head->GetChildMemberWithName("__value"));275 276  if (!head_value)277    return {};278 279  return head_value->Clone(ConstString("Value"));280}281 282SyntheticChildrenFrontEnd *283formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,284                                         lldb::ValueObjectSP valobj_sp) {285  if (valobj_sp)286    return new VariantFrontEnd(*valobj_sp);287  return nullptr;288}289