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 liblldb_AppleObjCClassDescriptorV2_h_ 10 #define liblldb_AppleObjCClassDescriptorV2_h_ 11 12 #include <mutex> 13 14 #include "AppleObjCRuntimeV2.h" 15 #include "lldb/lldb-private.h" 16 17 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" 18 19 namespace lldb_private { 20 21 class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor { 22 public: 23 friend class lldb_private::AppleObjCRuntimeV2; 24 25 ~ClassDescriptorV2() override = default; 26 27 ConstString GetClassName() override; 28 29 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override; 30 31 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override; 32 33 bool IsValid() override { 34 return true; // any Objective-C v2 runtime class descriptor we vend is valid 35 } 36 37 // a custom descriptor is used for tagged pointers 38 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 39 uint64_t *value_bits = nullptr, 40 uint64_t *payload = nullptr) override { 41 return false; 42 } 43 44 uint64_t GetInstanceSize() override; 45 46 ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; } 47 48 bool Describe( 49 std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, 50 std::function<bool(const char *, const char *)> const 51 &instance_method_func, 52 std::function<bool(const char *, const char *)> const &class_method_func, 53 std::function<bool(const char *, const char *, lldb::addr_t, 54 uint64_t)> const &ivar_func) const override; 55 56 size_t GetNumIVars() override { 57 GetIVarInformation(); 58 return m_ivars_storage.size(); 59 } 60 61 iVarDescriptor GetIVarAtIndex(size_t idx) override { 62 if (idx >= GetNumIVars()) 63 return iVarDescriptor(); 64 return m_ivars_storage[idx]; 65 } 66 67 protected: 68 void GetIVarInformation(); 69 70 private: 71 static const uint32_t RW_REALIZED = (1 << 31); 72 73 struct objc_class_t { 74 ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. 75 ObjCLanguageRuntime::ObjCISA m_superclass; 76 lldb::addr_t m_cache_ptr; 77 lldb::addr_t m_vtable_ptr; 78 lldb::addr_t m_data_ptr; 79 uint8_t m_flags; 80 81 objc_class_t() 82 : m_isa(0), m_superclass(0), m_cache_ptr(0), m_vtable_ptr(0), 83 m_data_ptr(0), m_flags(0) {} 84 85 void Clear() { 86 m_isa = 0; 87 m_superclass = 0; 88 m_cache_ptr = 0; 89 m_vtable_ptr = 0; 90 m_data_ptr = 0; 91 m_flags = 0; 92 } 93 94 bool Read(Process *process, lldb::addr_t addr); 95 }; 96 97 struct class_ro_t { 98 uint32_t m_flags; 99 uint32_t m_instanceStart; 100 uint32_t m_instanceSize; 101 uint32_t m_reserved; 102 103 lldb::addr_t m_ivarLayout_ptr; 104 lldb::addr_t m_name_ptr; 105 lldb::addr_t m_baseMethods_ptr; 106 lldb::addr_t m_baseProtocols_ptr; 107 lldb::addr_t m_ivars_ptr; 108 109 lldb::addr_t m_weakIvarLayout_ptr; 110 lldb::addr_t m_baseProperties_ptr; 111 112 std::string m_name; 113 114 bool Read(Process *process, lldb::addr_t addr); 115 }; 116 117 struct class_rw_t { 118 uint32_t m_flags; 119 uint32_t m_version; 120 121 lldb::addr_t m_ro_ptr; 122 union { 123 lldb::addr_t m_method_list_ptr; 124 lldb::addr_t m_method_lists_ptr; 125 }; 126 lldb::addr_t m_properties_ptr; 127 lldb::addr_t m_protocols_ptr; 128 129 ObjCLanguageRuntime::ObjCISA m_firstSubclass; 130 ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; 131 132 bool Read(Process *process, lldb::addr_t addr); 133 }; 134 135 struct method_list_t { 136 uint32_t m_entsize; 137 uint32_t m_count; 138 lldb::addr_t m_first_ptr; 139 140 bool Read(Process *process, lldb::addr_t addr); 141 }; 142 143 struct method_t { 144 lldb::addr_t m_name_ptr; 145 lldb::addr_t m_types_ptr; 146 lldb::addr_t m_imp_ptr; 147 148 std::string m_name; 149 std::string m_types; 150 151 static size_t GetSize(Process *process) { 152 size_t ptr_size = process->GetAddressByteSize(); 153 154 return ptr_size // SEL name; 155 + ptr_size // const char *types; 156 + ptr_size; // IMP imp; 157 } 158 159 bool Read(Process *process, lldb::addr_t addr); 160 }; 161 162 struct ivar_list_t { 163 uint32_t m_entsize; 164 uint32_t m_count; 165 lldb::addr_t m_first_ptr; 166 167 bool Read(Process *process, lldb::addr_t addr); 168 }; 169 170 struct ivar_t { 171 lldb::addr_t m_offset_ptr; 172 lldb::addr_t m_name_ptr; 173 lldb::addr_t m_type_ptr; 174 uint32_t m_alignment; 175 uint32_t m_size; 176 177 std::string m_name; 178 std::string m_type; 179 180 static size_t GetSize(Process *process) { 181 size_t ptr_size = process->GetAddressByteSize(); 182 183 return ptr_size // uintptr_t *offset; 184 + ptr_size // const char *name; 185 + ptr_size // const char *type; 186 + sizeof(uint32_t) // uint32_t alignment; 187 + sizeof(uint32_t); // uint32_t size; 188 } 189 190 bool Read(Process *process, lldb::addr_t addr); 191 }; 192 193 class iVarsStorage { 194 public: 195 iVarsStorage(); 196 197 size_t size(); 198 199 iVarDescriptor &operator[](size_t idx); 200 201 void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor); 202 203 private: 204 bool m_filled; 205 std::vector<iVarDescriptor> m_ivars; 206 std::recursive_mutex m_mutex; 207 }; 208 209 // The constructor should only be invoked by the runtime as it builds its 210 // caches 211 // or populates them. A ClassDescriptorV2 should only ever exist in a cache. 212 ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, 213 ObjCLanguageRuntime::ObjCISA isa, const char *name) 214 : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name), 215 m_ivars_storage() {} 216 217 bool Read_objc_class(Process *process, 218 std::unique_ptr<objc_class_t> &objc_class) const; 219 220 bool Read_class_row(Process *process, const objc_class_t &objc_class, 221 std::unique_ptr<class_ro_t> &class_ro, 222 std::unique_ptr<class_rw_t> &class_rw) const; 223 224 AppleObjCRuntimeV2 225 &m_runtime; // The runtime, so we can read information lazily. 226 lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., 227 // objects of this class type have this as 228 // their ISA) 229 ConstString m_name; // May be NULL 230 iVarsStorage m_ivars_storage; 231 }; 232 233 // tagged pointer descriptor 234 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor { 235 public: 236 ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) { 237 m_name = class_name; 238 if (!m_name) { 239 m_valid = false; 240 return; 241 } 242 m_valid = true; 243 m_payload = payload; 244 m_info_bits = (m_payload & 0xF0ULL) >> 4; 245 m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; 246 } 247 248 ClassDescriptorV2Tagged( 249 ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, 250 uint64_t payload) { 251 if (!actual_class_sp) { 252 m_valid = false; 253 return; 254 } 255 m_name = actual_class_sp->GetClassName(); 256 if (!m_name) { 257 m_valid = false; 258 return; 259 } 260 m_valid = true; 261 m_payload = payload; 262 m_info_bits = (m_payload & 0x0FULL); 263 m_value_bits = (m_payload & ~0x0FULL) >> 4; 264 } 265 266 ~ClassDescriptorV2Tagged() override = default; 267 268 ConstString GetClassName() override { return m_name; } 269 270 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override { 271 // tagged pointers can represent a class that has a superclass, but since 272 // that information is not 273 // stored in the object itself, we would have to query the runtime to 274 // discover the hierarchy 275 // for the time being, we skip this step in the interest of static discovery 276 return ObjCLanguageRuntime::ClassDescriptorSP(); 277 } 278 279 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override { 280 return ObjCLanguageRuntime::ClassDescriptorSP(); 281 } 282 283 bool IsValid() override { return m_valid; } 284 285 bool IsKVO() override { 286 return false; // tagged pointers are not KVO'ed 287 } 288 289 bool IsCFType() override { 290 return false; // tagged pointers are not CF objects 291 } 292 293 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 294 uint64_t *value_bits = nullptr, 295 uint64_t *payload = nullptr) override { 296 if (info_bits) 297 *info_bits = GetInfoBits(); 298 if (value_bits) 299 *value_bits = GetValueBits(); 300 if (payload) 301 *payload = GetPayload(); 302 return true; 303 } 304 305 uint64_t GetInstanceSize() override { 306 return (IsValid() ? m_pointer_size : 0); 307 } 308 309 ObjCLanguageRuntime::ObjCISA GetISA() override { 310 return 0; // tagged pointers have no ISA 311 } 312 313 // these calls are not part of any formal tagged pointers specification 314 virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); } 315 316 virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); } 317 318 virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); } 319 320 private: 321 ConstString m_name; 322 uint8_t m_pointer_size; 323 bool m_valid; 324 uint64_t m_info_bits; 325 uint64_t m_value_bits; 326 uint64_t m_payload; 327 }; 328 329 } // namespace lldb_private 330 331 #endif // liblldb_AppleObjCClassDescriptorV2_h_ 332