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