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" 15 #include "lldb/lldb-enumerations.h" 16 #include "lldb/lldb-private.h" 17 18 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" 19 20 namespace lldb_private { 21 22 class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor { 23 public: 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 valid 36 } 37 38 lldb::LanguageType GetImplementationLanguage() const override; 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 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 *)> 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 { 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 76 protected: 77 void GetIVarInformation(); 78 79 private: 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 uint32_t m_count; 147 lldb::addr_t m_first_ptr; 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 { 156 lldb::addr_t m_name_ptr; 157 lldb::addr_t m_types_ptr; 158 lldb::addr_t m_imp_ptr; 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; 183 lldb::addr_t m_first_ptr; 184 185 bool Read(Process *process, lldb::addr_t addr); 186 }; 187 188 struct ivar_t { 189 lldb::addr_t m_offset_ptr; 190 lldb::addr_t m_name_ptr; 191 lldb::addr_t m_type_ptr; 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 211 struct relative_list_entry_t { 212 uint16_t m_image_index; 213 int64_t m_list_offset; 214 215 bool Read(Process *process, lldb::addr_t addr); 216 }; 217 218 struct relative_list_list_t { 219 uint32_t m_entsize; 220 uint32_t m_count; 221 lldb::addr_t m_first_ptr; 222 223 bool Read(Process *process, lldb::addr_t addr); 224 }; 225 226 class iVarsStorage { 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. 245 ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, 246 ObjCLanguageRuntime::ObjCISA isa, const char *name) 247 : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name), 248 m_ivars_storage(), m_image_to_method_lists(), m_last_version_updated() { 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 262 bool ProcessRelativeMethodLists( 263 std::function<bool(const char *, const char *)> const 264 &instance_method_func, 265 lldb::addr_t relative_method_list_ptr) const; 266 267 AppleObjCRuntimeV2 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 273 iVarsStorage m_ivars_storage; 274 275 mutable std::map<uint16_t, std::vector<method_list_t>> 276 m_image_to_method_lists; 277 mutable std::optional<uint64_t> m_last_version_updated; 278 }; 279 280 // tagged pointer descriptor 281 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor { 282 public: 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 295 ClassDescriptorV2Tagged( 296 ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, 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 318 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override { 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 324 return ObjCLanguageRuntime::ClassDescriptorSP(); 325 } 326 327 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override { 328 return ObjCLanguageRuntime::ClassDescriptorSP(); 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 369 ObjCLanguageRuntime::ObjCISA GetISA() override { 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 384 private: 385 ConstString m_name; 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; 390 int64_t m_value_bits_signed = 0; 391 uint64_t m_payload = 0; 392 }; 393 394 } // namespace lldb_private 395 396 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H 397