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
123
141
152
153 std::optional<method_list_t>
154 GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;
155
156 struct method_t {
160
161 std::string m_name;
162 std::string m_types;
163
164 static size_t GetSize(Process *process, bool is_small) {
165 size_t field_size;
166 if (is_small)
167 field_size = 4; // uint32_t relative indirect fields
168 else
169 field_size = process->GetAddressByteSize();
170
171 return field_size // SEL name;
172 + field_size // const char *types;
173 + field_size; // IMP imp;
174 }
175
176 bool Read(DataExtractor &extractor, Process *process, lldb::addr_t addr,
177 lldb::addr_t relative_string_base_addr, bool is_small,
178 bool has_direct_sel, bool has_relative_types);
179 };
180
181 llvm::SmallVector<method_t, 0>
182 ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
183 lldb::addr_t relative_string_base_addr, bool is_small,
184 bool has_direct_sel, bool has_relative_types) const;
185
186 struct ivar_list_t {
187 uint32_t m_entsize;
188 uint32_t m_count;
190
191 bool Read(Process *process, lldb::addr_t addr);
192 };
193
194 struct ivar_t {
198 uint32_t m_alignment;
199 uint32_t m_size;
200
201 std::string m_name;
202 std::string m_type;
203
204 static size_t GetSize(Process *process) {
205 size_t ptr_size = process->GetAddressByteSize();
206
207 return ptr_size // uintptr_t *offset;
208 + ptr_size // const char *name;
209 + ptr_size // const char *type;
210 + sizeof(uint32_t) // uint32_t alignment;
211 + sizeof(uint32_t); // uint32_t size;
212 }
213
214 bool Read(Process *process, lldb::addr_t addr);
215 };
216
220
221 bool Read(Process *process, lldb::addr_t addr);
222 };
223
225 uint32_t m_entsize;
226 uint32_t m_count;
228
229 bool Read(Process *process, lldb::addr_t addr);
230 };
231
233 public:
234 iVarsStorage();
235
236 size_t size();
237
238 iVarDescriptor &operator[](size_t idx);
239
240 void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
241
242 private:
243 bool m_filled = false;
244 std::vector<iVarDescriptor> m_ivars;
245 std::recursive_mutex m_mutex;
246 };
247
248 // The constructor should only be invoked by the runtime as it builds its
249 // caches
250 // or populates them. A ClassDescriptorV2 should only ever exist in a cache.
256
257 bool Read_objc_class(Process *process,
258 std::unique_ptr<objc_class_t> &objc_class) const;
259
260 bool Read_class_row(Process *process, const objc_class_t &objc_class,
261 std::unique_ptr<class_ro_t> &class_ro,
262 std::unique_ptr<class_rw_t> &class_rw) const;
263
264 bool ProcessMethodList(std::function<bool(const char *, const char *)> const
265 &instance_method_func,
266 method_list_t &method_list) const;
267
269 std::function<bool(const char *, const char *)> const
270 &instance_method_func,
271 lldb::addr_t relative_method_list_ptr) const;
272
274 &m_runtime; // The runtime, so we can read information lazily.
275 lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e.,
276 // objects of this class type have this as
277 // their ISA)
278 ConstString m_name; // May be NULL
280
281 mutable std::map<uint16_t, std::vector<method_list_t>>
283 mutable std::optional<uint64_t> m_last_version_updated;
284};
285
286// tagged pointer descriptor
288public:
289 ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
290 m_name = class_name;
291 if (!m_name) {
292 m_valid = false;
293 return;
294 }
295 m_valid = true;
296 m_payload = payload;
297 m_info_bits = (m_payload & 0xF0ULL) >> 4;
298 m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
299 }
300
303 uint64_t u_payload, int64_t s_payload) {
304 if (!actual_class_sp) {
305 m_valid = false;
306 return;
307 }
308 m_name = actual_class_sp->GetClassName();
309 if (!m_name) {
310 m_valid = false;
311 return;
312 }
313 m_valid = true;
314 m_payload = u_payload;
315 m_info_bits = (m_payload & 0x0FULL);
316 m_value_bits = (m_payload & ~0x0FULL) >> 4;
317 m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
318 }
319
320 ~ClassDescriptorV2Tagged() override = default;
321
322 ConstString GetClassName() override { return m_name; }
323
325 // tagged pointers can represent a class that has a superclass, but since
326 // that information is not
327 // stored in the object itself, we would have to query the runtime to
328 // discover the hierarchy
329 // for the time being, we skip this step in the interest of static discovery
331 }
332
336
337 bool IsValid() override { return m_valid; }
338
339 bool IsKVO() override {
340 return false; // tagged pointers are not KVO'ed
341 }
342
343 bool IsCFType() override {
344 return false; // tagged pointers are not CF objects
345 }
346
347 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
348 uint64_t *value_bits = nullptr,
349 uint64_t *payload = nullptr) override {
350 if (info_bits)
351 *info_bits = GetInfoBits();
352 if (value_bits)
353 *value_bits = GetValueBits();
354 if (payload)
355 *payload = GetPayload();
356 return true;
357 }
358
359 bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
360 int64_t *value_bits = nullptr,
361 uint64_t *payload = nullptr) override {
362 if (info_bits)
363 *info_bits = GetInfoBits();
364 if (value_bits)
365 *value_bits = GetValueBitsSigned();
366 if (payload)
367 *payload = GetPayload();
368 return true;
369 }
370
371 uint64_t GetInstanceSize() override {
372 return (IsValid() ? m_pointer_size : 0);
373 }
374
376 return 0; // tagged pointers have no ISA
377 }
378
379 // these calls are not part of any formal tagged pointers specification
380 virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
381
382 virtual int64_t GetValueBitsSigned() {
383 return (IsValid() ? m_value_bits_signed : 0);
384 }
385
386 virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
387
388 virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
389
390private:
392 uint8_t m_pointer_size = 0;
393 bool m_valid = false;
394 uint64_t m_info_bits = 0;
395 uint64_t m_value_bits = 0;
397 uint64_t m_payload = 0;
398};
399
400} // namespace lldb_private
401
402#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
llvm::SmallVector< method_t, 0 > ReadMethods(llvm::ArrayRef< lldb::addr_t > addresses, lldb::addr_t relative_string_base_addr, bool is_small, bool has_direct_sel, bool has_relative_types) const
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
friend class lldb_private::AppleObjCRuntimeV2
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
An data extractor class.
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
A plug-in interface definition class for debugging a process.
Definition Process.h:357
uint32_t GetAddressByteSize() const
Definition Process.cpp:3663
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)
static size_t GetSize(Process *process, bool is_small)
bool Read(DataExtractor &extractor, Process *process, lldb::addr_t addr, lldb::addr_t relative_string_base_addr, bool is_small, bool has_direct_sel, bool has_relative_types)
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)