1 //===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "clang/AST/Type.h"
11 #include "lldb/Core/Log.h"
12 #include "lldb/Core/MappedHash.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/PluginManager.h"
15 #include "lldb/Core/Timer.h"
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Symbol/ClangASTContext.h"
18 #include "lldb/Symbol/Type.h"
19 #include "lldb/Symbol/TypeList.h"
20 #include "lldb/Target/ObjCLanguageRuntime.h"
21 #include "lldb/Target/Target.h"
23 #include "llvm/ADT/StringRef.h"
26 using namespace lldb_private;
28 //----------------------------------------------------------------------
30 //----------------------------------------------------------------------
31 ObjCLanguageRuntime::~ObjCLanguageRuntime()
35 ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
36 LanguageRuntime (process),
37 m_has_new_literals_and_indexing (eLazyBoolCalculate),
38 m_isa_to_descriptor(),
39 m_isa_to_descriptor_stop_id (UINT32_MAX)
45 ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
49 m_isa_to_descriptor[isa] = descriptor_sp;
50 // class_name is assumed to be valid
51 m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
58 ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
60 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
63 log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
65 m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
69 ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
71 MsgImplMap::iterator pos, end = m_impl_cache.end();
72 pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
75 return LLDB_INVALID_ADDRESS;
80 ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
82 CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
84 if (complete_class_iter != m_complete_class_cache.end())
86 // Check the weak pointer to make sure the type hasn't been unloaded
87 TypeSP complete_type_sp (complete_class_iter->second.lock());
90 return complete_type_sp;
92 m_complete_class_cache.erase(name);
95 if (m_negative_complete_class_cache.count(name) > 0)
98 const ModuleList &modules = m_process->GetTarget().GetImages();
100 SymbolContextList sc_list;
101 const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
102 eSymbolTypeObjCClass,
105 if (matching_symbols)
109 sc_list.GetContextAtIndex(0, sc);
111 ModuleSP module_sp(sc.module_sp);
116 const SymbolContext null_sc;
117 const bool exact_match = true;
118 const uint32_t max_matches = UINT32_MAX;
121 const uint32_t num_types = module_sp->FindTypes (null_sc,
130 for (i = 0; i < num_types; ++i)
132 TypeSP type_sp (types.GetTypeAtIndex(i));
134 if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType())
136 if (type_sp->IsCompleteObjCClass())
138 m_complete_class_cache[name] = type_sp;
145 m_negative_complete_class_cache.insert(name);
150 ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
152 return LLDB_INVALID_IVAR_OFFSET;
156 ObjCLanguageRuntime::MethodName::Clear()
162 m_type = eTypeUnspecified;
163 m_category_is_valid = false;
167 //ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
170 // if (name && name[0])
172 // // If "strict" is true. then the method must be specified with a
173 // // '+' or '-' at the beginning. If "strict" is false, then the '+'
174 // // or '-' can be omitted
175 // bool valid_prefix = false;
177 // if (name[0] == '+' || name[0] == '-')
179 // valid_prefix = name[1] == '[';
183 // // "strict" is false, the name just needs to start with '['
184 // valid_prefix = name[0] == '[';
189 // static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$");
190 // llvm::StringRef matches[4];
191 // // Since we are using a global regular expression, we must use the threadsafe version of execute
192 // if (g_regex.ExecuteThreadSafe(name, matches, 4))
194 // m_full.SetCString(name);
195 // if (matches[0].empty())
196 // m_type = eTypeUnspecified;
197 // else if (matches[0][0] == '+')
198 // m_type = eTypeClassMethod;
200 // m_type = eTypeInstanceMethod;
201 // m_class.SetString(matches[1]);
202 // m_selector.SetString(matches[3]);
203 // if (!matches[2].empty())
204 // m_category.SetString(matches[2]);
208 // return IsValid(strict);
212 ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
217 // If "strict" is true. then the method must be specified with a
218 // '+' or '-' at the beginning. If "strict" is false, then the '+'
219 // or '-' can be omitted
220 bool valid_prefix = false;
222 if (name[0] == '+' || name[0] == '-')
224 valid_prefix = name[1] == '[';
226 m_type = eTypeClassMethod;
228 m_type = eTypeInstanceMethod;
232 // "strict" is false, the name just needs to start with '['
233 valid_prefix = name[0] == '[';
238 int name_len = strlen (name);
239 // Objective C methods must have at least:
240 // "-[" or "+[" prefix
241 // One character for a class name
242 // One character for the space between the class name
243 // One character for the method name
245 if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']')
247 m_full.SetCStringWithLength(name, name_len);
251 return IsValid(strict);
255 ObjCLanguageRuntime::MethodName::GetClassName ()
261 const char *full = m_full.GetCString();
262 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
263 const char *paren_pos = strchr (class_start, '(');
266 m_class.SetCStringWithLength (class_start, paren_pos - class_start);
270 // No '(' was found in the full name, we can definitively say
271 // that our category was valid (and empty).
272 m_category_is_valid = true;
273 const char *space_pos = strchr (full, ' ');
276 m_class.SetCStringWithLength (class_start, space_pos - class_start);
277 if (!m_class_category)
279 // No category in name, so we can also fill in the m_class_category
280 m_class_category = m_class;
290 ObjCLanguageRuntime::MethodName::GetClassNameWithCategory ()
292 if (!m_class_category)
296 const char *full = m_full.GetCString();
297 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
298 const char *space_pos = strchr (full, ' ');
301 m_class_category.SetCStringWithLength (class_start, space_pos - class_start);
302 // If m_class hasn't been filled in and the class with category doesn't
303 // contain a '(', then we can also fill in the m_class
304 if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL)
306 m_class = m_class_category;
307 // No '(' was found in the full name, we can definitively say
308 // that our category was valid (and empty).
309 m_category_is_valid = true;
315 return m_class_category;
319 ObjCLanguageRuntime::MethodName::GetSelector ()
325 const char *full = m_full.GetCString();
326 const char *space_pos = strchr (full, ' ');
329 ++space_pos; // skip the space
330 m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1);
338 ObjCLanguageRuntime::MethodName::GetCategory ()
340 if (!m_category_is_valid && !m_category)
344 m_category_is_valid = true;
345 const char *full = m_full.GetCString();
346 const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
347 const char *open_paren_pos = strchr (class_start, '(');
350 ++open_paren_pos; // Skip the open paren
351 const char *close_paren_pos = strchr (open_paren_pos, ')');
353 m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos);
361 ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category)
368 if (m_type == eTypeClassMethod)
370 else if (m_type == eTypeInstanceMethod)
372 strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString());
373 return ConstString(strm.GetString().c_str());
376 if (!empty_if_no_category)
378 // Just return the full name since it doesn't have a category
379 return GetFullName();
382 return ConstString();
386 ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append)
393 const bool is_class_method = m_type == eTypeClassMethod;
394 const bool is_instance_method = m_type == eTypeInstanceMethod;
395 const ConstString &category = GetCategory();
396 if (is_class_method || is_instance_method)
398 names.push_back (m_full);
401 strm.Printf("%c[%s %s]",
402 is_class_method ? '+' : '-',
403 GetClassName().GetCString(),
404 GetSelector().GetCString());
405 names.push_back(ConstString(strm.GetString().c_str()));
410 const ConstString &class_name = GetClassName();
411 const ConstString &selector = GetSelector();
412 strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString());
413 names.push_back(ConstString(strm.GetString().c_str()));
415 strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString());
416 names.push_back(ConstString(strm.GetString().c_str()));
420 strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
421 names.push_back(ConstString(strm.GetString().c_str()));
423 strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
424 names.push_back(ConstString(strm.GetString().c_str()));
433 ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
437 bool check_version_specific) const
441 if ( (value % 2) == 1 && allow_tagged)
443 if ((value % ptr_size) == 0)
444 return (check_version_specific ? CheckPointer(value,ptr_size) : true);
449 ObjCLanguageRuntime::ObjCISA
450 ObjCLanguageRuntime::GetISA(const ConstString &name)
452 ISAToDescriptorIterator pos = GetDescriptorIterator (name);
453 if (pos != m_isa_to_descriptor.end())
458 ObjCLanguageRuntime::ISAToDescriptorIterator
459 ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
461 ISAToDescriptorIterator end = m_isa_to_descriptor.end();
465 UpdateISAToDescriptorMap();
466 if (m_hash_to_isa_map.empty())
468 // No name hashes were provided, we need to just linearly power through the
469 // names and find a match
470 for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
472 if (pos->second->GetClassName() == name)
478 // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
479 const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
480 std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
481 for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
483 ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
484 if (pos != m_isa_to_descriptor.end())
486 if (pos->second->GetClassName() == name)
496 ObjCLanguageRuntime::ObjCISA
497 ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
499 ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa));
502 ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
503 if (objc_super_class_sp)
504 return objc_super_class_sp->GetISA();
510 ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
512 ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
514 return objc_class_sp->GetClassName();
515 return ConstString();
518 ObjCLanguageRuntime::ClassDescriptorSP
519 ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name)
521 ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
522 if (pos != m_isa_to_descriptor.end())
524 return ClassDescriptorSP();
528 ObjCLanguageRuntime::ClassDescriptorSP
529 ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
531 ClassDescriptorSP objc_class_sp;
532 // if we get an invalid VO (which might still happen when playing around
533 // with pointers returned by the expression parser, don't consider this
534 // a valid ObjC object)
535 if (valobj.GetClangType().IsValid())
537 addr_t isa_pointer = valobj.GetPointerValue();
538 if (isa_pointer != LLDB_INVALID_ADDRESS)
540 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
542 Process *process = exe_ctx.GetProcessPtr();
546 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
547 if (isa != LLDB_INVALID_ADDRESS)
548 objc_class_sp = GetClassDescriptorFromISA (isa);
552 return objc_class_sp;
555 ObjCLanguageRuntime::ClassDescriptorSP
556 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
558 ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
561 if (!objc_class_sp->IsKVO())
562 return objc_class_sp;
564 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
565 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
566 return non_kvo_objc_class_sp;
568 return ClassDescriptorSP();
572 ObjCLanguageRuntime::ClassDescriptorSP
573 ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa)
577 UpdateISAToDescriptorMap();
578 ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
579 if (pos != m_isa_to_descriptor.end())
582 return ClassDescriptorSP();
585 ObjCLanguageRuntime::ClassDescriptorSP
586 ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
590 ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa);
591 if (objc_class_sp && objc_class_sp->IsValid())
593 if (!objc_class_sp->IsKVO())
594 return objc_class_sp;
596 ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
597 if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
598 return non_kvo_objc_class_sp;
601 return ClassDescriptorSP();