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