aboutsummaryrefslogblamecommitdiff
path: root/source/DataFormatters/NSIndexPath.cpp
blob: ee9583ef4cc1a37775f54c732a10ec95ec1bfae1 (plain) (tree)




















































































































































































































































































































                                                                                                                             
//===-- 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;
        }
    }
}