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