xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp (revision 624ea68cbc3ce422b3ee110c0c0af839eec2e278)
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   llvm::Expected<uint32_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(uint32_t idx) override {
83     if (!m_block_struct_type.IsValid()) {
84       return lldb::ValueObjectSP();
85     }
86 
87     if (idx >= CalculateNumChildrenIgnoringErrors()) {
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   lldb::ChildCacheState Update() override {
140     return lldb::ChildCacheState::eRefetch;
141   }
142 
143   // maybe return false if the block pointer is, say, null
144   bool MightHaveChildren() override { return true; }
145 
146   size_t GetIndexOfChildWithName(ConstString name) override {
147     if (!m_block_struct_type.IsValid())
148       return UINT32_MAX;
149 
150     const bool omit_empty_base_classes = false;
151     return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(),
152                                                        omit_empty_base_classes);
153   }
154 
155 private:
156   CompilerType m_block_struct_type;
157 };
158 
159 } // namespace formatters
160 } // namespace lldb_private
161 
162 bool lldb_private::formatters::BlockPointerSummaryProvider(
163     ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
164   lldb_private::SyntheticChildrenFrontEnd *synthetic_children =
165       BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP());
166   if (!synthetic_children) {
167     return false;
168   }
169 
170   synthetic_children->Update();
171 
172   static const ConstString s_FuncPtr_name("__FuncPtr");
173 
174   lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex(
175       synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name));
176 
177   if (!child_sp) {
178     return false;
179   }
180 
181   lldb::ValueObjectSP qualified_child_representation_sp =
182       child_sp->GetQualifiedRepresentationIfAvailable(
183           lldb::eDynamicDontRunTarget, true);
184 
185   const char *child_value =
186       qualified_child_representation_sp->GetValueAsCString();
187 
188   s.Printf("%s", child_value);
189 
190   return true;
191 }
192 
193 lldb_private::SyntheticChildrenFrontEnd *
194 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator(
195     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
196   if (!valobj_sp)
197     return nullptr;
198   return new BlockPointerSyntheticFrontEnd(valobj_sp);
199 }
200