LLDB mainline
AppleObjCClassDescriptorV2.h
Go to the documentation of this file.
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"
16#include "lldb/lldb-private.h"
17
19
20namespace lldb_private {
21
23public:
25
26 ~ClassDescriptorV2() override = default;
27
28 ConstString GetClassName() override;
29
31
33
34 bool IsValid() override {
35 return true; // any Objective-C v2 runtime class descriptor we vend is valid
36 }
37
39
40 // a custom descriptor is used for tagged pointers
41 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
42 uint64_t *value_bits = nullptr,
43 uint64_t *payload = nullptr) override {
44 return false;
45 }
46
47 bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
48 int64_t *value_bits = nullptr,
49 uint64_t *payload = nullptr) override {
50 return false;
51 }
52
53 uint64_t GetInstanceSize() override;
54
56
57 bool Describe(
58 std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
59 std::function<bool(const char *, const char *)> const
60 &instance_method_func,
61 std::function<bool(const char *, const char *)> const &class_method_func,
62 std::function<bool(const char *, const char *, lldb::addr_t,
63 uint64_t)> const &ivar_func) const override;
64
65 size_t GetNumIVars() override {
67 return m_ivars_storage.size();
68 }
69
70 iVarDescriptor GetIVarAtIndex(size_t idx) override {
71 if (idx >= GetNumIVars())
72 return iVarDescriptor();
73 return m_ivars_storage[idx];
74 }
75
76protected:
77 void GetIVarInformation();
78
79private:
80 static const uint32_t RW_REALIZED = (1u << 31);
81
82 struct objc_class_t {
83 ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass.
88 uint8_t m_flags = 0;
89
90 objc_class_t() = default;
91
92 void Clear() {
93 m_isa = 0;
94 m_superclass = 0;
95 m_cache_ptr = 0;
96 m_vtable_ptr = 0;
97 m_data_ptr = 0;
98 m_flags = 0;
99 }
100
101 bool Read(Process *process, lldb::addr_t addr);
102 };
103
104 struct class_ro_t {
105 uint32_t m_flags;
108 uint32_t m_reserved;
109
115
118
119 std::string m_name;
120
121 bool Read(Process *process, lldb::addr_t addr);
122 };
123
124 struct class_rw_t {
125 uint32_t m_flags;
126 uint32_t m_version;
127
129 union {
132 };
135
138
139 bool Read(Process *process, lldb::addr_t addr);
140 };
141
143 uint16_t m_entsize;
146 uint32_t m_count;
148
149 bool Read(Process *process, lldb::addr_t addr);
150 };
151
152 std::optional<method_list_t>
153 GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;
154
155 struct method_t {
159
160 std::string m_name;
161 std::string m_types;
162
163 static size_t GetSize(Process *process, bool is_small) {
164 size_t field_size;
165 if (is_small)
166 field_size = 4; // uint32_t relative indirect fields
167 else
168 field_size = process->GetAddressByteSize();
169
170 return field_size // SEL name;
171 + field_size // const char *types;
172 + field_size; // IMP imp;
173 }
174
175 bool Read(Process *process, lldb::addr_t addr,
176 lldb::addr_t relative_selector_base_addr, bool is_small,
177 bool has_direct_sel);
178 };
179
180 struct ivar_list_t {
181 uint32_t m_entsize;
182 uint32_t m_count;
184
185 bool Read(Process *process, lldb::addr_t addr);
186 };
187
188 struct ivar_t {
192 uint32_t m_alignment;
193 uint32_t m_size;
194
195 std::string m_name;
196 std::string m_type;
197
198 static size_t GetSize(Process *process) {
199 size_t ptr_size = process->GetAddressByteSize();
200
201 return ptr_size // uintptr_t *offset;
202 + ptr_size // const char *name;
203 + ptr_size // const char *type;
204 + sizeof(uint32_t) // uint32_t alignment;
205 + sizeof(uint32_t); // uint32_t size;
206 }
207
208 bool Read(Process *process, lldb::addr_t addr);
209 };
210
214
215 bool Read(Process *process, lldb::addr_t addr);
216 };
217
219 uint32_t m_entsize;
220 uint32_t m_count;
222
223 bool Read(Process *process, lldb::addr_t addr);
224 };
225
227 public:
228 iVarsStorage();
229
230 size_t size();
231
232 iVarDescriptor &operator[](size_t idx);
233
234 void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
235
236 private:
237 bool m_filled = false;
238 std::vector<iVarDescriptor> m_ivars;
239 std::recursive_mutex m_mutex;
240 };
241
242 // The constructor should only be invoked by the runtime as it builds its
243 // caches
244 // or populates them. A ClassDescriptorV2 should only ever exist in a cache.
246 ObjCLanguageRuntime::ObjCISA isa, const char *name)
247 : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
249 }
250
251 bool Read_objc_class(Process *process,
252 std::unique_ptr<objc_class_t> &objc_class) const;
253
254 bool Read_class_row(Process *process, const objc_class_t &objc_class,
255 std::unique_ptr<class_ro_t> &class_ro,
256 std::unique_ptr<class_rw_t> &class_rw) const;
257
258 bool ProcessMethodList(std::function<bool(const char *, const char *)> const
259 &instance_method_func,
260 method_list_t &method_list) const;
261
263 std::function<bool(const char *, const char *)> const
264 &instance_method_func,
265 lldb::addr_t relative_method_list_ptr) const;
266
268 &m_runtime; // The runtime, so we can read information lazily.
269 lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e.,
270 // objects of this class type have this as
271 // their ISA)
272 ConstString m_name; // May be NULL
274
275 mutable std::map<uint16_t, std::vector<method_list_t>>
277 mutable std::optional<uint64_t> m_last_version_updated;
278};
279
280// tagged pointer descriptor
282public:
283 ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
284 m_name = class_name;
285 if (!m_name) {
286 m_valid = false;
287 return;
288 }
289 m_valid = true;
290 m_payload = payload;
291 m_info_bits = (m_payload & 0xF0ULL) >> 4;
292 m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
293 }
294
297 uint64_t u_payload, int64_t s_payload) {
298 if (!actual_class_sp) {
299 m_valid = false;
300 return;
301 }
302 m_name = actual_class_sp->GetClassName();
303 if (!m_name) {
304 m_valid = false;
305 return;
306 }
307 m_valid = true;
308 m_payload = u_payload;
309 m_info_bits = (m_payload & 0x0FULL);
310 m_value_bits = (m_payload & ~0x0FULL) >> 4;
311 m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
312 }
313
314 ~ClassDescriptorV2Tagged() override = default;
315
316 ConstString GetClassName() override { return m_name; }
317
319 // tagged pointers can represent a class that has a superclass, but since
320 // that information is not
321 // stored in the object itself, we would have to query the runtime to
322 // discover the hierarchy
323 // for the time being, we skip this step in the interest of static discovery
325 }
326
329 }
330
331 bool IsValid() override { return m_valid; }
332
333 bool IsKVO() override {
334 return false; // tagged pointers are not KVO'ed
335 }
336
337 bool IsCFType() override {
338 return false; // tagged pointers are not CF objects
339 }
340
341 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
342 uint64_t *value_bits = nullptr,
343 uint64_t *payload = nullptr) override {
344 if (info_bits)
345 *info_bits = GetInfoBits();
346 if (value_bits)
347 *value_bits = GetValueBits();
348 if (payload)
349 *payload = GetPayload();
350 return true;
351 }
352
353 bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
354 int64_t *value_bits = nullptr,
355 uint64_t *payload = nullptr) override {
356 if (info_bits)
357 *info_bits = GetInfoBits();
358 if (value_bits)
359 *value_bits = GetValueBitsSigned();
360 if (payload)
361 *payload = GetPayload();
362 return true;
363 }
364
365 uint64_t GetInstanceSize() override {
366 return (IsValid() ? m_pointer_size : 0);
367 }
368
370 return 0; // tagged pointers have no ISA
371 }
372
373 // these calls are not part of any formal tagged pointers specification
374 virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
375
376 virtual int64_t GetValueBitsSigned() {
377 return (IsValid() ? m_value_bits_signed : 0);
378 }
379
380 virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
381
382 virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
383
384private:
386 uint8_t m_pointer_size = 0;
387 bool m_valid = false;
388 uint64_t m_info_bits = 0;
389 uint64_t m_value_bits = 0;
391 uint64_t m_payload = 0;
392};
393
394} // namespace lldb_private
395
396#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
bool GetTaggedPointerInfoSigned(uint64_t *info_bits=nullptr, int64_t *value_bits=nullptr, uint64_t *payload=nullptr) override
~ClassDescriptorV2Tagged() override=default
ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override
ObjCLanguageRuntime::ObjCISA GetISA() override
ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload)
bool GetTaggedPointerInfo(uint64_t *info_bits=nullptr, uint64_t *value_bits=nullptr, uint64_t *payload=nullptr) override
There are two routines in the ObjC runtime that tagged pointer clients can call to get the value from...
ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override
ClassDescriptorV2Tagged(ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, uint64_t u_payload, int64_t s_payload)
void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor)
ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override
ObjCLanguageRuntime::ObjCISA GetISA() override
bool Describe(std::function< void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, std::function< bool(const char *, const char *)> const &instance_method_func, std::function< bool(const char *, const char *)> const &class_method_func, std::function< bool(const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const override
bool Read_class_row(Process *process, const objc_class_t &objc_class, std::unique_ptr< class_ro_t > &class_ro, std::unique_ptr< class_rw_t > &class_rw) const
~ClassDescriptorV2() override=default
bool ProcessRelativeMethodLists(std::function< bool(const char *, const char *)> const &instance_method_func, lldb::addr_t relative_method_list_ptr) const
ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name)
bool ProcessMethodList(std::function< bool(const char *, const char *)> const &instance_method_func, method_list_t &method_list) const
bool Read_objc_class(Process *process, std::unique_ptr< objc_class_t > &objc_class) const
iVarDescriptor GetIVarAtIndex(size_t idx) override
bool GetTaggedPointerInfoSigned(uint64_t *info_bits=nullptr, int64_t *value_bits=nullptr, uint64_t *payload=nullptr) override
std::optional< uint64_t > m_last_version_updated
std::map< uint16_t, std::vector< method_list_t > > m_image_to_method_lists
ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override
bool GetTaggedPointerInfo(uint64_t *info_bits=nullptr, uint64_t *value_bits=nullptr, uint64_t *payload=nullptr) override
There are two routines in the ObjC runtime that tagged pointer clients can call to get the value from...
lldb::LanguageType GetImplementationLanguage() const override
Determine whether this class is implemented in Swift.
std::optional< method_list_t > GetMethodList(Process *process, lldb::addr_t method_list_ptr) const
A uniqued constant string class.
Definition: ConstString.h:40
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
A plug-in interface definition class for debugging a process.
Definition: Process.h:341
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3600
A class that represents a running process on the host machine.
LanguageType
Programming language type.
uint64_t addr_t
Definition: lldb-types.h:80
bool Read(Process *process, lldb::addr_t addr)
bool Read(Process *process, lldb::addr_t addr)
bool Read(Process *process, lldb::addr_t addr)
bool Read(Process *process, lldb::addr_t addr)
bool Read(Process *process, lldb::addr_t addr)
bool Read(Process *process, lldb::addr_t addr, lldb::addr_t relative_selector_base_addr, bool is_small, bool has_direct_sel)
static size_t GetSize(Process *process, bool is_small)
bool Read(Process *process, lldb::addr_t addr)
uint16_t m_image_index
int64_t m_list_offset
bool Read(Process *process, lldb::addr_t addr)