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
23using namespace lldb;
24using namespace lldb_private;
25using namespace lldb_private::formatters;
26
27namespace lldb_private {
28namespace formatters {
29
30class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
31public:
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_ptr: &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 language: 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(type: lldb::eBasicTypeObjCClass);
60 const char *const flags_name("__flags");
61 const CompilerType flags_type =
62 clang_ast_context->GetBasicType(type: lldb::eBasicTypeInt);
63 const char *const reserved_name("__reserved");
64 const CompilerType reserved_type =
65 clang_ast_context->GetBasicType(type: lldb::eBasicTypeInt);
66 const char *const FuncPtr_name("__FuncPtr");
67
68 m_block_struct_type = clang_ast_context->CreateStructForIdentifier(
69 type_name: llvm::StringRef(), type_fields: {{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, exe_ctx: 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: &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, valobj: value_object,
114 language_flags);
115
116 ValueObjectSP struct_pointer_sp =
117 m_backend.Cast(compiler_type: 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(error&: err);
125
126 if (!struct_sp || !err.Success()) {
127 return lldb::ValueObjectSP();
128 }
129
130 ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset(
131 offset: child_byte_offset, type: child_type, can_create: true,
132 name_const_str: 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: name.AsCString(),
152 omit_empty_base_classes);
153 }
154
155private:
156 CompilerType m_block_struct_type;
157};
158
159} // namespace formatters
160} // namespace lldb_private
161
162bool 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 idx: synthetic_children->GetIndexOfChildWithName(name: 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 dynValue: lldb::eDynamicDontRunTarget, synthValue: true);
184
185 const char *child_value =
186 qualified_child_representation_sp->GetValueAsCString();
187
188 s.Printf(format: "%s", child_value);
189
190 return true;
191}
192
193lldb_private::SyntheticChildrenFrontEnd *
194lldb_private::formatters::BlockPointerSyntheticFrontEndCreator(
195 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
196 if (!valobj_sp)
197 return nullptr;
198 return new BlockPointerSyntheticFrontEnd(valobj_sp);
199}
200

source code of lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp