15ffd83dbSDimitry Andric //===-- BlockPointer.cpp --------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "BlockPointer.h" 100b57cec5SDimitry Andric 115ffd83dbSDimitry Andric #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" 125ffd83dbSDimitry Andric #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" 135ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 140b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h" 15*0fca6ea1SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h" 160b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h" 170b57cec5SDimitry Andric #include "lldb/Symbol/CompilerType.h" 180b57cec5SDimitry Andric #include "lldb/Symbol/TypeSystem.h" 190b57cec5SDimitry Andric #include "lldb/Target/Target.h" 200b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h" 2181ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 229dba64beSDimitry Andric #include "lldb/Utility/Log.h" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric using namespace lldb; 250b57cec5SDimitry Andric using namespace lldb_private; 260b57cec5SDimitry Andric using namespace lldb_private::formatters; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace lldb_private { 290b57cec5SDimitry Andric namespace formatters { 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 320b57cec5SDimitry Andric public: 330b57cec5SDimitry Andric BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 340b57cec5SDimitry Andric : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() { 350b57cec5SDimitry Andric CompilerType block_pointer_type(m_backend.GetCompilerType()); 360b57cec5SDimitry Andric CompilerType function_pointer_type; 370b57cec5SDimitry Andric block_pointer_type.IsBlockPointerType(&function_pointer_type); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric TargetSP target_sp(m_backend.GetTargetSP()); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric if (!target_sp) { 420b57cec5SDimitry Andric return; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 459dba64beSDimitry Andric auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage( 469dba64beSDimitry Andric lldb::eLanguageTypeC_plus_plus); 479dba64beSDimitry Andric if (auto err = type_system_or_err.takeError()) { 4881ad6265SDimitry Andric LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), std::move(err), 4906c3fb27SDimitry Andric "Failed to get scratch TypeSystemClang: {0}"); 500b57cec5SDimitry Andric return; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 53bdd1243dSDimitry Andric auto ts = block_pointer_type.GetTypeSystem(); 54bdd1243dSDimitry Andric auto clang_ast_context = ts.dyn_cast_or_null<TypeSystemClang>(); 55bdd1243dSDimitry Andric if (!clang_ast_context) 56bdd1243dSDimitry Andric return; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric const char *const isa_name("__isa"); 590b57cec5SDimitry Andric const CompilerType isa_type = 600b57cec5SDimitry Andric clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass); 610b57cec5SDimitry Andric const char *const flags_name("__flags"); 620b57cec5SDimitry Andric const CompilerType flags_type = 630b57cec5SDimitry Andric clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 640b57cec5SDimitry Andric const char *const reserved_name("__reserved"); 650b57cec5SDimitry Andric const CompilerType reserved_type = 660b57cec5SDimitry Andric clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 670b57cec5SDimitry Andric const char *const FuncPtr_name("__FuncPtr"); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric m_block_struct_type = clang_ast_context->CreateStructForIdentifier( 7006c3fb27SDimitry Andric llvm::StringRef(), {{isa_name, isa_type}, 710b57cec5SDimitry Andric {flags_name, flags_type}, 720b57cec5SDimitry Andric {reserved_name, reserved_type}, 73fe6060f1SDimitry Andric {FuncPtr_name, function_pointer_type}}); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric ~BlockPointerSyntheticFrontEnd() override = default; 770b57cec5SDimitry Andric 78*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override { 790b57cec5SDimitry Andric const bool omit_empty_base_classes = false; 800b57cec5SDimitry Andric return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 83*0fca6ea1SDimitry Andric lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { 840b57cec5SDimitry Andric if (!m_block_struct_type.IsValid()) { 850b57cec5SDimitry Andric return lldb::ValueObjectSP(); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 88*0fca6ea1SDimitry Andric if (idx >= CalculateNumChildrenIgnoringErrors()) { 890b57cec5SDimitry Andric return lldb::ValueObjectSP(); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric const bool thread_and_frame_only_if_stopped = true; 930b57cec5SDimitry Andric ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock( 940b57cec5SDimitry Andric thread_and_frame_only_if_stopped); 950b57cec5SDimitry Andric const bool transparent_pointers = false; 960b57cec5SDimitry Andric const bool omit_empty_base_classes = false; 970b57cec5SDimitry Andric const bool ignore_array_bounds = false; 980b57cec5SDimitry Andric ValueObject *value_object = nullptr; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric std::string child_name; 1010b57cec5SDimitry Andric uint32_t child_byte_size = 0; 1020b57cec5SDimitry Andric int32_t child_byte_offset = 0; 1030b57cec5SDimitry Andric uint32_t child_bitfield_bit_size = 0; 1040b57cec5SDimitry Andric uint32_t child_bitfield_bit_offset = 0; 1050b57cec5SDimitry Andric bool child_is_base_class = false; 1060b57cec5SDimitry Andric bool child_is_deref_of_parent = false; 1070b57cec5SDimitry Andric uint64_t language_flags = 0; 1080b57cec5SDimitry Andric 109*0fca6ea1SDimitry Andric auto child_type_or_err = m_block_struct_type.GetChildCompilerTypeAtIndex( 1100b57cec5SDimitry Andric &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, 1110b57cec5SDimitry Andric ignore_array_bounds, child_name, child_byte_size, child_byte_offset, 112*0fca6ea1SDimitry Andric child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, 113*0fca6ea1SDimitry Andric child_is_deref_of_parent, value_object, language_flags); 114*0fca6ea1SDimitry Andric if (!child_type_or_err) 115*0fca6ea1SDimitry Andric return ValueObjectConstResult::Create( 116*0fca6ea1SDimitry Andric exe_ctx.GetBestExecutionContextScope(), 117*0fca6ea1SDimitry Andric Status(child_type_or_err.takeError())); 118*0fca6ea1SDimitry Andric CompilerType child_type = *child_type_or_err; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric ValueObjectSP struct_pointer_sp = 1210b57cec5SDimitry Andric m_backend.Cast(m_block_struct_type.GetPointerType()); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric if (!struct_pointer_sp) { 1240b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric Status err; 1280b57cec5SDimitry Andric ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric if (!struct_sp || !err.Success()) { 1310b57cec5SDimitry Andric return lldb::ValueObjectSP(); 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset( 1350b57cec5SDimitry Andric child_byte_offset, child_type, true, 1360b57cec5SDimitry Andric ConstString(child_name.c_str(), child_name.size()))); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric return child_sp; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric // return true if this object is now safe to use forever without ever 1420b57cec5SDimitry Andric // updating again; the typical (and tested) answer here is 'false' 143*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override { 144*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 145*0fca6ea1SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // maybe return false if the block pointer is, say, null 1480b57cec5SDimitry Andric bool MightHaveChildren() override { return true; } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override { 1510b57cec5SDimitry Andric if (!m_block_struct_type.IsValid()) 1520b57cec5SDimitry Andric return UINT32_MAX; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric const bool omit_empty_base_classes = false; 1550b57cec5SDimitry Andric return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(), 1560b57cec5SDimitry Andric omit_empty_base_classes); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric private: 1600b57cec5SDimitry Andric CompilerType m_block_struct_type; 1610b57cec5SDimitry Andric }; 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric } // namespace formatters 1640b57cec5SDimitry Andric } // namespace lldb_private 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric bool lldb_private::formatters::BlockPointerSummaryProvider( 1670b57cec5SDimitry Andric ValueObject &valobj, Stream &s, const TypeSummaryOptions &) { 1680b57cec5SDimitry Andric lldb_private::SyntheticChildrenFrontEnd *synthetic_children = 1690b57cec5SDimitry Andric BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP()); 1700b57cec5SDimitry Andric if (!synthetic_children) { 1710b57cec5SDimitry Andric return false; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric synthetic_children->Update(); 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric static const ConstString s_FuncPtr_name("__FuncPtr"); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex( 1790b57cec5SDimitry Andric synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name)); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric if (!child_sp) { 1820b57cec5SDimitry Andric return false; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric lldb::ValueObjectSP qualified_child_representation_sp = 1860b57cec5SDimitry Andric child_sp->GetQualifiedRepresentationIfAvailable( 1870b57cec5SDimitry Andric lldb::eDynamicDontRunTarget, true); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric const char *child_value = 1900b57cec5SDimitry Andric qualified_child_representation_sp->GetValueAsCString(); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric s.Printf("%s", child_value); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric return true; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric lldb_private::SyntheticChildrenFrontEnd * 1980b57cec5SDimitry Andric lldb_private::formatters::BlockPointerSyntheticFrontEndCreator( 1990b57cec5SDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 2000b57cec5SDimitry Andric if (!valobj_sp) 2010b57cec5SDimitry Andric return nullptr; 2020b57cec5SDimitry Andric return new BlockPointerSyntheticFrontEnd(valobj_sp); 2030b57cec5SDimitry Andric } 204