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