LLDB  mainline
ObjCLanguageRuntime.h
Go to the documentation of this file.
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 liblldb_ObjCLanguageRuntime_h_
10 #define liblldb_ObjCLanguageRuntime_h_
11 
12 #include <functional>
13 #include <map>
14 #include <memory>
15 #include <unordered_set>
16 
17 #include "llvm/Support/Casting.h"
18 
22 #include "lldb/Symbol/DeclVendor.h"
23 #include "lldb/Symbol/Type.h"
25 #include "lldb/lldb-private.h"
26 
28 
29 namespace lldb_private {
30 
31 class UtilityFunction;
32 
34 public:
35  enum class ObjCRuntimeVersions {
37  eAppleObjC_V1 = 1,
38  eAppleObjC_V2 = 2
39  };
40 
42 
44  typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
45 
46  // the information that we want to support retrieving from an ObjC class this
47  // needs to be pure virtual since there are at least 2 different
48  // implementations of the runtime, and more might come
50  public:
52  : m_is_kvo(eLazyBoolCalculate), m_is_cf(eLazyBoolCalculate),
53  m_type_wp() {}
54 
55  virtual ~ClassDescriptor() = default;
56 
57  virtual ConstString GetClassName() = 0;
58 
59  virtual ClassDescriptorSP GetSuperclass() = 0;
60 
61  virtual ClassDescriptorSP GetMetaclass() const = 0;
62 
63  // virtual if any implementation has some other version-specific rules but
64  // for the known v1/v2 this is all that needs to be done
65  virtual bool IsKVO() {
66  if (m_is_kvo == eLazyBoolCalculate) {
67  const char *class_name = GetClassName().AsCString();
68  if (class_name && *class_name)
69  m_is_kvo =
70  (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name);
71  }
72  return (m_is_kvo == eLazyBoolYes);
73  }
74 
75  // virtual if any implementation has some other version-specific rules but
76  // for the known v1/v2 this is all that needs to be done
77  virtual bool IsCFType() {
78  if (m_is_cf == eLazyBoolCalculate) {
79  const char *class_name = GetClassName().AsCString();
80  if (class_name && *class_name)
81  m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 ||
82  strcmp(class_name, "NSCFType") == 0);
83  }
84  return (m_is_cf == eLazyBoolYes);
85  }
86 
87  virtual bool IsValid() = 0;
88 
89  virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
90  uint64_t *value_bits = nullptr,
91  uint64_t *payload = nullptr) = 0;
92 
93  virtual uint64_t GetInstanceSize() = 0;
94 
95  // use to implement version-specific additional constraints on pointers
96  virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const {
97  return true;
98  }
99 
100  virtual ObjCISA GetISA() = 0;
101 
102  // This should return true iff the interface could be completed
103  virtual bool
104  Describe(std::function<void(ObjCISA)> const &superclass_func,
105  std::function<bool(const char *, const char *)> const
106  &instance_method_func,
107  std::function<bool(const char *, const char *)> const
108  &class_method_func,
109  std::function<bool(const char *, const char *, lldb::addr_t,
110  uint64_t)> const &ivar_func) const {
111  return false;
112  }
113 
114  lldb::TypeSP GetType() { return m_type_wp.lock(); }
115 
116  void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; }
117 
118  struct iVarDescriptor {
121  uint64_t m_size;
122  int32_t m_offset;
123  };
124 
125  virtual size_t GetNumIVars() { return 0; }
126 
127  virtual iVarDescriptor GetIVarAtIndex(size_t idx) {
128  return iVarDescriptor();
129  }
130 
131  protected:
132  bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size,
133  bool allow_NULLs = false, bool allow_tagged = false,
134  bool check_version_specific = false) const;
135 
136  private:
137  LazyBool m_is_kvo;
138  LazyBool m_is_cf;
139  lldb::TypeWP m_type_wp;
140  };
141 
143  public:
144  virtual ~EncodingToType();
145 
146  virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name,
147  bool for_expression);
148  virtual CompilerType RealizeType(const char *name, bool for_expression);
149 
150  virtual CompilerType RealizeType(clang::ASTContext &ast_ctx,
151  const char *name, bool for_expression) = 0;
152 
153  protected:
154  std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_up;
155  };
156 
158  public:
160 
161  ~ObjCExceptionPrecondition() override = default;
162 
163  bool EvaluatePrecondition(StoppointCallbackContext &context) override;
164  void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
165  Status ConfigurePrecondition(Args &args) override;
166 
167  protected:
168  void AddClassName(const char *class_name);
169 
170  private:
171  std::unordered_set<std::string> m_class_names;
172  };
173 
175  public:
176  virtual ~TaggedPointerVendor() = default;
177 
178  virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0;
179 
182 
183  protected:
184  TaggedPointerVendor() = default;
185 
186  private:
188  };
189 
190  ~ObjCLanguageRuntime() override;
191 
192  virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; }
193 
194  typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
195 
196  virtual EncodingToTypeSP GetEncodingToType();
197 
198  virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value);
199 
200  ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value);
201 
202  virtual ClassDescriptorSP
204 
205  virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa);
206 
207  ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa);
208 
211  }
212 
213  virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
214 
215  virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
216 
217  virtual bool HasReadObjCLibrary() = 0;
218 
219  virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
220  bool stop_others) = 0;
221 
223 
224  void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel,
225  lldb::addr_t impl_addr);
226 
228 
229  void AddToClassNameCache(lldb::addr_t class_addr, const char *name,
230  lldb::TypeSP type_sp);
231 
232  void AddToClassNameCache(lldb::addr_t class_addr,
233  const TypeAndOrName &class_or_type_name);
234 
235  lldb::TypeSP LookupInCompleteClassCache(ConstString &name);
236 
237  virtual UtilityFunction *CreateObjectChecker(const char *) = 0;
238 
241  }
242 
243  bool IsValidISA(ObjCISA isa) {
245  return m_isa_to_descriptor.count(isa) > 0;
246  }
247 
248  virtual void UpdateISAToDescriptorMapIfNeeded() = 0;
249 
253  }
254  }
255 
256  virtual ObjCISA GetISA(ConstString name);
257 
258  virtual ConstString GetActualTypeName(ObjCISA isa);
259 
260  virtual ObjCISA GetParentClass(ObjCISA isa);
261 
262  virtual DeclVendor *GetDeclVendor() { return nullptr; }
263 
264  // Finds the byte offset of the child_type ivar in parent_type. If it can't
265  // find the offset, returns LLDB_INVALID_IVAR_OFFSET.
266 
267  virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,
268  const char *ivar_name);
269 
270  // Given the name of an Objective-C runtime symbol (e.g., ivar offset
271  // symbol), try to determine from the runtime what the value of that symbol
272  // would be. Useful when the underlying binary is stripped.
274  return LLDB_INVALID_ADDRESS;
275  }
276 
278  if (m_has_new_literals_and_indexing == eLazyBoolCalculate) {
280  m_has_new_literals_and_indexing = eLazyBoolYes;
281  else
282  m_has_new_literals_and_indexing = eLazyBoolNo;
283  }
284 
285  return (m_has_new_literals_and_indexing == eLazyBoolYes);
286  }
287 
288  virtual void SymbolsDidLoad(const ModuleList &module_list) {
290  }
291 
292  bool GetTypeBitSize(const CompilerType &compiler_type,
293  uint64_t &size) override;
294 
295  /// Check whether the name is "self" or "_cmd" and should show up in
296  /// "frame variable".
297  static bool IsWhitelistedRuntimeValue(ConstString name);
298  bool IsRuntimeSupportValue(ValueObject &valobj) override;
299 
300 protected:
301  // Classes that inherit from ObjCLanguageRuntime can see and modify these
302  ObjCLanguageRuntime(Process *process);
303 
304  virtual bool CalculateHasNewLiteralsAndIndexing() { return false; }
305 
306  bool ISAIsCached(ObjCISA isa) const {
307  return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
308  }
309 
310  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) {
311  if (isa != 0) {
312  m_isa_to_descriptor[isa] = descriptor_sp;
313  return true;
314  }
315  return false;
316  }
317 
318  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
319  const char *class_name);
320 
321  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
322  uint32_t class_name_hash) {
323  if (isa != 0) {
324  m_isa_to_descriptor[isa] = descriptor_sp;
325  m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
326  return true;
327  }
328  return false;
329  }
330 
331 private:
332  // We keep a map of <Class,Selector>->Implementation so we don't have to call
333  // the resolver function over and over.
334 
335  // FIXME: We need to watch for the loading of Protocols, and flush the cache
336  // for any
337  // class that we see so changed.
338 
339  struct ClassAndSel {
340  ClassAndSel() {
341  sel_addr = LLDB_INVALID_ADDRESS;
342  class_addr = LLDB_INVALID_ADDRESS;
343  }
344 
345  ClassAndSel(lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr)
346  : class_addr(in_class_addr), sel_addr(in_sel_addr) {}
347 
348  bool operator==(const ClassAndSel &rhs) {
349  if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr)
350  return true;
351  else
352  return false;
353  }
354 
355  bool operator<(const ClassAndSel &rhs) const {
356  if (class_addr < rhs.class_addr)
357  return true;
358  else if (class_addr > rhs.class_addr)
359  return false;
360  else {
361  if (sel_addr < rhs.sel_addr)
362  return true;
363  else
364  return false;
365  }
366  }
367 
368  lldb::addr_t class_addr;
369  lldb::addr_t sel_addr;
370  };
371 
372  typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap;
373  typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
374  typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
375  typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
376  typedef HashToISAMap::iterator HashToISAIterator;
378 
379  MsgImplMap m_impl_cache;
380  LazyBool m_has_new_literals_and_indexing;
381  ISAToDescriptorMap m_isa_to_descriptor;
382  HashToISAMap m_hash_to_isa_map;
383  TypeSizeCache m_type_size_cache;
384 
385 protected:
387 
388  typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
389  CompleteClassMap m_complete_class_cache;
390 
392  size_t operator()(ConstString arg) const // for hashing
393  {
394  return (size_t)arg.GetCString();
395  }
397  ConstString arg2) const // for equality
398  {
399  return arg1.operator==(arg2);
400  }
401  };
402  typedef std::unordered_set<ConstString, ConstStringSetHelpers,
403  ConstStringSetHelpers>
406 
407  ISAToDescriptorIterator GetDescriptorIterator(ConstString name);
408 
409  friend class ::CommandObjectObjC_ClassTable_Dump;
410 
411  std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator>
412  GetDescriptorIteratorPair(bool update_if_needed = true);
413 
414  void ReadObjCLibraryIfNeeded(const ModuleList &module_list);
415 
417 };
418 
419 } // namespace lldb_private
420 
421 #endif // liblldb_ObjCLanguageRuntime_h_
bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr)
A command line argument class.
Definition: Args.h:32
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa)
Sometimes you can find the name of the type corresponding to an object, but we don&#39;t have debug infor...
Definition: Type.h:396
virtual EncodingToTypeSP GetEncodingToType()
static bool IsWhitelistedRuntimeValue(ConstString name)
Check whether the name is "self" or "_cmd" and should show up in "frame variable".
virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, bool stop_others)=0
virtual lldb::addr_t LookupRuntimeSymbol(ConstString name)
lldb::TypeSP LookupInCompleteClassCache(ConstString &name)
virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp)=0
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
bool GetTypeBitSize(const CompilerType &compiler_type, uint64_t &size) override
virtual ObjCISA GetISA(ConstString name)
bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
std::map< ConstString, lldb::TypeWP > CompleteClassMap
virtual UtilityFunction * CreateObjectChecker(const char *)=0
virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, const char *ivar_name)
bool operator==(const Address &lhs, const Address &rhs)
Definition: Address.cpp:973
virtual iVarDescriptor GetIVarAtIndex(size_t idx)
ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value)
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
LanguageType
Programming language type.
uint32_t GetStopID() const
Definition: Process.h:1337
std::unique_ptr< ClangASTContext > m_scratch_ast_ctx_up
A collection class for Module objects.
Definition: ModuleList.h:91
virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const
virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp)=0
virtual void SymbolsDidLoad(const ModuleList &module_list)
virtual ObjCISA GetParentClass(ObjCISA isa)
lldb::LanguageType GetLanguageType() const override
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
bool operator()(ConstString arg1, ConstString arg2) const
void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr)
bool IsRuntimeSupportValue(ValueObject &valobj) override
Identify whether a value is a language implementation detaul that should be hidden from the user inte...
uint64_t addr_t
Definition: lldb-types.h:83
std::unordered_set< ConstString, ConstStringSetHelpers, ConstStringSetHelpers > CompleteClassSet
virtual TaggedPointerVendor * GetTaggedPointerVendor()
A uniqued constant string class.
Definition: ConstString.h:38
void ReadObjCLibraryIfNeeded(const ModuleList &module_list)
void AddToClassNameCache(lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp)
lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel)
DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime)
ISAToDescriptorIterator GetDescriptorIterator(ConstString name)
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
General Outline: When we hit a breakpoint we need to package up whatever information is needed to eva...
virtual ObjCRuntimeVersions GetRuntimeVersion() const
virtual ConstString GetActualTypeName(ObjCISA isa)
"lldb/Expression/UtilityFunction.h" Encapsulates a bit of source code that provides a function that i...
virtual void UpdateISAToDescriptorMapIfNeeded()=0
bool operator<(const Address &lhs, const Address &rhs)
Definition: Address.cpp:942
std::shared_ptr< EncodingToType > EncodingToTypeSP
virtual ClassDescriptorSP GetClassDescriptorFromClassName(ConstString class_name)
std::pair< ISAToDescriptorIterator, ISAToDescriptorIterator > GetDescriptorIteratorPair(bool update_if_needed=true)
An error handling class.
Definition: Status.h:44
virtual bool Describe(std::function< void(ObjCISA)> const &superclass_func, std::function< bool(const char *, const char *)> const &instance_method_func, std::function< bool(const char *, const char *)> const &class_method_func, std::function< bool(const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const