xref: /NextBSD/contrib/llvm/tools/lldb/source/DataFormatters/NSIndexPath.cpp (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
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 "lldb/DataFormatters/CXXFormatterFunctions.h"
11 
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/Core/ValueObjectConstResult.h"
14 #include "lldb/DataFormatters/TypeSynthetic.h"
15 #include "lldb/Target/ObjCLanguageRuntime.h"
16 #include "lldb/Target/Process.h"
17 #include "lldb/Symbol/ClangASTContext.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 using namespace lldb_private::formatters;
22 
23 class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd
24 {
25 public:
NSIndexPathSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)26     NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
27     SyntheticChildrenFrontEnd (*valobj_sp.get()),
28     m_ptr_size(0),
29     m_ast_ctx(nullptr),
30     m_uint_star_type()
31     {
32         m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize();
33     }
34 
35     virtual size_t
CalculateNumChildren()36     CalculateNumChildren ()
37     {
38         return m_impl.GetNumIndexes();
39     }
40 
41     virtual lldb::ValueObjectSP
GetChildAtIndex(size_t idx)42     GetChildAtIndex (size_t idx)
43     {
44         return m_impl.GetIndexAtIndex(idx, m_uint_star_type);
45     }
46 
47     virtual bool
Update()48     Update()
49     {
50         m_impl.Clear();
51 
52         m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext());
53         if (!m_ast_ctx)
54             return false;
55 
56         m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false);
57 
58         static ConstString g__indexes("_indexes");
59         static ConstString g__length("_length");
60 
61         ProcessSP process_sp = m_backend.GetProcessSP();
62         if (!process_sp)
63             return false;
64 
65         ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
66 
67         if (!runtime)
68             return false;
69 
70         ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend));
71 
72         if (!descriptor.get() || !descriptor->IsValid())
73             return false;
74 
75         uint64_t info_bits(0),value_bits(0),payload(0);
76 
77         if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
78         {
79             m_impl.m_inlined.SetIndexes(payload, *process_sp);
80             m_impl.m_mode = Mode::Inlined;
81         }
82         else
83         {
84             ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id;
85             ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id;
86 
87             bool has_indexes(false),has_length(false);
88 
89             for (size_t x = 0;
90                  x < descriptor->GetNumIVars();
91                  x++)
92             {
93                 const auto& ivar = descriptor->GetIVarAtIndex(x);
94                 if (ivar.m_name == g__indexes)
95                 {
96                     _indexes_id = ivar;
97                     has_indexes = true;
98                 }
99                 else if (ivar.m_name == g__length)
100                 {
101                     _length_id = ivar;
102                     has_length = true;
103                 }
104 
105                 if (has_length && has_indexes)
106                     break;
107             }
108 
109             if (has_length && has_indexes)
110             {
111                 m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset,
112                                                                                     m_uint_star_type.GetPointerType(),
113                                                                                     true).get();
114                 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset,
115                                                                             m_uint_star_type,
116                                                                             true));
117                 if (length_sp)
118                 {
119                     m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0);
120                     if (m_impl.m_outsourced.m_indexes)
121                         m_impl.m_mode = Mode::Outsourced;
122                 }
123             }
124         }
125         return false;
126     }
127 
128     virtual bool
MightHaveChildren()129     MightHaveChildren ()
130     {
131         if (m_impl.m_mode == Mode::Invalid)
132             return false;
133         return true;
134     }
135 
136     virtual size_t
GetIndexOfChildWithName(const ConstString & name)137     GetIndexOfChildWithName (const ConstString &name)
138     {
139         const char* item_name = name.GetCString();
140         uint32_t idx = ExtractIndexFromString(item_name);
141         if (idx < UINT32_MAX && idx >= CalculateNumChildren())
142             return UINT32_MAX;
143         return idx;
144     }
145 
146     virtual lldb::ValueObjectSP
GetSyntheticValue()147     GetSyntheticValue () { return nullptr; }
148 
149     virtual
~NSIndexPathSyntheticFrontEnd()150     ~NSIndexPathSyntheticFrontEnd () {}
151 
152 protected:
153     ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp;
154 
155     enum class Mode {
156         Inlined,
157         Outsourced,
158         Invalid
159     };
160 
161     struct Impl {
162         Mode m_mode;
163 
164         size_t
GetNumIndexesNSIndexPathSyntheticFrontEnd::Impl165         GetNumIndexes ()
166         {
167             switch (m_mode)
168             {
169                 case Mode::Inlined:
170                     return m_inlined.GetNumIndexes();
171                 case Mode::Outsourced:
172                     return m_outsourced.m_count;
173                 default:
174                     return 0;
175             }
176         }
177 
178         lldb::ValueObjectSP
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl179         GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
180         {
181             if (idx >= GetNumIndexes())
182                 return nullptr;
183             switch (m_mode)
184             {
185                 default: return nullptr;
186                 case Mode::Inlined:
187                     return m_inlined.GetIndexAtIndex (idx, desired_type);
188                 case Mode::Outsourced:
189                     return m_outsourced.GetIndexAtIndex (idx);
190             }
191         }
192 
193         struct InlinedIndexes {
194         public:
SetIndexesNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes195           void SetIndexes(uint64_t value, Process& p)
196           {
197               m_indexes = value;
198               _lengthForInlinePayload(p.GetAddressByteSize());
199               m_process = &p;
200           }
201 
202           size_t
GetNumIndexesNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes203           GetNumIndexes ()
204           {
205               return m_count;
206           }
207 
208           lldb::ValueObjectSP
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes209           GetIndexAtIndex (size_t idx, const ClangASTType& desired_type)
210           {
211               std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx));
212               if (!value.second)
213                   return nullptr;
214 
215               Value v;
216               if (m_ptr_size == 8)
217               {
218                   Scalar scalar( (unsigned long long)value.first );
219                   v = Value(scalar);
220               }
221               else
222               {
223                   Scalar scalar( (unsigned int)value.first );
224                   v = Value(scalar);
225               }
226 
227               v.SetClangType(desired_type);
228 
229               StreamString idx_name;
230               idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
231 
232               return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData()));
233           }
234 
235             void
ClearNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes236             Clear ()
237             {
238                 m_indexes = 0;
239                 m_count = 0;
240                 m_ptr_size = 0;
241                 m_process = nullptr;
242             }
243 
244           private:
245           uint64_t m_indexes;
246           size_t m_count;
247           uint32_t m_ptr_size;
248           Process *m_process;
249 
250           // cfr. Foundation for the details of this code
_lengthForInlinePayloadNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes251           size_t _lengthForInlinePayload(uint32_t ptr_size) {
252               m_ptr_size = ptr_size;
253               if (m_ptr_size == 8)
254               m_count = ((m_indexes >> 3) & 0x7);
255               else
256               m_count = ((m_indexes >> 3) & 0x3);
257               return m_count;
258           }
259 
260           std::pair<uint64_t, bool>
_indexAtPositionForInlinePayloadNSIndexPathSyntheticFrontEnd::Impl::InlinedIndexes261           _indexAtPositionForInlinePayload(size_t pos)
262           {
263               if (m_ptr_size == 8)
264               {
265                 switch (pos) {
266                     case 5: return {((m_indexes >> 51) & 0x1ff),true};
267                     case 4: return {((m_indexes >> 42) & 0x1ff),true};
268                     case 3: return {((m_indexes >> 33) & 0x1ff),true};
269                     case 2: return {((m_indexes >> 24) & 0x1ff),true};
270                     case 1: return {((m_indexes >> 15) & 0x1ff),true};
271                     case 0: return {((m_indexes >>  6) & 0x1ff),true};
272                 }
273               }
274               else
275                   {
276                   switch (pos) {
277                       case 2: return {((m_indexes >> 23) & 0x1ff),true};
278                       case 1: return {((m_indexes >> 14) & 0x1ff),true};
279                       case 0: return {((m_indexes >>  5) & 0x1ff),true};
280                   }
281               }
282               return {0,false};
283           }
284 
285         };
286         struct OutsourcedIndexes {
287             ValueObject *m_indexes;
288             size_t m_count;
289 
290             lldb::ValueObjectSP
GetIndexAtIndexNSIndexPathSyntheticFrontEnd::Impl::OutsourcedIndexes291             GetIndexAtIndex (size_t idx)
292             {
293                 if (m_indexes)
294                 {
295                     ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true));
296                     return index_sp;
297                 }
298                 return nullptr;
299             }
300 
301             void
ClearNSIndexPathSyntheticFrontEnd::Impl::OutsourcedIndexes302             Clear ()
303             {
304                 m_indexes = nullptr;
305                 m_count = 0;
306             }
307         };
308 
309         union {
310             struct InlinedIndexes m_inlined;
311             struct OutsourcedIndexes m_outsourced;
312         };
313 
314         void
ClearNSIndexPathSyntheticFrontEnd::Impl315         Clear ()
316         {
317             m_mode = Mode::Invalid;
318             m_inlined.Clear();
319             m_outsourced.Clear();
320         }
321     } m_impl;
322 
323     uint32_t m_ptr_size;
324     ClangASTContext* m_ast_ctx;
325     ClangASTType m_uint_star_type;
326 };
327 
328 namespace lldb_private {
329     namespace formatters {
330 
NSIndexPathSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)331         SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
332         {
333             if (valobj_sp)
334                 return new NSIndexPathSyntheticFrontEnd(valobj_sp);
335             return nullptr;
336         }
337     }
338 }
339