1 //===-- BlockPointer.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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "BlockPointer.h" 10 11 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" 12 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" 13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 14 #include "lldb/Core/ValueObject.h" 15 #include "lldb/DataFormatters/FormattersHelpers.h" 16 #include "lldb/Symbol/CompilerType.h" 17 #include "lldb/Symbol/TypeSystem.h" 18 #include "lldb/Target/Target.h" 19 #include "lldb/Utility/LLDBAssert.h" 20 #include "lldb/Utility/Log.h" 21 22 using namespace lldb; 23 using namespace lldb_private; 24 using namespace lldb_private::formatters; 25 26 namespace lldb_private { 27 namespace formatters { 28 29 class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 30 public: 31 BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 32 : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() { 33 CompilerType block_pointer_type(m_backend.GetCompilerType()); 34 CompilerType function_pointer_type; 35 block_pointer_type.IsBlockPointerType(&function_pointer_type); 36 37 TargetSP target_sp(m_backend.GetTargetSP()); 38 39 if (!target_sp) { 40 return; 41 } 42 43 auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage( 44 lldb::eLanguageTypeC_plus_plus); 45 if (auto err = type_system_or_err.takeError()) { 46 LLDB_LOG_ERROR( 47 lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), 48 std::move(err), "Failed to get scratch TypeSystemClang"); 49 return; 50 } 51 52 TypeSystemClang *clang_ast_context = 53 llvm::cast<TypeSystemClang>(block_pointer_type.GetTypeSystem()); 54 55 std::shared_ptr<ClangASTImporter> clang_ast_importer; 56 auto *state = target_sp->GetPersistentExpressionStateForLanguage( 57 lldb::eLanguageTypeC_plus_plus); 58 if (state) { 59 auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); 60 clang_ast_importer = persistent_vars->GetClangASTImporter(); 61 } 62 63 if (!clang_ast_importer) { 64 return; 65 } 66 67 const char *const isa_name("__isa"); 68 const CompilerType isa_type = 69 clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass); 70 const char *const flags_name("__flags"); 71 const CompilerType flags_type = 72 clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 73 const char *const reserved_name("__reserved"); 74 const CompilerType reserved_type = 75 clang_ast_context->GetBasicType(lldb::eBasicTypeInt); 76 const char *const FuncPtr_name("__FuncPtr"); 77 const CompilerType FuncPtr_type = 78 clang_ast_importer->CopyType(*clang_ast_context, function_pointer_type); 79 80 m_block_struct_type = clang_ast_context->CreateStructForIdentifier( 81 ConstString(), {{isa_name, isa_type}, 82 {flags_name, flags_type}, 83 {reserved_name, reserved_type}, 84 {FuncPtr_name, FuncPtr_type}}); 85 } 86 87 ~BlockPointerSyntheticFrontEnd() override = default; 88 89 size_t CalculateNumChildren() override { 90 const bool omit_empty_base_classes = false; 91 return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); 92 } 93 94 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { 95 if (!m_block_struct_type.IsValid()) { 96 return lldb::ValueObjectSP(); 97 } 98 99 if (idx >= CalculateNumChildren()) { 100 return lldb::ValueObjectSP(); 101 } 102 103 const bool thread_and_frame_only_if_stopped = true; 104 ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock( 105 thread_and_frame_only_if_stopped); 106 const bool transparent_pointers = false; 107 const bool omit_empty_base_classes = false; 108 const bool ignore_array_bounds = false; 109 ValueObject *value_object = nullptr; 110 111 std::string child_name; 112 uint32_t child_byte_size = 0; 113 int32_t child_byte_offset = 0; 114 uint32_t child_bitfield_bit_size = 0; 115 uint32_t child_bitfield_bit_offset = 0; 116 bool child_is_base_class = false; 117 bool child_is_deref_of_parent = false; 118 uint64_t language_flags = 0; 119 120 const CompilerType child_type = 121 m_block_struct_type.GetChildCompilerTypeAtIndex( 122 &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, 123 ignore_array_bounds, child_name, child_byte_size, child_byte_offset, 124 child_bitfield_bit_size, child_bitfield_bit_offset, 125 child_is_base_class, child_is_deref_of_parent, value_object, 126 language_flags); 127 128 ValueObjectSP struct_pointer_sp = 129 m_backend.Cast(m_block_struct_type.GetPointerType()); 130 131 if (!struct_pointer_sp) { 132 return lldb::ValueObjectSP(); 133 } 134 135 Status err; 136 ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err); 137 138 if (!struct_sp || !err.Success()) { 139 return lldb::ValueObjectSP(); 140 } 141 142 ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset( 143 child_byte_offset, child_type, true, 144 ConstString(child_name.c_str(), child_name.size()))); 145 146 return child_sp; 147 } 148 149 // return true if this object is now safe to use forever without ever 150 // updating again; the typical (and tested) answer here is 'false' 151 bool Update() override { return false; } 152 153 // maybe return false if the block pointer is, say, null 154 bool MightHaveChildren() override { return true; } 155 156 size_t GetIndexOfChildWithName(ConstString name) override { 157 if (!m_block_struct_type.IsValid()) 158 return UINT32_MAX; 159 160 const bool omit_empty_base_classes = false; 161 return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(), 162 omit_empty_base_classes); 163 } 164 165 private: 166 CompilerType m_block_struct_type; 167 }; 168 169 } // namespace formatters 170 } // namespace lldb_private 171 172 bool lldb_private::formatters::BlockPointerSummaryProvider( 173 ValueObject &valobj, Stream &s, const TypeSummaryOptions &) { 174 lldb_private::SyntheticChildrenFrontEnd *synthetic_children = 175 BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP()); 176 if (!synthetic_children) { 177 return false; 178 } 179 180 synthetic_children->Update(); 181 182 static const ConstString s_FuncPtr_name("__FuncPtr"); 183 184 lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex( 185 synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name)); 186 187 if (!child_sp) { 188 return false; 189 } 190 191 lldb::ValueObjectSP qualified_child_representation_sp = 192 child_sp->GetQualifiedRepresentationIfAvailable( 193 lldb::eDynamicDontRunTarget, true); 194 195 const char *child_value = 196 qualified_child_representation_sp->GetValueAsCString(); 197 198 s.Printf("%s", child_value); 199 200 return true; 201 } 202 203 lldb_private::SyntheticChildrenFrontEnd * 204 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator( 205 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 206 if (!valobj_sp) 207 return nullptr; 208 return new BlockPointerSyntheticFrontEnd(valobj_sp); 209 } 210