1 //===-- AppleObjCRuntimeV2.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_APPLEOBJCRUNTIMEV2_H 10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 11 12 #include <map> 13 #include <memory> 14 #include <mutex> 15 16 #include "AppleObjCRuntime.h" 17 #include "lldb/lldb-private.h" 18 19 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" 20 21 class RemoteNXMapTable; 22 23 namespace lldb_private { 24 25 class AppleObjCRuntimeV2 : public AppleObjCRuntime { 26 public: 27 ~AppleObjCRuntimeV2() override = default; 28 29 // Static Functions 30 static void Initialize(); 31 32 static void Terminate(); 33 34 static lldb_private::LanguageRuntime * 35 CreateInstance(Process *process, lldb::LanguageType language); 36 37 static lldb_private::ConstString GetPluginNameStatic(); 38 39 static char ID; 40 isA(const void * ClassID)41 bool isA(const void *ClassID) const override { 42 return ClassID == &ID || AppleObjCRuntime::isA(ClassID); 43 } 44 classof(const LanguageRuntime * runtime)45 static bool classof(const LanguageRuntime *runtime) { 46 return runtime->isA(&ID); 47 } 48 49 // These are generic runtime functions: 50 bool GetDynamicTypeAndAddress(ValueObject &in_value, 51 lldb::DynamicValueType use_dynamic, 52 TypeAndOrName &class_type_or_name, 53 Address &address, 54 Value::ValueType &value_type) override; 55 56 llvm::Expected<std::unique_ptr<UtilityFunction>> 57 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override; 58 59 // PluginInterface protocol 60 ConstString GetPluginName() override; 61 62 uint32_t GetPluginVersion() override; 63 GetRuntimeVersion()64 ObjCRuntimeVersions GetRuntimeVersion() const override { 65 return ObjCRuntimeVersions::eAppleObjC_V2; 66 } 67 68 size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 69 const char *ivar_name) override; 70 71 void UpdateISAToDescriptorMapIfNeeded() override; 72 73 ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; 74 75 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; 76 77 DeclVendor *GetDeclVendor() override; 78 79 lldb::addr_t LookupRuntimeSymbol(ConstString name) override; 80 81 EncodingToTypeSP GetEncodingToType() override; 82 83 bool IsTaggedPointer(lldb::addr_t ptr) override; 84 GetTaggedPointerVendor()85 TaggedPointerVendor *GetTaggedPointerVendor() override { 86 return m_tagged_pointer_vendor_up.get(); 87 } 88 89 lldb::addr_t GetTaggedPointerObfuscator(); 90 91 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, 92 lldb::addr_t &cf_false) override; 93 94 // none of these are valid ISAs - we use them to infer the type 95 // of tagged pointers - if we have something meaningful to say 96 // we report an actual type - otherwise, we just say tagged 97 // there is no connection between the values here and the tagged pointers map 98 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; 99 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; 100 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; 101 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; 102 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 103 5; 104 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; 105 106 protected: 107 lldb::BreakpointResolverSP 108 CreateExceptionResolver(const lldb::BreakpointSP &bkpt, 109 bool catch_bp, bool throw_bp) override; 110 111 private: 112 class HashTableSignature { 113 public: 114 HashTableSignature(); 115 116 bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime, 117 RemoteNXMapTable &hash_table); 118 119 void UpdateSignature(const RemoteNXMapTable &hash_table); 120 121 protected: 122 uint32_t m_count; 123 uint32_t m_num_buckets; 124 lldb::addr_t m_buckets_ptr; 125 }; 126 127 class NonPointerISACache { 128 public: 129 static NonPointerISACache * 130 CreateInstance(AppleObjCRuntimeV2 &runtime, 131 const lldb::ModuleSP &objc_module_sp); 132 133 ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa); 134 135 private: 136 NonPointerISACache(AppleObjCRuntimeV2 &runtime, 137 const lldb::ModuleSP &objc_module_sp, 138 uint64_t objc_debug_isa_class_mask, 139 uint64_t objc_debug_isa_magic_mask, 140 uint64_t objc_debug_isa_magic_value, 141 uint64_t objc_debug_indexed_isa_magic_mask, 142 uint64_t objc_debug_indexed_isa_magic_value, 143 uint64_t objc_debug_indexed_isa_index_mask, 144 uint64_t objc_debug_indexed_isa_index_shift, 145 lldb::addr_t objc_indexed_classes); 146 147 bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa); 148 149 AppleObjCRuntimeV2 &m_runtime; 150 std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache; 151 lldb::ModuleWP m_objc_module_wp; 152 uint64_t m_objc_debug_isa_class_mask; 153 uint64_t m_objc_debug_isa_magic_mask; 154 uint64_t m_objc_debug_isa_magic_value; 155 156 uint64_t m_objc_debug_indexed_isa_magic_mask; 157 uint64_t m_objc_debug_indexed_isa_magic_value; 158 uint64_t m_objc_debug_indexed_isa_index_mask; 159 uint64_t m_objc_debug_indexed_isa_index_shift; 160 lldb::addr_t m_objc_indexed_classes; 161 162 std::vector<lldb::addr_t> m_indexed_isa_cache; 163 164 friend class AppleObjCRuntimeV2; 165 166 NonPointerISACache(const NonPointerISACache &) = delete; 167 const NonPointerISACache &operator=(const NonPointerISACache &) = delete; 168 }; 169 170 class TaggedPointerVendorV2 171 : public ObjCLanguageRuntime::TaggedPointerVendor { 172 public: 173 ~TaggedPointerVendorV2() override = default; 174 175 static TaggedPointerVendorV2 * 176 CreateInstance(AppleObjCRuntimeV2 &runtime, 177 const lldb::ModuleSP &objc_module_sp); 178 179 protected: 180 AppleObjCRuntimeV2 &m_runtime; 181 TaggedPointerVendorV2(AppleObjCRuntimeV2 & runtime)182 TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime) 183 : TaggedPointerVendor(), m_runtime(runtime) {} 184 185 private: 186 TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete; 187 const TaggedPointerVendorV2 & 188 operator=(const TaggedPointerVendorV2 &) = delete; 189 }; 190 191 class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { 192 public: 193 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 194 195 ObjCLanguageRuntime::ClassDescriptorSP 196 GetClassDescriptor(lldb::addr_t ptr) override; 197 198 protected: 199 TaggedPointerVendorRuntimeAssisted( 200 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 201 uint32_t objc_debug_taggedpointer_slot_shift, 202 uint32_t objc_debug_taggedpointer_slot_mask, 203 uint32_t objc_debug_taggedpointer_payload_lshift, 204 uint32_t objc_debug_taggedpointer_payload_rshift, 205 lldb::addr_t objc_debug_taggedpointer_classes); 206 207 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 208 typedef Cache::iterator CacheIterator; 209 Cache m_cache; 210 uint64_t m_objc_debug_taggedpointer_mask; 211 uint32_t m_objc_debug_taggedpointer_slot_shift; 212 uint32_t m_objc_debug_taggedpointer_slot_mask; 213 uint32_t m_objc_debug_taggedpointer_payload_lshift; 214 uint32_t m_objc_debug_taggedpointer_payload_rshift; 215 lldb::addr_t m_objc_debug_taggedpointer_classes; 216 217 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 218 219 TaggedPointerVendorRuntimeAssisted( 220 const TaggedPointerVendorRuntimeAssisted &) = delete; 221 const TaggedPointerVendorRuntimeAssisted & 222 operator=(const TaggedPointerVendorRuntimeAssisted &) = delete; 223 }; 224 225 class TaggedPointerVendorExtended 226 : public TaggedPointerVendorRuntimeAssisted { 227 public: 228 ObjCLanguageRuntime::ClassDescriptorSP 229 GetClassDescriptor(lldb::addr_t ptr) override; 230 231 protected: 232 TaggedPointerVendorExtended( 233 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 234 uint64_t objc_debug_taggedpointer_ext_mask, 235 uint32_t objc_debug_taggedpointer_slot_shift, 236 uint32_t objc_debug_taggedpointer_ext_slot_shift, 237 uint32_t objc_debug_taggedpointer_slot_mask, 238 uint32_t objc_debug_taggedpointer_ext_slot_mask, 239 uint32_t objc_debug_taggedpointer_payload_lshift, 240 uint32_t objc_debug_taggedpointer_payload_rshift, 241 uint32_t objc_debug_taggedpointer_ext_payload_lshift, 242 uint32_t objc_debug_taggedpointer_ext_payload_rshift, 243 lldb::addr_t objc_debug_taggedpointer_classes, 244 lldb::addr_t objc_debug_taggedpointer_ext_classes); 245 246 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr); 247 248 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 249 typedef Cache::iterator CacheIterator; 250 Cache m_ext_cache; 251 uint64_t m_objc_debug_taggedpointer_ext_mask; 252 uint32_t m_objc_debug_taggedpointer_ext_slot_shift; 253 uint32_t m_objc_debug_taggedpointer_ext_slot_mask; 254 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; 255 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; 256 lldb::addr_t m_objc_debug_taggedpointer_ext_classes; 257 258 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 259 260 TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete; 261 const TaggedPointerVendorExtended & 262 operator=(const TaggedPointerVendorExtended &) = delete; 263 }; 264 265 class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { 266 public: 267 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 268 269 ObjCLanguageRuntime::ClassDescriptorSP 270 GetClassDescriptor(lldb::addr_t ptr) override; 271 272 protected: TaggedPointerVendorLegacy(AppleObjCRuntimeV2 & runtime)273 TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime) 274 : TaggedPointerVendorV2(runtime) {} 275 276 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 277 278 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete; 279 const TaggedPointerVendorLegacy & 280 operator=(const TaggedPointerVendorLegacy &) = delete; 281 }; 282 283 struct DescriptorMapUpdateResult { 284 bool m_update_ran; 285 uint32_t m_num_found; 286 DescriptorMapUpdateResultDescriptorMapUpdateResult287 DescriptorMapUpdateResult(bool ran, uint32_t found) { 288 m_update_ran = ran; 289 m_num_found = found; 290 } 291 FailDescriptorMapUpdateResult292 static DescriptorMapUpdateResult Fail() { return {false, 0}; } 293 SuccessDescriptorMapUpdateResult294 static DescriptorMapUpdateResult Success(uint32_t found) { 295 return {true, found}; 296 } 297 }; 298 299 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); 300 301 ObjCISA GetPointerISA(ObjCISA isa); 302 303 lldb::addr_t GetISAHashTablePointer(); 304 305 bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table); 306 307 DescriptorMapUpdateResult 308 UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); 309 310 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, 311 uint32_t num_class_infos); 312 313 DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache(); 314 315 enum class SharedCacheWarningReason { 316 eExpressionExecutionFailure, 317 eNotEnoughClassesRead 318 }; 319 320 void WarnIfNoClassesCached(SharedCacheWarningReason reason); 321 322 lldb::addr_t GetSharedCacheReadOnlyAddress(); 323 324 bool GetCFBooleanValuesIfNeeded(); 325 326 friend class ClassDescriptorV2; 327 328 std::unique_ptr<UtilityFunction> m_get_class_info_code; 329 lldb::addr_t m_get_class_info_args; 330 std::mutex m_get_class_info_args_mutex; 331 332 std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code; 333 lldb::addr_t m_get_shared_cache_class_info_args; 334 std::mutex m_get_shared_cache_class_info_args_mutex; 335 336 std::unique_ptr<DeclVendor> m_decl_vendor_up; 337 lldb::addr_t m_tagged_pointer_obfuscator; 338 lldb::addr_t m_isa_hash_table_ptr; 339 HashTableSignature m_hash_signature; 340 bool m_has_object_getClass; 341 bool m_loaded_objc_opt; 342 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up; 343 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up; 344 EncodingToTypeSP m_encoding_to_type_sp; 345 bool m_noclasses_warning_emitted; 346 llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values; 347 }; 348 349 } // namespace lldb_private 350 351 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 352