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