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-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 IsValid()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 GetISA()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 GetNumIVars()56 size_t GetNumIVars() override { 57 GetIVarInformation(); 58 return m_ivars_storage.size(); 59 } 60 GetIVarAtIndex(size_t idx)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 objc_class_tobjc_class_t81 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 Clearobjc_class_t85 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 uint16_t m_entsize; 137 bool m_is_small; 138 bool m_has_direct_selector; 139 uint32_t m_count; 140 lldb::addr_t m_first_ptr; 141 142 bool Read(Process *process, lldb::addr_t addr); 143 }; 144 145 struct method_t { 146 lldb::addr_t m_name_ptr; 147 lldb::addr_t m_types_ptr; 148 lldb::addr_t m_imp_ptr; 149 150 std::string m_name; 151 std::string m_types; 152 GetSizemethod_t153 static size_t GetSize(Process *process, bool is_small) { 154 size_t field_size; 155 if (is_small) 156 field_size = 4; // uint32_t relative indirect fields 157 else 158 field_size = process->GetAddressByteSize(); 159 160 return field_size // SEL name; 161 + field_size // const char *types; 162 + field_size; // IMP imp; 163 } 164 165 bool Read(Process *process, lldb::addr_t addr, bool, bool); 166 }; 167 168 struct ivar_list_t { 169 uint32_t m_entsize; 170 uint32_t m_count; 171 lldb::addr_t m_first_ptr; 172 173 bool Read(Process *process, lldb::addr_t addr); 174 }; 175 176 struct ivar_t { 177 lldb::addr_t m_offset_ptr; 178 lldb::addr_t m_name_ptr; 179 lldb::addr_t m_type_ptr; 180 uint32_t m_alignment; 181 uint32_t m_size; 182 183 std::string m_name; 184 std::string m_type; 185 GetSizeivar_t186 static size_t GetSize(Process *process) { 187 size_t ptr_size = process->GetAddressByteSize(); 188 189 return ptr_size // uintptr_t *offset; 190 + ptr_size // const char *name; 191 + ptr_size // const char *type; 192 + sizeof(uint32_t) // uint32_t alignment; 193 + sizeof(uint32_t); // uint32_t size; 194 } 195 196 bool Read(Process *process, lldb::addr_t addr); 197 }; 198 199 class iVarsStorage { 200 public: 201 iVarsStorage(); 202 203 size_t size(); 204 205 iVarDescriptor &operator[](size_t idx); 206 207 void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor); 208 209 private: 210 bool m_filled; 211 std::vector<iVarDescriptor> m_ivars; 212 std::recursive_mutex m_mutex; 213 }; 214 215 // The constructor should only be invoked by the runtime as it builds its 216 // caches 217 // or populates them. A ClassDescriptorV2 should only ever exist in a cache. ClassDescriptorV2(AppleObjCRuntimeV2 & runtime,ObjCLanguageRuntime::ObjCISA isa,const char * name)218 ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, 219 ObjCLanguageRuntime::ObjCISA isa, const char *name) 220 : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name), 221 m_ivars_storage() {} 222 223 bool Read_objc_class(Process *process, 224 std::unique_ptr<objc_class_t> &objc_class) const; 225 226 bool Read_class_row(Process *process, const objc_class_t &objc_class, 227 std::unique_ptr<class_ro_t> &class_ro, 228 std::unique_ptr<class_rw_t> &class_rw) const; 229 230 AppleObjCRuntimeV2 231 &m_runtime; // The runtime, so we can read information lazily. 232 lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., 233 // objects of this class type have this as 234 // their ISA) 235 ConstString m_name; // May be NULL 236 iVarsStorage m_ivars_storage; 237 }; 238 239 // tagged pointer descriptor 240 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor { 241 public: ClassDescriptorV2Tagged(ConstString class_name,uint64_t payload)242 ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) { 243 m_name = class_name; 244 if (!m_name) { 245 m_valid = false; 246 return; 247 } 248 m_valid = true; 249 m_payload = payload; 250 m_info_bits = (m_payload & 0xF0ULL) >> 4; 251 m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; 252 } 253 ClassDescriptorV2Tagged(ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,uint64_t payload)254 ClassDescriptorV2Tagged( 255 ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, 256 uint64_t payload) { 257 if (!actual_class_sp) { 258 m_valid = false; 259 return; 260 } 261 m_name = actual_class_sp->GetClassName(); 262 if (!m_name) { 263 m_valid = false; 264 return; 265 } 266 m_valid = true; 267 m_payload = payload; 268 m_info_bits = (m_payload & 0x0FULL); 269 m_value_bits = (m_payload & ~0x0FULL) >> 4; 270 } 271 272 ~ClassDescriptorV2Tagged() override = default; 273 GetClassName()274 ConstString GetClassName() override { return m_name; } 275 GetSuperclass()276 ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override { 277 // tagged pointers can represent a class that has a superclass, but since 278 // that information is not 279 // stored in the object itself, we would have to query the runtime to 280 // discover the hierarchy 281 // for the time being, we skip this step in the interest of static discovery 282 return ObjCLanguageRuntime::ClassDescriptorSP(); 283 } 284 GetMetaclass()285 ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override { 286 return ObjCLanguageRuntime::ClassDescriptorSP(); 287 } 288 IsValid()289 bool IsValid() override { return m_valid; } 290 IsKVO()291 bool IsKVO() override { 292 return false; // tagged pointers are not KVO'ed 293 } 294 IsCFType()295 bool IsCFType() override { 296 return false; // tagged pointers are not CF objects 297 } 298 299 bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 300 uint64_t *value_bits = nullptr, 301 uint64_t *payload = nullptr) override { 302 if (info_bits) 303 *info_bits = GetInfoBits(); 304 if (value_bits) 305 *value_bits = GetValueBits(); 306 if (payload) 307 *payload = GetPayload(); 308 return true; 309 } 310 GetInstanceSize()311 uint64_t GetInstanceSize() override { 312 return (IsValid() ? m_pointer_size : 0); 313 } 314 GetISA()315 ObjCLanguageRuntime::ObjCISA GetISA() override { 316 return 0; // tagged pointers have no ISA 317 } 318 319 // these calls are not part of any formal tagged pointers specification GetValueBits()320 virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); } 321 GetInfoBits()322 virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); } 323 GetPayload()324 virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); } 325 326 private: 327 ConstString m_name; 328 uint8_t m_pointer_size; 329 bool m_valid; 330 uint64_t m_info_bits; 331 uint64_t m_value_bits; 332 uint64_t m_payload; 333 }; 334 335 } // namespace lldb_private 336 337 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H 338