1 //===-- ObjCLanguageRuntime.h ---------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef liblldb_ObjCLanguageRuntime_h_
11 #define liblldb_ObjCLanguageRuntime_h_
12 
13 // C Includes
14 // C++ Includes
15 #include <functional>
16 #include <map>
17 #include <unordered_set>
18 
19 // Other libraries and framework includes
20 // Project includes
21 #include "lldb/lldb-private.h"
22 #include "lldb/Core/PluginInterface.h"
23 #include "lldb/Symbol/Type.h"
24 #include "lldb/Symbol/TypeVendor.h"
25 #include "lldb/Target/LanguageRuntime.h"
26 
27 namespace lldb_private {
28 
29 class ClangUtilityFunction;
30 
31 class ObjCLanguageRuntime :
32     public LanguageRuntime
33 {
34 public:
35     class MethodName
36     {
37     public:
38         enum Type
39         {
40             eTypeUnspecified,
41             eTypeClassMethod,
42             eTypeInstanceMethod
43         };
44 
MethodName()45         MethodName () :
46             m_full(),
47             m_class(),
48             m_category(),
49             m_selector(),
50             m_type (eTypeUnspecified),
51             m_category_is_valid (false)
52         {
53         }
54 
MethodName(const char * name,bool strict)55         MethodName (const char *name, bool strict) :
56             m_full(),
57             m_class(),
58             m_category(),
59             m_selector(),
60             m_type (eTypeUnspecified),
61             m_category_is_valid (false)
62         {
63             SetName (name, strict);
64         }
65 
66         void
67         Clear();
68 
69         bool
IsValid(bool strict)70         IsValid (bool strict) const
71         {
72             // If "strict" is true, the name must have everything specified including
73             // the leading "+" or "-" on the method name
74             if (strict && m_type == eTypeUnspecified)
75                 return false;
76             // Other than that, m_full will only be filled in if the objective C
77             // name is valid.
78             return (bool)m_full;
79         }
80 
81         bool
HasCategory()82         HasCategory()
83         {
84             return (bool)GetCategory();
85         }
86 
87         Type
GetType()88         GetType () const
89         {
90             return m_type;
91         }
92 
93         const ConstString &
GetFullName()94         GetFullName () const
95         {
96             return m_full;
97         }
98 
99         ConstString
100         GetFullNameWithoutCategory (bool empty_if_no_category);
101 
102         bool
103         SetName (const char *name, bool strict);
104 
105         const ConstString &
106         GetClassName ();
107 
108         const ConstString &
109         GetClassNameWithCategory ();
110 
111         const ConstString &
112         GetCategory ();
113 
114         const ConstString &
115         GetSelector ();
116 
117         // Get all possible names for a method. Examples:
118         // If name is "+[NSString(my_additions) myStringWithCString:]"
119         //  names[0] => "+[NSString(my_additions) myStringWithCString:]"
120         //  names[1] => "+[NSString myStringWithCString:]"
121         // If name is specified without the leading '+' or '-' like "[NSString(my_additions) myStringWithCString:]"
122         //  names[0] => "+[NSString(my_additions) myStringWithCString:]"
123         //  names[1] => "-[NSString(my_additions) myStringWithCString:]"
124         //  names[2] => "+[NSString myStringWithCString:]"
125         //  names[3] => "-[NSString myStringWithCString:]"
126         size_t
127         GetFullNames (std::vector<ConstString> &names, bool append);
128     protected:
129         ConstString m_full;     // Full name:   "+[NSString(my_additions) myStringWithCString:]"
130         ConstString m_class;    // Class name:  "NSString"
131         ConstString m_class_category; // Class with category: "NSString(my_additions)"
132         ConstString m_category; // Category:    "my_additions"
133         ConstString m_selector; // Selector:    "myStringWithCString:"
134         Type m_type;
135         bool m_category_is_valid;
136 
137     };
138     typedef lldb::addr_t ObjCISA;
139 
140     class ClassDescriptor;
141     typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
142 
143     // the information that we want to support retrieving from an ObjC class
144     // this needs to be pure virtual since there are at least 2 different implementations
145     // of the runtime, and more might come
146     class ClassDescriptor
147     {
148     public:
149 
ClassDescriptor()150         ClassDescriptor() :
151             m_is_kvo (eLazyBoolCalculate),
152             m_is_cf (eLazyBoolCalculate),
153             m_type_wp ()
154         {
155         }
156 
157         virtual
~ClassDescriptor()158         ~ClassDescriptor ()
159         {
160         }
161 
162         virtual ConstString
163         GetClassName () = 0;
164 
165         virtual ClassDescriptorSP
166         GetSuperclass () = 0;
167 
168         // virtual if any implementation has some other version-specific rules
169         // but for the known v1/v2 this is all that needs to be done
170         virtual bool
IsKVO()171         IsKVO ()
172         {
173             if (m_is_kvo == eLazyBoolCalculate)
174             {
175                 const char* class_name = GetClassName().AsCString();
176                 if (class_name && *class_name)
177                     m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name);
178             }
179             return (m_is_kvo == eLazyBoolYes);
180         }
181 
182         // virtual if any implementation has some other version-specific rules
183         // but for the known v1/v2 this is all that needs to be done
184         virtual bool
IsCFType()185         IsCFType ()
186         {
187             if (m_is_cf == eLazyBoolCalculate)
188             {
189                 const char* class_name = GetClassName().AsCString();
190                 if (class_name && *class_name)
191                     m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 ||
192                                          strcmp(class_name,"NSCFType") == 0);
193             }
194             return (m_is_cf == eLazyBoolYes);
195         }
196 
197         virtual bool
198         IsValid () = 0;
199 
200         virtual bool
201         GetTaggedPointerInfo (uint64_t* info_bits = NULL,
202                               uint64_t* value_bits = NULL,
203                               uint64_t* payload = NULL) = 0;
204 
205         virtual uint64_t
206         GetInstanceSize () = 0;
207 
208         // use to implement version-specific additional constraints on pointers
209         virtual bool
CheckPointer(lldb::addr_t value,uint32_t ptr_size)210         CheckPointer (lldb::addr_t value,
211                       uint32_t ptr_size) const
212         {
213             return true;
214         }
215 
216         virtual ObjCISA
217         GetISA () = 0;
218 
219         // This should return true iff the interface could be completed
220         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)221         Describe (std::function <void (ObjCISA)> const &superclass_func,
222                   std::function <bool (const char*, const char*)> const &instance_method_func,
223                   std::function <bool (const char*, const char*)> const &class_method_func,
224                   std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func)
225         {
226             return false;
227         }
228 
229         lldb::TypeSP
GetType()230         GetType ()
231         {
232             return m_type_wp.lock();
233         }
234 
235         void
SetType(const lldb::TypeSP & type_sp)236         SetType (const lldb::TypeSP &type_sp)
237         {
238             m_type_wp = type_sp;
239         }
240 
241     protected:
242         bool
243         IsPointerValid (lldb::addr_t value,
244                         uint32_t ptr_size,
245                         bool allow_NULLs = false,
246                         bool allow_tagged = false,
247                         bool check_version_specific = false) const;
248 
249     private:
250         LazyBool m_is_kvo;
251         LazyBool m_is_cf;
252         lldb::TypeWP m_type_wp;
253     };
254 
255     virtual ClassDescriptorSP
256     GetClassDescriptor (ValueObject& in_value);
257 
258     ClassDescriptorSP
259     GetNonKVOClassDescriptor (ValueObject& in_value);
260 
261     virtual ClassDescriptorSP
262     GetClassDescriptorFromClassName (const ConstString &class_name);
263 
264     virtual ClassDescriptorSP
265     GetClassDescriptorFromISA (ObjCISA isa);
266 
267     ClassDescriptorSP
268     GetNonKVOClassDescriptor (ObjCISA isa);
269 
270     virtual
271     ~ObjCLanguageRuntime();
272 
273     virtual lldb::LanguageType
GetLanguageType()274     GetLanguageType () const
275     {
276         return lldb::eLanguageTypeObjC;
277     }
278 
279     virtual bool
280     IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
281 
282     virtual bool
283     ReadObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
284 
285     virtual bool
286     HasReadObjCLibrary () = 0;
287 
288     virtual lldb::ThreadPlanSP
289     GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
290 
291     lldb::addr_t
292     LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel);
293 
294     void
295     AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
296 
297     TypeAndOrName
298     LookupInClassNameCache (lldb::addr_t class_addr);
299 
300     void
301     AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp);
302 
303     void
304     AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
305 
306     lldb::TypeSP
307     LookupInCompleteClassCache (ConstString &name);
308 
309     virtual ClangUtilityFunction *
310     CreateObjectChecker (const char *) = 0;
311 
312     virtual ObjCRuntimeVersions
GetRuntimeVersion()313     GetRuntimeVersion ()
314     {
315         return eObjC_VersionUnknown;
316     }
317 
318     bool
IsValidISA(ObjCISA isa)319     IsValidISA(ObjCISA isa)
320     {
321         UpdateISAToDescriptorMap();
322         return m_isa_to_descriptor.count(isa) > 0;
323     }
324 
325     virtual void
326     UpdateISAToDescriptorMapIfNeeded() = 0;
327 
328     void
UpdateISAToDescriptorMap()329     UpdateISAToDescriptorMap()
330     {
331         if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id)
332         {
333             UpdateISAToDescriptorMapIfNeeded ();
334         }
335     }
336 
337     virtual ObjCISA
338     GetISA(const ConstString &name);
339 
340     virtual ConstString
341     GetActualTypeName(ObjCISA isa);
342 
343     virtual ObjCISA
344     GetParentClass(ObjCISA isa);
345 
346     virtual TypeVendor *
GetTypeVendor()347     GetTypeVendor()
348     {
349         return NULL;
350     }
351 
352     // Finds the byte offset of the child_type ivar in parent_type.  If it can't find the
353     // offset, returns LLDB_INVALID_IVAR_OFFSET.
354 
355     virtual size_t
356     GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name);
357 
358     // Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol),
359     // try to determine from the runtime what the value of that symbol would be.
360     // Useful when the underlying binary is stripped.
361     virtual lldb::addr_t
LookupRuntimeSymbol(const ConstString & name)362     LookupRuntimeSymbol (const ConstString &name)
363     {
364         return LLDB_INVALID_ADDRESS;
365     }
366 
367     //------------------------------------------------------------------
368     /// Chop up an objective C function prototype.
369     ///
370     /// Chop up an objective C function fullname and optionally fill in
371     /// any non-NULL ConstString objects. If a ConstString * is NULL,
372     /// then this name doesn't get filled in
373     ///
374     /// @param[in] name
375     ///     A fully specified objective C function name. The string might
376     ///     contain a category and it includes the leading "+" or "-" and
377     ///     the square brackets, no types for the arguments, just the plain
378     ///     selector. A few examples:
379     ///         "-[NSStringDrawingContext init]"
380     ///         "-[NSStringDrawingContext addString:inRect:]"
381     ///         "-[NSString(NSStringDrawing) sizeWithAttributes:]"
382     ///         "+[NSString(NSStringDrawing) usesFontLeading]"
383     ///
384     /// @param[out] class_name
385     ///     If non-NULL, this string will be filled in with the class
386     ///     name including the category. The examples above would return:
387     ///         "NSStringDrawingContext"
388     ///         "NSStringDrawingContext"
389     ///         "NSString(NSStringDrawing)"
390     ///         "NSString(NSStringDrawing)"
391     ///
392     /// @param[out] selector_name
393     ///     If non-NULL, this string will be filled in with the selector
394     ///     name. The examples above would return:
395     ///         "init"
396     ///         "addString:inRect:"
397     ///         "sizeWithAttributes:"
398     ///         "usesFontLeading"
399     ///
400     /// @param[out] name_sans_category
401     ///     If non-NULL, this string will be filled in with the class
402     ///     name _without_ the category. If there is no category, and empty
403     ///     string will be returned (as the result would be normally returned
404     ///     in the "class_name" argument). The examples above would return:
405     ///         <empty>
406     ///         <empty>
407     ///         "-[NSString sizeWithAttributes:]"
408     ///         "+[NSString usesFontLeading]"
409     ///
410     /// @param[out] class_name_sans_category
411     ///     If non-NULL, this string will be filled in with the prototype
412     ///     name _without_ the category. If there is no category, and empty
413     ///     string will be returned (as this is already the value that was
414     ///     passed in). The examples above would return:
415     ///         <empty>
416     ///         <empty>
417     ///         "NSString"
418     ///         "NSString"
419     ///
420     /// @return
421     ///     Returns the number of strings that were successfully filled
422     ///     in.
423     //------------------------------------------------------------------
424 //    static uint32_t
425 //    ParseMethodName (const char *name,
426 //                     ConstString *class_name,               // Class name (with category if there is one)
427 //                     ConstString *selector_name,            // selector only
428 //                     ConstString *name_sans_category,       // full function name with no category (empty if no category)
429 //                     ConstString *class_name_sans_category);// Class name without category (empty if no category)
430 
431     static bool
IsPossibleObjCMethodName(const char * name)432     IsPossibleObjCMethodName (const char *name)
433     {
434         if (!name)
435             return false;
436         bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
437         bool ends_right = (name[strlen(name) - 1] == ']');
438         return (starts_right && ends_right);
439     }
440 
441     static bool
IsPossibleObjCSelector(const char * name)442     IsPossibleObjCSelector (const char *name)
443     {
444         if (!name)
445             return false;
446 
447         if (strchr(name, ':') == NULL)
448             return true;
449         else if (name[strlen(name) - 1] == ':')
450             return true;
451         else
452             return false;
453     }
454 
455     bool
HasNewLiteralsAndIndexing()456     HasNewLiteralsAndIndexing ()
457     {
458         if (m_has_new_literals_and_indexing == eLazyBoolCalculate)
459         {
460             if (CalculateHasNewLiteralsAndIndexing())
461                 m_has_new_literals_and_indexing = eLazyBoolYes;
462             else
463                 m_has_new_literals_and_indexing = eLazyBoolNo;
464         }
465 
466         return (m_has_new_literals_and_indexing == eLazyBoolYes);
467     }
468 
469     virtual void
SymbolsDidLoad(const ModuleList & module_list)470     SymbolsDidLoad (const ModuleList& module_list)
471     {
472         m_negative_complete_class_cache.clear();
473     }
474 
475 protected:
476     //------------------------------------------------------------------
477     // Classes that inherit from ObjCLanguageRuntime can see and modify these
478     //------------------------------------------------------------------
479     ObjCLanguageRuntime(Process *process);
480 
CalculateHasNewLiteralsAndIndexing()481     virtual bool CalculateHasNewLiteralsAndIndexing()
482     {
483         return false;
484     }
485 
486 
487     bool
ISAIsCached(ObjCISA isa)488     ISAIsCached (ObjCISA isa) const
489     {
490         return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
491     }
492 
493     bool
AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp)494     AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
495     {
496         if (isa != 0)
497         {
498             m_isa_to_descriptor[isa] = descriptor_sp;
499             return true;
500         }
501         return false;
502     }
503 
504     bool
505     AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name);
506 
507     bool
AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,uint32_t class_name_hash)508     AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
509     {
510         if (isa != 0)
511         {
512             m_isa_to_descriptor[isa] = descriptor_sp;
513             m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
514             return true;
515         }
516         return false;
517     }
518 
519 private:
520     // We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
521     // function over and over.
522 
523     // FIXME: We need to watch for the loading of Protocols, and flush the cache for any
524     // class that we see so changed.
525 
526     struct ClassAndSel
527     {
ClassAndSelClassAndSel528         ClassAndSel()
529         {
530             sel_addr = LLDB_INVALID_ADDRESS;
531             class_addr = LLDB_INVALID_ADDRESS;
532         }
ClassAndSelClassAndSel533         ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) :
534             class_addr (in_class_addr),
535             sel_addr(in_sel_addr)
536         {
537         }
538         bool operator== (const ClassAndSel &rhs)
539         {
540             if (class_addr == rhs.class_addr
541                 && sel_addr == rhs.sel_addr)
542                 return true;
543             else
544                 return false;
545         }
546 
547         bool operator< (const ClassAndSel &rhs) const
548         {
549             if (class_addr < rhs.class_addr)
550                 return true;
551             else if (class_addr > rhs.class_addr)
552                 return false;
553             else
554             {
555                 if (sel_addr < rhs.sel_addr)
556                     return true;
557                 else
558                     return false;
559             }
560         }
561 
562         lldb::addr_t class_addr;
563         lldb::addr_t sel_addr;
564     };
565 
566     typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
567     typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
568     typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
569     typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
570     typedef HashToISAMap::iterator HashToISAIterator;
571 
572     MsgImplMap m_impl_cache;
573     LazyBool m_has_new_literals_and_indexing;
574     ISAToDescriptorMap m_isa_to_descriptor;
575     HashToISAMap m_hash_to_isa_map;
576 
577 protected:
578     uint32_t m_isa_to_descriptor_stop_id;
579 
580     typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
581     CompleteClassMap m_complete_class_cache;
582 
583     struct ConstStringSetHelpers {
operatorConstStringSetHelpers584         size_t operator () (const ConstString& arg) const // for hashing
585         {
586             return (size_t)arg.GetCString();
587         }
operatorConstStringSetHelpers588         bool operator () (const ConstString& arg1, const ConstString& arg2) const // for equality
589         {
590             return arg1.operator==(arg2);
591         }
592     };
593     typedef std::unordered_set<ConstString, ConstStringSetHelpers, ConstStringSetHelpers> CompleteClassSet;
594     CompleteClassSet m_negative_complete_class_cache;
595 
596     ISAToDescriptorIterator
597     GetDescriptorIterator (const ConstString &name);
598 
599     DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
600 };
601 
602 } // namespace lldb_private
603 
604 #endif  // liblldb_ObjCLanguageRuntime_h_
605