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