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/SymbolContext.h"
19 #include "lldb/Symbol/Type.h"
20 #include "lldb/Symbol/TypeList.h"
21 #include "lldb/Target/ObjCLanguageRuntime.h"
22 #include "lldb/Target/Target.h"
23 
24 #include "llvm/ADT/StringRef.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // Destructor
31 //----------------------------------------------------------------------
32 ObjCLanguageRuntime::~ObjCLanguageRuntime()
33 {
34 }
35 
36 ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
37     LanguageRuntime (process),
38     m_impl_cache(),
39     m_has_new_literals_and_indexing (eLazyBoolCalculate),
40     m_isa_to_descriptor(),
41     m_hash_to_isa_map(),
42     m_type_size_cache(),
43     m_isa_to_descriptor_stop_id (UINT32_MAX),
44     m_complete_class_cache(),
45     m_negative_complete_class_cache()
46 {
47 }
48 
49 bool
50 ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
51 {
52     if (isa != 0)
53     {
54         m_isa_to_descriptor[isa] = descriptor_sp;
55         // class_name is assumed to be valid
56         m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
57         return true;
58     }
59     return false;
60 }
61 
62 void
63 ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
64 {
65     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
66     if (log)
67     {
68         log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
69     }
70     m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
71 }
72 
73 lldb::addr_t
74 ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
75 {
76     MsgImplMap::iterator pos, end = m_impl_cache.end();
77     pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
78     if (pos != end)
79         return (*pos).second;
80     return LLDB_INVALID_ADDRESS;
81 }
82 
83 
84 lldb::TypeSP
85 ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
86 {
87     CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
88 
89     if (complete_class_iter != m_complete_class_cache.end())
90     {
91         // Check the weak pointer to make sure the type hasn't been unloaded
92         TypeSP complete_type_sp (complete_class_iter->second.lock());
93 
94         if (complete_type_sp)
95             return complete_type_sp;
96         else
97             m_complete_class_cache.erase(name);
98     }
99 
100     if (m_negative_complete_class_cache.count(name) > 0)
101         return TypeSP();
102 
103     const ModuleList &modules = m_process->GetTarget().GetImages();
104 
105     SymbolContextList sc_list;
106     const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
107                                                                         eSymbolTypeObjCClass,
108                                                                         sc_list);
109 
110     if (matching_symbols)
111     {
112         SymbolContext sc;
113 
114         sc_list.GetContextAtIndex(0, sc);
115 
116         ModuleSP module_sp(sc.module_sp);
117 
118         if (!module_sp)
119             return TypeSP();
120 
121         const SymbolContext null_sc;
122         const bool exact_match = true;
123         const uint32_t max_matches = UINT32_MAX;
124         TypeList types;
125 
126         const uint32_t num_types = module_sp->FindTypes (null_sc,
127                                                          name,
128                                                          exact_match,
129                                                          max_matches,
130                                                          types);
131 
132         if (num_types)
133         {
134             uint32_t i;
135             for (i = 0; i < num_types; ++i)
136             {
137                 TypeSP type_sp (types.GetTypeAtIndex(i));
138 
139                 if (ClangASTContext::IsObjCObjectOrInterfaceType(type_sp->GetForwardCompilerType ()))
140                 {
141                     if (type_sp->IsCompleteObjCClass())
142                     {
143                         m_complete_class_cache[name] = type_sp;
144                         return type_sp;
145                     }
146                 }
147             }
148         }
149     }
150     m_negative_complete_class_cache.insert(name);
151     return TypeSP();
152 }
153 
154 size_t
155 ObjCLanguageRuntime::GetByteOffsetForIvar (CompilerType &parent_qual_type, const char *ivar_name)
156 {
157     return LLDB_INVALID_IVAR_OFFSET;
158 }
159 
160 bool
161 ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
162                                                       uint32_t ptr_size,
163                                                       bool allow_NULLs,
164                                                       bool allow_tagged,
165                                                       bool check_version_specific) const
166 {
167     if (!value)
168         return allow_NULLs;
169     if ( (value % 2) == 1  && allow_tagged)
170         return true;
171     if ((value % ptr_size) == 0)
172         return (check_version_specific ? CheckPointer(value,ptr_size) : true);
173     else
174         return false;
175 }
176 
177 ObjCLanguageRuntime::ObjCISA
178 ObjCLanguageRuntime::GetISA(const ConstString &name)
179 {
180     ISAToDescriptorIterator pos = GetDescriptorIterator (name);
181     if (pos != m_isa_to_descriptor.end())
182         return pos->first;
183     return 0;
184 }
185 
186 ObjCLanguageRuntime::ISAToDescriptorIterator
187 ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
188 {
189     ISAToDescriptorIterator end = m_isa_to_descriptor.end();
190 
191     if (name)
192     {
193         UpdateISAToDescriptorMap();
194         if (m_hash_to_isa_map.empty())
195         {
196             // No name hashes were provided, we need to just linearly power through the
197             // names and find a match
198             for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
199             {
200                 if (pos->second->GetClassName() == name)
201                     return pos;
202             }
203         }
204         else
205         {
206             // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
207             const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
208             std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
209             for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
210             {
211                 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
212                 if (pos != m_isa_to_descriptor.end())
213                 {
214                     if (pos->second->GetClassName() == name)
215                         return pos;
216                 }
217             }
218         }
219     }
220     return end;
221 }
222 
223 std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,ObjCLanguageRuntime::ISAToDescriptorIterator>
224 ObjCLanguageRuntime::GetDescriptorIteratorPair (bool update_if_needed)
225 {
226     if (update_if_needed)
227         UpdateISAToDescriptorMapIfNeeded();
228 
229     return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
230                      ObjCLanguageRuntime::ISAToDescriptorIterator>(
231                         m_isa_to_descriptor.begin(),
232                         m_isa_to_descriptor.end());
233 }
234 
235 
236 ObjCLanguageRuntime::ObjCISA
237 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
238 {
239     ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa));
240     if (objc_class_sp)
241     {
242         ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
243         if (objc_super_class_sp)
244             return objc_super_class_sp->GetISA();
245     }
246     return 0;
247 }
248 
249 ConstString
250 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
251 {
252     ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
253     if (objc_class_sp)
254         return objc_class_sp->GetClassName();
255     return ConstString();
256 }
257 
258 ObjCLanguageRuntime::ClassDescriptorSP
259 ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name)
260 {
261     ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
262     if (pos != m_isa_to_descriptor.end())
263         return pos->second;
264     return ClassDescriptorSP();
265 
266 }
267 
268 ObjCLanguageRuntime::ClassDescriptorSP
269 ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
270 {
271     ClassDescriptorSP objc_class_sp;
272     // if we get an invalid VO (which might still happen when playing around
273     // with pointers returned by the expression parser, don't consider this
274     // a valid ObjC object)
275     if (valobj.GetCompilerType().IsValid())
276     {
277         addr_t isa_pointer = valobj.GetPointerValue();
278         if (isa_pointer != LLDB_INVALID_ADDRESS)
279         {
280             ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
281 
282             Process *process = exe_ctx.GetProcessPtr();
283             if (process)
284             {
285                 Error error;
286                 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
287                 if (isa != LLDB_INVALID_ADDRESS)
288                     objc_class_sp = GetClassDescriptorFromISA (isa);
289             }
290         }
291     }
292     return objc_class_sp;
293 }
294 
295 ObjCLanguageRuntime::ClassDescriptorSP
296 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
297 {
298     ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
299     if (objc_class_sp)
300     {
301         if (!objc_class_sp->IsKVO())
302             return objc_class_sp;
303 
304         ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
305         if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
306             return non_kvo_objc_class_sp;
307     }
308     return ClassDescriptorSP();
309 }
310 
311 
312 ObjCLanguageRuntime::ClassDescriptorSP
313 ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa)
314 {
315     if (isa)
316     {
317         UpdateISAToDescriptorMap();
318         ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
319         if (pos != m_isa_to_descriptor.end())
320             return pos->second;
321     }
322     return ClassDescriptorSP();
323 }
324 
325 ObjCLanguageRuntime::ClassDescriptorSP
326 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
327 {
328     if (isa)
329     {
330         ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa);
331         if (objc_class_sp && objc_class_sp->IsValid())
332         {
333             if (!objc_class_sp->IsKVO())
334                 return objc_class_sp;
335 
336             ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
337             if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
338                 return non_kvo_objc_class_sp;
339         }
340     }
341     return ClassDescriptorSP();
342 }
343 
344 
345 CompilerType
346 ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool for_expression)
347 {
348     if (m_scratch_ast_ctx_ap)
349         return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression);
350     return CompilerType();
351 }
352 
353 CompilerType
354 ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression)
355 {
356     clang::ASTContext *clang_ast = ast_ctx.getASTContext();
357     if (!clang_ast)
358         return CompilerType();
359     return RealizeType(*clang_ast, name, for_expression);
360 }
361 
362 ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
363 
364 ObjCLanguageRuntime::EncodingToTypeSP
365 ObjCLanguageRuntime::GetEncodingToType ()
366 {
367     return nullptr;
368 }
369 
370 bool
371 ObjCLanguageRuntime::GetTypeBitSize (const CompilerType& compiler_type,
372                                      uint64_t &size)
373 {
374     void *opaque_ptr = compiler_type.GetOpaqueQualType();
375     size = m_type_size_cache.Lookup(opaque_ptr);
376     // an ObjC object will at least have an ISA, so 0 is definitely not OK
377     if (size > 0)
378         return true;
379 
380     ClassDescriptorSP class_descriptor_sp = GetClassDescriptorFromClassName(compiler_type.GetTypeName());
381     if (!class_descriptor_sp)
382         return false;
383 
384     int32_t max_offset = INT32_MIN;
385     uint64_t sizeof_max = 0;
386     bool found = false;
387 
388     for (size_t idx = 0;
389          idx < class_descriptor_sp->GetNumIVars();
390          idx++)
391     {
392         const auto& ivar = class_descriptor_sp->GetIVarAtIndex(idx);
393         int32_t cur_offset = ivar.m_offset;
394         if (cur_offset > max_offset)
395         {
396             max_offset = cur_offset;
397             sizeof_max = ivar.m_size;
398             found = true;
399         }
400     }
401 
402     size = 8 * (max_offset + sizeof_max);
403     if (found)
404         m_type_size_cache.Insert(opaque_ptr, size);
405 
406     return found;
407 }
408 
409 //------------------------------------------------------------------
410 // Exception breakpoint Precondition class for ObjC:
411 //------------------------------------------------------------------
412 void
413 ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(const char *class_name)
414 {
415     m_class_names.insert(class_name);
416 }
417 
418 ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition()
419 {
420 }
421 
422 bool
423 ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(StoppointCallbackContext &context)
424 {
425     return true;
426 }
427 
428 void
429 ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(Stream &stream, lldb::DescriptionLevel level)
430 {
431 }
432 
433 Error
434 ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(Args &args)
435 {
436     Error error;
437     if (args.GetArgumentCount() > 0)
438         error.SetErrorString("The ObjC Exception breakpoint doesn't support extra options.");
439     return error;
440 }
441