diff options
Diffstat (limited to 'lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp')
| -rw-r--r-- | lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp | 207 | 
1 files changed, 207 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp new file mode 100644 index 0000000000000..5cfd978774fd0 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -0,0 +1,207 @@ +//===-- BlockPointer.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BlockPointer.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Target/Target.h" + +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { +namespace formatters { + +class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: +  BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) +      : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() { +    CompilerType block_pointer_type(m_backend.GetCompilerType()); +    CompilerType function_pointer_type; +    block_pointer_type.IsBlockPointerType(&function_pointer_type); + +    TargetSP target_sp(m_backend.GetTargetSP()); + +    if (!target_sp) { +      return; +    } + +    auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage( +        lldb::eLanguageTypeC_plus_plus); +    if (auto err = type_system_or_err.takeError()) { +      LLDB_LOG_ERROR( +          lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), +          std::move(err), "Failed to get scratch ClangASTContext"); +      return; +    } + +    ClangASTContext *clang_ast_context = +        llvm::dyn_cast<ClangASTContext>(&type_system_or_err.get()); + +    if (!clang_ast_context) { +      return; +    } + +    ClangASTImporterSP clang_ast_importer = target_sp->GetClangASTImporter(); + +    if (!clang_ast_importer) { +      return; +    } + +    const char *const isa_name("__isa"); +    const CompilerType isa_type = +        clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass); +    const char *const flags_name("__flags"); +    const CompilerType flags_type = +        clang_ast_context->GetBasicType(lldb::eBasicTypeInt); +    const char *const reserved_name("__reserved"); +    const CompilerType reserved_type = +        clang_ast_context->GetBasicType(lldb::eBasicTypeInt); +    const char *const FuncPtr_name("__FuncPtr"); +    const CompilerType FuncPtr_type = +        clang_ast_importer->CopyType(*clang_ast_context, function_pointer_type); + +    m_block_struct_type = clang_ast_context->CreateStructForIdentifier( +        ConstString(), {{isa_name, isa_type}, +                        {flags_name, flags_type}, +                        {reserved_name, reserved_type}, +                        {FuncPtr_name, FuncPtr_type}}); +  } + +  ~BlockPointerSyntheticFrontEnd() override = default; + +  size_t CalculateNumChildren() override { +    const bool omit_empty_base_classes = false; +    return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); +  } + +  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { +    if (!m_block_struct_type.IsValid()) { +      return lldb::ValueObjectSP(); +    } + +    if (idx >= CalculateNumChildren()) { +      return lldb::ValueObjectSP(); +    } + +    const bool thread_and_frame_only_if_stopped = true; +    ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock( +        thread_and_frame_only_if_stopped); +    const bool transparent_pointers = false; +    const bool omit_empty_base_classes = false; +    const bool ignore_array_bounds = false; +    ValueObject *value_object = nullptr; + +    std::string child_name; +    uint32_t child_byte_size = 0; +    int32_t child_byte_offset = 0; +    uint32_t child_bitfield_bit_size = 0; +    uint32_t child_bitfield_bit_offset = 0; +    bool child_is_base_class = false; +    bool child_is_deref_of_parent = false; +    uint64_t language_flags = 0; + +    const CompilerType child_type = +        m_block_struct_type.GetChildCompilerTypeAtIndex( +            &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, +            ignore_array_bounds, child_name, child_byte_size, child_byte_offset, +            child_bitfield_bit_size, child_bitfield_bit_offset, +            child_is_base_class, child_is_deref_of_parent, value_object, +            language_flags); + +    ValueObjectSP struct_pointer_sp = +        m_backend.Cast(m_block_struct_type.GetPointerType()); + +    if (!struct_pointer_sp) { +      return lldb::ValueObjectSP(); +    } + +    Status err; +    ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err); + +    if (!struct_sp || !err.Success()) { +      return lldb::ValueObjectSP(); +    } + +    ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset( +        child_byte_offset, child_type, true, +        ConstString(child_name.c_str(), child_name.size()))); + +    return child_sp; +  } + +  // return true if this object is now safe to use forever without ever +  // updating again; the typical (and tested) answer here is 'false' +  bool Update() override { return false; } + +  // maybe return false if the block pointer is, say, null +  bool MightHaveChildren() override { return true; } + +  size_t GetIndexOfChildWithName(ConstString name) override { +    if (!m_block_struct_type.IsValid()) +      return UINT32_MAX; + +    const bool omit_empty_base_classes = false; +    return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(), +                                                       omit_empty_base_classes); +  } + +private: +  CompilerType m_block_struct_type; +}; + +} // namespace formatters +} // namespace lldb_private + +bool lldb_private::formatters::BlockPointerSummaryProvider( +    ValueObject &valobj, Stream &s, const TypeSummaryOptions &) { +  lldb_private::SyntheticChildrenFrontEnd *synthetic_children = +      BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP()); +  if (!synthetic_children) { +    return false; +  } + +  synthetic_children->Update(); + +  static const ConstString s_FuncPtr_name("__FuncPtr"); + +  lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex( +      synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name)); + +  if (!child_sp) { +    return false; +  } + +  lldb::ValueObjectSP qualified_child_representation_sp = +      child_sp->GetQualifiedRepresentationIfAvailable( +          lldb::eDynamicDontRunTarget, true); + +  const char *child_value = +      qualified_child_representation_sp->GetValueAsCString(); + +  s.Printf("%s", child_value); + +  return true; +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::BlockPointerSyntheticFrontEndCreator( +    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { +  if (!valobj_sp) +    return nullptr; +  return new BlockPointerSyntheticFrontEnd(valobj_sp); +}  | 
