diff options
author | Sean Callanan <scallanan@apple.com> | 2016-05-02 21:15:31 +0000 |
---|---|---|
committer | Sean Callanan <scallanan@apple.com> | 2016-05-02 21:15:31 +0000 |
commit | c530ba98a9ee2ab97fcae2fd28a366050aa35919 (patch) | |
tree | 5500fc7a180e5f1fc0c4e7879ef05258113a9965 /lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp | |
parent | 52f869326331871498e1c13895444701731026cb (diff) | |
download | bcm5719-llvm-c530ba98a9ee2ab97fcae2fd28a366050aa35919.tar.gz bcm5719-llvm-c530ba98a9ee2ab97fcae2fd28a366050aa35919.zip |
Import block pointers from DWARF as Clang block pointers, not as structs.
Also added a data formatter that presents them as structs if you use frame
variable to look at their contents. Now the blocks testcase works.
<rdar://problem/15984431>
llvm-svn: 268307
Diffstat (limited to 'lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp')
-rw-r--r-- | lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp | 225 |
1 files changed, 225 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 00000000000..92e30d54f6e --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -0,0 +1,225 @@ +//===-- BlockPointer.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#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" + +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; + } + + Error err; + TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(&err, lldb::eLanguageTypeC_plus_plus); + + if (!err.Success() || !type_system) + { + return; + } + + ClangASTContext *clang_ast_context = llvm::dyn_cast<ClangASTContext>(type_system); + + 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); + } + + 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(); + } + + Error 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(const 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); +} |