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