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