490 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H10#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H11 12#include <map>13#include <memory>14#include <mutex>15#include <optional>16 17#include "AppleObjCRuntime.h"18#include "lldb/lldb-private.h"19 20#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"21 22#include "llvm/ADT/BitVector.h"23#include "llvm/ADT/SmallSet.h"24 25class RemoteNXMapTable;26 27namespace lldb_private {28 29class AppleObjCRuntimeV2 : public AppleObjCRuntime {30public:31 ~AppleObjCRuntimeV2() override = default;32 33 static void Initialize();34 35 static void Terminate();36 37 static lldb_private::LanguageRuntime *38 CreateInstance(Process *process, lldb::LanguageType language);39 40 static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; }41 42 LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) override;43 44 static char ID;45 46 bool isA(const void *ClassID) const override {47 return ClassID == &ID || AppleObjCRuntime::isA(ClassID);48 }49 50 static bool classof(const LanguageRuntime *runtime) {51 return runtime->isA(&ID);52 }53 54 bool GetDynamicTypeAndAddress(ValueObject &in_value,55 lldb::DynamicValueType use_dynamic,56 TypeAndOrName &class_type_or_name,57 Address &address, Value::ValueType &value_type,58 llvm::ArrayRef<uint8_t> &local_buffer) override;59 60 llvm::Expected<std::unique_ptr<UtilityFunction>>61 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;62 63 llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }64 65 ObjCRuntimeVersions GetRuntimeVersion() const override {66 return ObjCRuntimeVersions::eAppleObjC_V2;67 }68 69 size_t GetByteOffsetForIvar(CompilerType &parent_ast_type,70 const char *ivar_name) override;71 72 void UpdateISAToDescriptorMapIfNeeded() override;73 74 ClassDescriptorSP GetClassDescriptor(ValueObject &valobj) override;75 76 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override;77 78 DeclVendor *GetDeclVendor() override;79 80 lldb::addr_t LookupRuntimeSymbol(ConstString name) override;81 82 EncodingToTypeSP GetEncodingToType() override;83 84 bool IsTaggedPointer(lldb::addr_t ptr) override;85 86 TaggedPointerVendor *GetTaggedPointerVendor() override {87 return m_tagged_pointer_vendor_up.get();88 }89 90 lldb::addr_t GetTaggedPointerObfuscator();91 92 /// Returns the base address for relative method list selector strings.93 lldb::addr_t GetRelativeSelectorBaseAddr() {94 return m_relative_selector_base;95 }96 97 void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) {98 m_relative_selector_base = relative_selector_base;99 }100 101 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,102 lldb::addr_t &cf_false) override;103 104 void ModulesDidLoad(const ModuleList &module_list) override;105 106 bool IsSharedCacheImageLoaded(uint16_t image_index);107 108 std::optional<uint64_t> GetSharedCacheImageHeaderVersion();109 110 StructuredData::ObjectSP GetLanguageSpecificData(SymbolContext sc) override;111 112protected:113 lldb::BreakpointResolverSP114 CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,115 bool throw_bp) override;116 117private:118 class HashTableSignature {119 public:120 HashTableSignature();121 122 bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,123 RemoteNXMapTable &hash_table);124 125 void UpdateSignature(const RemoteNXMapTable &hash_table);126 127 protected:128 uint32_t m_count = 0;129 uint32_t m_num_buckets = 0;130 lldb::addr_t m_buckets_ptr = 0;131 };132 133 class NonPointerISACache {134 public:135 static NonPointerISACache *136 CreateInstance(AppleObjCRuntimeV2 &runtime,137 const lldb::ModuleSP &objc_module_sp);138 139 ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);140 141 private:142 NonPointerISACache(AppleObjCRuntimeV2 &runtime,143 const lldb::ModuleSP &objc_module_sp,144 uint64_t objc_debug_isa_class_mask,145 uint64_t objc_debug_isa_magic_mask,146 uint64_t objc_debug_isa_magic_value,147 uint64_t objc_debug_indexed_isa_magic_mask,148 uint64_t objc_debug_indexed_isa_magic_value,149 uint64_t objc_debug_indexed_isa_index_mask,150 uint64_t objc_debug_indexed_isa_index_shift,151 lldb::addr_t objc_indexed_classes);152 153 bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);154 155 AppleObjCRuntimeV2 &m_runtime;156 std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache;157 lldb::ModuleWP m_objc_module_wp;158 uint64_t m_objc_debug_isa_class_mask;159 uint64_t m_objc_debug_isa_magic_mask;160 uint64_t m_objc_debug_isa_magic_value;161 162 uint64_t m_objc_debug_indexed_isa_magic_mask;163 uint64_t m_objc_debug_indexed_isa_magic_value;164 uint64_t m_objc_debug_indexed_isa_index_mask;165 uint64_t m_objc_debug_indexed_isa_index_shift;166 lldb::addr_t m_objc_indexed_classes;167 168 std::vector<lldb::addr_t> m_indexed_isa_cache;169 170 friend class AppleObjCRuntimeV2;171 172 NonPointerISACache(const NonPointerISACache &) = delete;173 const NonPointerISACache &operator=(const NonPointerISACache &) = delete;174 };175 176 class TaggedPointerVendorV2177 : public ObjCLanguageRuntime::TaggedPointerVendor {178 public:179 ~TaggedPointerVendorV2() override = default;180 181 static TaggedPointerVendorV2 *182 CreateInstance(AppleObjCRuntimeV2 &runtime,183 const lldb::ModuleSP &objc_module_sp);184 185 protected:186 AppleObjCRuntimeV2 &m_runtime;187 188 TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)189 : TaggedPointerVendor(), m_runtime(runtime) {}190 191 private:192 TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;193 const TaggedPointerVendorV2 &194 operator=(const TaggedPointerVendorV2 &) = delete;195 };196 197 class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {198 public:199 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;200 201 ObjCLanguageRuntime::ClassDescriptorSP202 GetClassDescriptor(lldb::addr_t ptr) override;203 204 protected:205 TaggedPointerVendorRuntimeAssisted(206 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,207 uint32_t objc_debug_taggedpointer_slot_shift,208 uint32_t objc_debug_taggedpointer_slot_mask,209 uint32_t objc_debug_taggedpointer_payload_lshift,210 uint32_t objc_debug_taggedpointer_payload_rshift,211 lldb::addr_t objc_debug_taggedpointer_classes);212 213 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;214 typedef Cache::iterator CacheIterator;215 Cache m_cache;216 uint64_t m_objc_debug_taggedpointer_mask;217 uint32_t m_objc_debug_taggedpointer_slot_shift;218 uint32_t m_objc_debug_taggedpointer_slot_mask;219 uint32_t m_objc_debug_taggedpointer_payload_lshift;220 uint32_t m_objc_debug_taggedpointer_payload_rshift;221 lldb::addr_t m_objc_debug_taggedpointer_classes;222 223 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;224 225 TaggedPointerVendorRuntimeAssisted(226 const TaggedPointerVendorRuntimeAssisted &) = delete;227 const TaggedPointerVendorRuntimeAssisted &228 operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;229 };230 231 class TaggedPointerVendorExtended232 : public TaggedPointerVendorRuntimeAssisted {233 public:234 ObjCLanguageRuntime::ClassDescriptorSP235 GetClassDescriptor(lldb::addr_t ptr) override;236 237 protected:238 TaggedPointerVendorExtended(239 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,240 uint64_t objc_debug_taggedpointer_ext_mask,241 uint32_t objc_debug_taggedpointer_slot_shift,242 uint32_t objc_debug_taggedpointer_ext_slot_shift,243 uint32_t objc_debug_taggedpointer_slot_mask,244 uint32_t objc_debug_taggedpointer_ext_slot_mask,245 uint32_t objc_debug_taggedpointer_payload_lshift,246 uint32_t objc_debug_taggedpointer_payload_rshift,247 uint32_t objc_debug_taggedpointer_ext_payload_lshift,248 uint32_t objc_debug_taggedpointer_ext_payload_rshift,249 lldb::addr_t objc_debug_taggedpointer_classes,250 lldb::addr_t objc_debug_taggedpointer_ext_classes);251 252 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);253 254 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;255 typedef Cache::iterator CacheIterator;256 Cache m_ext_cache;257 uint64_t m_objc_debug_taggedpointer_ext_mask;258 uint32_t m_objc_debug_taggedpointer_ext_slot_shift;259 uint32_t m_objc_debug_taggedpointer_ext_slot_mask;260 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;261 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;262 lldb::addr_t m_objc_debug_taggedpointer_ext_classes;263 264 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;265 266 TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;267 const TaggedPointerVendorExtended &268 operator=(const TaggedPointerVendorExtended &) = delete;269 };270 271 class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {272 public:273 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;274 275 ObjCLanguageRuntime::ClassDescriptorSP276 GetClassDescriptor(lldb::addr_t ptr) override;277 278 protected:279 TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)280 : TaggedPointerVendorV2(runtime) {}281 282 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;283 284 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;285 const TaggedPointerVendorLegacy &286 operator=(const TaggedPointerVendorLegacy &) = delete;287 };288 289 struct DescriptorMapUpdateResult {290 bool m_update_ran;291 bool m_retry_update;292 uint32_t m_num_found;293 294 DescriptorMapUpdateResult(bool ran, bool retry, uint32_t found) {295 m_update_ran = ran;296 297 m_retry_update = retry;298 299 m_num_found = found;300 }301 302 static DescriptorMapUpdateResult Fail() { return {false, false, 0}; }303 304 static DescriptorMapUpdateResult Success(uint32_t found) {305 return {true, false, found};306 }307 308 static DescriptorMapUpdateResult Retry() { return {false, true, 0}; }309 };310 311 /// Abstraction to read the Objective-C class info.312 class ClassInfoExtractor {313 public:314 ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}315 std::mutex &GetMutex() { return m_mutex; }316 317 protected:318 /// The lifetime of this object is tied to that of the runtime.319 AppleObjCRuntimeV2 &m_runtime;320 std::mutex m_mutex;321 };322 323 /// We can read the class info from the Objective-C runtime using324 /// gdb_objc_realized_classes, objc_copyRealizedClassList or325 /// objc_getRealizedClassList_trylock. The RealizedClassList variants are326 /// preferred because they include lazily named classes, but they are not327 /// always available or safe to call.328 ///329 /// We potentially need more than one helper for the same process, because we330 /// may need to use gdb_objc_realized_classes until dyld is initialized and331 /// then switch over to objc_copyRealizedClassList or332 /// objc_getRealizedClassList_trylock for lazily named classes.333 class DynamicClassInfoExtractor : public ClassInfoExtractor {334 public:335 DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)336 : ClassInfoExtractor(runtime) {}337 338 DescriptorMapUpdateResult339 UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);340 341 private:342 enum Helper {343 gdb_objc_realized_classes,344 objc_copyRealizedClassList,345 objc_getRealizedClassList_trylock346 };347 348 /// Compute which helper to use. If dyld is not yet fully initialized we349 /// must use gdb_objc_realized_classes. Otherwise, we prefer350 /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList351 /// respectively, depending on availability.352 Helper ComputeHelper(ExecutionContext &exe_ctx) const;353 354 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,355 Helper helper);356 lldb::addr_t &GetClassInfoArgs(Helper helper);357 358 std::unique_ptr<UtilityFunction>359 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper,360 std::string code, std::string name);361 362 struct UtilityFunctionHelper {363 std::unique_ptr<UtilityFunction> utility_function;364 lldb::addr_t args = LLDB_INVALID_ADDRESS;365 };366 367 UtilityFunctionHelper m_gdb_objc_realized_classes_helper;368 UtilityFunctionHelper m_objc_copyRealizedClassList_helper;369 UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper;370 };371 372 /// Abstraction to read the Objective-C class info from the shared cache.373 class SharedCacheClassInfoExtractor : public ClassInfoExtractor {374 public:375 SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)376 : ClassInfoExtractor(runtime) {}377 378 DescriptorMapUpdateResult UpdateISAToDescriptorMap();379 380 private:381 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);382 383 std::unique_ptr<UtilityFunction>384 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);385 386 std::unique_ptr<UtilityFunction> m_utility_function;387 lldb::addr_t m_args = LLDB_INVALID_ADDRESS;388 };389 390 class SharedCacheImageHeaders {391 public:392 static std::unique_ptr<SharedCacheImageHeaders>393 CreateSharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime);394 395 void SetNeedsUpdate() { m_needs_update = true; }396 397 bool IsImageLoaded(uint16_t image_index);398 399 uint64_t GetVersion();400 401 private:402 SharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime,403 lldb::addr_t headerInfoRWs_ptr, uint32_t count,404 uint32_t entsize)405 : m_runtime(runtime), m_headerInfoRWs_ptr(headerInfoRWs_ptr),406 m_loaded_images(count, false), m_version(0), m_count(count),407 m_entsize(entsize), m_needs_update(true) {}408 llvm::Error UpdateIfNeeded();409 410 AppleObjCRuntimeV2 &m_runtime;411 lldb::addr_t m_headerInfoRWs_ptr;412 llvm::BitVector m_loaded_images;413 uint64_t m_version;414 uint32_t m_count;415 uint32_t m_entsize;416 bool m_needs_update;417 };418 419 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);420 421 ObjCISA GetPointerISA(ObjCISA isa);422 423 lldb::addr_t GetISAHashTablePointer();424 425 using ValueObjectSet = llvm::SmallPtrSet<ValueObject *, 8>;426 ClassDescriptorSP GetClassDescriptorImpl(ValueObject &valobj,427 ValueObjectSet &seen);428 429 /// Update the generation count of realized classes. This is not an exact430 /// count but rather a value that is incremented when new classes are realized431 /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will432 /// change when lazily named classes get realized.433 bool RealizedClassGenerationCountChanged();434 435 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,436 uint32_t num_class_infos);437 438 enum class SharedCacheWarningReason {439 eExpressionUnableToRun,440 eExpressionExecutionFailure,441 eNotEnoughClassesRead442 };443 444 void WarnIfNoClassesCached(SharedCacheWarningReason reason);445 void WarnIfNoExpandedSharedCache();446 447 lldb::addr_t GetSharedCacheReadOnlyAddress();448 lldb::addr_t GetSharedCacheBaseAddress();449 450 bool GetCFBooleanValuesIfNeeded();451 452 bool HasSymbol(ConstString Name);453 454 NonPointerISACache *GetNonPointerIsaCache() {455 if (!m_non_pointer_isa_cache_up)456 m_non_pointer_isa_cache_up.reset(457 NonPointerISACache::CreateInstance(*this, m_objc_module_sp));458 return m_non_pointer_isa_cache_up.get();459 }460 461 friend class ClassDescriptorV2;462 463 lldb::ModuleSP m_objc_module_sp;464 465 DynamicClassInfoExtractor m_dynamic_class_info_extractor;466 SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;467 468 std::unique_ptr<DeclVendor> m_decl_vendor_up;469 lldb::addr_t m_tagged_pointer_obfuscator;470 lldb::addr_t m_isa_hash_table_ptr;471 lldb::addr_t m_relative_selector_base;472 HashTableSignature m_hash_signature;473 bool m_has_object_getClass;474 bool m_has_objc_copyRealizedClassList;475 bool m_has_objc_getRealizedClassList_trylock;476 bool m_loaded_objc_opt;477 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;478 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;479 EncodingToTypeSP m_encoding_to_type_sp;480 std::once_flag m_no_classes_cached_warning;481 std::once_flag m_no_expanded_cache_warning;482 std::optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;483 uint64_t m_realized_class_generation_count;484 std::unique_ptr<SharedCacheImageHeaders> m_shared_cache_image_headers_up;485};486 487} // namespace lldb_private488 489#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H490