brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · 86f0a5a Raw
413 lines · cpp
1//===-- LibStdcpp.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 "LibStdcpp.h"10#include "LibCxx.h"11 12#include "Plugins/Language/CPlusPlus/Generic.h"13#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"14#include "lldb/DataFormatters/FormattersHelpers.h"15#include "lldb/DataFormatters/StringPrinter.h"16#include "lldb/DataFormatters/VectorIterator.h"17#include "lldb/Target/Target.h"18#include "lldb/Utility/DataBufferHeap.h"19#include "lldb/Utility/Endian.h"20#include "lldb/Utility/Status.h"21#include "lldb/Utility/Stream.h"22#include "lldb/ValueObject/ValueObject.h"23#include "lldb/ValueObject/ValueObjectConstResult.h"24#include <optional>25 26using namespace lldb;27using namespace lldb_private;28using namespace lldb_private::formatters;29 30namespace {31 32class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {33  /*34   (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,35   std::char_traits<char>, std::allocator<char> > > >) ibeg = {36   (_Base_ptr) _M_node = 0x0000000100103910 {37   (std::_Rb_tree_color) _M_color = _S_black38   (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c039   (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x000000000000000040   (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x000000000000000041   }42   }43   */44 45public:46  explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);47 48  llvm::Expected<uint32_t> CalculateNumChildren() override;49 50  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;51 52  lldb::ChildCacheState Update() override;53 54  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;55 56private:57  ExecutionContextRef m_exe_ctx_ref;58  lldb::addr_t m_pair_address = 0;59  CompilerType m_pair_type;60  lldb::ValueObjectSP m_pair_sp;61};62 63class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {64public:65  explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);66 67  llvm::Expected<uint32_t> CalculateNumChildren() override;68 69  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;70 71  lldb::ChildCacheState Update() override;72 73  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;74 75private:76 77  // The lifetime of a ValueObject and all its derivative ValueObjects78  // (children, clones, etc.) is managed by a ClusterManager. These79  // objects are only destroyed when every shared pointer to any of them80  // is destroyed, so we must not store a shared pointer to any ValueObject81  // derived from our backend ValueObject (since we're in the same cluster).82  ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)83};84 85} // end of anonymous namespace86 87LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(88    lldb::ValueObjectSP valobj_sp)89    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),90      m_pair_sp() {91  if (valobj_sp)92    Update();93}94 95lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {96  ValueObjectSP valobj_sp = m_backend.GetSP();97  if (!valobj_sp)98    return lldb::ChildCacheState::eRefetch;99 100  TargetSP target_sp(valobj_sp->GetTargetSP());101 102  if (!target_sp)103    return lldb::ChildCacheState::eRefetch;104 105  bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);106 107  if (!valobj_sp)108    return lldb::ChildCacheState::eRefetch;109  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();110 111  ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));112  if (!_M_node_sp)113    return lldb::ChildCacheState::eRefetch;114 115  m_pair_address = _M_node_sp->GetValueAsUnsigned(0);116  if (m_pair_address == 0)117    return lldb::ChildCacheState::eRefetch;118 119  m_pair_address += (is_64bit ? 32 : 16);120 121  CompilerType my_type(valobj_sp->GetCompilerType());122  if (my_type.GetNumTemplateArguments() >= 1) {123    CompilerType pair_type = my_type.GetTypeTemplateArgument(0);124    if (!pair_type)125      return lldb::ChildCacheState::eRefetch;126    m_pair_type = pair_type;127  } else128    return lldb::ChildCacheState::eRefetch;129 130  return lldb::ChildCacheState::eReuse;131}132 133llvm::Expected<uint32_t>134LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {135  return 2;136}137 138lldb::ValueObjectSP139LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {140  if (m_pair_address != 0 && m_pair_type) {141    if (!m_pair_sp)142      m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,143                                               m_exe_ctx_ref, m_pair_type);144    if (m_pair_sp)145      return m_pair_sp->GetChildAtIndex(idx);146  }147  return lldb::ValueObjectSP();148}149 150llvm::Expected<size_t>151LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(152    ConstString name) {153  if (name == "first")154    return 0;155  if (name == "second")156    return 1;157  return llvm::createStringError("Type has no child named '%s'",158                                 name.AsCString());159}160 161SyntheticChildrenFrontEnd *162lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(163    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {164  return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)165                    : nullptr);166}167 168/*169 (lldb) fr var ibeg --ptr-depth 1170 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)171 ibeg = {172 _M_current = 0x00000001001037a0 {173 *_M_current = 1174 }175 }176 */177 178SyntheticChildrenFrontEnd *179lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(180    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {181  return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(182                          valobj_sp, {ConstString("_M_current")})183                    : nullptr);184}185 186lldb_private::formatters::VectorIteratorSyntheticFrontEnd::187    VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,188                                    llvm::ArrayRef<ConstString> item_names)189    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),190      m_item_names(item_names), m_item_sp() {191  if (valobj_sp)192    Update();193}194 195lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {196  m_item_sp.reset();197 198  ValueObjectSP valobj_sp = m_backend.GetSP();199  if (!valobj_sp)200    return lldb::ChildCacheState::eRefetch;201 202  ValueObjectSP item_ptr =203      formatters::GetChildMemberWithName(*valobj_sp, m_item_names);204  if (!item_ptr)205    return lldb::ChildCacheState::eRefetch;206  if (item_ptr->GetValueAsUnsigned(0) == 0)207    return lldb::ChildCacheState::eRefetch;208  Status err;209  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();210  m_item_sp = CreateValueObjectFromAddress(211      "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,212      item_ptr->GetCompilerType().GetPointeeType());213  if (err.Fail())214    m_item_sp.reset();215  return lldb::ChildCacheState::eRefetch;216}217 218llvm::Expected<uint32_t>219VectorIteratorSyntheticFrontEnd::CalculateNumChildren() {220  return 1;221}222 223lldb::ValueObjectSP224VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {225  if (idx == 0)226    return m_item_sp;227  return lldb::ValueObjectSP();228}229 230llvm::Expected<size_t>231VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {232  if (name == "item")233    return 0;234  return llvm::createStringError("Type has no child named '%s'",235                                 name.AsCString());236}237 238bool lldb_private::formatters::LibStdcppStringSummaryProvider(239    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {240  ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});241  if (!ptr || !ptr->GetError().Success())242    stream << "Summary Unavailable";243  else244    stream << ptr->GetSummaryAsCString();245 246  return true;247}248 249LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(250    lldb::ValueObjectSP valobj_sp)251    : SyntheticChildrenFrontEnd(*valobj_sp) {252  if (valobj_sp)253    Update();254}255 256llvm::Expected<uint32_t>257LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {258  return 1;259}260 261lldb::ValueObjectSP262LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {263  if (!m_ptr_obj)264    return nullptr;265 266  if (idx == 0)267    return m_ptr_obj->GetSP();268 269  if (idx == 1) {270    ValueObjectSP valobj_sp = m_backend.GetSP();271    if (!valobj_sp)272      return nullptr;273 274    Status status;275    ValueObjectSP value_sp = m_ptr_obj->Dereference(status);276    if (status.Success())277      return value_sp;278  }279  return lldb::ValueObjectSP();280}281 282lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {283  auto backend = m_backend.GetSP();284  if (!backend)285    return lldb::ChildCacheState::eRefetch;286 287  auto valobj_sp = backend->GetNonSyntheticValue();288  if (!valobj_sp)289    return lldb::ChildCacheState::eRefetch;290 291  auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");292  if (!ptr_obj_sp)293    return lldb::ChildCacheState::eRefetch;294 295  auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);296  if (!cast_ptr_sp)297    return lldb::ChildCacheState::eRefetch;298 299  m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();300 301  return lldb::ChildCacheState::eRefetch;302}303 304llvm::Expected<size_t>305LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {306  if (name == "pointer")307    return 0;308 309  if (name == "object" || name == "$$dereference$$")310    return 1;311 312  return llvm::createStringError("Type has no child named '%s'",313                                 name.AsCString());314}315 316SyntheticChildrenFrontEnd *317lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(318    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {319  return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)320                    : nullptr);321}322 323bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(324    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {325  ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());326  if (!valobj_sp)327    return false;328 329  ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));330  if (!ptr_sp)331    return false;332 333  DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);334 335  ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});336  if (!pi_sp)337    return false;338 339  bool success;340  uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);341  // Empty control field. We're done.342  if (!success || pi_addr == 0)343    return true;344 345  int64_t shared_count = 0;346  if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {347    bool success;348    shared_count = count_sp->GetValueAsSigned(0, &success);349    if (!success)350      return false;351 352    stream.Printf(" strong=%" PRId64, shared_count);353  }354 355  // _M_weak_count is the number of weak references + (_M_use_count != 0).356  if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {357    bool success;358    int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);359    if (!success)360      return false;361 362    stream.Printf(" weak=%" PRId64, count - (shared_count != 0));363  }364 365  return true;366}367 368static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {369  switch (index_byte_size) {370  case 1:371    return 0xff;372  case 2:373    return 0xffff;374  default:375    return 0xffff'ffff;376  }377}378 379bool formatters::LibStdcppVariantSummaryProvider(380    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {381  ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();382  if (!valobj_sp)383    return false;384 385  ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");386  ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");387  if (!index_obj || !data_obj)388    return false;389 390  auto index_bytes = index_obj->GetByteSize();391  if (!index_bytes)392    return false;393  auto npos_value = LibStdcppVariantNposValue(*index_bytes);394  auto index = index_obj->GetValueAsUnsigned(0);395  if (index == npos_value) {396    stream.Printf(" No Value");397    return true;398  }399 400  auto variant_type =401      valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();402  if (!variant_type)403    return false;404  if (index >= variant_type.GetNumTemplateArguments(true)) {405    stream.Printf(" <Invalid>");406    return true;407  }408 409  auto active_type = variant_type.GetTypeTemplateArgument(index, true);410  stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";411  return true;412}413