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