You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
8.7 KiB
313 lines
8.7 KiB
//===-- NSIndexPath.cpp ---------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Cocoa.h"
|
|
|
|
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
|
#include "lldb/Core/ValueObject.h"
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
#include "lldb/DataFormatters/FormattersHelpers.h"
|
|
#include "lldb/DataFormatters/TypeSynthetic.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Target/Target.h"
|
|
|
|
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::formatters;
|
|
|
|
static constexpr size_t PACKED_INDEX_SHIFT_64(size_t i) {
|
|
return (60 - (13 * (4 - i)));
|
|
}
|
|
|
|
static constexpr size_t PACKED_INDEX_SHIFT_32(size_t i) {
|
|
return (32 - (13 * (2 - i)));
|
|
}
|
|
|
|
class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
|
|
public:
|
|
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
|
|
: SyntheticChildrenFrontEnd(*valobj_sp.get()), m_descriptor_sp(nullptr),
|
|
m_impl(), 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;
|
|
|
|
TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget(
|
|
*m_backend.GetExecutionContextRef().GetTargetSP());
|
|
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::Get(*process_sp);
|
|
|
|
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 { return m_impl.m_mode != Mode::Invalid; }
|
|
|
|
size_t GetIndexOfChildWithName(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 {
|
|
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) {
|
|
if (!m_process)
|
|
return nullptr;
|
|
|
|
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.GetString()));
|
|
}
|
|
|
|
void Clear() {
|
|
m_indexes = 0;
|
|
m_count = 0;
|
|
m_ptr_size = 0;
|
|
m_process = nullptr;
|
|
}
|
|
|
|
InlinedIndexes()
|
|
: 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) {
|
|
static const uint64_t PACKED_INDEX_MASK = ((1 << 13) - 1);
|
|
if (m_ptr_size == 8) {
|
|
switch (pos) {
|
|
case 3:
|
|
case 2:
|
|
case 1:
|
|
case 0:
|
|
return {(m_indexes >> PACKED_INDEX_SHIFT_64(pos)) &
|
|
PACKED_INDEX_MASK,
|
|
true};
|
|
default:
|
|
return {0, false};
|
|
}
|
|
} else {
|
|
switch (pos) {
|
|
case 0:
|
|
case 1:
|
|
return {(m_indexes >> PACKED_INDEX_SHIFT_32(pos)) &
|
|
PACKED_INDEX_MASK,
|
|
true};
|
|
default:
|
|
return {0, false};
|
|
}
|
|
}
|
|
return {0, false};
|
|
}
|
|
};
|
|
|
|
struct OutsourcedIndexes {
|
|
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;
|
|
}
|
|
|
|
OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {}
|
|
|
|
ValueObject *m_indexes;
|
|
size_t m_count;
|
|
};
|
|
|
|
union {
|
|
struct InlinedIndexes m_inlined;
|
|
struct OutsourcedIndexes m_outsourced;
|
|
};
|
|
|
|
void Clear() {
|
|
m_mode = Mode::Invalid;
|
|
m_inlined.Clear();
|
|
m_outsourced.Clear();
|
|
}
|
|
|
|
Impl() : m_mode(Mode::Invalid) {}
|
|
|
|
Mode m_mode;
|
|
} 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
|