Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
39642 views
//===-- LibStdcpp.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "LibStdcpp.h"9#include "LibCxx.h"1011#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"12#include "lldb/Core/ValueObject.h"13#include "lldb/Core/ValueObjectConstResult.h"14#include "lldb/DataFormatters/StringPrinter.h"15#include "lldb/DataFormatters/VectorIterator.h"16#include "lldb/Target/Target.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/Endian.h"19#include "lldb/Utility/Status.h"20#include "lldb/Utility/Stream.h"21#include <optional>2223using namespace lldb;24using namespace lldb_private;25using namespace lldb_private::formatters;2627namespace {2829class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {30/*31(std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,32std::char_traits<char>, std::allocator<char> > > >) ibeg = {33(_Base_ptr) _M_node = 0x0000000100103910 {34(std::_Rb_tree_color) _M_color = _S_black35(std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c036(std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x000000000000000037(std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x000000000000000038}39}40*/4142public:43explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);4445llvm::Expected<uint32_t> CalculateNumChildren() override;4647lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;4849lldb::ChildCacheState Update() override;5051bool MightHaveChildren() override;5253size_t GetIndexOfChildWithName(ConstString name) override;5455private:56ExecutionContextRef m_exe_ctx_ref;57lldb::addr_t m_pair_address = 0;58CompilerType m_pair_type;59lldb::ValueObjectSP m_pair_sp;60};6162class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {63public:64explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);6566llvm::Expected<uint32_t> CalculateNumChildren() override;6768lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;6970lldb::ChildCacheState Update() override;7172bool MightHaveChildren() override;7374size_t GetIndexOfChildWithName(ConstString name) override;75private:7677// 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).82ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned)83ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned)84};8586} // end of anonymous namespace8788LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(89lldb::ValueObjectSP valobj_sp)90: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),91m_pair_sp() {92if (valobj_sp)93Update();94}9596lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {97ValueObjectSP valobj_sp = m_backend.GetSP();98if (!valobj_sp)99return lldb::ChildCacheState::eRefetch;100101TargetSP target_sp(valobj_sp->GetTargetSP());102103if (!target_sp)104return lldb::ChildCacheState::eRefetch;105106bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);107108if (!valobj_sp)109return lldb::ChildCacheState::eRefetch;110m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();111112ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));113if (!_M_node_sp)114return lldb::ChildCacheState::eRefetch;115116m_pair_address = _M_node_sp->GetValueAsUnsigned(0);117if (m_pair_address == 0)118return lldb::ChildCacheState::eRefetch;119120m_pair_address += (is_64bit ? 32 : 16);121122CompilerType my_type(valobj_sp->GetCompilerType());123if (my_type.GetNumTemplateArguments() >= 1) {124CompilerType pair_type = my_type.GetTypeTemplateArgument(0);125if (!pair_type)126return lldb::ChildCacheState::eRefetch;127m_pair_type = pair_type;128} else129return lldb::ChildCacheState::eRefetch;130131return lldb::ChildCacheState::eReuse;132}133134llvm::Expected<uint32_t>135LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {136return 2;137}138139lldb::ValueObjectSP140LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {141if (m_pair_address != 0 && m_pair_type) {142if (!m_pair_sp)143m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,144m_exe_ctx_ref, m_pair_type);145if (m_pair_sp)146return m_pair_sp->GetChildAtIndex(idx);147}148return lldb::ValueObjectSP();149}150151bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }152153size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(154ConstString name) {155if (name == "first")156return 0;157if (name == "second")158return 1;159return UINT32_MAX;160}161162SyntheticChildrenFrontEnd *163lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(164CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {165return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)166: nullptr);167}168169/*170(lldb) fr var ibeg --ptr-depth 1171(__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)172ibeg = {173_M_current = 0x00000001001037a0 {174*_M_current = 1175}176}177*/178179SyntheticChildrenFrontEnd *180lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(181CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {182return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(183valobj_sp, {ConstString("_M_current")})184: nullptr);185}186187lldb_private::formatters::VectorIteratorSyntheticFrontEnd::188VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,189llvm::ArrayRef<ConstString> item_names)190: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),191m_item_names(item_names), m_item_sp() {192if (valobj_sp)193Update();194}195196lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {197m_item_sp.reset();198199ValueObjectSP valobj_sp = m_backend.GetSP();200if (!valobj_sp)201return lldb::ChildCacheState::eRefetch;202203if (!valobj_sp)204return lldb::ChildCacheState::eRefetch;205206ValueObjectSP item_ptr =207formatters::GetChildMemberWithName(*valobj_sp, m_item_names);208if (!item_ptr)209return lldb::ChildCacheState::eRefetch;210if (item_ptr->GetValueAsUnsigned(0) == 0)211return lldb::ChildCacheState::eRefetch;212Status err;213m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();214m_item_sp = CreateValueObjectFromAddress(215"item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,216item_ptr->GetCompilerType().GetPointeeType());217if (err.Fail())218m_item_sp.reset();219return lldb::ChildCacheState::eRefetch;220}221222llvm::Expected<uint32_t>223VectorIteratorSyntheticFrontEnd::CalculateNumChildren() {224return 1;225}226227lldb::ValueObjectSP228VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {229if (idx == 0)230return m_item_sp;231return lldb::ValueObjectSP();232}233234bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }235236size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(237ConstString name) {238if (name == "item")239return 0;240return UINT32_MAX;241}242243bool lldb_private::formatters::LibStdcppStringSummaryProvider(244ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {245const bool scalar_is_load_addr = true;246AddressType addr_type;247lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS;248if (valobj.IsPointerOrReferenceType()) {249Status error;250ValueObjectSP pointee_sp = valobj.Dereference(error);251if (pointee_sp && error.Success())252addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type);253} else254addr_of_string =255valobj.GetAddressOf(scalar_is_load_addr, &addr_type);256if (addr_of_string != LLDB_INVALID_ADDRESS) {257switch (addr_type) {258case eAddressTypeLoad: {259ProcessSP process_sp(valobj.GetProcessSP());260if (!process_sp)261return false;262263StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);264Status error;265lldb::addr_t addr_of_data =266process_sp->ReadPointerFromMemory(addr_of_string, error);267if (error.Fail() || addr_of_data == 0 ||268addr_of_data == LLDB_INVALID_ADDRESS)269return false;270options.SetLocation(addr_of_data);271options.SetTargetSP(valobj.GetTargetSP());272options.SetStream(&stream);273options.SetNeedsZeroTermination(false);274options.SetBinaryZeroIsTerminator(true);275lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(276addr_of_string + process_sp->GetAddressByteSize(), error);277if (error.Fail())278return false;279options.SetSourceSize(size_of_data);280options.SetHasSourceSize(true);281282if (!StringPrinter::ReadStringAndDumpToStream<283StringPrinter::StringElementType::UTF8>(options)) {284stream.Printf("Summary Unavailable");285return true;286} else287return true;288} break;289case eAddressTypeHost:290break;291case eAddressTypeInvalid:292case eAddressTypeFile:293break;294}295}296return false;297}298299bool lldb_private::formatters::LibStdcppWStringSummaryProvider(300ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {301const bool scalar_is_load_addr = true;302AddressType addr_type;303lldb::addr_t addr_of_string =304valobj.GetAddressOf(scalar_is_load_addr, &addr_type);305if (addr_of_string != LLDB_INVALID_ADDRESS) {306switch (addr_type) {307case eAddressTypeLoad: {308ProcessSP process_sp(valobj.GetProcessSP());309if (!process_sp)310return false;311312CompilerType wchar_compiler_type =313valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);314315if (!wchar_compiler_type)316return false;317318// Safe to pass nullptr for exe_scope here.319std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);320if (!size)321return false;322const uint32_t wchar_size = *size;323324StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);325Status error;326lldb::addr_t addr_of_data =327process_sp->ReadPointerFromMemory(addr_of_string, error);328if (error.Fail() || addr_of_data == 0 ||329addr_of_data == LLDB_INVALID_ADDRESS)330return false;331options.SetLocation(addr_of_data);332options.SetTargetSP(valobj.GetTargetSP());333options.SetStream(&stream);334options.SetNeedsZeroTermination(false);335options.SetBinaryZeroIsTerminator(false);336lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(337addr_of_string + process_sp->GetAddressByteSize(), error);338if (error.Fail())339return false;340options.SetSourceSize(size_of_data);341options.SetHasSourceSize(true);342options.SetPrefixToken("L");343344switch (wchar_size) {345case 8:346return StringPrinter::ReadStringAndDumpToStream<347StringPrinter::StringElementType::UTF8>(options);348case 16:349return StringPrinter::ReadStringAndDumpToStream<350StringPrinter::StringElementType::UTF16>(options);351case 32:352return StringPrinter::ReadStringAndDumpToStream<353StringPrinter::StringElementType::UTF32>(options);354default:355stream.Printf("size for wchar_t is not valid");356return true;357}358return true;359} break;360case eAddressTypeHost:361break;362case eAddressTypeInvalid:363case eAddressTypeFile:364break;365}366}367return false;368}369370LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(371lldb::ValueObjectSP valobj_sp)372: SyntheticChildrenFrontEnd(*valobj_sp) {373if (valobj_sp)374Update();375}376377llvm::Expected<uint32_t>378LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {379return 1;380}381382lldb::ValueObjectSP383LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {384if (idx == 0)385return m_ptr_obj->GetSP();386if (idx == 1) {387if (m_ptr_obj && !m_obj_obj) {388Status error;389ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);390if (error.Success())391m_obj_obj = obj_obj->Clone(ConstString("object")).get();392}393if (m_obj_obj)394return m_obj_obj->GetSP();395}396return lldb::ValueObjectSP();397}398399lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {400auto backend = m_backend.GetSP();401if (!backend)402return lldb::ChildCacheState::eRefetch;403404auto valobj_sp = backend->GetNonSyntheticValue();405if (!valobj_sp)406return lldb::ChildCacheState::eRefetch;407408auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");409if (!ptr_obj_sp)410return lldb::ChildCacheState::eRefetch;411412m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get();413m_obj_obj = nullptr;414415return lldb::ChildCacheState::eRefetch;416}417418bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }419420size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(421ConstString name) {422if (name == "pointer")423return 0;424if (name == "object" || name == "$$dereference$$")425return 1;426return UINT32_MAX;427}428429SyntheticChildrenFrontEnd *430lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(431CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {432return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)433: nullptr);434}435436bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(437ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {438ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());439if (!valobj_sp)440return false;441442ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));443if (!ptr_sp)444return false;445446ValueObjectSP usecount_sp(447valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));448if (!usecount_sp)449return false;450451if (ptr_sp->GetValueAsUnsigned(0) == 0 ||452usecount_sp->GetValueAsUnsigned(0) == 0) {453stream.Printf("nullptr");454return true;455}456457Status error;458ValueObjectSP pointee_sp = ptr_sp->Dereference(error);459if (pointee_sp && error.Success()) {460if (pointee_sp->DumpPrintableRepresentation(461stream, ValueObject::eValueObjectRepresentationStyleSummary,462lldb::eFormatInvalid,463ValueObject::PrintableRepresentationSpecialCases::eDisable,464false)) {465return true;466}467}468469stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));470return true;471}472473474