diff options
Diffstat (limited to 'source/DataFormatters/NSIndexPath.cpp')
-rw-r--r-- | source/DataFormatters/NSIndexPath.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/source/DataFormatters/NSIndexPath.cpp b/source/DataFormatters/NSIndexPath.cpp new file mode 100644 index 000000000000..ee9583ef4cc1 --- /dev/null +++ b/source/DataFormatters/NSIndexPath.cpp @@ -0,0 +1,309 @@ +//===-- NSIndexPath.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/DataFormatters/CXXFormatterFunctions.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Symbol/ClangASTContext.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd +{ +public: + NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : + SyntheticChildrenFrontEnd (*valobj_sp.get()), + m_ptr_size(0), + m_ast_ctx(nullptr), + m_uint_star_type() + { + m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize(); + } + + virtual size_t + CalculateNumChildren () + { + return m_impl.GetNumIndexes(); + } + + virtual lldb::ValueObjectSP + GetChildAtIndex (size_t idx) + { + return m_impl.GetIndexAtIndex(idx, m_uint_star_type); + } + + virtual bool + Update() + { + m_impl.m_mode = Mode::Invalid; + + m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext()); + if (!m_ast_ctx) + return false; + + m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false); + + static ConstString g__indexes("_indexes"); + static ConstString g__length("_length"); + + ProcessSP process_sp = m_backend.GetProcessSP(); + if (!process_sp) + return false; + + ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); + + if (!runtime) + return false; + + ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend)); + + if (!descriptor.get() || !descriptor->IsValid()) + return false; + + uint64_t info_bits(0),value_bits(0),payload(0); + + if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) + { + m_impl.m_mode = Mode::Inlined; + m_impl.m_inlined.SetIndexes(payload, *process_sp); + } + else + { + ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id; + ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id; + + bool has_indexes(false),has_length(false); + + for (size_t x = 0; + x < descriptor->GetNumIVars(); + x++) + { + const auto& ivar = descriptor->GetIVarAtIndex(x); + if (ivar.m_name == g__indexes) + { + _indexes_id = ivar; + has_indexes = true; + } + else if (ivar.m_name == g__length) + { + _length_id = ivar; + has_length = true; + } + + if (has_length && has_indexes) + break; + } + + if (has_length && has_indexes) + { + m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset, + m_uint_star_type.GetPointerType(), + true).get(); + ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset, + m_uint_star_type, + true)); + if (length_sp) + { + m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0); + if (m_impl.m_outsourced.m_indexes) + m_impl.m_mode = Mode::Outsourced; + } + } + } + return false; + } + + virtual bool + MightHaveChildren () + { + if (m_impl.m_mode == Mode::Invalid) + return false; + return true; + } + + virtual size_t + GetIndexOfChildWithName (const ConstString &name) + { + const char* item_name = name.GetCString(); + uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; + } + + virtual lldb::ValueObjectSP + GetSyntheticValue () { return nullptr; } + + virtual + ~NSIndexPathSyntheticFrontEnd () {} + +protected: + ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp; + + enum class Mode { + Inlined, + Outsourced, + Invalid + }; + + struct Impl { + Mode m_mode; + + size_t + GetNumIndexes () + { + switch (m_mode) + { + case Mode::Inlined: + return m_inlined.GetNumIndexes(); + case Mode::Outsourced: + return m_outsourced.m_count; + default: + return 0; + } + } + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx, const ClangASTType& desired_type) + { + if (idx >= GetNumIndexes()) + return nullptr; + switch (m_mode) + { + default: return nullptr; + case Mode::Inlined: + return m_inlined.GetIndexAtIndex (idx, desired_type); + case Mode::Outsourced: + return m_outsourced.GetIndexAtIndex (idx); + } + } + + struct InlinedIndexes { + public: + void SetIndexes(uint64_t value, Process& p) + { + m_indexes = value; + _lengthForInlinePayload(p.GetAddressByteSize()); + m_process = &p; + } + + size_t + GetNumIndexes () + { + return m_count; + } + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx, const ClangASTType& desired_type) + { + std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx)); + if (!value.second) + return nullptr; + Value v; + if (m_ptr_size == 8) + { + Scalar scalar( (unsigned long long)value.first ); + v = Value(scalar); + } + else + { + Scalar scalar( (unsigned int)value.first ); + v = Value(scalar); + } + v.SetClangType(desired_type); + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData())); + } + + private: + uint64_t m_indexes; + size_t m_count; + uint32_t m_ptr_size; + Process *m_process; + + // cfr. Foundation for the details of this code + size_t _lengthForInlinePayload(uint32_t ptr_size) { + m_ptr_size = ptr_size; + if (m_ptr_size == 8) + m_count = ((m_indexes >> 3) & 0x7); + else + m_count = ((m_indexes >> 3) & 0x3); + return m_count; + } + + std::pair<uint64_t, bool> + _indexAtPositionForInlinePayload(size_t pos) { + if (m_ptr_size == 8) + { + switch (pos) { + case 5: return {((m_indexes >> 51) & 0x1ff),true}; + case 4: return {((m_indexes >> 42) & 0x1ff),true}; + case 3: return {((m_indexes >> 33) & 0x1ff),true}; + case 2: return {((m_indexes >> 24) & 0x1ff),true}; + case 1: return {((m_indexes >> 15) & 0x1ff),true}; + case 0: return {((m_indexes >> 6) & 0x1ff),true}; + } + } + else + { + switch (pos) { + case 2: return {((m_indexes >> 23) & 0x1ff),true}; + case 1: return {((m_indexes >> 14) & 0x1ff),true}; + case 0: return {((m_indexes >> 5) & 0x1ff),true}; + } + } + return {0,false}; + } + + }; + struct OutsourcedIndexes { + ValueObject *m_indexes; + size_t m_count; + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx) + { + if (m_indexes) + { + ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMemberFromPointer(idx, true)); + return index_sp; + } + return nullptr; + } + }; + + union { + struct InlinedIndexes m_inlined; + struct OutsourcedIndexes m_outsourced; + }; + } m_impl; + + uint32_t m_ptr_size; + ClangASTContext* m_ast_ctx; + ClangASTType m_uint_star_type; +}; + +namespace lldb_private { + namespace formatters { + + SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) + { + if (valobj_sp) + return new NSIndexPathSyntheticFrontEnd(valobj_sp); + return nullptr; + } + } +} |