brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.3 KiB · b536019 Raw
327 lines · cpp
1//===-- NSIndexPath.cpp ---------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Cocoa.h"10 11#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"12#include "lldb/DataFormatters/FormattersHelpers.h"13#include "lldb/DataFormatters/TypeSynthetic.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/Target.h"16#include "lldb/ValueObject/ValueObject.h"17#include "lldb/ValueObject/ValueObjectConstResult.h"18 19#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"20using namespace lldb;21using namespace lldb_private;22using namespace lldb_private::formatters;23 24static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {25  return (60 - (13 * (4 - i)));26}27 28static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {29  return (32 - (13 * (2 - i)));30}31 32class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {33public:34  NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)35      : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),36        m_impl(), m_uint_star_type() {37    m_ptr_size =38        m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();39  }40 41  ~NSIndexPathSyntheticFrontEnd() override = default;42 43  llvm::Expected<uint32_t> CalculateNumChildren() override {44    return m_impl.GetNumIndexes();45  }46 47  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {48    return m_impl.GetIndexAtIndex(idx, m_uint_star_type);49  }50 51  lldb::ChildCacheState Update() override {52    m_impl.Clear();53 54    auto type_system = m_backend.GetCompilerType().GetTypeSystem();55    if (!type_system)56      return lldb::ChildCacheState::eRefetch;57 58    auto ast = ScratchTypeSystemClang::GetForTarget(59        *m_backend.GetExecutionContextRef().GetTargetSP());60    if (!ast)61      return lldb::ChildCacheState::eRefetch;62 63    m_uint_star_type = ast->GetPointerSizedIntType(false);64 65    static ConstString g__indexes("_indexes");66    static ConstString g__length("_length");67 68    ProcessSP process_sp = m_backend.GetProcessSP();69    if (!process_sp)70      return lldb::ChildCacheState::eRefetch;71 72    ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);73 74    if (!runtime)75      return lldb::ChildCacheState::eRefetch;76 77    ObjCLanguageRuntime::ClassDescriptorSP descriptor(78        runtime->GetClassDescriptor(m_backend));79 80    if (!descriptor.get() || !descriptor->IsValid())81      return lldb::ChildCacheState::eRefetch;82 83    uint64_t info_bits(0), value_bits(0), payload(0);84 85    if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {86      m_impl.m_inlined.SetIndexes(payload, *process_sp);87      m_impl.m_mode = Mode::Inlined;88    } else {89      ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;90      ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;91 92      bool has_indexes(false), has_length(false);93 94      for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {95        const auto &ivar = descriptor->GetIVarAtIndex(x);96        if (ivar.m_name == g__indexes) {97          _indexes_id = ivar;98          has_indexes = true;99        } else if (ivar.m_name == g__length) {100          _length_id = ivar;101          has_length = true;102        }103 104        if (has_length && has_indexes)105          break;106      }107 108      if (has_length && has_indexes) {109        m_impl.m_outsourced.m_indexes =110            m_backend111                .GetSyntheticChildAtOffset(_indexes_id.m_offset,112                                           m_uint_star_type.GetPointerType(),113                                           true)114                .get();115        ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(116            _length_id.m_offset, m_uint_star_type, true));117        if (length_sp) {118          m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);119          if (m_impl.m_outsourced.m_indexes)120            m_impl.m_mode = Mode::Outsourced;121        }122      }123    }124    return lldb::ChildCacheState::eRefetch;125  }126 127  bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }128 129  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {130    auto optional_idx = ExtractIndexFromString(name.AsCString());131    if (!optional_idx) {132      return llvm::createStringError("Type has no child named '%s'",133                                     name.AsCString());134    }135    uint32_t idx = *optional_idx;136    if (idx >= CalculateNumChildrenIgnoringErrors())137      return llvm::createStringError("Type has no child named '%s'",138                                     name.AsCString());139    return idx;140  }141 142  lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }143 144protected:145  ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;146 147  enum class Mode { Inlined, Outsourced, Invalid };148 149  struct Impl {150    size_t GetNumIndexes() {151      switch (m_mode) {152      case Mode::Inlined:153        return m_inlined.GetNumIndexes();154      case Mode::Outsourced:155        return m_outsourced.m_count;156      default:157        return 0;158      }159    }160 161    lldb::ValueObjectSP GetIndexAtIndex(size_t idx,162                                        const CompilerType &desired_type) {163      if (idx >= GetNumIndexes())164        return nullptr;165      switch (m_mode) {166      default:167        return nullptr;168      case Mode::Inlined:169        return m_inlined.GetIndexAtIndex(idx, desired_type);170      case Mode::Outsourced:171        return m_outsourced.GetIndexAtIndex(idx);172      }173    }174 175    struct InlinedIndexes {176    public:177      void SetIndexes(uint64_t value, Process &p) {178        m_indexes = value;179        _lengthForInlinePayload(p.GetAddressByteSize());180        m_process = &p;181      }182 183      size_t GetNumIndexes() { return m_count; }184 185      lldb::ValueObjectSP GetIndexAtIndex(size_t idx,186                                          const CompilerType &desired_type) {187        if (!m_process)188          return nullptr;189 190        std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));191        if (!value.second)192          return nullptr;193 194        Value v;195        if (m_ptr_size == 8) {196          Scalar scalar((unsigned long long)value.first);197          v = Value(scalar);198        } else {199          Scalar scalar((unsigned int)value.first);200          v = Value(scalar);201        }202 203        v.SetCompilerType(desired_type);204 205        StreamString idx_name;206        idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);207 208        return ValueObjectConstResult::Create(209            m_process, v, ConstString(idx_name.GetString()));210      }211 212      void Clear() {213        m_indexes = 0;214        m_count = 0;215        m_ptr_size = 0;216        m_process = nullptr;217      }218 219      InlinedIndexes() {}220 221    private:222      uint64_t m_indexes = 0;223      size_t m_count = 0;224      uint32_t m_ptr_size = 0;225      Process *m_process = nullptr;226 227      // cfr. Foundation for the details of this code228      size_t _lengthForInlinePayload(uint32_t ptr_size) {229        m_ptr_size = ptr_size;230        if (m_ptr_size == 8)231          m_count = ((m_indexes >> 3) & 0x7);232        else233          m_count = ((m_indexes >> 3) & 0x3);234        return m_count;235      }236 237      std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {238        static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);239        if (m_ptr_size == 8) {240          switch (pos) {241          case 3:242          case 2:243          case 1:244          case 0:245            return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &246                        PACKED_INDEX_MASK,247                    true};248          default:249            return {0, false};250          }251        } else {252          switch (pos) {253          case 0:254          case 1:255            return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &256                        PACKED_INDEX_MASK,257                    true};258          default:259            return {0, false};260          }261        }262        return {0, false};263      }264    };265 266    struct OutsourcedIndexes {267      lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {268        if (m_indexes) {269          ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));270          return index_sp;271        }272        return nullptr;273      }274 275      void Clear() {276        m_indexes = nullptr;277        m_count = 0;278      }279 280      OutsourcedIndexes() {}281 282      ValueObject *m_indexes = nullptr;283      size_t m_count = 0;284    };285 286    union {287      struct InlinedIndexes m_inlined;288      struct OutsourcedIndexes m_outsourced;289    };290 291    void Clear() {292      switch (m_mode) {293      case Mode::Inlined:294        m_inlined.Clear();295        break;296      case Mode::Outsourced:297        m_outsourced.Clear();298        break;299      case Mode::Invalid:300        break;301      }302      m_mode = Mode::Invalid;303    }304 305    Impl() {}306 307    Mode m_mode = Mode::Invalid;308  } m_impl;309 310  uint32_t m_ptr_size = 0;311  CompilerType m_uint_star_type;312};313 314namespace lldb_private {315namespace formatters {316 317SyntheticChildrenFrontEnd *318NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,319                                    lldb::ValueObjectSP valobj_sp) {320  if (valobj_sp)321    return new NSIndexPathSyntheticFrontEnd(valobj_sp);322  return nullptr;323}324 325} // namespace formatters326} // namespace lldb_private327