1dda28197Spatrick //===-- BlockPointer.cpp --------------------------------------------------===// 2061da546Spatrick // 3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information. 5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6061da546Spatrick // 7061da546Spatrick //===----------------------------------------------------------------------===// 8061da546Spatrick 9061da546Spatrick #include "BlockPointer.h" 10061da546Spatrick 11dda28197Spatrick #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" 12dda28197Spatrick #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" 13dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 14061da546Spatrick #include "lldb/Core/ValueObject.h" 15061da546Spatrick #include "lldb/DataFormatters/FormattersHelpers.h" 16061da546Spatrick #include "lldb/Symbol/CompilerType.h" 17061da546Spatrick #include "lldb/Symbol/TypeSystem.h" 18061da546Spatrick #include "lldb/Target/Target.h" 19061da546Spatrick #include "lldb/Utility/LLDBAssert.h" 20061da546Spatrick #include "lldb/Utility/Log.h" 21061da546Spatrick 22061da546Spatrick using namespace lldb; 23061da546Spatrick using namespace lldb_private; 24061da546Spatrick using namespace lldb_private::formatters; 25061da546Spatrick 26061da546Spatrick namespace lldb_private { 27061da546Spatrick namespace formatters { 28061da546Spatrick 29061da546Spatrick class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 30061da546Spatrick public: 31061da546Spatrick BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 32061da546Spatrick : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() { 33061da546Spatrick CompilerType block_pointer_type(m_backend.GetCompilerType()); 34061da546Spatrick CompilerType function_pointer_type; 35061da546Spatrick block_pointer_type.IsBlockPointerType(&function_pointer_type); 36061da546Spatrick 37061da546Spatrick TargetSP target_sp(m_backend.GetTargetSP()); 38061da546Spatrick 39061da546Spatrick if (!target_sp) { 40061da546Spatrick return; 41061da546Spatrick } 42061da546Spatrick 43061da546Spatrick auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage( 44061da546Spatrick lldb::eLanguageTypeC_plus_plus); 45061da546Spatrick if (auto err = type_system_or_err.takeError()) { 46061da546Spatrick LLDB_LOG_ERROR( 47061da546Spatrick lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), 48dda28197Spatrick std::move(err), "Failed to get scratch TypeSystemClang"); 49061da546Spatrick return; 50061da546Spatrick } 51061da546Spatrick 52dda28197Spatrick TypeSystemClang *clang_ast_context = 53*be691f3bSpatrick llvm::cast<TypeSystemClang>(block_pointer_type.GetTypeSystem()); 54061da546Spatrick 55dda28197Spatrick std::shared_ptr<ClangASTImporter> clang_ast_importer; 56dda28197Spatrick auto *state = target_sp->GetPersistentExpressionStateForLanguage( 57dda28197Spatrick lldb::eLanguageTypeC_plus_plus); 58dda28197Spatrick if (state) { 59dda28197Spatrick auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); 60dda28197Spatrick clang_ast_importer = persistent_vars->GetClangASTImporter(); 61dda28197Spatrick } 62061da546Spatrick 63061da546Spatrick if (!clang_ast_importer) { 64061da546Spatrick return; 65061da546Spatrick } 66061da546Spatrick 67061da546Spatrick const char *const isa_name("__isa"); 68061da546Spatrick const CompilerType isa_type = 69061da546Spatrick clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass); 70061da546Spatrick const char *const flags_name("__flags"); 71061da546Spatrick const CompilerType flags_type = 72061da546Spatrick clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 73061da546Spatrick const char *const reserved_name("__reserved"); 74061da546Spatrick const CompilerType reserved_type = 75061da546Spatrick clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 76061da546Spatrick const char *const FuncPtr_name("__FuncPtr"); 77061da546Spatrick 78061da546Spatrick m_block_struct_type = clang_ast_context->CreateStructForIdentifier( 79061da546Spatrick ConstString(), {{isa_name, isa_type}, 80061da546Spatrick {flags_name, flags_type}, 81061da546Spatrick {reserved_name, reserved_type}, 82*be691f3bSpatrick {FuncPtr_name, function_pointer_type}}); 83061da546Spatrick } 84061da546Spatrick 85061da546Spatrick ~BlockPointerSyntheticFrontEnd() override = default; 86061da546Spatrick 87061da546Spatrick size_t CalculateNumChildren() override { 88061da546Spatrick const bool omit_empty_base_classes = false; 89061da546Spatrick return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); 90061da546Spatrick } 91061da546Spatrick 92061da546Spatrick lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { 93061da546Spatrick if (!m_block_struct_type.IsValid()) { 94061da546Spatrick return lldb::ValueObjectSP(); 95061da546Spatrick } 96061da546Spatrick 97061da546Spatrick if (idx >= CalculateNumChildren()) { 98061da546Spatrick return lldb::ValueObjectSP(); 99061da546Spatrick } 100061da546Spatrick 101061da546Spatrick const bool thread_and_frame_only_if_stopped = true; 102061da546Spatrick ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock( 103061da546Spatrick thread_and_frame_only_if_stopped); 104061da546Spatrick const bool transparent_pointers = false; 105061da546Spatrick const bool omit_empty_base_classes = false; 106061da546Spatrick const bool ignore_array_bounds = false; 107061da546Spatrick ValueObject *value_object = nullptr; 108061da546Spatrick 109061da546Spatrick std::string child_name; 110061da546Spatrick uint32_t child_byte_size = 0; 111061da546Spatrick int32_t child_byte_offset = 0; 112061da546Spatrick uint32_t child_bitfield_bit_size = 0; 113061da546Spatrick uint32_t child_bitfield_bit_offset = 0; 114061da546Spatrick bool child_is_base_class = false; 115061da546Spatrick bool child_is_deref_of_parent = false; 116061da546Spatrick uint64_t language_flags = 0; 117061da546Spatrick 118061da546Spatrick const CompilerType child_type = 119061da546Spatrick m_block_struct_type.GetChildCompilerTypeAtIndex( 120061da546Spatrick &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, 121061da546Spatrick ignore_array_bounds, child_name, child_byte_size, child_byte_offset, 122061da546Spatrick child_bitfield_bit_size, child_bitfield_bit_offset, 123061da546Spatrick child_is_base_class, child_is_deref_of_parent, value_object, 124061da546Spatrick language_flags); 125061da546Spatrick 126061da546Spatrick ValueObjectSP struct_pointer_sp = 127061da546Spatrick m_backend.Cast(m_block_struct_type.GetPointerType()); 128061da546Spatrick 129061da546Spatrick if (!struct_pointer_sp) { 130061da546Spatrick return lldb::ValueObjectSP(); 131061da546Spatrick } 132061da546Spatrick 133061da546Spatrick Status err; 134061da546Spatrick ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err); 135061da546Spatrick 136061da546Spatrick if (!struct_sp || !err.Success()) { 137061da546Spatrick return lldb::ValueObjectSP(); 138061da546Spatrick } 139061da546Spatrick 140061da546Spatrick ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset( 141061da546Spatrick child_byte_offset, child_type, true, 142061da546Spatrick ConstString(child_name.c_str(), child_name.size()))); 143061da546Spatrick 144061da546Spatrick return child_sp; 145061da546Spatrick } 146061da546Spatrick 147061da546Spatrick // return true if this object is now safe to use forever without ever 148061da546Spatrick // updating again; the typical (and tested) answer here is 'false' 149061da546Spatrick bool Update() override { return false; } 150061da546Spatrick 151061da546Spatrick // maybe return false if the block pointer is, say, null 152061da546Spatrick bool MightHaveChildren() override { return true; } 153061da546Spatrick 154061da546Spatrick size_t GetIndexOfChildWithName(ConstString name) override { 155061da546Spatrick if (!m_block_struct_type.IsValid()) 156061da546Spatrick return UINT32_MAX; 157061da546Spatrick 158061da546Spatrick const bool omit_empty_base_classes = false; 159061da546Spatrick return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(), 160061da546Spatrick omit_empty_base_classes); 161061da546Spatrick } 162061da546Spatrick 163061da546Spatrick private: 164061da546Spatrick CompilerType m_block_struct_type; 165061da546Spatrick }; 166061da546Spatrick 167061da546Spatrick } // namespace formatters 168061da546Spatrick } // namespace lldb_private 169061da546Spatrick 170061da546Spatrick bool lldb_private::formatters::BlockPointerSummaryProvider( 171061da546Spatrick ValueObject &valobj, Stream &s, const TypeSummaryOptions &) { 172061da546Spatrick lldb_private::SyntheticChildrenFrontEnd *synthetic_children = 173061da546Spatrick BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP()); 174061da546Spatrick if (!synthetic_children) { 175061da546Spatrick return false; 176061da546Spatrick } 177061da546Spatrick 178061da546Spatrick synthetic_children->Update(); 179061da546Spatrick 180061da546Spatrick static const ConstString s_FuncPtr_name("__FuncPtr"); 181061da546Spatrick 182061da546Spatrick lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex( 183061da546Spatrick synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name)); 184061da546Spatrick 185061da546Spatrick if (!child_sp) { 186061da546Spatrick return false; 187061da546Spatrick } 188061da546Spatrick 189061da546Spatrick lldb::ValueObjectSP qualified_child_representation_sp = 190061da546Spatrick child_sp->GetQualifiedRepresentationIfAvailable( 191061da546Spatrick lldb::eDynamicDontRunTarget, true); 192061da546Spatrick 193061da546Spatrick const char *child_value = 194061da546Spatrick qualified_child_representation_sp->GetValueAsCString(); 195061da546Spatrick 196061da546Spatrick s.Printf("%s", child_value); 197061da546Spatrick 198061da546Spatrick return true; 199061da546Spatrick } 200061da546Spatrick 201061da546Spatrick lldb_private::SyntheticChildrenFrontEnd * 202061da546Spatrick lldb_private::formatters::BlockPointerSyntheticFrontEndCreator( 203061da546Spatrick CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 204061da546Spatrick if (!valobj_sp) 205061da546Spatrick return nullptr; 206061da546Spatrick return new BlockPointerSyntheticFrontEnd(valobj_sp); 207061da546Spatrick } 208