350 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- NSIndexPath.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 "Cocoa.h"
 | 
						|
 | 
						|
#include "lldb/Core/ValueObject.h"
 | 
						|
#include "lldb/Core/ValueObjectConstResult.h"
 | 
						|
#include "lldb/DataFormatters/FormattersHelpers.h"
 | 
						|
#include "lldb/DataFormatters/TypeSynthetic.h"
 | 
						|
#include "lldb/Symbol/ClangASTContext.h"
 | 
						|
#include "lldb/Target/ObjCLanguageRuntime.h"
 | 
						|
#include "lldb/Target/Process.h"
 | 
						|
#include "lldb/Target/Target.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_uint_star_type()
 | 
						|
    {
 | 
						|
        m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
 | 
						|
    }
 | 
						|
 | 
						|
    ~NSIndexPathSyntheticFrontEnd() override = default;
 | 
						|
 | 
						|
    size_t
 | 
						|
    CalculateNumChildren() override
 | 
						|
    {
 | 
						|
        return m_impl.GetNumIndexes();
 | 
						|
    }
 | 
						|
    
 | 
						|
    lldb::ValueObjectSP
 | 
						|
    GetChildAtIndex(size_t idx) override
 | 
						|
    {
 | 
						|
        return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
 | 
						|
    }
 | 
						|
    
 | 
						|
    bool
 | 
						|
    Update() override
 | 
						|
    {
 | 
						|
        m_impl.Clear();
 | 
						|
        
 | 
						|
        TypeSystem* type_system = m_backend.GetCompilerType().GetTypeSystem();
 | 
						|
        if (!type_system)
 | 
						|
            return false;
 | 
						|
 | 
						|
        ClangASTContext *ast = m_backend.GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext();
 | 
						|
        if (!ast)
 | 
						|
            return false;
 | 
						|
 | 
						|
        m_uint_star_type = ast->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_inlined.SetIndexes(payload, *process_sp);
 | 
						|
            m_impl.m_mode = Mode::Inlined;
 | 
						|
        }
 | 
						|
        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;
 | 
						|
    }
 | 
						|
    
 | 
						|
    bool
 | 
						|
    MightHaveChildren() override
 | 
						|
    {
 | 
						|
        if (m_impl.m_mode == Mode::Invalid)
 | 
						|
            return false;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
    
 | 
						|
    size_t
 | 
						|
    GetIndexOfChildWithName(const ConstString &name) override
 | 
						|
    {
 | 
						|
        const char* item_name = name.GetCString();
 | 
						|
        uint32_t idx = ExtractIndexFromString(item_name);
 | 
						|
        if (idx < UINT32_MAX && idx >= CalculateNumChildren())
 | 
						|
            return UINT32_MAX;
 | 
						|
        return idx;
 | 
						|
    }
 | 
						|
    
 | 
						|
    lldb::ValueObjectSP
 | 
						|
    GetSyntheticValue() override
 | 
						|
    {
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
 | 
						|
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 CompilerType& 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 CompilerType& 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.SetCompilerType(desired_type);
 | 
						|
 | 
						|
              StreamString idx_name;
 | 
						|
              idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
 | 
						|
 | 
						|
              return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
 | 
						|
          }
 | 
						|
            
 | 
						|
            void
 | 
						|
            Clear ()
 | 
						|
            {
 | 
						|
                m_indexes = 0;
 | 
						|
                m_count = 0;
 | 
						|
                m_ptr_size = 0;
 | 
						|
                m_process = nullptr;
 | 
						|
            }
 | 
						|
                    
 | 
						|
        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->GetSyntheticArrayMember(idx, true));
 | 
						|
                    return index_sp;
 | 
						|
                }
 | 
						|
                return nullptr;
 | 
						|
            }
 | 
						|
            
 | 
						|
            void
 | 
						|
            Clear ()
 | 
						|
            {
 | 
						|
                m_indexes = nullptr;
 | 
						|
                m_count = 0;
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        union {
 | 
						|
            struct InlinedIndexes m_inlined;
 | 
						|
            struct OutsourcedIndexes m_outsourced;
 | 
						|
        };
 | 
						|
        
 | 
						|
        void
 | 
						|
        Clear ()
 | 
						|
        {
 | 
						|
            m_mode = Mode::Invalid;
 | 
						|
            m_inlined.Clear();
 | 
						|
            m_outsourced.Clear();
 | 
						|
        }
 | 
						|
    } m_impl;
 | 
						|
    
 | 
						|
    uint32_t m_ptr_size;
 | 
						|
    CompilerType 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;
 | 
						|
        }
 | 
						|
 | 
						|
    } // namespace formatters
 | 
						|
} // namespace lldb_private
 |