diff options
author | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2013-08-23 18:06:42 +0000 |
commit | 424d4dadd208e2a1e9a43c3d55f47f03ba0c4509 (patch) | |
tree | 05d762b98a499804ce690e6ce04033f1ddf4dee6 /contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp | |
parent | cde487f27a84e02a560384f75178fddca68740f6 (diff) | |
parent | dcd15f81789e389c1cb27d264fcdddfd0a6002bd (diff) | |
download | FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.zip FreeBSD-src-424d4dadd208e2a1e9a43c3d55f47f03ba0c4509.tar.gz |
Merge lldb r188801 to contrib/llvm/tools/lldb/
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp new file mode 100644 index 0000000..64ddfcc --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -0,0 +1,605 @@ +//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Type.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/MappedHash.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ObjCLanguageRuntime::~ObjCLanguageRuntime() +{ +} + +ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) : + LanguageRuntime (process), + m_has_new_literals_and_indexing (eLazyBoolCalculate), + m_isa_to_descriptor(), + m_isa_to_descriptor_stop_id (UINT32_MAX) +{ + +} + +bool +ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name) +{ + if (isa != 0) + { + m_isa_to_descriptor[isa] = descriptor_sp; + // class_name is assumed to be valid + m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa)); + return true; + } + return false; +} + +void +ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + if (log) + { + log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr); + } + m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr)); +} + +lldb::addr_t +ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector) +{ + MsgImplMap::iterator pos, end = m_impl_cache.end(); + pos = m_impl_cache.find (ClassAndSel(class_addr, selector)); + if (pos != end) + return (*pos).second; + return LLDB_INVALID_ADDRESS; +} + + +lldb::TypeSP +ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name) +{ + CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name); + + if (complete_class_iter != m_complete_class_cache.end()) + { + // Check the weak pointer to make sure the type hasn't been unloaded + TypeSP complete_type_sp (complete_class_iter->second.lock()); + + if (complete_type_sp) + return complete_type_sp; + else + m_complete_class_cache.erase(name); + } + + if (m_negative_complete_class_cache.count(name) > 0) + return TypeSP(); + + const ModuleList &modules = m_process->GetTarget().GetImages(); + + SymbolContextList sc_list; + const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name, + eSymbolTypeObjCClass, + sc_list); + + if (matching_symbols) + { + SymbolContext sc; + + sc_list.GetContextAtIndex(0, sc); + + ModuleSP module_sp(sc.module_sp); + + if (!module_sp) + return TypeSP(); + + const SymbolContext null_sc; + const bool exact_match = true; + const uint32_t max_matches = UINT32_MAX; + TypeList types; + + const uint32_t num_types = module_sp->FindTypes (null_sc, + name, + exact_match, + max_matches, + types); + + if (num_types) + { + uint32_t i; + for (i = 0; i < num_types; ++i) + { + TypeSP type_sp (types.GetTypeAtIndex(i)); + + if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType()) + { + if (type_sp->IsCompleteObjCClass()) + { + m_complete_class_cache[name] = type_sp; + return type_sp; + } + } + } + } + } + m_negative_complete_class_cache.insert(name); + return TypeSP(); +} + +size_t +ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name) +{ + return LLDB_INVALID_IVAR_OFFSET; +} + +void +ObjCLanguageRuntime::MethodName::Clear() +{ + m_full.Clear(); + m_class.Clear(); + m_category.Clear(); + m_selector.Clear(); + m_type = eTypeUnspecified; + m_category_is_valid = false; +} + +//bool +//ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict) +//{ +// Clear(); +// if (name && name[0]) +// { +// // If "strict" is true. then the method must be specified with a +// // '+' or '-' at the beginning. If "strict" is false, then the '+' +// // or '-' can be omitted +// bool valid_prefix = false; +// +// if (name[0] == '+' || name[0] == '-') +// { +// valid_prefix = name[1] == '['; +// } +// else if (!strict) +// { +// // "strict" is false, the name just needs to start with '[' +// valid_prefix = name[0] == '['; +// } +// +// if (valid_prefix) +// { +// 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:]*)\\]$"); +// llvm::StringRef matches[4]; +// // Since we are using a global regular expression, we must use the threadsafe version of execute +// if (g_regex.ExecuteThreadSafe(name, matches, 4)) +// { +// m_full.SetCString(name); +// if (matches[0].empty()) +// m_type = eTypeUnspecified; +// else if (matches[0][0] == '+') +// m_type = eTypeClassMethod; +// else +// m_type = eTypeInstanceMethod; +// m_class.SetString(matches[1]); +// m_selector.SetString(matches[3]); +// if (!matches[2].empty()) +// m_category.SetString(matches[2]); +// } +// } +// } +// return IsValid(strict); +//} + +bool +ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict) +{ + Clear(); + if (name && name[0]) + { + // If "strict" is true. then the method must be specified with a + // '+' or '-' at the beginning. If "strict" is false, then the '+' + // or '-' can be omitted + bool valid_prefix = false; + + if (name[0] == '+' || name[0] == '-') + { + valid_prefix = name[1] == '['; + if (name[0] == '+') + m_type = eTypeClassMethod; + else + m_type = eTypeInstanceMethod; + } + else if (!strict) + { + // "strict" is false, the name just needs to start with '[' + valid_prefix = name[0] == '['; + } + + if (valid_prefix) + { + int name_len = strlen (name); + // Objective C methods must have at least: + // "-[" or "+[" prefix + // One character for a class name + // One character for the space between the class name + // One character for the method name + // "]" suffix + if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']') + { + m_full.SetCStringWithLength(name, name_len); + } + } + } + return IsValid(strict); +} + +const ConstString & +ObjCLanguageRuntime::MethodName::GetClassName () +{ + if (!m_class) + { + if (IsValid(false)) + { + const char *full = m_full.GetCString(); + const char *class_start = (full[0] == '[' ? full + 1 : full + 2); + const char *paren_pos = strchr (class_start, '('); + if (paren_pos) + { + m_class.SetCStringWithLength (class_start, paren_pos - class_start); + } + else + { + // No '(' was found in the full name, we can definitively say + // that our category was valid (and empty). + m_category_is_valid = true; + const char *space_pos = strchr (full, ' '); + if (space_pos) + { + m_class.SetCStringWithLength (class_start, space_pos - class_start); + if (!m_class_category) + { + // No category in name, so we can also fill in the m_class_category + m_class_category = m_class; + } + } + } + } + } + return m_class; +} + +const ConstString & +ObjCLanguageRuntime::MethodName::GetClassNameWithCategory () +{ + if (!m_class_category) + { + if (IsValid(false)) + { + const char *full = m_full.GetCString(); + const char *class_start = (full[0] == '[' ? full + 1 : full + 2); + const char *space_pos = strchr (full, ' '); + if (space_pos) + { + m_class_category.SetCStringWithLength (class_start, space_pos - class_start); + // If m_class hasn't been filled in and the class with category doesn't + // contain a '(', then we can also fill in the m_class + if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL) + { + m_class = m_class_category; + // No '(' was found in the full name, we can definitively say + // that our category was valid (and empty). + m_category_is_valid = true; + + } + } + } + } + return m_class_category; +} + +const ConstString & +ObjCLanguageRuntime::MethodName::GetSelector () +{ + if (!m_selector) + { + if (IsValid(false)) + { + const char *full = m_full.GetCString(); + const char *space_pos = strchr (full, ' '); + if (space_pos) + { + ++space_pos; // skip the space + m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1); + } + } + } + return m_selector; +} + +const ConstString & +ObjCLanguageRuntime::MethodName::GetCategory () +{ + if (!m_category_is_valid && !m_category) + { + if (IsValid(false)) + { + m_category_is_valid = true; + const char *full = m_full.GetCString(); + const char *class_start = (full[0] == '[' ? full + 1 : full + 2); + const char *open_paren_pos = strchr (class_start, '('); + if (open_paren_pos) + { + ++open_paren_pos; // Skip the open paren + const char *close_paren_pos = strchr (open_paren_pos, ')'); + if (close_paren_pos) + m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos); + } + } + } + return m_category; +} + +ConstString +ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category) +{ + if (IsValid(false)) + { + if (HasCategory()) + { + StreamString strm; + if (m_type == eTypeClassMethod) + strm.PutChar('+'); + else if (m_type == eTypeInstanceMethod) + strm.PutChar('-'); + strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString()); + return ConstString(strm.GetString().c_str()); + } + + if (!empty_if_no_category) + { + // Just return the full name since it doesn't have a category + return GetFullName(); + } + } + return ConstString(); +} + +size_t +ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append) +{ + if (!append) + names.clear(); + if (IsValid(false)) + { + StreamString strm; + const bool is_class_method = m_type == eTypeClassMethod; + const bool is_instance_method = m_type == eTypeInstanceMethod; + const ConstString &category = GetCategory(); + if (is_class_method || is_instance_method) + { + names.push_back (m_full); + if (category) + { + strm.Printf("%c[%s %s]", + is_class_method ? '+' : '-', + GetClassName().GetCString(), + GetSelector().GetCString()); + names.push_back(ConstString(strm.GetString().c_str())); + } + } + else + { + const ConstString &class_name = GetClassName(); + const ConstString &selector = GetSelector(); + strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString()); + names.push_back(ConstString(strm.GetString().c_str())); + strm.Clear(); + strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString()); + names.push_back(ConstString(strm.GetString().c_str())); + strm.Clear(); + if (category) + { + strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString()); + names.push_back(ConstString(strm.GetString().c_str())); + strm.Clear(); + strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString()); + names.push_back(ConstString(strm.GetString().c_str())); + } + } + } + return names.size(); +} + + +bool +ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value, + uint32_t ptr_size, + bool allow_NULLs, + bool allow_tagged, + bool check_version_specific) const +{ + if (!value) + return allow_NULLs; + if ( (value % 2) == 1 && allow_tagged) + return true; + if ((value % ptr_size) == 0) + return (check_version_specific ? CheckPointer(value,ptr_size) : true); + else + return false; +} + +ObjCLanguageRuntime::ObjCISA +ObjCLanguageRuntime::GetISA(const ConstString &name) +{ + ISAToDescriptorIterator pos = GetDescriptorIterator (name); + if (pos != m_isa_to_descriptor.end()) + return pos->first; + return 0; +} + +ObjCLanguageRuntime::ISAToDescriptorIterator +ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name) +{ + ISAToDescriptorIterator end = m_isa_to_descriptor.end(); + + if (name) + { + UpdateISAToDescriptorMap(); + if (m_hash_to_isa_map.empty()) + { + // No name hashes were provided, we need to just linearly power through the + // names and find a match + for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos) + { + if (pos->second->GetClassName() == name) + return pos; + } + } + else + { + // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor + const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString()); + std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash); + for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos) + { + ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second); + if (pos != m_isa_to_descriptor.end()) + { + if (pos->second->GetClassName() == name) + return pos; + } + } + } + } + return end; +} + + +ObjCLanguageRuntime::ObjCISA +ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) +{ + ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa)); + if (objc_class_sp) + { + ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass()); + if (objc_super_class_sp) + return objc_super_class_sp->GetISA(); + } + return 0; +} + +ConstString +ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) +{ + ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa)); + if (objc_class_sp) + return objc_class_sp->GetClassName(); + return ConstString(); +} + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name) +{ + ISAToDescriptorIterator pos = GetDescriptorIterator (class_name); + if (pos != m_isa_to_descriptor.end()) + return pos->second; + return ClassDescriptorSP(); + +} + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj) +{ + ClassDescriptorSP objc_class_sp; + // if we get an invalid VO (which might still happen when playing around + // with pointers returned by the expression parser, don't consider this + // a valid ObjC object) + if (valobj.GetClangType().IsValid()) + { + addr_t isa_pointer = valobj.GetPointerValue(); + if (isa_pointer != LLDB_INVALID_ADDRESS) + { + ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + Error error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa != LLDB_INVALID_ADDRESS) + objc_class_sp = GetClassDescriptorFromISA (isa); + } + } + } + return objc_class_sp; +} + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj) +{ + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj)); + if (objc_class_sp) + { + if (!objc_class_sp->IsKVO()) + return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; + } + return ClassDescriptorSP(); +} + + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa) +{ + if (isa) + { + UpdateISAToDescriptorMap(); + ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa); + if (pos != m_isa_to_descriptor.end()) + return pos->second; + } + return ClassDescriptorSP(); +} + +ObjCLanguageRuntime::ClassDescriptorSP +ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) +{ + if (isa) + { + ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa); + if (objc_class_sp && objc_class_sp->IsValid()) + { + if (!objc_class_sp->IsKVO()) + return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; + } + } + return ClassDescriptorSP(); +} + + + |