15ffd83dbSDimitry Andric //===-- BlockPointer.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "BlockPointer.h"
100b57cec5SDimitry Andric 
115ffd83dbSDimitry Andric #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
125ffd83dbSDimitry Andric #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
135ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
140b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
150b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/CompilerType.h"
170b57cec5SDimitry Andric #include "lldb/Symbol/TypeSystem.h"
180b57cec5SDimitry Andric #include "lldb/Target/Target.h"
190b57cec5SDimitry Andric #include "lldb/Utility/LLDBAssert.h"
2081ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
219dba64beSDimitry Andric #include "lldb/Utility/Log.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace lldb;
240b57cec5SDimitry Andric using namespace lldb_private;
250b57cec5SDimitry Andric using namespace lldb_private::formatters;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace lldb_private {
280b57cec5SDimitry Andric namespace formatters {
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
310b57cec5SDimitry Andric public:
BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)320b57cec5SDimitry Andric   BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
330b57cec5SDimitry Andric       : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() {
340b57cec5SDimitry Andric     CompilerType block_pointer_type(m_backend.GetCompilerType());
350b57cec5SDimitry Andric     CompilerType function_pointer_type;
360b57cec5SDimitry Andric     block_pointer_type.IsBlockPointerType(&function_pointer_type);
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric     TargetSP target_sp(m_backend.GetTargetSP());
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric     if (!target_sp) {
410b57cec5SDimitry Andric       return;
420b57cec5SDimitry Andric     }
430b57cec5SDimitry Andric 
449dba64beSDimitry Andric     auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(
459dba64beSDimitry Andric         lldb::eLanguageTypeC_plus_plus);
469dba64beSDimitry Andric     if (auto err = type_system_or_err.takeError()) {
4781ad6265SDimitry Andric       LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), std::move(err),
4806c3fb27SDimitry Andric                      "Failed to get scratch TypeSystemClang: {0}");
490b57cec5SDimitry Andric       return;
500b57cec5SDimitry Andric     }
510b57cec5SDimitry Andric 
52bdd1243dSDimitry Andric     auto ts = block_pointer_type.GetTypeSystem();
53bdd1243dSDimitry Andric     auto clang_ast_context = ts.dyn_cast_or_null<TypeSystemClang>();
54bdd1243dSDimitry Andric     if (!clang_ast_context)
55bdd1243dSDimitry Andric       return;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric     const char *const isa_name("__isa");
580b57cec5SDimitry Andric     const CompilerType isa_type =
590b57cec5SDimitry Andric         clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass);
600b57cec5SDimitry Andric     const char *const flags_name("__flags");
610b57cec5SDimitry Andric     const CompilerType flags_type =
620b57cec5SDimitry Andric         clang_ast_context->GetBasicType(lldb::eBasicTypeInt);
630b57cec5SDimitry Andric     const char *const reserved_name("__reserved");
640b57cec5SDimitry Andric     const CompilerType reserved_type =
650b57cec5SDimitry Andric         clang_ast_context->GetBasicType(lldb::eBasicTypeInt);
660b57cec5SDimitry Andric     const char *const FuncPtr_name("__FuncPtr");
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric     m_block_struct_type = clang_ast_context->CreateStructForIdentifier(
6906c3fb27SDimitry Andric         llvm::StringRef(), {{isa_name, isa_type},
700b57cec5SDimitry Andric                             {flags_name, flags_type},
710b57cec5SDimitry Andric                             {reserved_name, reserved_type},
72fe6060f1SDimitry Andric                             {FuncPtr_name, function_pointer_type}});
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   ~BlockPointerSyntheticFrontEnd() override = default;
760b57cec5SDimitry Andric 
CalculateNumChildren()770b57cec5SDimitry Andric   size_t CalculateNumChildren() override {
780b57cec5SDimitry Andric     const bool omit_empty_base_classes = false;
790b57cec5SDimitry Andric     return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr);
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric 
GetChildAtIndex(size_t idx)820b57cec5SDimitry Andric   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
830b57cec5SDimitry Andric     if (!m_block_struct_type.IsValid()) {
840b57cec5SDimitry Andric       return lldb::ValueObjectSP();
850b57cec5SDimitry Andric     }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric     if (idx >= CalculateNumChildren()) {
880b57cec5SDimitry Andric       return lldb::ValueObjectSP();
890b57cec5SDimitry Andric     }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric     const bool thread_and_frame_only_if_stopped = true;
920b57cec5SDimitry Andric     ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock(
930b57cec5SDimitry Andric         thread_and_frame_only_if_stopped);
940b57cec5SDimitry Andric     const bool transparent_pointers = false;
950b57cec5SDimitry Andric     const bool omit_empty_base_classes = false;
960b57cec5SDimitry Andric     const bool ignore_array_bounds = false;
970b57cec5SDimitry Andric     ValueObject *value_object = nullptr;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric     std::string child_name;
1000b57cec5SDimitry Andric     uint32_t child_byte_size = 0;
1010b57cec5SDimitry Andric     int32_t child_byte_offset = 0;
1020b57cec5SDimitry Andric     uint32_t child_bitfield_bit_size = 0;
1030b57cec5SDimitry Andric     uint32_t child_bitfield_bit_offset = 0;
1040b57cec5SDimitry Andric     bool child_is_base_class = false;
1050b57cec5SDimitry Andric     bool child_is_deref_of_parent = false;
1060b57cec5SDimitry Andric     uint64_t language_flags = 0;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric     const CompilerType child_type =
1090b57cec5SDimitry Andric         m_block_struct_type.GetChildCompilerTypeAtIndex(
1100b57cec5SDimitry Andric             &exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
1110b57cec5SDimitry Andric             ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
1120b57cec5SDimitry Andric             child_bitfield_bit_size, child_bitfield_bit_offset,
1130b57cec5SDimitry Andric             child_is_base_class, child_is_deref_of_parent, value_object,
1140b57cec5SDimitry Andric             language_flags);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric     ValueObjectSP struct_pointer_sp =
1170b57cec5SDimitry Andric         m_backend.Cast(m_block_struct_type.GetPointerType());
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     if (!struct_pointer_sp) {
1200b57cec5SDimitry Andric       return lldb::ValueObjectSP();
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     Status err;
1240b57cec5SDimitry Andric     ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err);
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric     if (!struct_sp || !err.Success()) {
1270b57cec5SDimitry Andric       return lldb::ValueObjectSP();
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric     ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset(
1310b57cec5SDimitry Andric         child_byte_offset, child_type, true,
1320b57cec5SDimitry Andric         ConstString(child_name.c_str(), child_name.size())));
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     return child_sp;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   // return true if this object is now safe to use forever without ever
1380b57cec5SDimitry Andric   // updating again; the typical (and tested) answer here is 'false'
Update()1390b57cec5SDimitry Andric   bool Update() override { return false; }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   // maybe return false if the block pointer is, say, null
MightHaveChildren()1420b57cec5SDimitry Andric   bool MightHaveChildren() override { return true; }
1430b57cec5SDimitry Andric 
GetIndexOfChildWithName(ConstString name)1440b57cec5SDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override {
1450b57cec5SDimitry Andric     if (!m_block_struct_type.IsValid())
1460b57cec5SDimitry Andric       return UINT32_MAX;
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric     const bool omit_empty_base_classes = false;
1490b57cec5SDimitry Andric     return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(),
1500b57cec5SDimitry Andric                                                        omit_empty_base_classes);
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric private:
1540b57cec5SDimitry Andric   CompilerType m_block_struct_type;
1550b57cec5SDimitry Andric };
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric } // namespace formatters
1580b57cec5SDimitry Andric } // namespace lldb_private
1590b57cec5SDimitry Andric 
BlockPointerSummaryProvider(ValueObject & valobj,Stream & s,const TypeSummaryOptions &)1600b57cec5SDimitry Andric bool lldb_private::formatters::BlockPointerSummaryProvider(
1610b57cec5SDimitry Andric     ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
1620b57cec5SDimitry Andric   lldb_private::SyntheticChildrenFrontEnd *synthetic_children =
1630b57cec5SDimitry Andric       BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP());
1640b57cec5SDimitry Andric   if (!synthetic_children) {
1650b57cec5SDimitry Andric     return false;
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   synthetic_children->Update();
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   static const ConstString s_FuncPtr_name("__FuncPtr");
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex(
1730b57cec5SDimitry Andric       synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name));
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   if (!child_sp) {
1760b57cec5SDimitry Andric     return false;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   lldb::ValueObjectSP qualified_child_representation_sp =
1800b57cec5SDimitry Andric       child_sp->GetQualifiedRepresentationIfAvailable(
1810b57cec5SDimitry Andric           lldb::eDynamicDontRunTarget, true);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   const char *child_value =
1840b57cec5SDimitry Andric       qualified_child_representation_sp->GetValueAsCString();
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   s.Printf("%s", child_value);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   return true;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric lldb_private::SyntheticChildrenFrontEnd *
BlockPointerSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)1920b57cec5SDimitry Andric lldb_private::formatters::BlockPointerSyntheticFrontEndCreator(
1930b57cec5SDimitry Andric     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
1940b57cec5SDimitry Andric   if (!valobj_sp)
1950b57cec5SDimitry Andric     return nullptr;
1960b57cec5SDimitry Andric   return new BlockPointerSyntheticFrontEnd(valobj_sp);
1970b57cec5SDimitry Andric }
198