1061da546Spatrick //===-- AppleObjCClassDescriptorV2.h ----------------------------*- C++ -*-===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9dda28197Spatrick #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
10dda28197Spatrick #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
11061da546Spatrick 
12061da546Spatrick #include <mutex>
13061da546Spatrick 
14061da546Spatrick #include "AppleObjCRuntimeV2.h"
15061da546Spatrick #include "lldb/lldb-private.h"
16061da546Spatrick 
17061da546Spatrick #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
18061da546Spatrick 
19061da546Spatrick namespace lldb_private {
20061da546Spatrick 
21061da546Spatrick class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
22061da546Spatrick public:
23061da546Spatrick   friend class lldb_private::AppleObjCRuntimeV2;
24061da546Spatrick 
25061da546Spatrick   ~ClassDescriptorV2() override = default;
26061da546Spatrick 
27061da546Spatrick   ConstString GetClassName() override;
28061da546Spatrick 
29061da546Spatrick   ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override;
30061da546Spatrick 
31061da546Spatrick   ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override;
32061da546Spatrick 
IsValid()33061da546Spatrick   bool IsValid() override {
34061da546Spatrick     return true; // any Objective-C v2 runtime class descriptor we vend is valid
35061da546Spatrick   }
36061da546Spatrick 
37061da546Spatrick   // a custom descriptor is used for tagged pointers
38061da546Spatrick   bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
39061da546Spatrick                             uint64_t *value_bits = nullptr,
40061da546Spatrick                             uint64_t *payload = nullptr) override {
41061da546Spatrick     return false;
42061da546Spatrick   }
43061da546Spatrick 
44be691f3bSpatrick   bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
45be691f3bSpatrick                                   int64_t *value_bits = nullptr,
46be691f3bSpatrick                                   uint64_t *payload = nullptr) override {
47be691f3bSpatrick     return false;
48be691f3bSpatrick   }
49be691f3bSpatrick 
50061da546Spatrick   uint64_t GetInstanceSize() override;
51061da546Spatrick 
GetISA()52061da546Spatrick   ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }
53061da546Spatrick 
54061da546Spatrick   bool Describe(
55061da546Spatrick       std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
56061da546Spatrick       std::function<bool(const char *, const char *)> const
57061da546Spatrick           &instance_method_func,
58061da546Spatrick       std::function<bool(const char *, const char *)> const &class_method_func,
59061da546Spatrick       std::function<bool(const char *, const char *, lldb::addr_t,
60061da546Spatrick                          uint64_t)> const &ivar_func) const override;
61061da546Spatrick 
GetNumIVars()62061da546Spatrick   size_t GetNumIVars() override {
63061da546Spatrick     GetIVarInformation();
64061da546Spatrick     return m_ivars_storage.size();
65061da546Spatrick   }
66061da546Spatrick 
GetIVarAtIndex(size_t idx)67061da546Spatrick   iVarDescriptor GetIVarAtIndex(size_t idx) override {
68061da546Spatrick     if (idx >= GetNumIVars())
69061da546Spatrick       return iVarDescriptor();
70061da546Spatrick     return m_ivars_storage[idx];
71061da546Spatrick   }
72061da546Spatrick 
73061da546Spatrick protected:
74061da546Spatrick   void GetIVarInformation();
75061da546Spatrick 
76061da546Spatrick private:
77061da546Spatrick   static const uint32_t RW_REALIZED = (1 << 31);
78061da546Spatrick 
79061da546Spatrick   struct objc_class_t {
80be691f3bSpatrick     ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass.
81be691f3bSpatrick     ObjCLanguageRuntime::ObjCISA m_superclass = 0;
82be691f3bSpatrick     lldb::addr_t m_cache_ptr = 0;
83be691f3bSpatrick     lldb::addr_t m_vtable_ptr = 0;
84be691f3bSpatrick     lldb::addr_t m_data_ptr = 0;
85be691f3bSpatrick     uint8_t m_flags = 0;
86061da546Spatrick 
87be691f3bSpatrick     objc_class_t() = default;
88061da546Spatrick 
Clearobjc_class_t89061da546Spatrick     void Clear() {
90061da546Spatrick       m_isa = 0;
91061da546Spatrick       m_superclass = 0;
92061da546Spatrick       m_cache_ptr = 0;
93061da546Spatrick       m_vtable_ptr = 0;
94061da546Spatrick       m_data_ptr = 0;
95061da546Spatrick       m_flags = 0;
96061da546Spatrick     }
97061da546Spatrick 
98061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
99061da546Spatrick   };
100061da546Spatrick 
101061da546Spatrick   struct class_ro_t {
102061da546Spatrick     uint32_t m_flags;
103061da546Spatrick     uint32_t m_instanceStart;
104061da546Spatrick     uint32_t m_instanceSize;
105061da546Spatrick     uint32_t m_reserved;
106061da546Spatrick 
107061da546Spatrick     lldb::addr_t m_ivarLayout_ptr;
108061da546Spatrick     lldb::addr_t m_name_ptr;
109061da546Spatrick     lldb::addr_t m_baseMethods_ptr;
110061da546Spatrick     lldb::addr_t m_baseProtocols_ptr;
111061da546Spatrick     lldb::addr_t m_ivars_ptr;
112061da546Spatrick 
113061da546Spatrick     lldb::addr_t m_weakIvarLayout_ptr;
114061da546Spatrick     lldb::addr_t m_baseProperties_ptr;
115061da546Spatrick 
116061da546Spatrick     std::string m_name;
117061da546Spatrick 
118061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
119061da546Spatrick   };
120061da546Spatrick 
121061da546Spatrick   struct class_rw_t {
122061da546Spatrick     uint32_t m_flags;
123061da546Spatrick     uint32_t m_version;
124061da546Spatrick 
125061da546Spatrick     lldb::addr_t m_ro_ptr;
126061da546Spatrick     union {
127061da546Spatrick       lldb::addr_t m_method_list_ptr;
128061da546Spatrick       lldb::addr_t m_method_lists_ptr;
129061da546Spatrick     };
130061da546Spatrick     lldb::addr_t m_properties_ptr;
131061da546Spatrick     lldb::addr_t m_protocols_ptr;
132061da546Spatrick 
133061da546Spatrick     ObjCLanguageRuntime::ObjCISA m_firstSubclass;
134061da546Spatrick     ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
135061da546Spatrick 
136061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
137061da546Spatrick   };
138061da546Spatrick 
139061da546Spatrick   struct method_list_t {
140dda28197Spatrick     uint16_t m_entsize;
141dda28197Spatrick     bool m_is_small;
142dda28197Spatrick     bool m_has_direct_selector;
143061da546Spatrick     uint32_t m_count;
144061da546Spatrick     lldb::addr_t m_first_ptr;
145061da546Spatrick 
146061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
147061da546Spatrick   };
148061da546Spatrick 
149061da546Spatrick   struct method_t {
150061da546Spatrick     lldb::addr_t m_name_ptr;
151061da546Spatrick     lldb::addr_t m_types_ptr;
152061da546Spatrick     lldb::addr_t m_imp_ptr;
153061da546Spatrick 
154061da546Spatrick     std::string m_name;
155061da546Spatrick     std::string m_types;
156061da546Spatrick 
GetSizemethod_t157dda28197Spatrick     static size_t GetSize(Process *process, bool is_small) {
158dda28197Spatrick       size_t field_size;
159dda28197Spatrick       if (is_small)
160dda28197Spatrick         field_size = 4; // uint32_t relative indirect fields
161dda28197Spatrick       else
162dda28197Spatrick         field_size = process->GetAddressByteSize();
163061da546Spatrick 
164dda28197Spatrick       return field_size    // SEL name;
165dda28197Spatrick              + field_size  // const char *types;
166dda28197Spatrick              + field_size; // IMP imp;
167061da546Spatrick     }
168061da546Spatrick 
169be691f3bSpatrick     bool Read(Process *process, lldb::addr_t addr,
170be691f3bSpatrick               lldb::addr_t relative_method_lists_base_addr, bool, bool);
171061da546Spatrick   };
172061da546Spatrick 
173061da546Spatrick   struct ivar_list_t {
174061da546Spatrick     uint32_t m_entsize;
175061da546Spatrick     uint32_t m_count;
176061da546Spatrick     lldb::addr_t m_first_ptr;
177061da546Spatrick 
178061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
179061da546Spatrick   };
180061da546Spatrick 
181061da546Spatrick   struct ivar_t {
182061da546Spatrick     lldb::addr_t m_offset_ptr;
183061da546Spatrick     lldb::addr_t m_name_ptr;
184061da546Spatrick     lldb::addr_t m_type_ptr;
185061da546Spatrick     uint32_t m_alignment;
186061da546Spatrick     uint32_t m_size;
187061da546Spatrick 
188061da546Spatrick     std::string m_name;
189061da546Spatrick     std::string m_type;
190061da546Spatrick 
GetSizeivar_t191061da546Spatrick     static size_t GetSize(Process *process) {
192061da546Spatrick       size_t ptr_size = process->GetAddressByteSize();
193061da546Spatrick 
194061da546Spatrick       return ptr_size            // uintptr_t *offset;
195061da546Spatrick              + ptr_size          // const char *name;
196061da546Spatrick              + ptr_size          // const char *type;
197061da546Spatrick              + sizeof(uint32_t)  // uint32_t alignment;
198061da546Spatrick              + sizeof(uint32_t); // uint32_t size;
199061da546Spatrick     }
200061da546Spatrick 
201061da546Spatrick     bool Read(Process *process, lldb::addr_t addr);
202061da546Spatrick   };
203061da546Spatrick 
204061da546Spatrick   class iVarsStorage {
205061da546Spatrick   public:
206061da546Spatrick     iVarsStorage();
207061da546Spatrick 
208061da546Spatrick     size_t size();
209061da546Spatrick 
210061da546Spatrick     iVarDescriptor &operator[](size_t idx);
211061da546Spatrick 
212061da546Spatrick     void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
213061da546Spatrick 
214061da546Spatrick   private:
215be691f3bSpatrick     bool m_filled = false;
216061da546Spatrick     std::vector<iVarDescriptor> m_ivars;
217061da546Spatrick     std::recursive_mutex m_mutex;
218061da546Spatrick   };
219061da546Spatrick 
220061da546Spatrick   // The constructor should only be invoked by the runtime as it builds its
221061da546Spatrick   // caches
222061da546Spatrick   // or populates them.  A ClassDescriptorV2 should only ever exist in a cache.
ClassDescriptorV2(AppleObjCRuntimeV2 & runtime,ObjCLanguageRuntime::ObjCISA isa,const char * name)223061da546Spatrick   ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
224061da546Spatrick                     ObjCLanguageRuntime::ObjCISA isa, const char *name)
225061da546Spatrick       : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
226061da546Spatrick         m_ivars_storage() {}
227061da546Spatrick 
228061da546Spatrick   bool Read_objc_class(Process *process,
229061da546Spatrick                        std::unique_ptr<objc_class_t> &objc_class) const;
230061da546Spatrick 
231061da546Spatrick   bool Read_class_row(Process *process, const objc_class_t &objc_class,
232061da546Spatrick                       std::unique_ptr<class_ro_t> &class_ro,
233061da546Spatrick                       std::unique_ptr<class_rw_t> &class_rw) const;
234061da546Spatrick 
235061da546Spatrick   AppleObjCRuntimeV2
236061da546Spatrick       &m_runtime; // The runtime, so we can read information lazily.
237061da546Spatrick   lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t.  (I.e.,
238061da546Spatrick                                  // objects of this class type have this as
239061da546Spatrick                                  // their ISA)
240061da546Spatrick   ConstString m_name;            // May be NULL
241061da546Spatrick   iVarsStorage m_ivars_storage;
242061da546Spatrick };
243061da546Spatrick 
244061da546Spatrick // tagged pointer descriptor
245061da546Spatrick class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
246061da546Spatrick public:
ClassDescriptorV2Tagged(ConstString class_name,uint64_t payload)247061da546Spatrick   ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
248061da546Spatrick     m_name = class_name;
249061da546Spatrick     if (!m_name) {
250061da546Spatrick       m_valid = false;
251061da546Spatrick       return;
252061da546Spatrick     }
253061da546Spatrick     m_valid = true;
254061da546Spatrick     m_payload = payload;
255061da546Spatrick     m_info_bits = (m_payload & 0xF0ULL) >> 4;
256061da546Spatrick     m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
257061da546Spatrick   }
258061da546Spatrick 
ClassDescriptorV2Tagged(ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,uint64_t u_payload,int64_t s_payload)259061da546Spatrick   ClassDescriptorV2Tagged(
260061da546Spatrick       ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
261be691f3bSpatrick       uint64_t u_payload, int64_t s_payload) {
262061da546Spatrick     if (!actual_class_sp) {
263061da546Spatrick       m_valid = false;
264061da546Spatrick       return;
265061da546Spatrick     }
266061da546Spatrick     m_name = actual_class_sp->GetClassName();
267061da546Spatrick     if (!m_name) {
268061da546Spatrick       m_valid = false;
269061da546Spatrick       return;
270061da546Spatrick     }
271061da546Spatrick     m_valid = true;
272be691f3bSpatrick     m_payload = u_payload;
273061da546Spatrick     m_info_bits = (m_payload & 0x0FULL);
274061da546Spatrick     m_value_bits = (m_payload & ~0x0FULL) >> 4;
275be691f3bSpatrick     m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
276061da546Spatrick   }
277061da546Spatrick 
278061da546Spatrick   ~ClassDescriptorV2Tagged() override = default;
279061da546Spatrick 
GetClassName()280061da546Spatrick   ConstString GetClassName() override { return m_name; }
281061da546Spatrick 
GetSuperclass()282061da546Spatrick   ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override {
283061da546Spatrick     // tagged pointers can represent a class that has a superclass, but since
284061da546Spatrick     // that information is not
285061da546Spatrick     // stored in the object itself, we would have to query the runtime to
286061da546Spatrick     // discover the hierarchy
287061da546Spatrick     // for the time being, we skip this step in the interest of static discovery
288061da546Spatrick     return ObjCLanguageRuntime::ClassDescriptorSP();
289061da546Spatrick   }
290061da546Spatrick 
GetMetaclass()291061da546Spatrick   ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override {
292061da546Spatrick     return ObjCLanguageRuntime::ClassDescriptorSP();
293061da546Spatrick   }
294061da546Spatrick 
IsValid()295061da546Spatrick   bool IsValid() override { return m_valid; }
296061da546Spatrick 
IsKVO()297061da546Spatrick   bool IsKVO() override {
298061da546Spatrick     return false; // tagged pointers are not KVO'ed
299061da546Spatrick   }
300061da546Spatrick 
IsCFType()301061da546Spatrick   bool IsCFType() override {
302061da546Spatrick     return false; // tagged pointers are not CF objects
303061da546Spatrick   }
304061da546Spatrick 
305061da546Spatrick   bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
306061da546Spatrick                             uint64_t *value_bits = nullptr,
307061da546Spatrick                             uint64_t *payload = nullptr) override {
308061da546Spatrick     if (info_bits)
309061da546Spatrick       *info_bits = GetInfoBits();
310061da546Spatrick     if (value_bits)
311061da546Spatrick       *value_bits = GetValueBits();
312061da546Spatrick     if (payload)
313061da546Spatrick       *payload = GetPayload();
314061da546Spatrick     return true;
315061da546Spatrick   }
316061da546Spatrick 
317be691f3bSpatrick   bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
318be691f3bSpatrick                                   int64_t *value_bits = nullptr,
319be691f3bSpatrick                                   uint64_t *payload = nullptr) override {
320be691f3bSpatrick     if (info_bits)
321be691f3bSpatrick       *info_bits = GetInfoBits();
322be691f3bSpatrick     if (value_bits)
323be691f3bSpatrick       *value_bits = GetValueBitsSigned();
324be691f3bSpatrick     if (payload)
325be691f3bSpatrick       *payload = GetPayload();
326be691f3bSpatrick     return true;
327be691f3bSpatrick   }
328be691f3bSpatrick 
GetInstanceSize()329061da546Spatrick   uint64_t GetInstanceSize() override {
330061da546Spatrick     return (IsValid() ? m_pointer_size : 0);
331061da546Spatrick   }
332061da546Spatrick 
GetISA()333061da546Spatrick   ObjCLanguageRuntime::ObjCISA GetISA() override {
334061da546Spatrick     return 0; // tagged pointers have no ISA
335061da546Spatrick   }
336061da546Spatrick 
337061da546Spatrick   // these calls are not part of any formal tagged pointers specification
GetValueBits()338061da546Spatrick   virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
339061da546Spatrick 
GetValueBitsSigned()340be691f3bSpatrick   virtual int64_t GetValueBitsSigned() {
341be691f3bSpatrick     return (IsValid() ? m_value_bits_signed : 0);
342be691f3bSpatrick   }
343be691f3bSpatrick 
GetInfoBits()344061da546Spatrick   virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
345061da546Spatrick 
GetPayload()346061da546Spatrick   virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
347061da546Spatrick 
348061da546Spatrick private:
349061da546Spatrick   ConstString m_name;
350*f6aab3d8Srobert   uint8_t m_pointer_size = 0;
351*f6aab3d8Srobert   bool m_valid = false;
352*f6aab3d8Srobert   uint64_t m_info_bits = 0;
353*f6aab3d8Srobert   uint64_t m_value_bits = 0;
354*f6aab3d8Srobert   int64_t m_value_bits_signed = 0;
355*f6aab3d8Srobert   uint64_t m_payload = 0;
356061da546Spatrick };
357061da546Spatrick 
358061da546Spatrick } // namespace lldb_private
359061da546Spatrick 
360dda28197Spatrick #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
361