403 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H10#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H11 12#include <mutex>13 14#include "AppleObjCRuntimeV2.h"15#include "lldb/lldb-enumerations.h"16#include "lldb/lldb-private.h"17 18#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"19 20namespace lldb_private {21 22class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {23public:24 friend class lldb_private::AppleObjCRuntimeV2;25 26 ~ClassDescriptorV2() override = default;27 28 ConstString GetClassName() override;29 30 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override;31 32 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override;33 34 bool IsValid() override {35 return true; // any Objective-C v2 runtime class descriptor we vend is valid36 }37 38 lldb::LanguageType GetImplementationLanguage() const override;39 40 // a custom descriptor is used for tagged pointers41 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 55 ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }56 57 bool Describe(58 std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,59 std::function<bool(const char *, const char *)> const60 &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 {66 GetIVarInformation();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.84 ObjCLanguageRuntime::ObjCISA m_superclass = 0;85 lldb::addr_t m_cache_ptr = 0;86 lldb::addr_t m_vtable_ptr = 0;87 lldb::addr_t m_data_ptr = 0;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;106 uint32_t m_instanceStart;107 uint32_t m_instanceSize;108 uint32_t m_reserved;109 110 lldb::addr_t m_ivarLayout_ptr;111 lldb::addr_t m_name_ptr;112 lldb::addr_t m_baseMethods_ptr;113 lldb::addr_t m_baseProtocols_ptr;114 lldb::addr_t m_ivars_ptr;115 116 lldb::addr_t m_weakIvarLayout_ptr;117 lldb::addr_t m_baseProperties_ptr;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 128 lldb::addr_t m_ro_ptr;129 union {130 lldb::addr_t m_method_list_ptr;131 lldb::addr_t m_method_lists_ptr;132 };133 lldb::addr_t m_properties_ptr;134 lldb::addr_t m_protocols_ptr;135 136 ObjCLanguageRuntime::ObjCISA m_firstSubclass;137 ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;138 139 bool Read(Process *process, lldb::addr_t addr);140 };141 142 struct method_list_t {143 uint16_t m_entsize;144 bool m_is_small;145 bool m_has_direct_selector;146 bool m_has_relative_types;147 uint32_t m_count;148 lldb::addr_t m_first_ptr;149 150 bool Read(Process *process, lldb::addr_t addr);151 };152 153 std::optional<method_list_t>154 GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;155 156 struct method_t {157 lldb::addr_t m_name_ptr;158 lldb::addr_t m_types_ptr;159 lldb::addr_t m_imp_ptr;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 fields168 else169 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;189 lldb::addr_t m_first_ptr;190 191 bool Read(Process *process, lldb::addr_t addr);192 };193 194 struct ivar_t {195 lldb::addr_t m_offset_ptr;196 lldb::addr_t m_name_ptr;197 lldb::addr_t m_type_ptr;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 217 struct relative_list_entry_t {218 uint16_t m_image_index;219 int64_t m_list_offset;220 221 bool Read(Process *process, lldb::addr_t addr);222 };223 224 struct relative_list_list_t {225 uint32_t m_entsize;226 uint32_t m_count;227 lldb::addr_t m_first_ptr;228 229 bool Read(Process *process, lldb::addr_t addr);230 };231 232 class iVarsStorage {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 its249 // caches250 // or populates them. A ClassDescriptorV2 should only ever exist in a cache.251 ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,252 ObjCLanguageRuntime::ObjCISA isa, const char *name)253 : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),254 m_ivars_storage(), m_image_to_method_lists(), m_last_version_updated() {255 }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 *)> const265 &instance_method_func,266 method_list_t &method_list) const;267 268 bool ProcessRelativeMethodLists(269 std::function<bool(const char *, const char *)> const270 &instance_method_func,271 lldb::addr_t relative_method_list_ptr) const;272 273 AppleObjCRuntimeV2274 &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 as277 // their ISA)278 ConstString m_name; // May be NULL279 iVarsStorage m_ivars_storage;280 281 mutable std::map<uint16_t, std::vector<method_list_t>>282 m_image_to_method_lists;283 mutable std::optional<uint64_t> m_last_version_updated;284};285 286// tagged pointer descriptor287class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {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 301 ClassDescriptorV2Tagged(302 ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,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 324 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override {325 // tagged pointers can represent a class that has a superclass, but since326 // that information is not327 // stored in the object itself, we would have to query the runtime to328 // discover the hierarchy329 // for the time being, we skip this step in the interest of static discovery330 return ObjCLanguageRuntime::ClassDescriptorSP();331 }332 333 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override {334 return ObjCLanguageRuntime::ClassDescriptorSP();335 }336 337 bool IsValid() override { return m_valid; }338 339 bool IsKVO() override {340 return false; // tagged pointers are not KVO'ed341 }342 343 bool IsCFType() override {344 return false; // tagged pointers are not CF objects345 }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 375 ObjCLanguageRuntime::ObjCISA GetISA() override {376 return 0; // tagged pointers have no ISA377 }378 379 // these calls are not part of any formal tagged pointers specification380 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:391 ConstString m_name;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;396 int64_t m_value_bits_signed = 0;397 uint64_t m_payload = 0;398};399 400} // namespace lldb_private401 402#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H403