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