blob: 3ce672f9d6819b6673e2c9376a2d305e72f394dc [file] [log] [blame]
Raphael Isemann80814282020-01-24 08:23:27 +01001//===-- ObjCLanguageRuntime.cpp -------------------------------------------===//
Jim Ingham22777012010-09-23 02:01:19 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Jim Ingham22777012010-09-23 02:01:19 +00006//
7//===----------------------------------------------------------------------===//
Jim Ingham6c68fb42010-09-30 00:54:27 +00008#include "clang/AST/Type.h"
Jim Ingham22777012010-09-23 02:01:19 +00009
Alex Langfordb57017102019-07-15 22:56:12 +000010#include "ObjCLanguageRuntime.h"
11
Greg Claytona66c4d92013-02-13 22:56:14 +000012#include "lldb/Core/MappedHash.h"
Greg Clayton1f746072012-08-29 21:13:06 +000013#include "lldb/Core/Module.h"
Jim Ingham22777012010-09-23 02:01:19 +000014#include "lldb/Core/PluginManager.h"
Jim Ingham6c68fb42010-09-30 00:54:27 +000015#include "lldb/Core/ValueObject.h"
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +010016#include "lldb/Symbol/TypeSystemClang.h"
Zachary Turner32abc6e2015-03-03 19:23:09 +000017#include "lldb/Symbol/SymbolContext.h"
Greg Claytonae088e52016-02-10 21:28:13 +000018#include "lldb/Symbol/SymbolFile.h"
Jim Ingham61be0902011-05-02 18:13:59 +000019#include "lldb/Symbol/Type.h"
Greg Clayton1f746072012-08-29 21:13:06 +000020#include "lldb/Symbol/TypeList.h"
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000021#include "lldb/Symbol/Variable.h"
Sean Callanan72772842012-02-22 23:57:45 +000022#include "lldb/Target/Target.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000023#include "lldb/Utility/Log.h"
Pavel Labath38d06322017-06-29 14:32:17 +000024#include "lldb/Utility/Timer.h"
Jim Ingham22777012010-09-23 02:01:19 +000025
Greg Clayton1b3815c2013-01-30 00:18:29 +000026#include "llvm/ADT/StringRef.h"
Pavel Labathb39fca92018-02-23 17:49:26 +000027#include "llvm/Support/DJB.h"
Greg Clayton1b3815c2013-01-30 00:18:29 +000028
Jim Ingham22777012010-09-23 02:01:19 +000029using namespace lldb;
30using namespace lldb_private;
31
Alex Langford056f6f12019-06-08 18:45:00 +000032char ObjCLanguageRuntime::ID = 0;
33
Jim Ingham22777012010-09-23 02:01:19 +000034// Destructor
Kate Stoneb9c1b512016-09-06 20:57:50 +000035ObjCLanguageRuntime::~ObjCLanguageRuntime() {}
36
37ObjCLanguageRuntime::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
Adrian Prantl1db0f0c2019-05-02 23:07:23 +000044bool ObjCLanguageRuntime::IsWhitelistedRuntimeValue(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
Kate Stoneb9c1b512016-09-06 20:57:50 +000050bool 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
Pavel Labathb39fca92018-02-23 17:49:26 +000056 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));
Kate Stoneb9c1b512016-09-06 20:57:50 +000057 return true;
58 }
59 return false;
Jim Ingham22777012010-09-23 02:01:19 +000060}
61
Kate Stoneb9c1b512016-09-06 20:57:50 +000062void 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) {
Jonas Devlieghere63e5fb72019-07-24 17:56:10 +000067 LLDB_LOGF(log,
68 "Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
69 " implementation 0x%" PRIx64 ".",
70 class_addr, selector, impl_addr);
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 }
72 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
73 ClassAndSel(class_addr, selector), impl_addr));
Jim Ingham5a369122010-09-28 01:25:32 +000074}
75
Kate Stoneb9c1b512016-09-06 20:57:50 +000076lldb::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
85lldb::TypeSP
86ObjCLanguageRuntime::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;
Adrian Prantl1ad655e2019-10-17 19:56:40 +0000106 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
107 const size_t matching_symbols = sc_list.GetSize();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000108
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
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 const bool exact_match = true;
120 const uint32_t max_matches = UINT32_MAX;
121 TypeList types;
122
123 llvm::DenseSet<SymbolFile *> searched_symbol_files;
Adrian Prantlbf9d84c2019-10-01 15:40:41 +0000124 module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files,
125 types);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126
Adrian Prantlbf9d84c2019-10-01 15:40:41 +0000127 for (uint32_t i = 0; i < types.GetSize(); ++i) {
128 TypeSP type_sp(types.GetTypeAtIndex(i));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100130 if (TypeSystemClang::IsObjCObjectOrInterfaceType(
Adrian Prantlbf9d84c2019-10-01 15:40:41 +0000131 type_sp->GetForwardCompilerType())) {
132 if (type_sp->IsCompleteObjCClass()) {
133 m_complete_class_cache[name] = type_sp;
134 return type_sp;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 }
136 }
Greg Claytona66c4d92013-02-13 22:56:14 +0000137 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 }
139 m_negative_complete_class_cache.insert(name);
140 return TypeSP();
141}
142
143size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
144 const char *ivar_name) {
145 return LLDB_INVALID_IVAR_OFFSET;
146}
147
148bool 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
Greg Claytona66c4d92013-02-13 22:56:14 +0000158 return false;
159}
160
Enrico Granata3467d802012-09-04 18:47:54 +0000161ObjCLanguageRuntime::ObjCISA
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000162ObjCLanguageRuntime::GetISA(ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163 ISAToDescriptorIterator pos = GetDescriptorIterator(name);
164 if (pos != m_isa_to_descriptor.end())
165 return pos->first;
166 return 0;
Sean Callananbc47dfc2012-09-11 21:44:01 +0000167}
168
Greg Claytona66c4d92013-02-13 22:56:14 +0000169ObjCLanguageRuntime::ISAToDescriptorIterator
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000170ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000171 ISAToDescriptorIterator end = m_isa_to_descriptor.end();
Greg Claytona66c4d92013-02-13 22:56:14 +0000172
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173 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
Adrian Prantl05097242018-04-30 16:49:04 +0000177 // the names and find a match
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 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
Pavel Labathb39fca92018-02-23 17:49:26 +0000186 const uint32_t name_hash = llvm::djbHash(name.GetStringRef());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000187 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;
Greg Claytona66c4d92013-02-13 22:56:14 +0000196 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000197 }
Greg Claytona66c4d92013-02-13 22:56:14 +0000198 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000199 }
200 return end;
Greg Claytona66c4d92013-02-13 22:56:14 +0000201}
202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
204 ObjCLanguageRuntime::ISAToDescriptorIterator>
205ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
206 if (update_if_needed)
207 UpdateISAToDescriptorMapIfNeeded();
Enrico Granataba4b8b02015-05-06 21:01:07 +0000208
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209 return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
210 ObjCLanguageRuntime::ISAToDescriptorIterator>(
211 m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
212}
Greg Claytona66c4d92013-02-13 22:56:14 +0000213
Sean Callananbc47dfc2012-09-11 21:44:01 +0000214ObjCLanguageRuntime::ObjCISA
Kate Stoneb9c1b512016-09-06 20:57:50 +0000215ObjCLanguageRuntime::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;
Enrico Granata3467d802012-09-04 18:47:54 +0000223}
224
Greg Clayton77fbc812012-10-09 17:51:53 +0000225ObjCLanguageRuntime::ClassDescriptorSP
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226ObjCLanguageRuntime::GetClassDescriptorFromClassName(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000227 ConstString class_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
229 if (pos != m_isa_to_descriptor.end())
230 return pos->second;
231 return ClassDescriptorSP();
232}
233
234ObjCLanguageRuntime::ClassDescriptorSP
235ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
236 ClassDescriptorSP objc_class_sp;
Adrian Prantl05097242018-04-30 16:49:04 +0000237 // 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)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000240 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) {
Zachary Turner97206d52017-05-12 04:51:55 +0000247 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248 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
257ObjCLanguageRuntime::ClassDescriptorSP
258ObjCLanguageRuntime::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
272ObjCLanguageRuntime::ClassDescriptorSP
273ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
274 if (isa) {
275 UpdateISAToDescriptorMap();
276 ObjCLanguageRuntime::ISAToDescriptorIterator pos =
277 m_isa_to_descriptor.find(isa);
Greg Claytona66c4d92013-02-13 22:56:14 +0000278 if (pos != m_isa_to_descriptor.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279 return pos->second;
280 }
281 return ClassDescriptorSP();
Greg Claytonf0246d12012-10-11 18:07:21 +0000282}
283
284ObjCLanguageRuntime::ClassDescriptorSP
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285ObjCLanguageRuntime::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;
Greg Claytonf0246d12012-10-11 18:07:21 +0000295 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000296 }
297 return ClassDescriptorSP();
Greg Claytonf0246d12012-10-11 18:07:21 +0000298}
299
Greg Claytona1e5dc82015-08-11 22:53:00 +0000300CompilerType
Kate Stoneb9c1b512016-09-06 20:57:50 +0000301ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
302 bool for_expression) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000303 if (m_scratch_ast_ctx_up)
304 return RealizeType(*m_scratch_ast_ctx_up, name, for_expression);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 return CompilerType();
306}
307
Enrico Granata5d84a692014-08-19 21:46:37 +0000308ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
309
Kate Stoneb9c1b512016-09-06 20:57:50 +0000310ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
311 return nullptr;
Enrico Granata5d84a692014-08-19 21:46:37 +0000312}
Enrico Granata3842b9f2015-01-28 00:45:42 +0000313
Kate Stoneb9c1b512016-09-06 20:57:50 +0000314bool 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;
Enrico Granata3842b9f2015-01-28 00:45:42 +0000338 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339 }
340
341 size = 8 * (max_offset + sizeof_max);
342 if (found)
343 m_type_size_cache.Insert(opaque_ptr, size);
344
345 return found;
Enrico Granata3842b9f2015-01-28 00:45:42 +0000346}
Jim Inghama72b31c2015-04-22 19:42:18 +0000347
Alex Langford7f9c9f22019-06-21 19:43:07 +0000348lldb::BreakpointPreconditionSP
349ObjCLanguageRuntime::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
Jim Inghama72b31c2015-04-22 19:42:18 +0000360// Exception breakpoint Precondition class for ObjC:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000361void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
362 const char *class_name) {
363 m_class_names.insert(class_name);
Jim Inghama72b31c2015-04-22 19:42:18 +0000364}
365
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {}
367
368bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
369 StoppointCallbackContext &context) {
370 return true;
Jim Inghama72b31c2015-04-22 19:42:18 +0000371}
372
Kate Stoneb9c1b512016-09-06 20:57:50 +0000373void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
374 Stream &stream, lldb::DescriptionLevel level) {}
Jim Inghama72b31c2015-04-22 19:42:18 +0000375
Zachary Turner97206d52017-05-12 04:51:55 +0000376Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000377 Args &args) {
Zachary Turner97206d52017-05-12 04:51:55 +0000378 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000379 if (args.GetArgumentCount() > 0)
380 error.SetErrorString(
381 "The ObjC Exception breakpoint doesn't support extra options.");
382 return error;
Jim Inghama72b31c2015-04-22 19:42:18 +0000383}
Alex Langford24604ec2019-07-12 18:34:37 +0000384
385llvm::Optional<CompilerType>
386ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {
387 CompilerType class_type;
388 bool is_pointer_type = false;
389
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100390 if (TypeSystemClang::IsObjCObjectPointerType(base_type, &class_type))
Alex Langford24604ec2019-07-12 18:34:37 +0000391 is_pointer_type = true;
Raphael Isemann6e3b0cc2020-01-23 10:04:13 +0100392 else if (TypeSystemClang::IsObjCObjectOrInterfaceType(base_type))
Alex Langford24604ec2019-07-12 18:34:37 +0000393 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.GetConstTypeName());
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}