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