diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index 18cdb6cae073..2bb911c6e566 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -43,6 +43,9 @@ public: ClangASTContext (const char *triple = NULL); ~ClangASTContext(); + + static ClangASTContext* + GetASTContext (clang::ASTContext* ast_ctx); clang::ASTContext * getASTContext(); diff --git a/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/lldb/include/lldb/Target/ObjCLanguageRuntime.h index 7bac57256444..603a1ea325e4 100644 --- a/lldb/include/lldb/Target/ObjCLanguageRuntime.h +++ b/lldb/include/lldb/Target/ObjCLanguageRuntime.h @@ -20,6 +20,7 @@ // Project includes #include "lldb/lldb-private.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/ClangASTType.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeVendor.h" #include "lldb/Target/LanguageRuntime.h" @@ -238,6 +239,25 @@ public: m_type_wp = type_sp; } + struct iVarDescriptor { + ConstString m_name; + ClangASTType m_type; + uint64_t m_size; + int32_t m_offset; + }; + + virtual size_t + GetNumIVars () + { + return 0; + } + + virtual iVarDescriptor + GetIVarAtIndex (size_t idx) + { + return iVarDescriptor(); + } + protected: bool IsPointerValid (lldb::addr_t value, @@ -252,6 +272,25 @@ public: lldb::TypeWP m_type_wp; }; + class EncodingToType + { + public: + virtual ClangASTType RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype); + virtual ClangASTType RealizeType (const char* name, bool allow_unknownanytype); + + virtual ClangASTType RealizeType (clang::ASTContext& ast_ctx, const char* name, bool allow_unknownanytype) = 0; + + virtual ~EncodingToType(); + + protected: + std::unique_ptr m_scratch_ast_ctx_ap; + }; + + typedef std::shared_ptr EncodingToTypeSP; + + virtual EncodingToTypeSP + GetEncodingToType (); + virtual ClassDescriptorSP GetClassDescriptor (ValueObject& in_value); diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 6390f83aeb79..0d50f4625e2e 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -664,6 +664,8 @@ 94CD704E16F8DDEA00CF1E42 /* Cocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD704C16F8DDEA00CF1E42 /* Cocoa.cpp */; }; 94CD705016F8DF1C00CF1E42 /* LibCxxList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD704F16F8DF1C00CF1E42 /* LibCxxList.cpp */; }; 94CD705216F8F5BC00CF1E42 /* LibCxxMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD705116F8F5BC00CF1E42 /* LibCxxMap.cpp */; }; + 94CD7D0919A3FBA300908B7C /* AppleObjCClassDescriptorV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD7D0819A3FBA300908B7C /* AppleObjCClassDescriptorV2.cpp */; }; + 94CD7D0C19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CD7D0B19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp */; }; 94D0B10C16D5535900EA9C70 /* LibCxx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D0B10A16D5535900EA9C70 /* LibCxx.cpp */; }; 94D0B10D16D5535900EA9C70 /* LibStdcpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */; }; 94D6A0AA16CEB55F00833B6E /* NSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A716CEB55F00833B6E /* NSArray.cpp */; }; @@ -1970,6 +1972,10 @@ 94CD704C16F8DDEA00CF1E42 /* Cocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Cocoa.cpp; path = source/DataFormatters/Cocoa.cpp; sourceTree = ""; }; 94CD704F16F8DF1C00CF1E42 /* LibCxxList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxList.cpp; path = source/DataFormatters/LibCxxList.cpp; sourceTree = ""; }; 94CD705116F8F5BC00CF1E42 /* LibCxxMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxMap.cpp; path = source/DataFormatters/LibCxxMap.cpp; sourceTree = ""; }; + 94CD7D0719A3FB8600908B7C /* AppleObjCClassDescriptorV2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleObjCClassDescriptorV2.h; sourceTree = ""; }; + 94CD7D0819A3FBA300908B7C /* AppleObjCClassDescriptorV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleObjCClassDescriptorV2.cpp; sourceTree = ""; }; + 94CD7D0A19A3FBC300908B7C /* AppleObjCTypeEncodingParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleObjCTypeEncodingParser.h; sourceTree = ""; }; + 94CD7D0B19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppleObjCTypeEncodingParser.cpp; sourceTree = ""; }; 94D0B10A16D5535900EA9C70 /* LibCxx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxx.cpp; path = source/DataFormatters/LibCxx.cpp; sourceTree = ""; }; 94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibStdcpp.cpp; path = source/DataFormatters/LibStdcpp.cpp; sourceTree = ""; }; 94D6A0A716CEB55F00833B6E /* NSArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSArray.cpp; path = source/DataFormatters/NSArray.cpp; sourceTree = ""; }; @@ -4045,6 +4051,8 @@ 4CCA644113B40B82003BDF98 /* AppleObjCRuntime */ = { isa = PBXGroup; children = ( + 94CD7D0719A3FB8600908B7C /* AppleObjCClassDescriptorV2.h */, + 94CD7D0819A3FBA300908B7C /* AppleObjCClassDescriptorV2.cpp */, 4CCA644213B40B82003BDF98 /* AppleObjCRuntime.cpp */, 4CCA644313B40B82003BDF98 /* AppleObjCRuntime.h */, 4CCA644413B40B82003BDF98 /* AppleObjCRuntimeV1.cpp */, @@ -4053,6 +4061,8 @@ 4CCA644713B40B82003BDF98 /* AppleObjCRuntimeV2.h */, 4CCA644813B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp */, 4CCA644913B40B82003BDF98 /* AppleObjCTrampolineHandler.h */, + 94CD7D0A19A3FBC300908B7C /* AppleObjCTypeEncodingParser.h */, + 94CD7D0B19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp */, 49DA65041485C942005FF180 /* AppleObjCTypeVendor.h */, 49DA65021485C92A005FF180 /* AppleObjCTypeVendor.cpp */, 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */, @@ -5143,11 +5153,13 @@ 26957D9813D381C900670048 /* RegisterContextDarwin_arm.cpp in Sources */, 26957D9A13D381C900670048 /* RegisterContextDarwin_i386.cpp in Sources */, 26957D9C13D381C900670048 /* RegisterContextDarwin_x86_64.cpp in Sources */, + 94CD7D0919A3FBA300908B7C /* AppleObjCClassDescriptorV2.cpp in Sources */, 265205A813D3E3F700132FE2 /* RegisterContextKDP_arm.cpp in Sources */, 265205AA13D3E3F700132FE2 /* RegisterContextKDP_i386.cpp in Sources */, 265205AC13D3E3F700132FE2 /* RegisterContextKDP_x86_64.cpp in Sources */, 2628A4D513D4977900F5487A /* ThreadKDP.cpp in Sources */, 26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */, + 94CD7D0C19A3FBCE00908B7C /* AppleObjCTypeEncodingParser.cpp in Sources */, 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */, 262D24E613FB8710002D1960 /* RegisterContextMemory.cpp in Sources */, 26F4A21C13FBA31A0064B613 /* ThreadMemory.cpp in Sources */, diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp new file mode 100644 index 000000000000..44c7e9d98fd8 --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -0,0 +1,526 @@ +//===-- AppleObjCClassDescriptorV2.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AppleObjCClassDescriptorV2.h" + +using namespace lldb; +using namespace lldb_private; + +bool +ClassDescriptorV2::Read_objc_class (Process* process, std::unique_ptr &objc_class) const +{ + objc_class.reset(new objc_class_t); + + bool ret = objc_class->Read (process, m_objc_class_ptr); + + if (!ret) + objc_class.reset(); + + return ret; +} + +bool +ClassDescriptorV2::objc_class_t::Read(Process *process, lldb::addr_t addr) +{ + size_t ptr_size = process->GetAddressByteSize(); + + size_t objc_class_size = ptr_size // uintptr_t isa; + + ptr_size // Class superclass; + + ptr_size // void *cache; + + ptr_size // IMP *vtable; + + ptr_size; // uintptr_t data_NEVER_USE; + + DataBufferHeap objc_class_buf (objc_class_size, '\0'); + Error error; + + process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; + m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; + m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; + m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; + lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; + + m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); + m_data_ptr = data_NEVER_USE & ~(lldb::addr_t)3; + + return true; +} + +bool +ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) +{ + size_t ptr_size = process->GetAddressByteSize(); + + size_t size = sizeof(uint32_t) // uint32_t flags; + + sizeof(uint32_t) // uint32_t version; + + ptr_size // const class_ro_t *ro; + + ptr_size // union { method_list_t **method_lists; method_list_t *method_list; }; + + ptr_size // struct chained_property_list *properties; + + ptr_size // const protocol_list_t **protocols; + + ptr_size // Class firstSubclass; + + ptr_size; // Class nextSiblingClass; + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_flags = extractor.GetU32_unchecked(&cursor); + m_version = extractor.GetU32_unchecked(&cursor); + m_ro_ptr = extractor.GetAddress_unchecked(&cursor); + m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); + m_properties_ptr = extractor.GetAddress_unchecked(&cursor); + m_firstSubclass = extractor.GetAddress_unchecked(&cursor); + m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); + + return true; +} + +bool +ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) +{ + size_t ptr_size = process->GetAddressByteSize(); + + size_t size = sizeof(uint32_t) // uint32_t flags; + + sizeof(uint32_t) // uint32_t instanceStart; + + sizeof(uint32_t) // uint32_t instanceSize; + + (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only + + ptr_size // const uint8_t *ivarLayout; + + ptr_size // const char *name; + + ptr_size // const method_list_t *baseMethods; + + ptr_size // const protocol_list_t *baseProtocols; + + ptr_size // const ivar_list_t *ivars; + + ptr_size // const uint8_t *weakIvarLayout; + + ptr_size; // const property_list_t *baseProperties; + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_flags = extractor.GetU32_unchecked(&cursor); + m_instanceStart = extractor.GetU32_unchecked(&cursor); + m_instanceSize = extractor.GetU32_unchecked(&cursor); + if (ptr_size == 8) + m_reserved = extractor.GetU32_unchecked(&cursor); + else + m_reserved = 0; + m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); + m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); + m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); + + DataBufferHeap name_buf(1024, '\0'); + + process->ReadCStringFromMemory(m_name_ptr, (char*)name_buf.GetBytes(), name_buf.GetByteSize(), error); + + if (error.Fail()) + { + return false; + } + + m_name.assign((char*)name_buf.GetBytes()); + + return true; +} + +bool +ClassDescriptorV2::Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr &class_ro, std::unique_ptr &class_rw) const +{ + class_ro.reset(); + class_rw.reset(); + + Error error; + uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(objc_class.m_data_ptr, sizeof(uint32_t), 0, error); + if (!error.Success()) + return false; + + if (class_row_t_flags & RW_REALIZED) + { + class_rw.reset(new class_rw_t); + + if (!class_rw->Read(process, objc_class.m_data_ptr)) + { + class_rw.reset(); + return false; + } + + class_ro.reset(new class_ro_t); + + if (!class_ro->Read(process, class_rw->m_ro_ptr)) + { + class_rw.reset(); + class_ro.reset(); + return false; + } + } + else + { + class_ro.reset(new class_ro_t); + + if (!class_ro->Read(process, objc_class.m_data_ptr)) + { + class_ro.reset(); + return false; + } + } + + return true; +} + +bool +ClassDescriptorV2::method_list_t::Read(Process *process, lldb::addr_t addr) +{ + size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; + + sizeof(uint32_t); // uint32_t count; + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; + m_count = extractor.GetU32_unchecked(&cursor); + m_first_ptr = addr + cursor; + + return true; +} + +bool +ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) +{ + size_t size = GetSize(process); + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_types_ptr = extractor.GetAddress_unchecked(&cursor); + m_imp_ptr = extractor.GetAddress_unchecked(&cursor); + + const size_t buffer_size = 1024; + size_t count; + + DataBufferHeap string_buf(buffer_size, 0); + + count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); + m_name.assign((char*)string_buf.GetBytes(), count); + + count = process->ReadCStringFromMemory(m_types_ptr, (char*)string_buf.GetBytes(), buffer_size, error); + m_types.assign((char*)string_buf.GetBytes(), count); + + return true; +} + +bool +ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) +{ + size_t size = sizeof(uint32_t) // uint32_t entsize; + + sizeof(uint32_t); // uint32_t count; + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_entsize = extractor.GetU32_unchecked(&cursor); + m_count = extractor.GetU32_unchecked(&cursor); + m_first_ptr = addr + cursor; + + return true; +} + +bool +ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) +{ + size_t size = GetSize(process); + + DataBufferHeap buffer (size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) + { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_offset_ptr = extractor.GetAddress_unchecked(&cursor); + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_type_ptr = extractor.GetAddress_unchecked(&cursor); + m_alignment = extractor.GetU32_unchecked(&cursor); + m_size = extractor.GetU32_unchecked(&cursor); + + const size_t buffer_size = 1024; + size_t count; + + DataBufferHeap string_buf(buffer_size, 0); + + count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); + m_name.assign((char*)string_buf.GetBytes(), count); + + count = process->ReadCStringFromMemory(m_type_ptr, (char*)string_buf.GetBytes(), buffer_size, error); + m_type.assign((char*)string_buf.GetBytes(), count); + + return true; +} + +bool +ClassDescriptorV2::Describe (std::function const &superclass_func, + std::function const &instance_method_func, + std::function const &class_method_func, + std::function const &ivar_func) const +{ + lldb_private::Process *process = m_runtime.GetProcess(); + + std::unique_ptr objc_class; + std::unique_ptr class_ro; + std::unique_ptr class_rw; + + if (!Read_objc_class(process, objc_class)) + return 0; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return 0; + + static ConstString NSObject_name("NSObject"); + + if (m_name != NSObject_name && superclass_func) + superclass_func(objc_class->m_superclass); + + if (instance_method_func) + { + std::unique_ptr base_method_list; + + base_method_list.reset(new method_list_t); + if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) + return false; + + if (base_method_list->m_entsize != method_t::GetSize(process)) + return false; + + std::unique_ptr method; + method.reset(new method_t); + + for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) + { + method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize)); + + if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) + break; + } + } + + if (class_method_func) + { + ClassDescriptorV2 metaclass(m_runtime, objc_class->m_isa, NULL); // The metaclass is not in the cache + + // We don't care about the metaclass's superclass, or its class methods. Its instance methods are + // our class methods. + + metaclass.Describe(std::function (nullptr), + class_method_func, + std::function (nullptr), + std::function (nullptr)); + } + + if (ivar_func) + { + ivar_list_t ivar_list; + if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) + return false; + + if (ivar_list.m_entsize != ivar_t::GetSize(process)) + return false; + + ivar_t ivar; + + for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) + { + ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); + + if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), ivar.m_offset_ptr, ivar.m_size)) + break; + } + } + + return true; +} + +ConstString +ClassDescriptorV2::GetClassName () +{ + if (!m_name) + { + lldb_private::Process *process = m_runtime.GetProcess(); + + if (process) + { + std::unique_ptr objc_class; + std::unique_ptr class_ro; + std::unique_ptr class_rw; + + if (!Read_objc_class(process, objc_class)) + return m_name; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return m_name; + + m_name = ConstString(class_ro->m_name.c_str()); + } + } + return m_name; +} + +ObjCLanguageRuntime::ClassDescriptorSP +ClassDescriptorV2::GetSuperclass () +{ + lldb_private::Process *process = m_runtime.GetProcess(); + + if (!process) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + std::unique_ptr objc_class; + + if (!Read_objc_class(process, objc_class)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(objc_class->m_superclass); +} + +uint64_t +ClassDescriptorV2::GetInstanceSize () +{ + lldb_private::Process *process = m_runtime.GetProcess(); + + if (process) + { + std::unique_ptr objc_class; + std::unique_ptr class_ro; + std::unique_ptr class_rw; + + if (!Read_objc_class(process, objc_class)) + return 0; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return 0; + + return class_ro->m_instanceSize; + } + + return 0; +} + +ClassDescriptorV2::iVarsStorage::iVarsStorage (): +m_filled(false), +m_ivars(), +m_mutex(Mutex::eMutexTypeRecursive) +{} + +size_t +ClassDescriptorV2::iVarsStorage::size () +{ + return m_ivars.size(); +} + +ClassDescriptorV2::iVarDescriptor& +ClassDescriptorV2::iVarsStorage::operator[] (size_t idx) +{ + return m_ivars[idx]; +} + +void +ClassDescriptorV2::iVarsStorage::fill (AppleObjCRuntimeV2& runtime, ClassDescriptorV2& descriptor) +{ + if (m_filled) + return; + Mutex::Locker lock(m_mutex); + m_filled = true; + ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(runtime.GetEncodingToType()); + Process* process(runtime.GetProcess()); + if (!encoding_to_type_sp) + return; + descriptor.Describe(nullptr, + nullptr, + nullptr, + [this,process,encoding_to_type_sp](const char * name, const char * type, lldb::addr_t offset_ptr, uint64_t size) -> bool { + const bool allow_unknownanytype = false; + const bool stop_loop = false; + ClangASTType ivar_type = encoding_to_type_sp->RealizeType(type, allow_unknownanytype); + if (ivar_type) + { + Scalar offset_scalar; + Error error; + size_t read = process->ReadScalarIntegerFromMemory(offset_ptr, 4, true, offset_scalar, error); + if (error.Success() && 4 == read) + m_ivars.push_back({ ConstString(name), ivar_type, size, offset_scalar.SInt() }); + } + return stop_loop; + }); +} + +void +ClassDescriptorV2::GetIVarInformation () +{ + m_ivars_storage.fill(m_runtime, *this); +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h new file mode 100644 index 000000000000..ccd8d5147ebc --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -0,0 +1,411 @@ +//===-- AppleObjCClassDescriptorV2.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AppleObjCClassDescriptorV2_h_ +#define liblldb_AppleObjCClassDescriptorV2_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes + +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "AppleObjCRuntimeV2.h" + +namespace lldb_private { + +class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor +{ +public: + friend class lldb_private::AppleObjCRuntimeV2; + +private: + // The constructor should only be invoked by the runtime as it builds its caches + // or populates them. A ClassDescriptorV2 should only ever exist in a cache. + ClassDescriptorV2 (AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name) : + m_runtime (runtime), + m_objc_class_ptr (isa), + m_name (name), + m_ivars_storage() + { + } + +public: + virtual ConstString + GetClassName (); + + virtual ObjCLanguageRuntime::ClassDescriptorSP + GetSuperclass (); + + virtual bool + IsValid () + { + return true; // any Objective-C v2 runtime class descriptor we vend is valid + } + + // a custom descriptor is used for tagged pointers + virtual bool + GetTaggedPointerInfo (uint64_t* info_bits = NULL, + uint64_t* value_bits = NULL, + uint64_t* payload = NULL) + { + return false; + } + + virtual uint64_t + GetInstanceSize (); + + virtual ObjCLanguageRuntime::ObjCISA + GetISA () + { + return m_objc_class_ptr; + } + + virtual bool + Describe (std::function const &superclass_func, + std::function const &instance_method_func, + std::function const &class_method_func, + std::function const &ivar_func) const; + + virtual + ~ClassDescriptorV2 () + { + } + + virtual size_t + GetNumIVars () + { + GetIVarInformation(); + return m_ivars_storage.size(); + } + + virtual iVarDescriptor + GetIVarAtIndex (size_t idx) + { + if (idx >= GetNumIVars()) + return iVarDescriptor(); + return m_ivars_storage[idx]; + } + +protected: + void + GetIVarInformation (); + +private: + static const uint32_t RW_REALIZED = (1 << 31); + + struct objc_class_t { + ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. + ObjCLanguageRuntime::ObjCISA m_superclass; + lldb::addr_t m_cache_ptr; + lldb::addr_t m_vtable_ptr; + lldb::addr_t m_data_ptr; + uint8_t m_flags; + + objc_class_t () : + m_isa (0), + m_superclass (0), + m_cache_ptr (0), + m_vtable_ptr (0), + m_data_ptr (0), + m_flags (0) + { + } + + void + Clear() + { + m_isa = 0; + m_superclass = 0; + m_cache_ptr = 0; + m_vtable_ptr = 0; + m_data_ptr = 0; + m_flags = 0; + } + + bool + Read(Process *process, lldb::addr_t addr); + }; + + struct class_ro_t { + uint32_t m_flags; + uint32_t m_instanceStart; + uint32_t m_instanceSize; + uint32_t m_reserved; + + lldb::addr_t m_ivarLayout_ptr; + lldb::addr_t m_name_ptr; + lldb::addr_t m_baseMethods_ptr; + lldb::addr_t m_baseProtocols_ptr; + lldb::addr_t m_ivars_ptr; + + lldb::addr_t m_weakIvarLayout_ptr; + lldb::addr_t m_baseProperties_ptr; + + std::string m_name; + + bool + Read(Process *process, lldb::addr_t addr); + }; + + struct class_rw_t { + uint32_t m_flags; + uint32_t m_version; + + lldb::addr_t m_ro_ptr; + union { + lldb::addr_t m_method_list_ptr; + lldb::addr_t m_method_lists_ptr; + }; + lldb::addr_t m_properties_ptr; + lldb::addr_t m_protocols_ptr; + + ObjCLanguageRuntime::ObjCISA m_firstSubclass; + ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; + + bool + Read(Process *process, lldb::addr_t addr); + }; + + struct method_list_t + { + uint32_t m_entsize; + uint32_t m_count; + lldb::addr_t m_first_ptr; + + bool + Read(Process *process, lldb::addr_t addr); + }; + + struct method_t + { + lldb::addr_t m_name_ptr; + lldb::addr_t m_types_ptr; + lldb::addr_t m_imp_ptr; + + std::string m_name; + std::string m_types; + + static size_t GetSize(Process *process) + { + size_t ptr_size = process->GetAddressByteSize(); + + return ptr_size // SEL name; + + ptr_size // const char *types; + + ptr_size; // IMP imp; + } + + bool + Read(Process *process, lldb::addr_t addr); + }; + + struct ivar_list_t + { + uint32_t m_entsize; + uint32_t m_count; + lldb::addr_t m_first_ptr; + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct ivar_t + { + lldb::addr_t m_offset_ptr; + lldb::addr_t m_name_ptr; + lldb::addr_t m_type_ptr; + uint32_t m_alignment; + uint32_t m_size; + + std::string m_name; + std::string m_type; + + static size_t GetSize(Process *process) + { + size_t ptr_size = process->GetAddressByteSize(); + + return ptr_size // uintptr_t *offset; + + ptr_size // const char *name; + + ptr_size // const char *type; + + sizeof(uint32_t) // uint32_t alignment; + + sizeof(uint32_t); // uint32_t size; + } + + bool + Read(Process *process, lldb::addr_t addr); + }; + + class iVarsStorage + { + public: + iVarsStorage (); + + size_t + size (); + + iVarDescriptor& + operator[] (size_t idx); + + void + fill (AppleObjCRuntimeV2& runtime, ClassDescriptorV2& descriptor); + + private: + bool m_filled; + std::vector m_ivars; + Mutex m_mutex; + }; + + bool + Read_objc_class (Process* process, std::unique_ptr &objc_class) const; + + bool + Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr &class_ro, std::unique_ptr &class_rw) const; + + AppleObjCRuntimeV2 &m_runtime; // The runtime, so we can read information lazily. + lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., objects of this class type have this as their ISA) + ConstString m_name; // May be NULL + iVarsStorage m_ivars_storage; +}; + +// tagged pointer descriptor +class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor +{ +public: + ClassDescriptorV2Tagged (ConstString class_name, + uint64_t payload) + { + m_name = class_name; + if (!m_name) + { + m_valid = false; + return; + } + m_valid = true; + m_payload = payload; + m_info_bits = (m_payload & 0xF0ULL) >> 4; + m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; + } + + ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, + uint64_t payload) + { + if (!actual_class_sp) + { + m_valid = false; + return; + } + m_name = actual_class_sp->GetClassName(); + if (!m_name) + { + m_valid = false; + return; + } + m_valid = true; + m_payload = payload; + m_info_bits = (m_payload & 0x0FULL); + m_value_bits = (m_payload & ~0x0FULL) >> 4; + } + + virtual ConstString + GetClassName () + { + return m_name; + } + + virtual ObjCLanguageRuntime::ClassDescriptorSP + GetSuperclass () + { + // tagged pointers can represent a class that has a superclass, but since that information is not + // stored in the object itself, we would have to query the runtime to discover the hierarchy + // for the time being, we skip this step in the interest of static discovery + return ObjCLanguageRuntime::ClassDescriptorSP(); + } + + virtual bool + IsValid () + { + return m_valid; + } + + virtual bool + IsKVO () + { + return false; // tagged pointers are not KVO'ed + } + + virtual bool + IsCFType () + { + return false; // tagged pointers are not CF objects + } + + virtual bool + GetTaggedPointerInfo (uint64_t* info_bits = NULL, + uint64_t* value_bits = NULL, + uint64_t* payload = NULL) + { + if (info_bits) + *info_bits = GetInfoBits(); + if (value_bits) + *value_bits = GetValueBits(); + if (payload) + *payload = GetPayload(); + return true; + } + + virtual uint64_t + GetInstanceSize () + { + return (IsValid() ? m_pointer_size : 0); + } + + virtual ObjCLanguageRuntime::ObjCISA + GetISA () + { + return 0; // tagged pointers have no ISA + } + + // these calls are not part of any formal tagged pointers specification + virtual uint64_t + GetValueBits () + { + return (IsValid() ? m_value_bits : 0); + } + + virtual uint64_t + GetInfoBits () + { + return (IsValid() ? m_info_bits : 0); + } + + virtual uint64_t + GetPayload () + { + return (IsValid() ? m_payload : 0); + } + + virtual + ~ClassDescriptorV2Tagged () + {} + +private: + ConstString m_name; + uint8_t m_pointer_size; + bool m_valid; + uint64_t m_info_bits; + uint64_t m_value_bits; + uint64_t m_payload; + +}; + +} // namespace lldb_private + +#endif // liblldb_AppleObjCRuntime_h_ + diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index e20433506542..e3b8ef5c79d8 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -42,9 +42,13 @@ #include "lldb/Target/Thread.h" #include "AppleObjCRuntimeV2.h" +#include "AppleObjCClassDescriptorV2.h" +#include "AppleObjCTypeEncodingParser.h" #include "AppleObjCTypeVendor.h" #include "AppleObjCTrampolineHandler.h" +#include "clang/AST/ASTContext.h" + #include using namespace lldb; @@ -348,7 +352,8 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, m_has_object_getClass (false), m_loaded_objc_opt (false), m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this,objc_module_sp)), - m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp)) + m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp)), + m_encoding_to_type_sp() { static const ConstString g_gdb_object_getClass("gdb_object_getClass"); m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL); @@ -855,757 +860,6 @@ AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate (Process *process, AppleObjC return true; } -class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor -{ -public: - friend class lldb_private::AppleObjCRuntimeV2; - -private: - // The constructor should only be invoked by the runtime as it builds its caches - // or populates them. A ClassDescriptorV2 should only ever exist in a cache. - ClassDescriptorV2 (AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name) : - m_runtime (runtime), - m_objc_class_ptr (isa), - m_name (name) - { - } - -public: - virtual ConstString - GetClassName () - { - if (!m_name) - { - lldb_private::Process *process = m_runtime.GetProcess(); - - if (process) - { - std::unique_ptr objc_class; - std::unique_ptr class_ro; - std::unique_ptr class_rw; - - if (!Read_objc_class(process, objc_class)) - return m_name; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return m_name; - - m_name = ConstString(class_ro->m_name.c_str()); - } - } - return m_name; - } - - virtual ObjCLanguageRuntime::ClassDescriptorSP - GetSuperclass () - { - lldb_private::Process *process = m_runtime.GetProcess(); - - if (!process) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - std::unique_ptr objc_class; - - if (!Read_objc_class(process, objc_class)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(objc_class->m_superclass); - } - - virtual bool - IsValid () - { - return true; // any Objective-C v2 runtime class descriptor we vend is valid - } - - // a custom descriptor is used for tagged pointers - virtual bool - GetTaggedPointerInfo (uint64_t* info_bits = NULL, - uint64_t* value_bits = NULL, - uint64_t* payload = NULL) - { - return false; - } - - virtual uint64_t - GetInstanceSize () - { - lldb_private::Process *process = m_runtime.GetProcess(); - - if (process) - { - std::unique_ptr objc_class; - std::unique_ptr class_ro; - std::unique_ptr class_rw; - - if (!Read_objc_class(process, objc_class)) - return 0; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return 0; - - return class_ro->m_instanceSize; - } - - return 0; - } - - virtual ObjCLanguageRuntime::ObjCISA - GetISA () - { - return m_objc_class_ptr; - } - - virtual bool - Describe (std::function const &superclass_func, - std::function const &instance_method_func, - std::function const &class_method_func, - std::function const &ivar_func) - { - lldb_private::Process *process = m_runtime.GetProcess(); - - std::unique_ptr objc_class; - std::unique_ptr class_ro; - std::unique_ptr class_rw; - - if (!Read_objc_class(process, objc_class)) - return 0; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return 0; - - static ConstString NSObject_name("NSObject"); - - if (m_name != NSObject_name && superclass_func) - superclass_func(objc_class->m_superclass); - - if (instance_method_func) - { - std::unique_ptr base_method_list; - - base_method_list.reset(new method_list_t); - if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) - return false; - - if (base_method_list->m_entsize != method_t::GetSize(process)) - return false; - - std::unique_ptr method; - method.reset(new method_t); - - for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) - { - method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize)); - - if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) - break; - } - } - - if (class_method_func) - { - ClassDescriptorV2 metaclass(m_runtime, objc_class->m_isa, NULL); // The metaclass is not in the cache - - // We don't care about the metaclass's superclass, or its class methods. Its instance methods are - // our class methods. - - metaclass.Describe(std::function (nullptr), - class_method_func, - std::function (nullptr), - std::function (nullptr)); - } - - if (ivar_func) - { - ivar_list_t ivar_list; - if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) - return false; - - if (ivar_list.m_entsize != ivar_t::GetSize(process)) - return false; - - ivar_t ivar; - - for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) - { - ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); - - if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), ivar.m_offset_ptr, ivar.m_size)) - break; - } - } - - return true; - } - - virtual - ~ClassDescriptorV2 () - { - } - -private: - static const uint32_t RW_REALIZED = (1 << 31); - - struct objc_class_t { - ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. - ObjCLanguageRuntime::ObjCISA m_superclass; - lldb::addr_t m_cache_ptr; - lldb::addr_t m_vtable_ptr; - lldb::addr_t m_data_ptr; - uint8_t m_flags; - - objc_class_t () : - m_isa (0), - m_superclass (0), - m_cache_ptr (0), - m_vtable_ptr (0), - m_data_ptr (0), - m_flags (0) - { - } - - void - Clear() - { - m_isa = 0; - m_superclass = 0; - m_cache_ptr = 0; - m_vtable_ptr = 0; - m_data_ptr = 0; - m_flags = 0; - } - - bool Read(Process *process, lldb::addr_t addr) - { - size_t ptr_size = process->GetAddressByteSize(); - - size_t objc_class_size = ptr_size // uintptr_t isa; - + ptr_size // Class superclass; - + ptr_size // void *cache; - + ptr_size // IMP *vtable; - + ptr_size; // uintptr_t data_NEVER_USE; - - DataBufferHeap objc_class_buf (objc_class_size, '\0'); - Error error; - - process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; - m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; - m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; - m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; - lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; - - m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); - m_data_ptr = data_NEVER_USE & ~(lldb::addr_t)3; - - return true; - } - }; - - struct class_ro_t { - uint32_t m_flags; - uint32_t m_instanceStart; - uint32_t m_instanceSize; - uint32_t m_reserved; - - lldb::addr_t m_ivarLayout_ptr; - lldb::addr_t m_name_ptr; - lldb::addr_t m_baseMethods_ptr; - lldb::addr_t m_baseProtocols_ptr; - lldb::addr_t m_ivars_ptr; - - lldb::addr_t m_weakIvarLayout_ptr; - lldb::addr_t m_baseProperties_ptr; - - std::string m_name; - - bool Read(Process *process, lldb::addr_t addr) - { - size_t ptr_size = process->GetAddressByteSize(); - - size_t size = sizeof(uint32_t) // uint32_t flags; - + sizeof(uint32_t) // uint32_t instanceStart; - + sizeof(uint32_t) // uint32_t instanceSize; - + (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only - + ptr_size // const uint8_t *ivarLayout; - + ptr_size // const char *name; - + ptr_size // const method_list_t *baseMethods; - + ptr_size // const protocol_list_t *baseProtocols; - + ptr_size // const ivar_list_t *ivars; - + ptr_size // const uint8_t *weakIvarLayout; - + ptr_size; // const property_list_t *baseProperties; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_flags = extractor.GetU32_unchecked(&cursor); - m_instanceStart = extractor.GetU32_unchecked(&cursor); - m_instanceSize = extractor.GetU32_unchecked(&cursor); - if (ptr_size == 8) - m_reserved = extractor.GetU32_unchecked(&cursor); - else - m_reserved = 0; - m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); - m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); - m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); - - DataBufferHeap name_buf(1024, '\0'); - - process->ReadCStringFromMemory(m_name_ptr, (char*)name_buf.GetBytes(), name_buf.GetByteSize(), error); - - if (error.Fail()) - { - return false; - } - - m_name.assign((char*)name_buf.GetBytes()); - - return true; - } - }; - - struct class_rw_t { - uint32_t m_flags; - uint32_t m_version; - - lldb::addr_t m_ro_ptr; - union { - lldb::addr_t m_method_list_ptr; - lldb::addr_t m_method_lists_ptr; - }; - lldb::addr_t m_properties_ptr; - lldb::addr_t m_protocols_ptr; - - ObjCLanguageRuntime::ObjCISA m_firstSubclass; - ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; - - bool Read(Process *process, lldb::addr_t addr) - { - size_t ptr_size = process->GetAddressByteSize(); - - size_t size = sizeof(uint32_t) // uint32_t flags; - + sizeof(uint32_t) // uint32_t version; - + ptr_size // const class_ro_t *ro; - + ptr_size // union { method_list_t **method_lists; method_list_t *method_list; }; - + ptr_size // struct chained_property_list *properties; - + ptr_size // const protocol_list_t **protocols; - + ptr_size // Class firstSubclass; - + ptr_size; // Class nextSiblingClass; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_flags = extractor.GetU32_unchecked(&cursor); - m_version = extractor.GetU32_unchecked(&cursor); - m_ro_ptr = extractor.GetAddress_unchecked(&cursor); - m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); - m_properties_ptr = extractor.GetAddress_unchecked(&cursor); - m_firstSubclass = extractor.GetAddress_unchecked(&cursor); - m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); - - return true; - } - }; - - struct method_list_t - { - uint32_t m_entsize; - uint32_t m_count; - lldb::addr_t m_first_ptr; - - bool Read(Process *process, lldb::addr_t addr) - { - size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; - + sizeof(uint32_t); // uint32_t count; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; - m_count = extractor.GetU32_unchecked(&cursor); - m_first_ptr = addr + cursor; - - return true; - } - }; - - struct method_t - { - lldb::addr_t m_name_ptr; - lldb::addr_t m_types_ptr; - lldb::addr_t m_imp_ptr; - - std::string m_name; - std::string m_types; - - static size_t GetSize(Process *process) - { - size_t ptr_size = process->GetAddressByteSize(); - - return ptr_size // SEL name; - + ptr_size // const char *types; - + ptr_size; // IMP imp; - } - - bool Read(Process *process, lldb::addr_t addr) - { - size_t size = GetSize(process); - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_types_ptr = extractor.GetAddress_unchecked(&cursor); - m_imp_ptr = extractor.GetAddress_unchecked(&cursor); - - const size_t buffer_size = 1024; - size_t count; - - DataBufferHeap string_buf(buffer_size, 0); - - count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); - m_name.assign((char*)string_buf.GetBytes(), count); - - count = process->ReadCStringFromMemory(m_types_ptr, (char*)string_buf.GetBytes(), buffer_size, error); - m_types.assign((char*)string_buf.GetBytes(), count); - - return true; - } - }; - - struct ivar_list_t - { - uint32_t m_entsize; - uint32_t m_count; - lldb::addr_t m_first_ptr; - - bool Read(Process *process, lldb::addr_t addr) - { - size_t size = sizeof(uint32_t) // uint32_t entsize; - + sizeof(uint32_t); // uint32_t count; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_entsize = extractor.GetU32_unchecked(&cursor); - m_count = extractor.GetU32_unchecked(&cursor); - m_first_ptr = addr + cursor; - - return true; - } - }; - - struct ivar_t - { - lldb::addr_t m_offset_ptr; - lldb::addr_t m_name_ptr; - lldb::addr_t m_type_ptr; - uint32_t m_alignment; - uint32_t m_size; - - std::string m_name; - std::string m_type; - - static size_t GetSize(Process *process) - { - size_t ptr_size = process->GetAddressByteSize(); - - return ptr_size // uintptr_t *offset; - + ptr_size // const char *name; - + ptr_size // const char *type; - + sizeof(uint32_t) // uint32_t alignment; - + sizeof(uint32_t); // uint32_t size; - } - - bool Read(Process *process, lldb::addr_t addr) - { - size_t size = GetSize(process); - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_offset_ptr = extractor.GetAddress_unchecked(&cursor); - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_type_ptr = extractor.GetAddress_unchecked(&cursor); - m_alignment = extractor.GetU32_unchecked(&cursor); - m_size = extractor.GetU32_unchecked(&cursor); - - const size_t buffer_size = 1024; - size_t count; - - DataBufferHeap string_buf(buffer_size, 0); - - count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); - m_name.assign((char*)string_buf.GetBytes(), count); - - count = process->ReadCStringFromMemory(m_type_ptr, (char*)string_buf.GetBytes(), buffer_size, error); - m_type.assign((char*)string_buf.GetBytes(), count); - - return true; - } - }; - - bool Read_objc_class (Process* process, std::unique_ptr &objc_class) - { - objc_class.reset(new objc_class_t); - - bool ret = objc_class->Read (process, m_objc_class_ptr); - - if (!ret) - objc_class.reset(); - - return ret; - } - - bool Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr &class_ro, std::unique_ptr &class_rw) - { - class_ro.reset(); - class_rw.reset(); - - Error error; - uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(objc_class.m_data_ptr, sizeof(uint32_t), 0, error); - if (!error.Success()) - return false; - - if (class_row_t_flags & RW_REALIZED) - { - class_rw.reset(new class_rw_t); - - if (!class_rw->Read(process, objc_class.m_data_ptr)) - { - class_rw.reset(); - return false; - } - - class_ro.reset(new class_ro_t); - - if (!class_ro->Read(process, class_rw->m_ro_ptr)) - { - class_rw.reset(); - class_ro.reset(); - return false; - } - } - else - { - class_ro.reset(new class_ro_t); - - if (!class_ro->Read(process, objc_class.m_data_ptr)) - { - class_ro.reset(); - return false; - } - } - - return true; - } - - AppleObjCRuntimeV2 &m_runtime; // The runtime, so we can read information lazily. - lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., objects of this class type have this as their ISA) - ConstString m_name; // May be NULL -}; - -// tagged pointer descriptor -class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor -{ -public: - ClassDescriptorV2Tagged (ConstString class_name, - uint64_t payload) - { - m_name = class_name; - if (!m_name) - { - m_valid = false; - return; - } - m_valid = true; - m_payload = payload; - m_info_bits = (m_payload & 0xF0ULL) >> 4; - m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; - } - - ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, - uint64_t payload) - { - if (!actual_class_sp) - { - m_valid = false; - return; - } - m_name = actual_class_sp->GetClassName(); - if (!m_name) - { - m_valid = false; - return; - } - m_valid = true; - m_payload = payload; - m_info_bits = (m_payload & 0x0FULL); - m_value_bits = (m_payload & ~0x0FULL) >> 4; - } - - virtual ConstString - GetClassName () - { - return m_name; - } - - virtual ObjCLanguageRuntime::ClassDescriptorSP - GetSuperclass () - { - // tagged pointers can represent a class that has a superclass, but since that information is not - // stored in the object itself, we would have to query the runtime to discover the hierarchy - // for the time being, we skip this step in the interest of static discovery - return ObjCLanguageRuntime::ClassDescriptorSP(); - } - - virtual bool - IsValid () - { - return m_valid; - } - - virtual bool - IsKVO () - { - return false; // tagged pointers are not KVO'ed - } - - virtual bool - IsCFType () - { - return false; // tagged pointers are not CF objects - } - - virtual bool - GetTaggedPointerInfo (uint64_t* info_bits = NULL, - uint64_t* value_bits = NULL, - uint64_t* payload = NULL) - { - if (info_bits) - *info_bits = GetInfoBits(); - if (value_bits) - *value_bits = GetValueBits(); - if (payload) - *payload = GetPayload(); - return true; - } - - virtual uint64_t - GetInstanceSize () - { - return (IsValid() ? m_pointer_size : 0); - } - - virtual ObjCLanguageRuntime::ObjCISA - GetISA () - { - return 0; // tagged pointers have no ISA - } - - // these calls are not part of any formal tagged pointers specification - virtual uint64_t - GetValueBits () - { - return (IsValid() ? m_value_bits : 0); - } - - virtual uint64_t - GetInfoBits () - { - return (IsValid() ? m_info_bits : 0); - } - - virtual uint64_t - GetPayload () - { - return (IsValid() ? m_payload : 0); - } - - virtual - ~ClassDescriptorV2Tagged () - {} - -private: - ConstString m_name; - uint8_t m_pointer_size; - bool m_valid; - uint64_t m_info_bits; - uint64_t m_value_bits; - uint64_t m_payload; - -}; - ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptorFromISA (ObjCISA isa) { @@ -1621,6 +875,18 @@ ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj) { ClassDescriptorSP objc_class_sp; + if (valobj.IsBaseClass()) + { + ValueObject *parent = valobj.GetParent(); + // if I am my own parent, bail out of here fast.. + if (parent && parent != &valobj) + { + ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent); + if (parent_descriptor_sp) + return parent_descriptor_sp->GetSuperclass(); + } + return nullptr; + } // 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) @@ -2651,3 +1917,11 @@ AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjC } return false; } + +ObjCLanguageRuntime::EncodingToTypeSP +AppleObjCRuntimeV2::GetEncodingToType () +{ + if (!m_encoding_to_type_sp) + m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this)); + return m_encoding_to_type_sp; +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index c6addc624a58..3c47cebf2acd 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -105,6 +105,9 @@ public: virtual lldb::addr_t LookupRuntimeSymbol (const ConstString &name); + virtual EncodingToTypeSP + GetEncodingToType (); + protected: virtual lldb::BreakpointResolverSP CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp); @@ -277,6 +280,7 @@ private: bool m_loaded_objc_opt; std::unique_ptr m_non_pointer_isa_cache_ap; std::unique_ptr m_tagged_pointer_vendor_ap; + EncodingToTypeSP m_encoding_to_type_sp; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp new file mode 100644 index 000000000000..3e59b75702c0 --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -0,0 +1,275 @@ +//===-- AppleObjCTypeEncodingParser.cpp -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AppleObjCTypeEncodingParser.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTType.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/StringLexer.h" + +#include + +using namespace lldb_private; +using namespace lldb_utility; + +AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser (ObjCLanguageRuntime& runtime) : +ObjCLanguageRuntime::EncodingToType() +{ + if (!m_scratch_ast_ctx_ap) + m_scratch_ast_ctx_ap.reset(new ClangASTContext(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().str().c_str())); +} + +std::string +AppleObjCTypeEncodingParser::ReadStructName(lldb_utility::StringLexer& type) +{ + StreamString buffer; + while (type.HasAtLeast(1) && type.Peek() != '=') + buffer.Printf("%c",type.Next()); + return buffer.GetString(); +} + +std::string +AppleObjCTypeEncodingParser::ReadStructElementName(lldb_utility::StringLexer& type) +{ + StreamString buffer; + while (type.HasAtLeast(1) && type.Peek() != '"') + buffer.Printf("%c",type.Next()); + return buffer.GetString(); +} + +uint +AppleObjCTypeEncodingParser::ReadNumber (lldb_utility::StringLexer& type) +{ + uint total = 0; + while (type.HasAtLeast(1) && isdigit(type.Peek())) + total = 10*total + (type.Next() - '0'); + return total; +} + +// as an extension to the published grammar recent runtimes emit structs like this: +// "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}" + +AppleObjCTypeEncodingParser::StructElement::StructElement() : +name(""), +type(clang::QualType()), +bitfield(0) +{} + +AppleObjCTypeEncodingParser::StructElement +AppleObjCTypeEncodingParser::ReadStructElement (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype) +{ + StructElement retval; + if (type.NextIf('"')) + retval.name = ReadStructElementName(type); + if (!type.NextIf('"')) + return retval; + uint32_t bitfield_size = 0; + retval.type = BuildType(ast_ctx, type, allow_unknownanytype, &bitfield_size); + retval.bitfield = bitfield_size; + return retval; +} + +clang::QualType +AppleObjCTypeEncodingParser::BuildStruct (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype) +{ + return BuildAggregate(ast_ctx, type, allow_unknownanytype, '{', '}', clang::TTK_Struct); +} + +clang::QualType +AppleObjCTypeEncodingParser::BuildUnion (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype) +{ + return BuildAggregate(ast_ctx, type, allow_unknownanytype, '(', ')', clang::TTK_Union); +} + +clang::QualType +AppleObjCTypeEncodingParser::BuildAggregate (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype, char opener, char closer, uint kind) +{ + if (!type.NextIf(opener)) + return clang::QualType(); + std::string name(ReadStructName(type)); + if (!type.NextIf('=')) + return clang::QualType(); + bool in_union = true; + std::vector elements; + while (in_union && type.HasAtLeast(1)) + { + if (type.NextIf(closer)) + { + in_union = false; + break; + } + else + { + auto element = ReadStructElement(ast_ctx, type, allow_unknownanytype); + if (element.type.isNull()) + break; + else + elements.push_back(element); + } + } + if (in_union) + return clang::QualType(); + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + ClangASTType union_type(lldb_ctx->CreateRecordType(nullptr, lldb::eAccessPublic, name.c_str(), kind, lldb::eLanguageTypeC)); + if (union_type) + { + union_type.StartTagDeclarationDefinition(); + + unsigned int count = 0; + for (auto element: elements) + { + if (element.name.empty()) + { + StreamString elem_name; + elem_name.Printf("__unnamed_%u",count); + element.name = std::string(elem_name.GetData()); + } + union_type.AddFieldToRecordType(element.name.c_str(), ClangASTType(&ast_ctx,element.type.getAsOpaquePtr()), lldb::eAccessPublic, element.bitfield); + ++count; + } + + union_type.CompleteTagDeclarationDefinition(); + } + return union_type.GetQualType(); +} + +clang::QualType +AppleObjCTypeEncodingParser::BuildArray (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype) +{ + if (!type.NextIf('[')) + return clang::QualType(); + uint size = ReadNumber(type); + clang::QualType element_type(BuildType(ast_ctx, type, allow_unknownanytype)); + if (!type.NextIf(']')) + return clang::QualType(); + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + ClangASTType array_type(lldb_ctx->CreateArrayType(ClangASTType(&ast_ctx,element_type.getAsOpaquePtr()), size, false)); + return array_type.GetQualType(); +} + +clang::QualType +AppleObjCTypeEncodingParser::BuildType (clang::ASTContext &ast_ctx, StringLexer& type, bool allow_unknownanytype, uint32_t *bitfield_bit_size) +{ + if (!type.HasAtLeast(1)) + return clang::QualType(); + + if (type.NextIf('c')) + return ast_ctx.CharTy; + if (type.NextIf('i')) + return ast_ctx.IntTy; + if (type.NextIf('s')) + return ast_ctx.ShortTy; + if (type.NextIf('l')) + { + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); + } + if (type.NextIf('q')) + return ast_ctx.LongLongTy; + if (type.NextIf('C')) + return ast_ctx.UnsignedCharTy; + if (type.NextIf('I')) + return ast_ctx.UnsignedIntTy; + if (type.NextIf('S')) + return ast_ctx.UnsignedShortTy; + if (type.NextIf('L')) + { + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + return lldb_ctx->GetIntTypeFromBitSize(32, false).GetQualType(); + } + if (type.NextIf('Q')) + return ast_ctx.UnsignedLongLongTy; + if (type.NextIf('f')) + return ast_ctx.FloatTy; + if (type.NextIf('d')) + return ast_ctx.DoubleTy; + if (type.NextIf('B')) + return ast_ctx.BoolTy; + if (type.NextIf('v')) + return ast_ctx.VoidTy; + if (type.NextIf('*')) + return ast_ctx.getPointerType(ast_ctx.CharTy); + if (type.NextIf('@')) + return ast_ctx.getObjCIdType(); + if (type.NextIf('#')) + return ast_ctx.getObjCClassType(); + if (type.NextIf(':')) + return ast_ctx.getObjCSelType(); + + if (type.NextIf('b')) + { + uint size = ReadNumber(type); + if (bitfield_bit_size) + { + *bitfield_bit_size = size; + return ast_ctx.UnsignedIntTy; // FIXME: the spec is fairly vague here. + } + else + return clang::QualType(); + } + + if (type.NextIf('r')) + { + clang::QualType target_type = BuildType(ast_ctx, type, allow_unknownanytype); + if (target_type.isNull()) + return clang::QualType(); + else if (target_type == ast_ctx.UnknownAnyTy) + return ast_ctx.UnknownAnyTy; + else + return ast_ctx.getConstType(target_type); + } + + if (type.NextIf('^')) + { + clang::QualType target_type = BuildType(ast_ctx, type, allow_unknownanytype); + if (target_type.isNull()) + return clang::QualType(); + else if (target_type == ast_ctx.UnknownAnyTy) + return ast_ctx.UnknownAnyTy; + else + return ast_ctx.getPointerType(target_type); + } + + if (type.NextIf('?')) + return allow_unknownanytype ? ast_ctx.UnknownAnyTy : clang::QualType(); + + if (type.Peek() == '{') + return BuildStruct(ast_ctx, type, allow_unknownanytype); + + if (type.Peek() == '[') + return BuildArray(ast_ctx, type, allow_unknownanytype); + + if (type.Peek() == '(') + return BuildUnion(ast_ctx, type, allow_unknownanytype); + + return clang::QualType(); +} + +ClangASTType +AppleObjCTypeEncodingParser::RealizeType (clang::ASTContext &ast_ctx, const char* name, bool allow_unknownanytype) +{ + if (name && name[0]) + { + StringLexer lexer(name); + clang::QualType qual_type = BuildType(ast_ctx, lexer, allow_unknownanytype); + return ClangASTType(&ast_ctx, qual_type.getAsOpaquePtr()); + } + return ClangASTType(); +} + diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h new file mode 100644 index 000000000000..00685463d4e1 --- /dev/null +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -0,0 +1,78 @@ +//===-- AppleObjCTypeEncodingParser.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AppleObjCTypeEncodingParser_h_ +#define liblldb_AppleObjCTypeEncodingParser_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes + +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ObjCLanguageRuntime.h" + +#include "clang/AST/ASTContext.h" + +namespace lldb_utility { + class StringLexer; +} + +namespace lldb_private { + + class AppleObjCTypeEncodingParser : public ObjCLanguageRuntime::EncodingToType + { + public: + AppleObjCTypeEncodingParser (ObjCLanguageRuntime& runtime); + virtual ClangASTType RealizeType (clang::ASTContext &ast_ctx, const char* name, bool allow_unknownanytype); + virtual ~AppleObjCTypeEncodingParser() {} + + private: + struct StructElement { + std::string name; + clang::QualType type; + uint32_t bitfield; + + StructElement (); + ~StructElement () = default; + }; + + clang::QualType + BuildType (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype, uint32_t *bitfield_bit_size = nullptr); + + clang::QualType + BuildStruct (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype); + + clang::QualType + BuildAggregate (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype, char opener, char closer, uint kind); + + clang::QualType + BuildUnion (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype); + + clang::QualType + BuildArray (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype); + + std::string + ReadStructName(lldb_utility::StringLexer& type); + + StructElement + ReadStructElement (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool allow_unknownanytype); + + std::string + ReadStructElementName(lldb_utility::StringLexer& type); + + uint + ReadNumber (lldb_utility::StringLexer& type); + + }; + +} // namespace lldb_private + +#endif // liblldb_AppleObjCTypeEncodingParser_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp index 254dc75fc7dc..76e6b262e5d4 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.cpp @@ -164,7 +164,8 @@ private: AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) : TypeVendor(), m_runtime(runtime), - m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()) + m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()), + m_type_realizer_sp(m_runtime.GetEncodingToType()) { m_external_source = new AppleObjCExternalASTSource (*this); llvm::IntrusiveRefCntPtr external_source_owning_ptr (m_external_source); @@ -323,7 +324,7 @@ public: } } - clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance) + clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) { if (!m_is_valid || m_type_vector.size() < 3) return NULL; @@ -339,12 +340,14 @@ public: const bool isDefined = false; const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None; const bool HasRelatedResultType = false; + const bool allow_unknownanytype = true; std::vector selector_components; const char *name_cursor = name; bool is_zero_argument = true; + while (*name_cursor != '\0') { const char *colon_loc = strchr(name_cursor, ':'); @@ -363,7 +366,7 @@ public: clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data()); - clang::QualType ret_type = BuildType(ast_ctx, m_type_vector[0].c_str()); + clang::QualType ret_type = type_realizer_sp->RealizeType(interface_decl->getASTContext(), m_type_vector[0].c_str(), allow_unknownanytype).GetQualType(); if (ret_type.isNull()) return NULL; @@ -389,7 +392,8 @@ public: ai != ae; ++ai) { - clang::QualType arg_type = BuildType(ast_ctx, m_type_vector[ai].c_str()); + const bool allow_unknownanytype = true; + clang::QualType arg_type = type_realizer_sp->RealizeType(ast_ctx, m_type_vector[ai].c_str(), allow_unknownanytype).GetQualType(); if (arg_type.isNull()) return NULL; // well, we just wasted a bunch of time. Wish we could delete the stuff we'd just made! @@ -410,81 +414,6 @@ public: return ret; } private: - clang::QualType BuildType (clang::ASTContext &ast_ctx, const char *type) - { - if (!type) - return clang::QualType(); - - switch (*type) - { - default: - return ast_ctx.UnknownAnyTy; - case 'r': - { - clang::QualType target_type = BuildType(ast_ctx, type+1); - if (target_type.isNull()) - return clang::QualType(); - else if (target_type == ast_ctx.UnknownAnyTy) - return ast_ctx.UnknownAnyTy; - else - return ast_ctx.getConstType(target_type); - } - case '^': - { - clang::QualType target_type = BuildType(ast_ctx, type+1); - if (target_type.isNull()) - return clang::QualType(); - else if (target_type == ast_ctx.UnknownAnyTy) - return ast_ctx.UnknownAnyTy; - else - return ast_ctx.getPointerType(target_type); - } - case 'c': - return ast_ctx.CharTy; - case 'i': - return ast_ctx.IntTy; - case 's': - return ast_ctx.ShortTy; - case 'l': - if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64) - return ast_ctx.IntTy; - else - return ast_ctx.LongTy; - case 'q': - return ast_ctx.LongLongTy; - case 'C': - return ast_ctx.UnsignedCharTy; - case 'I': - return ast_ctx.UnsignedIntTy; - case 'S': - return ast_ctx.UnsignedShortTy; - case 'L': - if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64) - return ast_ctx.UnsignedIntTy; - else - return ast_ctx.UnsignedLongTy; - case 'Q': - return ast_ctx.UnsignedLongLongTy; - case 'f': - return ast_ctx.FloatTy; - case 'd': - return ast_ctx.DoubleTy; - case 'B': - return ast_ctx.BoolTy; - case 'v': - return ast_ctx.VoidTy; - case '*': - return ast_ctx.getPointerType(ast_ctx.CharTy); - case '@': - return ast_ctx.getObjCIdType(); - case '#': - return ast_ctx.getObjCClassType(); - case ':': - return ast_ctx.getObjCSelType(); - } - return clang::QualType(); - } - typedef std::vector TypeVector; TypeVector m_type_vector; @@ -532,7 +461,7 @@ AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) ObjCRuntimeMethodType method_type(types); - clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true); + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true, m_type_realizer_sp); if (log) log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types); @@ -550,7 +479,7 @@ AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) ObjCRuntimeMethodType method_type(types); - clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false); + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false, m_type_realizer_sp); if (log) log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.h index 5a24f397ac26..1079b69020ce 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeVendor.h @@ -51,6 +51,7 @@ private: ObjCLanguageRuntime &m_runtime; ClangASTContext m_ast_ctx; + ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp; AppleObjCExternalASTSource *m_external_source; typedef llvm::DenseMap ISAToInterfaceMap; diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index f2d8bd8fbc69..aae96bfa9a3b 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -79,6 +79,16 @@ using namespace lldb_private; using namespace llvm; using namespace clang; +typedef llvm::DenseMap ClangASTMap; + +static ClangASTMap & +GetASTMap() +{ + static ClangASTMap g_map; + return g_map; +} + + clang::AccessSpecifier ClangASTContext::ConvertAccessTypeToAccessSpecifier (AccessType access) { @@ -291,6 +301,11 @@ ClangASTContext::ClangASTContext (const char *target_triple) : //---------------------------------------------------------------------- ClangASTContext::~ClangASTContext() { + if (m_ast_ap.get()) + { + GetASTMap().erase(m_ast_ap.get()); + } + m_builtins_ap.reset(); m_selector_table_ap.reset(); m_identifier_table_ap.reset(); @@ -393,10 +408,19 @@ ClangASTContext::getASTContext() } m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false); + + GetASTMap().insert(std::make_pair(m_ast_ap.get(), this)); } return m_ast_ap.get(); } +ClangASTContext* +ClangASTContext::GetASTContext (clang::ASTContext* ast) +{ + ClangASTContext *clang_ast = GetASTMap().lookup(ast); + return clang_ast; +} + Builtin::Context * ClangASTContext::getBuiltinContext() { diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp index 64ddfcc6c796..1f2abd876c84 100644 --- a/lldb/source/Target/ObjCLanguageRuntime.cpp +++ b/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -602,4 +602,27 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) } +ClangASTType +ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype) +{ + if (m_scratch_ast_ctx_ap) + return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype); + return ClangASTType(); +} +ClangASTType +ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype) +{ + clang::ASTContext *clang_ast = ast_ctx.getASTContext(); + if (!clang_ast) + return ClangASTType(); + return RealizeType(*clang_ast, name, allow_unknownanytype); +} + +ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} + +ObjCLanguageRuntime::EncodingToTypeSP +ObjCLanguageRuntime::GetEncodingToType () +{ + return nullptr; +}