1 //===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
8 #include "clang/AST/Type.h"
10 #include "ObjCLanguageRuntime.h"
12 #include "lldb/Core/MappedHash.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/PluginManager.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Symbol/ClangASTContext.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"
26 #include "llvm/ADT/StringRef.h"
27 #include "llvm/Support/DJB.h"
30 using namespace lldb_private;
32 char ObjCLanguageRuntime::ID = 0;
35 ObjCLanguageRuntime::~ObjCLanguageRuntime() {}
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() {}
44 bool 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;
50 bool ObjCLanguageRuntime::AddClass(ObjCISA isa,
51 const ClassDescriptorSP &descriptor_sp,
52 const char *class_name) {
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));
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));
68 "Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
69 " implementation 0x%" PRIx64 ".",
70 class_addr, selector, impl_addr);
72 m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
73 ClassAndSel(class_addr, selector), impl_addr));
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));
82 return LLDB_INVALID_ADDRESS;
86 ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
87 CompleteClassMap::iterator complete_class_iter =
88 m_complete_class_cache.find(name);
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());
95 return complete_type_sp;
97 m_complete_class_cache.erase(name);
100 if (m_negative_complete_class_cache.count(name) > 0)
103 const ModuleList &modules = m_process->GetTarget().GetImages();
105 SymbolContextList sc_list;
106 modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
107 const size_t matching_symbols = sc_list.GetSize();
109 if (matching_symbols) {
112 sc_list.GetContextAtIndex(0, sc);
114 ModuleSP module_sp(sc.module_sp);
119 const bool exact_match = true;
120 const uint32_t max_matches = UINT32_MAX;
123 llvm::DenseSet<SymbolFile *> searched_symbol_files;
124 module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files,
127 for (uint32_t i = 0; i < types.GetSize(); ++i) {
128 TypeSP type_sp(types.GetTypeAtIndex(i));
130 if (ClangASTContext::IsObjCObjectOrInterfaceType(
131 type_sp->GetForwardCompilerType())) {
132 if (type_sp->IsCompleteObjCClass()) {
133 m_complete_class_cache[name] = type_sp;
139 m_negative_complete_class_cache.insert(name);
143 size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
144 const char *ivar_name) {
145 return LLDB_INVALID_IVAR_OFFSET;
148 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 {
153 if ((value % 2) == 1 && allow_tagged)
155 if ((value % ptr_size) == 0)
156 return (check_version_specific ? CheckPointer(value, ptr_size) : true);
161 ObjCLanguageRuntime::ObjCISA
162 ObjCLanguageRuntime::GetISA(ConstString name) {
163 ISAToDescriptorIterator pos = GetDescriptorIterator(name);
164 if (pos != m_isa_to_descriptor.end())
169 ObjCLanguageRuntime::ISAToDescriptorIterator
170 ObjCLanguageRuntime::GetDescriptorIterator(ConstString name) {
171 ISAToDescriptorIterator end = m_isa_to_descriptor.end();
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();
180 if (pos->second->GetClassName() == name)
184 // Name hashes were provided, so use them to efficiently lookup name to
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;
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)
203 std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
204 ObjCLanguageRuntime::ISAToDescriptorIterator>
205 ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
206 if (update_if_needed)
207 UpdateISAToDescriptorMapIfNeeded();
209 return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
210 ObjCLanguageRuntime::ISAToDescriptorIterator>(
211 m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
214 ObjCLanguageRuntime::ObjCISA
215 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
216 ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
218 ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
219 if (objc_super_class_sp)
220 return objc_super_class_sp->GetISA();
225 ObjCLanguageRuntime::ClassDescriptorSP
226 ObjCLanguageRuntime::GetClassDescriptorFromClassName(
227 ConstString class_name) {
228 ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
229 if (pos != m_isa_to_descriptor.end())
231 return ClassDescriptorSP();
234 ObjCLanguageRuntime::ClassDescriptorSP
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
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());
245 Process *process = exe_ctx.GetProcessPtr();
248 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
249 if (isa != LLDB_INVALID_ADDRESS)
250 objc_class_sp = GetClassDescriptorFromISA(isa);
254 return objc_class_sp;
257 ObjCLanguageRuntime::ClassDescriptorSP
258 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) {
259 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
260 GetClassDescriptor(valobj));
262 if (!objc_class_sp->IsKVO())
263 return objc_class_sp;
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;
269 return ClassDescriptorSP();
272 ObjCLanguageRuntime::ClassDescriptorSP
273 ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
275 UpdateISAToDescriptorMap();
276 ObjCLanguageRuntime::ISAToDescriptorIterator pos =
277 m_isa_to_descriptor.find(isa);
278 if (pos != m_isa_to_descriptor.end())
281 return ClassDescriptorSP();
284 ObjCLanguageRuntime::ClassDescriptorSP
285 ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA 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;
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;
297 return ClassDescriptorSP();
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();
308 ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
310 ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
314 bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
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
322 ClassDescriptorSP class_descriptor_sp =
323 GetClassDescriptorFromClassName(compiler_type.GetTypeName());
324 if (!class_descriptor_sp)
327 int32_t max_offset = INT32_MIN;
328 uint64_t sizeof_max = 0;
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;
341 size = 8 * (max_offset + sizeof_max);
343 m_type_size_cache.Insert(opaque_ptr, size);
348 lldb::BreakpointPreconditionSP
349 ObjCLanguageRuntime::GetBreakpointExceptionPrecondition(LanguageType language,
351 if (language != eLanguageTypeObjC)
352 return lldb::BreakpointPreconditionSP();
354 return lldb::BreakpointPreconditionSP();
355 BreakpointPreconditionSP precondition_sp(
356 new ObjCLanguageRuntime::ObjCExceptionPrecondition());
357 return precondition_sp;
360 // Exception breakpoint Precondition class for ObjC:
361 void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
362 const char *class_name) {
363 m_class_names.insert(class_name);
366 ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {}
368 bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
369 StoppointCallbackContext &context) {
373 void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
374 Stream &stream, lldb::DescriptionLevel level) {}
376 Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
379 if (args.GetArgumentCount() > 0)
380 error.SetErrorString(
381 "The ObjC Exception breakpoint doesn't support extra options.");
385 llvm::Optional<CompilerType>
386 ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {
387 CompilerType class_type;
388 bool is_pointer_type = false;
390 if (ClangASTContext::IsObjCObjectPointerType(base_type, &class_type))
391 is_pointer_type = true;
392 else if (ClangASTContext::IsObjCObjectOrInterfaceType(base_type))
393 class_type = base_type;
400 ConstString class_name(class_type.GetConstTypeName());
404 TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name);
405 if (!complete_objc_class_type_sp)
408 CompilerType complete_class(
409 complete_objc_class_type_sp->GetFullCompilerType());
410 if (complete_class.GetCompleteType()) {
412 return complete_class.GetPointerType();
414 return complete_class;