477 lines · c
1//===-- ObjCLanguageRuntime.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_OBJCLANGUAGERUNTIME_H10#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H11 12#include <functional>13#include <map>14#include <memory>15#include <optional>16#include <unordered_set>17 18#include "llvm/Support/Casting.h"19 20#include "lldb/Breakpoint/BreakpointPrecondition.h"21#include "lldb/Core/PluginInterface.h"22#include "lldb/Symbol/CompilerType.h"23#include "lldb/Symbol/Type.h"24#include "lldb/Target/LanguageRuntime.h"25#include "lldb/Utility/ConstString.h"26#include "lldb/Utility/ThreadSafeDenseMap.h"27#include "lldb/lldb-enumerations.h"28#include "lldb/lldb-private.h"29 30class CommandObjectObjC_ClassTable_Dump;31 32namespace lldb_private {33 34class TypeSystemClang;35class UtilityFunction;36 37class ObjCLanguageRuntime : public LanguageRuntime {38public:39 enum class ObjCRuntimeVersions {40 eObjC_VersionUnknown = 0,41 eAppleObjC_V1 = 1,42 eAppleObjC_V2 = 2,43 eGNUstep_libobjc2 = 3,44 };45 46 typedef lldb::addr_t ObjCISA;47 48 class ClassDescriptor;49 typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;50 51 // the information that we want to support retrieving from an ObjC class this52 // needs to be pure virtual since there are at least 2 different53 // implementations of the runtime, and more might come54 class ClassDescriptor {55 public:56 ClassDescriptor() : m_type_wp() {}57 58 virtual ~ClassDescriptor() = default;59 60 virtual ConstString GetClassName() = 0;61 62 virtual ClassDescriptorSP GetSuperclass() = 0;63 64 virtual ClassDescriptorSP GetMetaclass() const = 0;65 66 // virtual if any implementation has some other version-specific rules but67 // for the known v1/v2 this is all that needs to be done68 virtual bool IsKVO() {69 if (m_is_kvo == eLazyBoolCalculate) {70 const char *class_name = GetClassName().AsCString();71 if (class_name && *class_name)72 m_is_kvo =73 (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name);74 }75 return (m_is_kvo == eLazyBoolYes);76 }77 78 // virtual if any implementation has some other version-specific rules but79 // for the known v1/v2 this is all that needs to be done80 virtual bool IsCFType() {81 if (m_is_cf == eLazyBoolCalculate) {82 const char *class_name = GetClassName().AsCString();83 if (class_name && *class_name)84 m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 ||85 strcmp(class_name, "NSCFType") == 0);86 }87 return (m_is_cf == eLazyBoolYes);88 }89 90 /// Determine whether this class is implemented in Swift.91 virtual lldb::LanguageType GetImplementationLanguage() const {92 return lldb::eLanguageTypeObjC;93 }94 95 virtual bool IsValid() = 0;96 97 /// There are two routines in the ObjC runtime that tagged pointer clients98 /// can call to get the value from their tagged pointer, one that retrieves99 /// it as an unsigned value and one a signed value. These two100 /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls.101 /// @{102 virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,103 uint64_t *value_bits = nullptr,104 uint64_t *payload = nullptr) = 0;105 106 virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,107 int64_t *value_bits = nullptr,108 uint64_t *payload = nullptr) = 0;109 /// @}110 111 virtual uint64_t GetInstanceSize() = 0;112 113 // use to implement version-specific additional constraints on pointers114 virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const {115 return true;116 }117 118 virtual ObjCISA GetISA() = 0;119 120 // This should return true iff the interface could be completed121 virtual bool122 Describe(std::function<void(ObjCISA)> const &superclass_func,123 std::function<bool(const char *, const char *)> const124 &instance_method_func,125 std::function<bool(const char *, const char *)> const126 &class_method_func,127 std::function<bool(const char *, const char *, lldb::addr_t,128 uint64_t)> const &ivar_func) const {129 return false;130 }131 132 lldb::TypeSP GetType() { return m_type_wp.lock(); }133 134 void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; }135 136 struct iVarDescriptor {137 ConstString m_name;138 CompilerType m_type;139 uint64_t m_size;140 int32_t m_offset;141 };142 143 virtual size_t GetNumIVars() { return 0; }144 145 virtual iVarDescriptor GetIVarAtIndex(size_t idx) {146 return iVarDescriptor();147 }148 149 protected:150 bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size,151 bool allow_NULLs = false, bool allow_tagged = false,152 bool check_version_specific = false) const;153 154 private:155 LazyBool m_is_kvo = eLazyBoolCalculate;156 LazyBool m_is_cf = eLazyBoolCalculate;157 lldb::TypeWP m_type_wp;158 };159 160 class EncodingToType {161 public:162 virtual ~EncodingToType();163 164 virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name,165 bool for_expression) = 0;166 virtual CompilerType RealizeType(const char *name, bool for_expression);167 168 protected:169 std::shared_ptr<TypeSystemClang> m_scratch_ast_ctx_sp;170 };171 172 class ObjCExceptionPrecondition : public BreakpointPrecondition {173 public:174 ObjCExceptionPrecondition();175 176 ~ObjCExceptionPrecondition() override = default;177 178 bool EvaluatePrecondition(StoppointCallbackContext &context) override;179 void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;180 Status ConfigurePrecondition(Args &args) override;181 182 protected:183 void AddClassName(const char *class_name);184 185 private:186 std::unordered_set<std::string> m_class_names;187 };188 189 static lldb::BreakpointPreconditionSP190 GetBreakpointExceptionPrecondition(lldb::LanguageType language,191 bool throw_bp);192 193 class TaggedPointerVendor {194 public:195 virtual ~TaggedPointerVendor() = default;196 197 virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0;198 199 virtual ObjCLanguageRuntime::ClassDescriptorSP200 GetClassDescriptor(lldb::addr_t ptr) = 0;201 202 protected:203 TaggedPointerVendor() = default;204 205 private:206 TaggedPointerVendor(const TaggedPointerVendor &) = delete;207 const TaggedPointerVendor &operator=(const TaggedPointerVendor &) = delete;208 };209 210 ~ObjCLanguageRuntime() override;211 212 static char ID;213 214 bool isA(const void *ClassID) const override {215 return ClassID == &ID || LanguageRuntime::isA(ClassID);216 }217 218 static bool classof(const LanguageRuntime *runtime) {219 return runtime->isA(&ID);220 }221 222 static ObjCLanguageRuntime *Get(Process &process) {223 return llvm::cast_or_null<ObjCLanguageRuntime>(224 process.GetLanguageRuntime(lldb::eLanguageTypeObjC));225 }226 227 virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; }228 229 typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;230 231 virtual EncodingToTypeSP GetEncodingToType();232 233 virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value);234 235 ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value);236 237 virtual ClassDescriptorSP238 GetClassDescriptorFromClassName(ConstString class_name);239 240 virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa);241 242 ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa);243 244 lldb::LanguageType GetLanguageType() const override {245 return lldb::eLanguageTypeObjC;246 }247 248 virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0;249 250 virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0;251 252 virtual bool HasReadObjCLibrary() = 0;253 254 // These two methods actually use different caches. The only time we'll255 // cache a sel_str is if we found a "selector specific stub" for the selector256 // and conversely we only add to the SEL cache if we saw a regular dispatch.257 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel);258 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr,259 llvm::StringRef sel_str);260 261 void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel,262 lldb::addr_t impl_addr);263 264 void AddToMethodCache(lldb::addr_t class_addr, llvm::StringRef sel_str,265 lldb::addr_t impl_addr);266 267 TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr);268 269 void AddToClassNameCache(lldb::addr_t class_addr, const char *name,270 lldb::TypeSP type_sp);271 272 void AddToClassNameCache(lldb::addr_t class_addr,273 const TypeAndOrName &class_or_type_name);274 275 lldb::TypeSP LookupInCompleteClassCache(ConstString &name);276 277 std::optional<CompilerType> GetRuntimeType(CompilerType base_type) override;278 279 virtual llvm::Expected<std::unique_ptr<UtilityFunction>>280 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0;281 282 virtual ObjCRuntimeVersions GetRuntimeVersion() const {283 return ObjCRuntimeVersions::eObjC_VersionUnknown;284 }285 286 bool IsValidISA(ObjCISA isa) {287 UpdateISAToDescriptorMap();288 return m_isa_to_descriptor.count(isa) > 0;289 }290 291 virtual void UpdateISAToDescriptorMapIfNeeded() = 0;292 293 void UpdateISAToDescriptorMap() {294 if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) {295 UpdateISAToDescriptorMapIfNeeded();296 }297 }298 299 virtual ObjCISA GetISA(ConstString name);300 301 virtual ObjCISA GetParentClass(ObjCISA isa);302 303 // Finds the byte offset of the child_type ivar in parent_type. If it can't304 // find the offset, returns LLDB_INVALID_IVAR_OFFSET.305 306 virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,307 const char *ivar_name);308 309 bool HasNewLiteralsAndIndexing() {310 if (m_has_new_literals_and_indexing == eLazyBoolCalculate) {311 if (CalculateHasNewLiteralsAndIndexing())312 m_has_new_literals_and_indexing = eLazyBoolYes;313 else314 m_has_new_literals_and_indexing = eLazyBoolNo;315 }316 317 return (m_has_new_literals_and_indexing == eLazyBoolYes);318 }319 320 void SymbolsDidLoad(const ModuleList &module_list) override {321 m_negative_complete_class_cache.clear();322 }323 324 std::optional<uint64_t>325 GetTypeBitSize(const CompilerType &compiler_type) override;326 327 /// Check whether the name is "self" or "_cmd" and should show up in328 /// "frame variable".329 bool IsAllowedRuntimeValue(ConstString name) override;330 331protected:332 // Classes that inherit from ObjCLanguageRuntime can see and modify these333 ObjCLanguageRuntime(Process *process);334 335 virtual bool CalculateHasNewLiteralsAndIndexing() { return false; }336 337 bool ISAIsCached(ObjCISA isa) const {338 return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();339 }340 341 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) {342 if (isa != 0) {343 m_isa_to_descriptor[isa] = descriptor_sp;344 return true;345 }346 return false;347 }348 349 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,350 const char *class_name);351 352 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,353 uint32_t class_name_hash) {354 if (isa != 0) {355 m_isa_to_descriptor[isa] = descriptor_sp;356 m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));357 return true;358 }359 return false;360 }361 362private:363 // We keep two maps of <Class,Selector>->Implementation so we don't have364 // to call the resolver function over and over.365 // The first comes from regular obj_msgSend type dispatch, and maps the366 // class + uniqued SEL value to an implementation.367 // The second comes from the "selector-specific stubs", which are always368 // of the form _objc_msgSend$SelectorName, so we don't know the uniqued369 // selector, only the string name.370 371 // FIXME: We need to watch for the loading of Protocols, and flush the cache372 // for any373 // class that we see so changed.374 375 struct ClassAndSel {376 ClassAndSel() = default;377 378 ClassAndSel(lldb::addr_t in_class_addr, lldb::addr_t in_sel_addr)379 : class_addr(in_class_addr), sel_addr(in_sel_addr) {}380 381 bool operator==(const ClassAndSel &rhs) {382 if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr)383 return true;384 else385 return false;386 }387 388 bool operator<(const ClassAndSel &rhs) const {389 return std::tie(class_addr, sel_addr) <390 std::tie(rhs.class_addr, rhs.sel_addr);391 }392 393 lldb::addr_t class_addr = LLDB_INVALID_ADDRESS;394 lldb::addr_t sel_addr = LLDB_INVALID_ADDRESS;395 };396 397 struct ClassAndSelStr {398 ClassAndSelStr() = default;399 400 ClassAndSelStr(lldb::addr_t in_class_addr, llvm::StringRef in_sel_name)401 : class_addr(in_class_addr), sel_name(in_sel_name) {}402 403 bool operator==(const ClassAndSelStr &rhs) {404 return class_addr == rhs.class_addr && sel_name == rhs.sel_name;405 }406 407 bool operator<(const ClassAndSelStr &rhs) const {408 if (class_addr < rhs.class_addr)409 return true;410 else if (class_addr > rhs.class_addr)411 return false;412 else413 return ConstString::Compare(sel_name, rhs.sel_name);414 }415 416 lldb::addr_t class_addr = LLDB_INVALID_ADDRESS;417 ConstString sel_name;418 };419 420 typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap;421 typedef std::map<ClassAndSelStr, lldb::addr_t> MsgImplStrMap;422 typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;423 typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;424 typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;425 typedef HashToISAMap::iterator HashToISAIterator;426 typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache;427 428 MsgImplMap m_impl_cache;429 MsgImplStrMap m_impl_str_cache;430 LazyBool m_has_new_literals_and_indexing;431 ISAToDescriptorMap m_isa_to_descriptor;432 HashToISAMap m_hash_to_isa_map;433 TypeSizeCache m_type_size_cache;434 435protected:436 uint32_t m_isa_to_descriptor_stop_id;437 438 typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;439 CompleteClassMap m_complete_class_cache;440 441 struct ConstStringSetHelpers {442 size_t operator()(ConstString arg) const // for hashing443 {444 return (size_t)arg.GetCString();445 }446 bool operator()(ConstString arg1,447 ConstString arg2) const // for equality448 {449 return arg1.operator==(arg2);450 }451 };452 typedef std::unordered_set<ConstString, ConstStringSetHelpers,453 ConstStringSetHelpers>454 CompleteClassSet;455 CompleteClassSet m_negative_complete_class_cache;456 457 ISAToDescriptorIterator GetDescriptorIterator(ConstString name);458 459 friend class ::CommandObjectObjC_ClassTable_Dump;460 461 std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator>462 GetDescriptorIteratorPair(bool update_if_needed = true);463 464 void ReadObjCLibraryIfNeeded(const ModuleList &module_list);465 466 ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete;467 const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete;468 469private:470 CompilerType LookupInRuntime(ConstString class_name);471 CompilerType LookupInModulesVendor(ConstString class_name, Target &process);472};473 474} // namespace lldb_private475 476#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H477