blob: cd97707ccfa768680b02c9f747a4328e962ff1aa [file] [log] [blame]
Greg Clayton05e8d192012-02-01 01:46:19 +00001//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
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
Greg Claytona66c4d92013-02-13 22:56:14 +000010#include "lldb/Core/MappedHash.h"
Greg Clayton1f746072012-08-29 21:13:06 +000011#include "lldb/Core/Module.h"
Jim Ingham22777012010-09-23 02:01:19 +000012#include "lldb/Core/PluginManager.h"
Jim Ingham6c68fb42010-09-30 00:54:27 +000013#include "lldb/Core/ValueObject.h"
14#include "lldb/Symbol/ClangASTContext.h"
Zachary Turner32abc6e2015-03-03 19:23:09 +000015#include "lldb/Symbol/SymbolContext.h"
Greg Claytonae088e52016-02-10 21:28:13 +000016#include "lldb/Symbol/SymbolFile.h"
Jim Ingham61be0902011-05-02 18:13:59 +000017#include "lldb/Symbol/Type.h"
Greg Clayton1f746072012-08-29 21:13:06 +000018#include "lldb/Symbol/TypeList.h"
Jim Ingham5a369122010-09-28 01:25:32 +000019#include "lldb/Target/ObjCLanguageRuntime.h"
Sean Callanan72772842012-02-22 23:57:45 +000020#include "lldb/Target/Target.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000021#include "lldb/Utility/Log.h"
Pavel Labath38d06322017-06-29 14:32:17 +000022#include "lldb/Utility/Timer.h"
Jim Ingham22777012010-09-23 02:01:19 +000023
Greg Clayton1b3815c2013-01-30 00:18:29 +000024#include "llvm/ADT/StringRef.h"
Pavel Labathb39fca92018-02-23 17:49:26 +000025#include "llvm/Support/DJB.h"
Greg Clayton1b3815c2013-01-30 00:18:29 +000026
Jim Ingham22777012010-09-23 02:01:19 +000027using namespace lldb;
28using namespace lldb_private;
29
30//----------------------------------------------------------------------
31// Destructor
32//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000033ObjCLanguageRuntime::~ObjCLanguageRuntime() {}
34
35ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process)
36 : LanguageRuntime(process), m_impl_cache(),
37 m_has_new_literals_and_indexing(eLazyBoolCalculate),
38 m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
39 m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
40 m_negative_complete_class_cache() {}
41
42bool ObjCLanguageRuntime::AddClass(ObjCISA isa,
43 const ClassDescriptorSP &descriptor_sp,
44 const char *class_name) {
45 if (isa != 0) {
46 m_isa_to_descriptor[isa] = descriptor_sp;
47 // class_name is assumed to be valid
Pavel Labathb39fca92018-02-23 17:49:26 +000048 m_hash_to_isa_map.insert(std::make_pair(llvm::djbHash(class_name), isa));
Kate Stoneb9c1b512016-09-06 20:57:50 +000049 return true;
50 }
51 return false;
Jim Ingham22777012010-09-23 02:01:19 +000052}
53
Kate Stoneb9c1b512016-09-06 20:57:50 +000054void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
55 lldb::addr_t selector,
56 lldb::addr_t impl_addr) {
57 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
58 if (log) {
59 log->Printf("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
60 " implementation 0x%" PRIx64 ".",
61 class_addr, selector, impl_addr);
62 }
63 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
64 ClassAndSel(class_addr, selector), impl_addr));
Jim Ingham5a369122010-09-28 01:25:32 +000065}
66
Kate Stoneb9c1b512016-09-06 20:57:50 +000067lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
68 lldb::addr_t selector) {
69 MsgImplMap::iterator pos, end = m_impl_cache.end();
70 pos = m_impl_cache.find(ClassAndSel(class_addr, selector));
71 if (pos != end)
72 return (*pos).second;
73 return LLDB_INVALID_ADDRESS;
74}
75
76lldb::TypeSP
77ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
78 CompleteClassMap::iterator complete_class_iter =
79 m_complete_class_cache.find(name);
80
81 if (complete_class_iter != m_complete_class_cache.end()) {
82 // Check the weak pointer to make sure the type hasn't been unloaded
83 TypeSP complete_type_sp(complete_class_iter->second.lock());
84
85 if (complete_type_sp)
86 return complete_type_sp;
87 else
88 m_complete_class_cache.erase(name);
89 }
90
91 if (m_negative_complete_class_cache.count(name) > 0)
92 return TypeSP();
93
94 const ModuleList &modules = m_process->GetTarget().GetImages();
95
96 SymbolContextList sc_list;
97 const size_t matching_symbols =
98 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
99
100 if (matching_symbols) {
101 SymbolContext sc;
102
103 sc_list.GetContextAtIndex(0, sc);
104
105 ModuleSP module_sp(sc.module_sp);
106
107 if (!module_sp)
108 return TypeSP();
109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 const bool exact_match = true;
111 const uint32_t max_matches = UINT32_MAX;
112 TypeList types;
113
114 llvm::DenseSet<SymbolFile *> searched_symbol_files;
115 const uint32_t num_types = module_sp->FindTypes(
Zachary Turner576495e2019-01-14 22:41:21 +0000116 name, exact_match, max_matches, searched_symbol_files, types);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117
118 if (num_types) {
119 uint32_t i;
120 for (i = 0; i < num_types; ++i) {
121 TypeSP type_sp(types.GetTypeAtIndex(i));
122
123 if (ClangASTContext::IsObjCObjectOrInterfaceType(
124 type_sp->GetForwardCompilerType())) {
125 if (type_sp->IsCompleteObjCClass()) {
126 m_complete_class_cache[name] = type_sp;
127 return type_sp;
128 }
129 }
130 }
Greg Claytona66c4d92013-02-13 22:56:14 +0000131 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 }
133 m_negative_complete_class_cache.insert(name);
134 return TypeSP();
135}
136
137size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
138 const char *ivar_name) {
139 return LLDB_INVALID_IVAR_OFFSET;
140}
141
142bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid(
143 lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged,
144 bool check_version_specific) const {
145 if (!value)
146 return allow_NULLs;
147 if ((value % 2) == 1 && allow_tagged)
148 return true;
149 if ((value % ptr_size) == 0)
150 return (check_version_specific ? CheckPointer(value, ptr_size) : true);
151 else
Greg Claytona66c4d92013-02-13 22:56:14 +0000152 return false;
153}
154
Enrico Granata3467d802012-09-04 18:47:54 +0000155ObjCLanguageRuntime::ObjCISA
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000156ObjCLanguageRuntime::GetISA(ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 ISAToDescriptorIterator pos = GetDescriptorIterator(name);
158 if (pos != m_isa_to_descriptor.end())
159 return pos->first;
160 return 0;
Sean Callananbc47dfc2012-09-11 21:44:01 +0000161}
162
Greg Claytona66c4d92013-02-13 22:56:14 +0000163ObjCLanguageRuntime::ISAToDescriptorIterator
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000164ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 ISAToDescriptorIterator end = m_isa_to_descriptor.end();
Greg Claytona66c4d92013-02-13 22:56:14 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 if (name) {
168 UpdateISAToDescriptorMap();
169 if (m_hash_to_isa_map.empty()) {
170 // No name hashes were provided, we need to just linearly power through
Adrian Prantl05097242018-04-30 16:49:04 +0000171 // the names and find a match
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin();
173 pos != end; ++pos) {
174 if (pos->second->GetClassName() == name)
175 return pos;
176 }
177 } else {
178 // Name hashes were provided, so use them to efficiently lookup name to
179 // isa/descriptor
Pavel Labathb39fca92018-02-23 17:49:26 +0000180 const uint32_t name_hash = llvm::djbHash(name.GetStringRef());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000181 std::pair<HashToISAIterator, HashToISAIterator> range =
182 m_hash_to_isa_map.equal_range(name_hash);
183 for (HashToISAIterator range_pos = range.first; range_pos != range.second;
184 ++range_pos) {
185 ISAToDescriptorIterator pos =
186 m_isa_to_descriptor.find(range_pos->second);
187 if (pos != m_isa_to_descriptor.end()) {
188 if (pos->second->GetClassName() == name)
189 return pos;
Greg Claytona66c4d92013-02-13 22:56:14 +0000190 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000191 }
Greg Claytona66c4d92013-02-13 22:56:14 +0000192 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000193 }
194 return end;
Greg Claytona66c4d92013-02-13 22:56:14 +0000195}
196
Kate Stoneb9c1b512016-09-06 20:57:50 +0000197std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
198 ObjCLanguageRuntime::ISAToDescriptorIterator>
199ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
200 if (update_if_needed)
201 UpdateISAToDescriptorMapIfNeeded();
Enrico Granataba4b8b02015-05-06 21:01:07 +0000202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
204 ObjCLanguageRuntime::ISAToDescriptorIterator>(
205 m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
206}
Greg Claytona66c4d92013-02-13 22:56:14 +0000207
Sean Callananbc47dfc2012-09-11 21:44:01 +0000208ObjCLanguageRuntime::ObjCISA
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
210 ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
211 if (objc_class_sp) {
212 ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
213 if (objc_super_class_sp)
214 return objc_super_class_sp->GetISA();
215 }
216 return 0;
Enrico Granata3467d802012-09-04 18:47:54 +0000217}
218
Enrico Granata3467d802012-09-04 18:47:54 +0000219ConstString
Kate Stoneb9c1b512016-09-06 20:57:50 +0000220ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) {
221 ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(isa));
222 if (objc_class_sp)
223 return objc_class_sp->GetClassName();
224 return ConstString();
Enrico Granata3467d802012-09-04 18:47:54 +0000225}
Greg Clayton77fbc812012-10-09 17:51:53 +0000226
227ObjCLanguageRuntime::ClassDescriptorSP
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228ObjCLanguageRuntime::GetClassDescriptorFromClassName(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000229 ConstString class_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
231 if (pos != m_isa_to_descriptor.end())
232 return pos->second;
233 return ClassDescriptorSP();
234}
235
236ObjCLanguageRuntime::ClassDescriptorSP
237ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
238 ClassDescriptorSP objc_class_sp;
Adrian Prantl05097242018-04-30 16:49:04 +0000239 // if we get an invalid VO (which might still happen when playing around with
240 // pointers returned by the expression parser, don't consider this a valid
241 // ObjC object)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000242 if (valobj.GetCompilerType().IsValid()) {
243 addr_t isa_pointer = valobj.GetPointerValue();
244 if (isa_pointer != LLDB_INVALID_ADDRESS) {
245 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
246
247 Process *process = exe_ctx.GetProcessPtr();
248 if (process) {
Zachary Turner97206d52017-05-12 04:51:55 +0000249 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000250 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
251 if (isa != LLDB_INVALID_ADDRESS)
252 objc_class_sp = GetClassDescriptorFromISA(isa);
253 }
254 }
255 }
256 return objc_class_sp;
257}
258
259ObjCLanguageRuntime::ClassDescriptorSP
260ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) {
261 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
262 GetClassDescriptor(valobj));
263 if (objc_class_sp) {
264 if (!objc_class_sp->IsKVO())
265 return objc_class_sp;
266
267 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
268 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
269 return non_kvo_objc_class_sp;
270 }
271 return ClassDescriptorSP();
272}
273
274ObjCLanguageRuntime::ClassDescriptorSP
275ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
276 if (isa) {
277 UpdateISAToDescriptorMap();
278 ObjCLanguageRuntime::ISAToDescriptorIterator pos =
279 m_isa_to_descriptor.find(isa);
Greg Claytona66c4d92013-02-13 22:56:14 +0000280 if (pos != m_isa_to_descriptor.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000281 return pos->second;
282 }
283 return ClassDescriptorSP();
Greg Claytonf0246d12012-10-11 18:07:21 +0000284}
285
286ObjCLanguageRuntime::ClassDescriptorSP
Kate Stoneb9c1b512016-09-06 20:57:50 +0000287ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) {
288 if (isa) {
289 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa);
290 if (objc_class_sp && objc_class_sp->IsValid()) {
291 if (!objc_class_sp->IsKVO())
292 return objc_class_sp;
293
294 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
295 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
296 return non_kvo_objc_class_sp;
Greg Claytonf0246d12012-10-11 18:07:21 +0000297 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 }
299 return ClassDescriptorSP();
Greg Claytonf0246d12012-10-11 18:07:21 +0000300}
301
Greg Claytona1e5dc82015-08-11 22:53:00 +0000302CompilerType
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
304 bool for_expression) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000305 if (m_scratch_ast_ctx_up)
306 return RealizeType(*m_scratch_ast_ctx_up, name, for_expression);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 return CompilerType();
308}
309
310CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType(
311 ClangASTContext &ast_ctx, const char *name, bool for_expression) {
312 clang::ASTContext *clang_ast = ast_ctx.getASTContext();
313 if (!clang_ast)
Greg Claytona1e5dc82015-08-11 22:53:00 +0000314 return CompilerType();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000315 return RealizeType(*clang_ast, name, for_expression);
Enrico Granata5d84a692014-08-19 21:46:37 +0000316}
317
318ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
321 return nullptr;
Enrico Granata5d84a692014-08-19 21:46:37 +0000322}
Enrico Granata3842b9f2015-01-28 00:45:42 +0000323
Kate Stoneb9c1b512016-09-06 20:57:50 +0000324bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
325 uint64_t &size) {
326 void *opaque_ptr = compiler_type.GetOpaqueQualType();
327 size = m_type_size_cache.Lookup(opaque_ptr);
328 // an ObjC object will at least have an ISA, so 0 is definitely not OK
329 if (size > 0)
330 return true;
331
332 ClassDescriptorSP class_descriptor_sp =
333 GetClassDescriptorFromClassName(compiler_type.GetTypeName());
334 if (!class_descriptor_sp)
335 return false;
336
337 int32_t max_offset = INT32_MIN;
338 uint64_t sizeof_max = 0;
339 bool found = false;
340
341 for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
342 const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
343 int32_t cur_offset = ivar.m_offset;
344 if (cur_offset > max_offset) {
345 max_offset = cur_offset;
346 sizeof_max = ivar.m_size;
347 found = true;
Enrico Granata3842b9f2015-01-28 00:45:42 +0000348 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000349 }
350
351 size = 8 * (max_offset + sizeof_max);
352 if (found)
353 m_type_size_cache.Insert(opaque_ptr, size);
354
355 return found;
Enrico Granata3842b9f2015-01-28 00:45:42 +0000356}
Jim Inghama72b31c2015-04-22 19:42:18 +0000357
358//------------------------------------------------------------------
359// Exception breakpoint Precondition class for ObjC:
360//------------------------------------------------------------------
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}