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