1 //===-- ObjCLanguageRuntime.cpp ---------------------------------*- 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 #include "clang/AST/Type.h"
10 
11 #include "lldb/Core/Log.h"
12 #include "lldb/Core/MappedHash.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/PluginManager.h"
15 #include "lldb/Core/Timer.h"
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Symbol/ClangASTContext.h"
18 #include "lldb/Symbol/Type.h"
19 #include "lldb/Symbol/TypeList.h"
20 #include "lldb/Target/ObjCLanguageRuntime.h"
21 #include "lldb/Target/Target.h"
22 
23 #include "llvm/ADT/StringRef.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 //----------------------------------------------------------------------
29 // Destructor
30 //----------------------------------------------------------------------
~ObjCLanguageRuntime()31 ObjCLanguageRuntime::~ObjCLanguageRuntime()
32 {
33 }
34 
ObjCLanguageRuntime(Process * process)35 ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
36     LanguageRuntime (process),
37     m_has_new_literals_and_indexing (eLazyBoolCalculate),
38     m_isa_to_descriptor(),
39     m_isa_to_descriptor_stop_id (UINT32_MAX)
40 {
41 
42 }
43 
44 bool
AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,const char * class_name)45 ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
46 {
47     if (isa != 0)
48     {
49         m_isa_to_descriptor[isa] = descriptor_sp;
50         // class_name is assumed to be valid
51         m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
52         return true;
53     }
54     return false;
55 }
56 
57 void
AddToMethodCache(lldb::addr_t class_addr,lldb::addr_t selector,lldb::addr_t impl_addr)58 ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
59 {
60     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
61     if (log)
62     {
63         log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
64     }
65     m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
66 }
67 
68 lldb::addr_t
LookupInMethodCache(lldb::addr_t class_addr,lldb::addr_t selector)69 ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
70 {
71     MsgImplMap::iterator pos, end = m_impl_cache.end();
72     pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
73     if (pos != end)
74         return (*pos).second;
75     return LLDB_INVALID_ADDRESS;
76 }
77 
78 
79 lldb::TypeSP
LookupInCompleteClassCache(ConstString & name)80 ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
81 {
82     CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
83 
84     if (complete_class_iter != m_complete_class_cache.end())
85     {
86         // Check the weak pointer to make sure the type hasn't been unloaded
87         TypeSP complete_type_sp (complete_class_iter->second.lock());
88 
89         if (complete_type_sp)
90             return complete_type_sp;
91         else
92             m_complete_class_cache.erase(name);
93     }
94 
95     if (m_negative_complete_class_cache.count(name) > 0)
96         return TypeSP();
97 
98     const ModuleList &modules = m_process->GetTarget().GetImages();
99 
100     SymbolContextList sc_list;
101     const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
102                                                                         eSymbolTypeObjCClass,
103                                                                         sc_list);
104 
105     if (matching_symbols)
106     {
107         SymbolContext sc;
108 
109         sc_list.GetContextAtIndex(0, sc);
110 
111         ModuleSP module_sp(sc.module_sp);
112 
113         if (!module_sp)
114             return TypeSP();
115 
116         const SymbolContext null_sc;
117         const bool exact_match = true;
118         const uint32_t max_matches = UINT32_MAX;
119         TypeList types;
120 
121         const uint32_t num_types = module_sp->FindTypes (null_sc,
122                                                          name,
123                                                          exact_match,
124                                                          max_matches,
125                                                          types);
126 
127         if (num_types)
128         {
129             uint32_t i;
130             for (i = 0; i < num_types; ++i)
131             {
132                 TypeSP type_sp (types.GetTypeAtIndex(i));
133 
134                 if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType())
135                 {
136                     if (type_sp->IsCompleteObjCClass())
137                     {
138                         m_complete_class_cache[name] = type_sp;
139                         return type_sp;
140                     }
141                 }
142             }
143         }
144     }
145     m_negative_complete_class_cache.insert(name);
146     return TypeSP();
147 }
148 
149 size_t
GetByteOffsetForIvar(ClangASTType & parent_qual_type,const char * ivar_name)150 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
151 {
152     return LLDB_INVALID_IVAR_OFFSET;
153 }
154 
155 void
Clear()156 ObjCLanguageRuntime::MethodName::Clear()
157 {
158     m_full.Clear();
159     m_class.Clear();
160     m_category.Clear();
161     m_selector.Clear();
162     m_type = eTypeUnspecified;
163     m_category_is_valid = false;
164 }
165 
166 //bool
167 //ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
168 //{
169 //    Clear();
170 //    if (name && name[0])
171 //    {
172 //        // If "strict" is true. then the method must be specified with a
173 //        // '+' or '-' at the beginning. If "strict" is false, then the '+'
174 //        // or '-' can be omitted
175 //        bool valid_prefix = false;
176 //
177 //        if (name[0] == '+' || name[0] == '-')
178 //        {
179 //            valid_prefix = name[1] == '[';
180 //        }
181 //        else if (!strict)
182 //        {
183 //            // "strict" is false, the name just needs to start with '['
184 //            valid_prefix = name[0] == '[';
185 //        }
186 //
187 //        if (valid_prefix)
188 //        {
189 //            static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$");
190 //            llvm::StringRef matches[4];
191 //            // Since we are using a global regular expression, we must use the threadsafe version of execute
192 //            if (g_regex.ExecuteThreadSafe(name, matches, 4))
193 //            {
194 //                m_full.SetCString(name);
195 //                if (matches[0].empty())
196 //                    m_type = eTypeUnspecified;
197 //                else if (matches[0][0] == '+')
198 //                    m_type = eTypeClassMethod;
199 //                else
200 //                    m_type = eTypeInstanceMethod;
201 //                m_class.SetString(matches[1]);
202 //                m_selector.SetString(matches[3]);
203 //                if (!matches[2].empty())
204 //                    m_category.SetString(matches[2]);
205 //            }
206 //        }
207 //    }
208 //    return IsValid(strict);
209 //}
210 
211 bool
SetName(const char * name,bool strict)212 ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
213 {
214     Clear();
215     if (name && name[0])
216     {
217         // If "strict" is true. then the method must be specified with a
218         // '+' or '-' at the beginning. If "strict" is false, then the '+'
219         // or '-' can be omitted
220         bool valid_prefix = false;
221 
222         if (name[0] == '+' || name[0] == '-')
223         {
224             valid_prefix = name[1] == '[';
225             if (name[0] == '+')
226                 m_type = eTypeClassMethod;
227             else
228                 m_type = eTypeInstanceMethod;
229         }
230         else if (!strict)
231         {
232             // "strict" is false, the name just needs to start with '['
233             valid_prefix = name[0] == '[';
234         }
235 
236         if (valid_prefix)
237         {
238             int name_len = strlen (name);
239             // Objective C methods must have at least:
240             //      "-[" or "+[" prefix
241             //      One character for a class name
242             //      One character for the space between the class name
243             //      One character for the method name
244             //      "]" suffix
245             if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']')
246             {
247                 m_full.SetCStringWithLength(name, name_len);
248             }
249         }
250     }
251     return IsValid(strict);
252 }
253 
254 const ConstString &
GetClassName()255 ObjCLanguageRuntime::MethodName::GetClassName ()
256 {
257     if (!m_class)
258     {
259         if (IsValid(false))
260         {
261             const char *full = m_full.GetCString();
262             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
263             const char *paren_pos = strchr (class_start, '(');
264             if (paren_pos)
265             {
266                 m_class.SetCStringWithLength (class_start, paren_pos - class_start);
267             }
268             else
269             {
270                 // No '(' was found in the full name, we can definitively say
271                 // that our category was valid (and empty).
272                 m_category_is_valid = true;
273                 const char *space_pos = strchr (full, ' ');
274                 if (space_pos)
275                 {
276                     m_class.SetCStringWithLength (class_start, space_pos - class_start);
277                     if (!m_class_category)
278                     {
279                         // No category in name, so we can also fill in the m_class_category
280                         m_class_category = m_class;
281                     }
282                 }
283             }
284         }
285     }
286     return m_class;
287 }
288 
289 const ConstString &
GetClassNameWithCategory()290 ObjCLanguageRuntime::MethodName::GetClassNameWithCategory ()
291 {
292     if (!m_class_category)
293     {
294         if (IsValid(false))
295         {
296             const char *full = m_full.GetCString();
297             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
298             const char *space_pos = strchr (full, ' ');
299             if (space_pos)
300             {
301                 m_class_category.SetCStringWithLength (class_start, space_pos - class_start);
302                 // If m_class hasn't been filled in and the class with category doesn't
303                 // contain a '(', then we can also fill in the m_class
304                 if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL)
305                 {
306                     m_class = m_class_category;
307                     // No '(' was found in the full name, we can definitively say
308                     // that our category was valid (and empty).
309                     m_category_is_valid = true;
310 
311                 }
312             }
313         }
314     }
315     return m_class_category;
316 }
317 
318 const ConstString &
GetSelector()319 ObjCLanguageRuntime::MethodName::GetSelector ()
320 {
321     if (!m_selector)
322     {
323         if (IsValid(false))
324         {
325             const char *full = m_full.GetCString();
326             const char *space_pos = strchr (full, ' ');
327             if (space_pos)
328             {
329                 ++space_pos; // skip the space
330                 m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1);
331             }
332         }
333     }
334     return m_selector;
335 }
336 
337 const ConstString &
GetCategory()338 ObjCLanguageRuntime::MethodName::GetCategory ()
339 {
340     if (!m_category_is_valid && !m_category)
341     {
342         if (IsValid(false))
343         {
344             m_category_is_valid = true;
345             const char *full = m_full.GetCString();
346             const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
347             const char *open_paren_pos = strchr (class_start, '(');
348             if (open_paren_pos)
349             {
350                 ++open_paren_pos; // Skip the open paren
351                 const char *close_paren_pos = strchr (open_paren_pos, ')');
352                 if (close_paren_pos)
353                     m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos);
354             }
355         }
356     }
357     return m_category;
358 }
359 
360 ConstString
GetFullNameWithoutCategory(bool empty_if_no_category)361 ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category)
362 {
363     if (IsValid(false))
364     {
365         if (HasCategory())
366         {
367             StreamString strm;
368             if (m_type == eTypeClassMethod)
369                 strm.PutChar('+');
370             else if (m_type == eTypeInstanceMethod)
371                 strm.PutChar('-');
372             strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString());
373             return ConstString(strm.GetString().c_str());
374         }
375 
376         if (!empty_if_no_category)
377         {
378             // Just return the full name since it doesn't have a category
379             return GetFullName();
380         }
381     }
382     return ConstString();
383 }
384 
385 size_t
GetFullNames(std::vector<ConstString> & names,bool append)386 ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append)
387 {
388     if (!append)
389         names.clear();
390     if (IsValid(false))
391     {
392         StreamString strm;
393         const bool is_class_method = m_type == eTypeClassMethod;
394         const bool is_instance_method = m_type == eTypeInstanceMethod;
395         const ConstString &category = GetCategory();
396         if (is_class_method || is_instance_method)
397         {
398             names.push_back (m_full);
399             if (category)
400             {
401                 strm.Printf("%c[%s %s]",
402                             is_class_method ? '+' : '-',
403                             GetClassName().GetCString(),
404                             GetSelector().GetCString());
405                 names.push_back(ConstString(strm.GetString().c_str()));
406             }
407         }
408         else
409         {
410             const ConstString &class_name = GetClassName();
411             const ConstString &selector = GetSelector();
412             strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString());
413             names.push_back(ConstString(strm.GetString().c_str()));
414             strm.Clear();
415             strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString());
416             names.push_back(ConstString(strm.GetString().c_str()));
417             strm.Clear();
418             if (category)
419             {
420                 strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
421                 names.push_back(ConstString(strm.GetString().c_str()));
422                 strm.Clear();
423                 strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
424                 names.push_back(ConstString(strm.GetString().c_str()));
425             }
426         }
427     }
428     return names.size();
429 }
430 
431 
432 bool
IsPointerValid(lldb::addr_t value,uint32_t ptr_size,bool allow_NULLs,bool allow_tagged,bool check_version_specific) const433 ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
434                                                       uint32_t ptr_size,
435                                                       bool allow_NULLs,
436                                                       bool allow_tagged,
437                                                       bool check_version_specific) const
438 {
439     if (!value)
440         return allow_NULLs;
441     if ( (value % 2) == 1  && allow_tagged)
442         return true;
443     if ((value % ptr_size) == 0)
444         return (check_version_specific ? CheckPointer(value,ptr_size) : true);
445     else
446         return false;
447 }
448 
449 ObjCLanguageRuntime::ObjCISA
GetISA(const ConstString & name)450 ObjCLanguageRuntime::GetISA(const ConstString &name)
451 {
452     ISAToDescriptorIterator pos = GetDescriptorIterator (name);
453     if (pos != m_isa_to_descriptor.end())
454         return pos->first;
455     return 0;
456 }
457 
458 ObjCLanguageRuntime::ISAToDescriptorIterator
GetDescriptorIterator(const ConstString & name)459 ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
460 {
461     ISAToDescriptorIterator end = m_isa_to_descriptor.end();
462 
463     if (name)
464     {
465         UpdateISAToDescriptorMap();
466         if (m_hash_to_isa_map.empty())
467         {
468             // No name hashes were provided, we need to just linearly power through the
469             // names and find a match
470             for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
471             {
472                 if (pos->second->GetClassName() == name)
473                     return pos;
474             }
475         }
476         else
477         {
478             // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
479             const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
480             std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
481             for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
482             {
483                 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
484                 if (pos != m_isa_to_descriptor.end())
485                 {
486                     if (pos->second->GetClassName() == name)
487                         return pos;
488                 }
489             }
490         }
491     }
492     return end;
493 }
494 
495 
496 ObjCLanguageRuntime::ObjCISA
GetParentClass(ObjCLanguageRuntime::ObjCISA isa)497 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
498 {
499     ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa));
500     if (objc_class_sp)
501     {
502         ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
503         if (objc_super_class_sp)
504             return objc_super_class_sp->GetISA();
505     }
506     return 0;
507 }
508 
509 ConstString
GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)510 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
511 {
512     ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
513     if (objc_class_sp)
514         return objc_class_sp->GetClassName();
515     return ConstString();
516 }
517 
518 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptorFromClassName(const ConstString & class_name)519 ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name)
520 {
521     ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
522     if (pos != m_isa_to_descriptor.end())
523         return pos->second;
524     return ClassDescriptorSP();
525 
526 }
527 
528 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ValueObject & valobj)529 ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
530 {
531     ClassDescriptorSP objc_class_sp;
532     // if we get an invalid VO (which might still happen when playing around
533     // with pointers returned by the expression parser, don't consider this
534     // a valid ObjC object)
535     if (valobj.GetClangType().IsValid())
536     {
537         addr_t isa_pointer = valobj.GetPointerValue();
538         if (isa_pointer != LLDB_INVALID_ADDRESS)
539         {
540             ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
541 
542             Process *process = exe_ctx.GetProcessPtr();
543             if (process)
544             {
545                 Error error;
546                 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
547                 if (isa != LLDB_INVALID_ADDRESS)
548                     objc_class_sp = GetClassDescriptorFromISA (isa);
549             }
550         }
551     }
552     return objc_class_sp;
553 }
554 
555 ObjCLanguageRuntime::ClassDescriptorSP
GetNonKVOClassDescriptor(ValueObject & valobj)556 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
557 {
558     ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
559     if (objc_class_sp)
560     {
561         if (!objc_class_sp->IsKVO())
562             return objc_class_sp;
563 
564         ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
565         if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
566             return non_kvo_objc_class_sp;
567     }
568     return ClassDescriptorSP();
569 }
570 
571 
572 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptorFromISA(ObjCISA isa)573 ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa)
574 {
575     if (isa)
576     {
577         UpdateISAToDescriptorMap();
578         ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
579         if (pos != m_isa_to_descriptor.end())
580             return pos->second;
581     }
582     return ClassDescriptorSP();
583 }
584 
585 ObjCLanguageRuntime::ClassDescriptorSP
GetNonKVOClassDescriptor(ObjCISA isa)586 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
587 {
588     if (isa)
589     {
590         ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa);
591         if (objc_class_sp && objc_class_sp->IsValid())
592         {
593             if (!objc_class_sp->IsKVO())
594                 return objc_class_sp;
595 
596             ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
597             if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
598                 return non_kvo_objc_class_sp;
599         }
600     }
601     return ClassDescriptorSP();
602 }
603 
604 
605 
606