1 //===-- AppleObjCClassDescriptorV2.h ----------------------------*- C++ -*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
11 
12 #include <mutex>
13 
14 #include "AppleObjCRuntimeV2.h"
15 #include "lldb/lldb-private.h"
16 
17 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
18 
19 namespace lldb_private {
20 
21 class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
22 public:
23   friend class lldb_private::AppleObjCRuntimeV2;
24 
25   ~ClassDescriptorV2() override = default;
26 
27   ConstString GetClassName() override;
28 
29   ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override;
30 
31   ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override;
32 
33   bool IsValid() override {
34     return true; // any Objective-C v2 runtime class descriptor we vend is valid
35   }
36 
37   // a custom descriptor is used for tagged pointers
38   bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
39                             uint64_t *value_bits = nullptr,
40                             uint64_t *payload = nullptr) override {
41     return false;
42   }
43 
44   bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
45                                   int64_t *value_bits = nullptr,
46                                   uint64_t *payload = nullptr) override {
47     return false;
48   }
49 
50   uint64_t GetInstanceSize() override;
51 
52   ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }
53 
54   bool Describe(
55       std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
56       std::function<bool(const char *, const char *)> const
57           &instance_method_func,
58       std::function<bool(const char *, const char *)> const &class_method_func,
59       std::function<bool(const char *, const char *, lldb::addr_t,
60                          uint64_t)> const &ivar_func) const override;
61 
62   size_t GetNumIVars() override {
63     GetIVarInformation();
64     return m_ivars_storage.size();
65   }
66 
67   iVarDescriptor GetIVarAtIndex(size_t idx) override {
68     if (idx >= GetNumIVars())
69       return iVarDescriptor();
70     return m_ivars_storage[idx];
71   }
72 
73 protected:
74   void GetIVarInformation();
75 
76 private:
77   static const uint32_t RW_REALIZED = (1 << 31);
78 
79   struct objc_class_t {
80     ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass.
81     ObjCLanguageRuntime::ObjCISA m_superclass = 0;
82     lldb::addr_t m_cache_ptr = 0;
83     lldb::addr_t m_vtable_ptr = 0;
84     lldb::addr_t m_data_ptr = 0;
85     uint8_t m_flags = 0;
86 
87     objc_class_t() = default;
88 
89     void Clear() {
90       m_isa = 0;
91       m_superclass = 0;
92       m_cache_ptr = 0;
93       m_vtable_ptr = 0;
94       m_data_ptr = 0;
95       m_flags = 0;
96     }
97 
98     bool Read(Process *process, lldb::addr_t addr);
99   };
100 
101   struct class_ro_t {
102     uint32_t m_flags;
103     uint32_t m_instanceStart;
104     uint32_t m_instanceSize;
105     uint32_t m_reserved;
106 
107     lldb::addr_t m_ivarLayout_ptr;
108     lldb::addr_t m_name_ptr;
109     lldb::addr_t m_baseMethods_ptr;
110     lldb::addr_t m_baseProtocols_ptr;
111     lldb::addr_t m_ivars_ptr;
112 
113     lldb::addr_t m_weakIvarLayout_ptr;
114     lldb::addr_t m_baseProperties_ptr;
115 
116     std::string m_name;
117 
118     bool Read(Process *process, lldb::addr_t addr);
119   };
120 
121   struct class_rw_t {
122     uint32_t m_flags;
123     uint32_t m_version;
124 
125     lldb::addr_t m_ro_ptr;
126     union {
127       lldb::addr_t m_method_list_ptr;
128       lldb::addr_t m_method_lists_ptr;
129     };
130     lldb::addr_t m_properties_ptr;
131     lldb::addr_t m_protocols_ptr;
132 
133     ObjCLanguageRuntime::ObjCISA m_firstSubclass;
134     ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
135 
136     bool Read(Process *process, lldb::addr_t addr);
137   };
138 
139   struct method_list_t {
140     uint16_t m_entsize;
141     bool m_is_small;
142     bool m_has_direct_selector;
143     uint32_t m_count;
144     lldb::addr_t m_first_ptr;
145 
146     bool Read(Process *process, lldb::addr_t addr);
147   };
148 
149   struct method_t {
150     lldb::addr_t m_name_ptr;
151     lldb::addr_t m_types_ptr;
152     lldb::addr_t m_imp_ptr;
153 
154     std::string m_name;
155     std::string m_types;
156 
157     static size_t GetSize(Process *process, bool is_small) {
158       size_t field_size;
159       if (is_small)
160         field_size = 4; // uint32_t relative indirect fields
161       else
162         field_size = process->GetAddressByteSize();
163 
164       return field_size    // SEL name;
165              + field_size  // const char *types;
166              + field_size; // IMP imp;
167     }
168 
169     bool Read(Process *process, lldb::addr_t addr,
170               lldb::addr_t relative_method_lists_base_addr, bool, bool);
171   };
172 
173   struct ivar_list_t {
174     uint32_t m_entsize;
175     uint32_t m_count;
176     lldb::addr_t m_first_ptr;
177 
178     bool Read(Process *process, lldb::addr_t addr);
179   };
180 
181   struct ivar_t {
182     lldb::addr_t m_offset_ptr;
183     lldb::addr_t m_name_ptr;
184     lldb::addr_t m_type_ptr;
185     uint32_t m_alignment;
186     uint32_t m_size;
187 
188     std::string m_name;
189     std::string m_type;
190 
191     static size_t GetSize(Process *process) {
192       size_t ptr_size = process->GetAddressByteSize();
193 
194       return ptr_size            // uintptr_t *offset;
195              + ptr_size          // const char *name;
196              + ptr_size          // const char *type;
197              + sizeof(uint32_t)  // uint32_t alignment;
198              + sizeof(uint32_t); // uint32_t size;
199     }
200 
201     bool Read(Process *process, lldb::addr_t addr);
202   };
203 
204   class iVarsStorage {
205   public:
206     iVarsStorage();
207 
208     size_t size();
209 
210     iVarDescriptor &operator[](size_t idx);
211 
212     void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
213 
214   private:
215     bool m_filled = false;
216     std::vector<iVarDescriptor> m_ivars;
217     std::recursive_mutex m_mutex;
218   };
219 
220   // The constructor should only be invoked by the runtime as it builds its
221   // caches
222   // or populates them.  A ClassDescriptorV2 should only ever exist in a cache.
223   ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
224                     ObjCLanguageRuntime::ObjCISA isa, const char *name)
225       : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
226         m_ivars_storage() {}
227 
228   bool Read_objc_class(Process *process,
229                        std::unique_ptr<objc_class_t> &objc_class) const;
230 
231   bool Read_class_row(Process *process, const objc_class_t &objc_class,
232                       std::unique_ptr<class_ro_t> &class_ro,
233                       std::unique_ptr<class_rw_t> &class_rw) const;
234 
235   AppleObjCRuntimeV2
236       &m_runtime; // The runtime, so we can read information lazily.
237   lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t.  (I.e.,
238                                  // objects of this class type have this as
239                                  // their ISA)
240   ConstString m_name;            // May be NULL
241   iVarsStorage m_ivars_storage;
242 };
243 
244 // tagged pointer descriptor
245 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
246 public:
247   ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
248     m_name = class_name;
249     if (!m_name) {
250       m_valid = false;
251       return;
252     }
253     m_valid = true;
254     m_payload = payload;
255     m_info_bits = (m_payload & 0xF0ULL) >> 4;
256     m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
257   }
258 
259   ClassDescriptorV2Tagged(
260       ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
261       uint64_t u_payload, int64_t s_payload) {
262     if (!actual_class_sp) {
263       m_valid = false;
264       return;
265     }
266     m_name = actual_class_sp->GetClassName();
267     if (!m_name) {
268       m_valid = false;
269       return;
270     }
271     m_valid = true;
272     m_payload = u_payload;
273     m_info_bits = (m_payload & 0x0FULL);
274     m_value_bits = (m_payload & ~0x0FULL) >> 4;
275     m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
276   }
277 
278   ~ClassDescriptorV2Tagged() override = default;
279 
280   ConstString GetClassName() override { return m_name; }
281 
282   ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override {
283     // tagged pointers can represent a class that has a superclass, but since
284     // that information is not
285     // stored in the object itself, we would have to query the runtime to
286     // discover the hierarchy
287     // for the time being, we skip this step in the interest of static discovery
288     return ObjCLanguageRuntime::ClassDescriptorSP();
289   }
290 
291   ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override {
292     return ObjCLanguageRuntime::ClassDescriptorSP();
293   }
294 
295   bool IsValid() override { return m_valid; }
296 
297   bool IsKVO() override {
298     return false; // tagged pointers are not KVO'ed
299   }
300 
301   bool IsCFType() override {
302     return false; // tagged pointers are not CF objects
303   }
304 
305   bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
306                             uint64_t *value_bits = nullptr,
307                             uint64_t *payload = nullptr) override {
308     if (info_bits)
309       *info_bits = GetInfoBits();
310     if (value_bits)
311       *value_bits = GetValueBits();
312     if (payload)
313       *payload = GetPayload();
314     return true;
315   }
316 
317   bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
318                                   int64_t *value_bits = nullptr,
319                                   uint64_t *payload = nullptr) override {
320     if (info_bits)
321       *info_bits = GetInfoBits();
322     if (value_bits)
323       *value_bits = GetValueBitsSigned();
324     if (payload)
325       *payload = GetPayload();
326     return true;
327   }
328 
329   uint64_t GetInstanceSize() override {
330     return (IsValid() ? m_pointer_size : 0);
331   }
332 
333   ObjCLanguageRuntime::ObjCISA GetISA() override {
334     return 0; // tagged pointers have no ISA
335   }
336 
337   // these calls are not part of any formal tagged pointers specification
338   virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
339 
340   virtual int64_t GetValueBitsSigned() {
341     return (IsValid() ? m_value_bits_signed : 0);
342   }
343 
344   virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
345 
346   virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
347 
348 private:
349   ConstString m_name;
350   uint8_t m_pointer_size;
351   bool m_valid;
352   uint64_t m_info_bits;
353   uint64_t m_value_bits;
354   int64_t m_value_bits_signed;
355   uint64_t m_payload;
356 };
357 
358 } // namespace lldb_private
359 
360 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
361