Files
clang-p2996/lldb/source/Target/ObjCLanguageRuntime.cpp
Kate Stone b9c1b51e45 *** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style.  This kind of mass change has
*** two obvious implications:

Firstly, merging this particular commit into a downstream fork may be a huge
effort.  Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit.  The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):

    find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
    find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;

The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.

Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit.  There are alternatives available that will attempt
to look through this change and find the appropriate prior commit.  YMMV.

llvm-svn: 280751
2016-09-06 20:57:50 +00:00

388 lines
13 KiB
C++

//===-- 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/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.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_impl_cache(),
m_has_new_literals_and_indexing(eLazyBoolCalculate),
m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
m_negative_complete_class_cache() {}
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;
llvm::DenseSet<SymbolFile *> searched_symbol_files;
const uint32_t num_types = module_sp->FindTypes(
null_sc, name, exact_match, max_matches, searched_symbol_files, types);
if (num_types) {
uint32_t i;
for (i = 0; i < num_types; ++i) {
TypeSP type_sp(types.GetTypeAtIndex(i));
if (ClangASTContext::IsObjCObjectOrInterfaceType(
type_sp->GetForwardCompilerType())) {
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(CompilerType &parent_qual_type,
const char *ivar_name) {
return LLDB_INVALID_IVAR_OFFSET;
}
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;
}
std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
ObjCLanguageRuntime::ISAToDescriptorIterator>
ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
if (update_if_needed)
UpdateISAToDescriptorMapIfNeeded();
return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
ObjCLanguageRuntime::ISAToDescriptorIterator>(
m_isa_to_descriptor.begin(), m_isa_to_descriptor.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.GetCompilerType().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();
}
CompilerType
ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
bool for_expression) {
if (m_scratch_ast_ctx_ap)
return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression);
return CompilerType();
}
CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType(
ClangASTContext &ast_ctx, const char *name, bool for_expression) {
clang::ASTContext *clang_ast = ast_ctx.getASTContext();
if (!clang_ast)
return CompilerType();
return RealizeType(*clang_ast, name, for_expression);
}
ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
return nullptr;
}
bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
uint64_t &size) {
void *opaque_ptr = compiler_type.GetOpaqueQualType();
size = m_type_size_cache.Lookup(opaque_ptr);
// an ObjC object will at least have an ISA, so 0 is definitely not OK
if (size > 0)
return true;
ClassDescriptorSP class_descriptor_sp =
GetClassDescriptorFromClassName(compiler_type.GetTypeName());
if (!class_descriptor_sp)
return false;
int32_t max_offset = INT32_MIN;
uint64_t sizeof_max = 0;
bool found = false;
for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
int32_t cur_offset = ivar.m_offset;
if (cur_offset > max_offset) {
max_offset = cur_offset;
sizeof_max = ivar.m_size;
found = true;
}
}
size = 8 * (max_offset + sizeof_max);
if (found)
m_type_size_cache.Insert(opaque_ptr, size);
return found;
}
//------------------------------------------------------------------
// Exception breakpoint Precondition class for ObjC:
//------------------------------------------------------------------
void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
const char *class_name) {
m_class_names.insert(class_name);
}
ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {}
bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
StoppointCallbackContext &context) {
return true;
}
void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
Stream &stream, lldb::DescriptionLevel level) {}
Error ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
Args &args) {
Error error;
if (args.GetArgumentCount() > 0)
error.SetErrorString(
"The ObjC Exception breakpoint doesn't support extra options.");
return error;
}