Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp
39644 views
//===-- NSIndexPath.cpp ---------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Cocoa.h"910#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"11#include "lldb/Core/ValueObject.h"12#include "lldb/Core/ValueObjectConstResult.h"13#include "lldb/DataFormatters/FormattersHelpers.h"14#include "lldb/DataFormatters/TypeSynthetic.h"15#include "lldb/Target/Process.h"16#include "lldb/Target/Target.h"1718#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"19using namespace lldb;20using namespace lldb_private;21using namespace lldb_private::formatters;2223static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {24return (60 - (13 * (4 - i)));25}2627static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {28return (32 - (13 * (2 - i)));29}3031class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {32public:33NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)34: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),35m_impl(), m_uint_star_type() {36m_ptr_size =37m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();38}3940~NSIndexPathSyntheticFrontEnd() override = default;4142llvm::Expected<uint32_t> CalculateNumChildren() override {43return m_impl.GetNumIndexes();44}4546lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {47return m_impl.GetIndexAtIndex(idx, m_uint_star_type);48}4950lldb::ChildCacheState Update() override {51m_impl.Clear();5253auto type_system = m_backend.GetCompilerType().GetTypeSystem();54if (!type_system)55return lldb::ChildCacheState::eRefetch;5657auto ast = ScratchTypeSystemClang::GetForTarget(58*m_backend.GetExecutionContextRef().GetTargetSP());59if (!ast)60return lldb::ChildCacheState::eRefetch;6162m_uint_star_type = ast->GetPointerSizedIntType(false);6364static ConstString g__indexes("_indexes");65static ConstString g__length("_length");6667ProcessSP process_sp = m_backend.GetProcessSP();68if (!process_sp)69return lldb::ChildCacheState::eRefetch;7071ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);7273if (!runtime)74return lldb::ChildCacheState::eRefetch;7576ObjCLanguageRuntime::ClassDescriptorSP descriptor(77runtime->GetClassDescriptor(m_backend));7879if (!descriptor.get() || !descriptor->IsValid())80return lldb::ChildCacheState::eRefetch;8182uint64_t info_bits(0), value_bits(0), payload(0);8384if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) {85m_impl.m_inlined.SetIndexes(payload, *process_sp);86m_impl.m_mode = Mode::Inlined;87} else {88ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;89ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;9091bool has_indexes(false), has_length(false);9293for (size_t x = 0; x < descriptor->GetNumIVars(); x++) {94const auto &ivar = descriptor->GetIVarAtIndex(x);95if (ivar.m_name == g__indexes) {96_indexes_id = ivar;97has_indexes = true;98} else if (ivar.m_name == g__length) {99_length_id = ivar;100has_length = true;101}102103if (has_length && has_indexes)104break;105}106107if (has_length && has_indexes) {108m_impl.m_outsourced.m_indexes =109m_backend110.GetSyntheticChildAtOffset(_indexes_id.m_offset,111m_uint_star_type.GetPointerType(),112true)113.get();114ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(115_length_id.m_offset, m_uint_star_type, true));116if (length_sp) {117m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);118if (m_impl.m_outsourced.m_indexes)119m_impl.m_mode = Mode::Outsourced;120}121}122}123return lldb::ChildCacheState::eRefetch;124}125126bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; }127128size_t GetIndexOfChildWithName(ConstString name) override {129const char *item_name = name.GetCString();130uint32_t idx = ExtractIndexFromString(item_name);131if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())132return UINT32_MAX;133return idx;134}135136lldb::ValueObjectSP GetSyntheticValue() override { return nullptr; }137138protected:139ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;140141enum class Mode { Inlined, Outsourced, Invalid };142143struct Impl {144size_t GetNumIndexes() {145switch (m_mode) {146case Mode::Inlined:147return m_inlined.GetNumIndexes();148case Mode::Outsourced:149return m_outsourced.m_count;150default:151return 0;152}153}154155lldb::ValueObjectSP GetIndexAtIndex(size_t idx,156const CompilerType &desired_type) {157if (idx >= GetNumIndexes())158return nullptr;159switch (m_mode) {160default:161return nullptr;162case Mode::Inlined:163return m_inlined.GetIndexAtIndex(idx, desired_type);164case Mode::Outsourced:165return m_outsourced.GetIndexAtIndex(idx);166}167}168169struct InlinedIndexes {170public:171void SetIndexes(uint64_t value, Process &p) {172m_indexes = value;173_lengthForInlinePayload(p.GetAddressByteSize());174m_process = &p;175}176177size_t GetNumIndexes() { return m_count; }178179lldb::ValueObjectSP GetIndexAtIndex(size_t idx,180const CompilerType &desired_type) {181if (!m_process)182return nullptr;183184std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));185if (!value.second)186return nullptr;187188Value v;189if (m_ptr_size == 8) {190Scalar scalar((unsigned long long)value.first);191v = Value(scalar);192} else {193Scalar scalar((unsigned int)value.first);194v = Value(scalar);195}196197v.SetCompilerType(desired_type);198199StreamString idx_name;200idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);201202return ValueObjectConstResult::Create(203m_process, v, ConstString(idx_name.GetString()));204}205206void Clear() {207m_indexes = 0;208m_count = 0;209m_ptr_size = 0;210m_process = nullptr;211}212213InlinedIndexes() {}214215private:216uint64_t m_indexes = 0;217size_t m_count = 0;218uint32_t m_ptr_size = 0;219Process *m_process = nullptr;220221// cfr. Foundation for the details of this code222size_t _lengthForInlinePayload(uint32_t ptr_size) {223m_ptr_size = ptr_size;224if (m_ptr_size == 8)225m_count = ((m_indexes >> 3) & 0x7);226else227m_count = ((m_indexes >> 3) & 0x3);228return m_count;229}230231std::pair<uint64_t, bool> _indexAtPositionForInlinePayload(size_t pos) {232static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);233if (m_ptr_size == 8) {234switch (pos) {235case 3:236case 2:237case 1:238case 0:239return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &240PACKED_INDEX_MASK,241true};242default:243return {0, false};244}245} else {246switch (pos) {247case 0:248case 1:249return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &250PACKED_INDEX_MASK,251true};252default:253return {0, false};254}255}256return {0, false};257}258};259260struct OutsourcedIndexes {261lldb::ValueObjectSP GetIndexAtIndex(size_t idx) {262if (m_indexes) {263ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));264return index_sp;265}266return nullptr;267}268269void Clear() {270m_indexes = nullptr;271m_count = 0;272}273274OutsourcedIndexes() {}275276ValueObject *m_indexes = nullptr;277size_t m_count = 0;278};279280union {281struct InlinedIndexes m_inlined;282struct OutsourcedIndexes m_outsourced;283};284285void Clear() {286switch (m_mode) {287case Mode::Inlined:288m_inlined.Clear();289break;290case Mode::Outsourced:291m_outsourced.Clear();292break;293case Mode::Invalid:294break;295}296m_mode = Mode::Invalid;297}298299Impl() {}300301Mode m_mode = Mode::Invalid;302} m_impl;303304uint32_t m_ptr_size = 0;305CompilerType m_uint_star_type;306};307308namespace lldb_private {309namespace formatters {310311SyntheticChildrenFrontEnd *312NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,313lldb::ValueObjectSP valobj_sp) {314if (valobj_sp)315return new NSIndexPathSyntheticFrontEnd(valobj_sp);316return nullptr;317}318319} // namespace formatters320} // namespace lldb_private321322323