diff options
author | Enrico Granata <egranata@apple.com> | 2012-09-04 18:47:54 +0000 |
---|---|---|
committer | Enrico Granata <egranata@apple.com> | 2012-09-04 18:47:54 +0000 |
commit | 3467d80ba38b194b98543d950d107cb49c822b68 (patch) | |
tree | c744d20665a52f43d34ef3b0809cb5900b738b31 | |
parent | d92e2bc2e9b11e9ced2fddac25620b82de2f218a (diff) | |
download | bcm5719-llvm-3467d80ba38b194b98543d950d107cb49c822b68.tar.gz bcm5719-llvm-3467d80ba38b194b98543d950d107cb49c822b68.zip |
<rdar://problem/11485744> Implement important data formatters in C++. Have the Objective-C language runtime plugin expose class descriptors objects akin to the objc_runtime.py Pythonic implementation. Rewrite the data formatters for some core Cocoa classes in C++ instead of Python.
llvm-svn: 163155
20 files changed, 1176 insertions, 216 deletions
diff --git a/lldb/examples/summaries/cocoa/CFArray.py b/lldb/examples/summaries/cocoa/CFArray.py index 0a818529d94..11188d04565 100644 --- a/lldb/examples/summaries/cocoa/CFArray.py +++ b/lldb/examples/summaries/cocoa/CFArray.py @@ -5,7 +5,8 @@ part of The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ -# synthetic children provider for NSArray +# example summary provider for NSArray +# the real summary is now C++ code built into LLDB import lldb import ctypes import lldb.runtime.objc.objc_runtime diff --git a/lldb/examples/summaries/cocoa/CFDictionary.py b/lldb/examples/summaries/cocoa/CFDictionary.py index 9607613058b..061f5c56f9d 100644 --- a/lldb/examples/summaries/cocoa/CFDictionary.py +++ b/lldb/examples/summaries/cocoa/CFDictionary.py @@ -5,7 +5,8 @@ part of The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ -# summary provider for NSDictionary +# example summary provider for NSDictionary +# the real summary is now C++ code built into LLDB import lldb import ctypes import lldb.runtime.objc.objc_runtime diff --git a/lldb/examples/summaries/cocoa/NSData.py b/lldb/examples/summaries/cocoa/NSData.py index eef51981d16..3aa30b29f54 100644 --- a/lldb/examples/summaries/cocoa/NSData.py +++ b/lldb/examples/summaries/cocoa/NSData.py @@ -5,7 +5,8 @@ part of The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ -# summary provider for NSData +# example summary provider for NSData +# the real summary is now C++ code built into LLDB import lldb import ctypes import lldb.runtime.objc.objc_runtime diff --git a/lldb/examples/summaries/cocoa/NSNumber.py b/lldb/examples/summaries/cocoa/NSNumber.py index 7cf06fedbe1..4a74143903d 100644 --- a/lldb/examples/summaries/cocoa/NSNumber.py +++ b/lldb/examples/summaries/cocoa/NSNumber.py @@ -5,7 +5,8 @@ part of The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ -# summary provider for NSNumber +# example summary provider for NSNumber +# the real summary is now C++ code built into LLDB import lldb import ctypes import lldb.runtime.objc.objc_runtime diff --git a/lldb/include/lldb/Core/FormatClasses.h b/lldb/include/lldb/Core/FormatClasses.h index 10cb3764ad2..8d536076da9 100644 --- a/lldb/include/lldb/Core/FormatClasses.h +++ b/lldb/include/lldb/Core/FormatClasses.h @@ -1091,6 +1091,14 @@ public: uint32_t m_flags; }; + typedef enum Type + { + eTypeUnknown, + eTypeString, + eTypeScript, + eTypeCallback + } Type; + TypeSummaryImpl (const TypeSummaryImpl::Flags& flags); bool @@ -1205,6 +1213,9 @@ public: virtual bool IsScripted() = 0; + virtual Type + GetType () = 0; + uint32_t& GetRevision () { @@ -1265,9 +1276,89 @@ struct StringSummaryFormat : public TypeSummaryImpl } + virtual Type + GetType () + { + return TypeSummaryImpl::eTypeString; + } + private: DISALLOW_COPY_AND_ASSIGN(StringSummaryFormat); }; + +// summaries implemented via a C++ function +struct CXXFunctionSummaryFormat : public TypeSummaryImpl +{ + + // we should convert these to SBValue and SBStream if we ever cross + // the boundary towards the external world + typedef bool (*Callback)(ValueObject& valobj, + Stream& dest); + + + Callback m_impl; + std::string m_description; + + CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags& flags, + Callback impl, + const char* description); + + Callback + GetBackendFunction () const + { + return m_impl; + } + + const char* + GetTextualInfo () const + { + return m_description.c_str(); + } + + void + SetBackendFunction (Callback cb_func) + { + m_impl = cb_func; + } + + void + SetTextualInfo (const char* descr) + { + if (descr) + m_description.assign(descr); + else + m_description.clear(); + } + + virtual + ~CXXFunctionSummaryFormat() + { + } + + virtual bool + FormatObject(ValueObject *valobj, + std::string& dest); + + virtual std::string + GetDescription(); + + virtual bool + IsScripted() + { + return false; + } + + virtual Type + GetType () + { + return TypeSummaryImpl::eTypeCallback; + } + + typedef STD_SHARED_PTR(CXXFunctionSummaryFormat) SharedPointer; + +private: + DISALLOW_COPY_AND_ASSIGN(CXXFunctionSummaryFormat); +}; #ifndef LLDB_DISABLE_PYTHON @@ -1331,6 +1422,12 @@ struct ScriptSummaryFormat : public TypeSummaryImpl return true; } + virtual Type + GetType () + { + return TypeSummaryImpl::eTypeScript; + } + typedef STD_SHARED_PTR(ScriptSummaryFormat) SharedPointer; diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 9059435dc17..8cd7a16e40c 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -571,6 +571,9 @@ public: //------------------------------------------------------------------ virtual ObjectFile * GetObjectFile (); + + uint32_t + GetVersion (uint32_t *versions, uint32_t num_versions); // Load an object file from memory. ObjectFile * diff --git a/lldb/include/lldb/Target/ObjCLanguageRuntime.h b/lldb/include/lldb/Target/ObjCLanguageRuntime.h index ec921525c70..24891ed15c5 100644 --- a/lldb/include/lldb/Target/ObjCLanguageRuntime.h +++ b/lldb/include/lldb/Target/ObjCLanguageRuntime.h @@ -29,6 +29,145 @@ class ObjCLanguageRuntime : public LanguageRuntime { public: + + typedef lldb::addr_t ObjCISA; + + class ClassDescriptor; + typedef STD_SHARED_PTR(ClassDescriptor) ClassDescriptorSP; + + // the information that we want to support retrieving from an ObjC class + // this needs to be pure virtual since there are at least 2 different implementations + // of the runtime, and more might come + class ClassDescriptor + { + public: + + ClassDescriptor() : + m_is_kvo(eLazyBoolCalculate), + m_is_cf(eLazyBoolCalculate) + {} + + ClassDescriptor (ObjCISA isa, lldb::ProcessSP process) : + m_is_kvo(eLazyBoolCalculate), + m_is_cf(eLazyBoolCalculate) + {} + + virtual ConstString + GetClassName () = 0; + + virtual ClassDescriptorSP + GetSuperclass () = 0; + + // virtual if any implementation has some other version-specific rules + // but for the known v1/v2 this is all that needs to be done + virtual bool + IsKVO () + { + if (m_is_kvo == eLazyBoolCalculate) + { + const char* class_name = GetClassName().AsCString(); + m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name); + } + return (m_is_kvo == eLazyBoolYes); + } + + // virtual if any implementation has some other version-specific rules + // but for the known v1/v2 this is all that needs to be done + virtual bool + IsCFType () + { + if (m_is_cf == eLazyBoolCalculate) + { + const char* class_name = GetClassName().AsCString(); + m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 || + strcmp(class_name,"NSCFType") == 0); + } + return (m_is_cf == eLazyBoolYes); + } + + virtual bool + IsValid () = 0; + + virtual bool + IsTagged () = 0; + + virtual uint64_t + GetInstanceSize () = 0; + + // use to implement version-specific additional constraints on pointers + virtual bool + CheckPointer (lldb::addr_t value, + uint32_t ptr_size) + { + return true; + } + + virtual ObjCISA + GetISA () = 0; + + virtual + ~ClassDescriptor () + {} + + protected: + bool + IsPointerValid (lldb::addr_t value, + uint32_t ptr_size, + bool allow_NULLs = false, + bool allow_tagged = false, + bool check_version_specific = false); + + private: + LazyBool m_is_kvo; + LazyBool m_is_cf; + }; + + // a convenience subclass of ClassDescriptor meant to represent invalid objects + class ClassDescriptor_Invalid : public ClassDescriptor + { + public: + ClassDescriptor_Invalid() {} + + virtual ConstString + GetClassName () { return ConstString(""); } + + virtual ClassDescriptorSP + GetSuperclass () { return ClassDescriptorSP(new ClassDescriptor_Invalid()); } + + virtual bool + IsValid () { return false; } + + virtual bool + IsTagged () { return false; } + + virtual uint64_t + GetInstanceSize () { return 0; } + + virtual ObjCISA + GetISA () { return 0; } + + virtual bool + CheckPointer (lldb::addr_t value, + uint32_t ptr_size) { return false; } + + virtual + ~ClassDescriptor_Invalid () + {} + + }; + + virtual ClassDescriptorSP + GetClassDescriptor (ValueObject& in_value) + { + return ClassDescriptorSP(); + } + + virtual ClassDescriptorSP + GetClassDescriptor (ObjCISA isa) + { + return ClassDescriptorSP(); + } + virtual ~ObjCLanguageRuntime(); @@ -77,8 +216,6 @@ public: return eObjC_VersionUnknown; } - typedef lldb::addr_t ObjCISA; - virtual bool IsValidISA(ObjCISA isa) = 0; @@ -86,10 +223,10 @@ public: GetISA(ValueObject& valobj) = 0; virtual ConstString - GetActualTypeName(ObjCISA isa) = 0; + GetActualTypeName(ObjCISA isa); virtual ObjCISA - GetParentClass(ObjCISA isa) = 0; + GetParentClass(ObjCISA isa); virtual SymbolVendor * GetSymbolVendor() @@ -267,6 +404,11 @@ private: LazyBool m_has_new_literals_and_indexing; protected: + + typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; + typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; + ISAToDescriptorMap m_isa_to_descriptor_cache; + typedef std::map<lldb::addr_t,TypeAndOrName> ClassNameMap; typedef ClassNameMap::iterator ClassNameIterator; ClassNameMap m_class_name_cache; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 139d67f198e..a3534a9e3bd 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -529,6 +529,7 @@ 9475C18F14E5F858001BFC6D /* SBTypeNameSpecifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 9475C18C14E5F826001BFC6D /* SBTypeNameSpecifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; 949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */; }; 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; }; + 94CDEB9D15F0258500DD2A7A /* CXXFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CDEB9C15F0258400DD2A7A /* CXXFormatterFunctions.cpp */; }; 94EA1D5C15E6C9B400D4171A /* PythonDataObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */; }; 94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94FA3DDF1405D50300833217 /* ValueObjectConstResultChild.cpp */; }; 9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1535,6 +1536,8 @@ 94A9112D13D5DF210046D8A6 /* FormatClasses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatClasses.cpp; path = source/Core/FormatClasses.cpp; sourceTree = "<group>"; }; 94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectSyntheticFilter.h; path = include/lldb/Core/ValueObjectSyntheticFilter.h; sourceTree = "<group>"; }; 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectSyntheticFilter.cpp; path = source/Core/ValueObjectSyntheticFilter.cpp; sourceTree = "<group>"; }; + 94CDEB9A15F0226900DD2A7A /* CXXFormatterFunctions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CXXFormatterFunctions.h; path = include/lldb/Core/CXXFormatterFunctions.h; sourceTree = "<group>"; }; + 94CDEB9C15F0258400DD2A7A /* CXXFormatterFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CXXFormatterFunctions.cpp; path = source/Core/CXXFormatterFunctions.cpp; sourceTree = "<group>"; }; 94E367CC140C4EC4001C7A5A /* modify-python-lldb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = "modify-python-lldb.py"; sourceTree = "<group>"; }; 94E367CE140C4EEA001C7A5A /* python-typemaps.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-typemaps.swig"; sourceTree = "<group>"; }; 94EA1D5A15E6C99B00D4171A /* PythonDataObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonDataObjects.h; path = include/lldb/Interpreter/PythonDataObjects.h; sourceTree = "<group>"; }; @@ -2455,6 +2458,8 @@ 266603C91345B5A8004DA8B6 /* ConnectionSharedMemory.cpp */, 26BC7D7C10F1B77400F91463 /* ConstString.h */, 26BC7E9410F1B85900F91463 /* ConstString.cpp */, + 94CDEB9A15F0226900DD2A7A /* CXXFormatterFunctions.h */, + 94CDEB9C15F0258400DD2A7A /* CXXFormatterFunctions.cpp */, 26BC7D5910F1B77400F91463 /* DataBuffer.h */, 26BC7D5B10F1B77400F91463 /* DataBufferHeap.h */, 26BC7E7210F1B85900F91463 /* DataBufferHeap.cpp */, @@ -4111,6 +4116,7 @@ 2697A39315E404B1003E682C /* OptionValueArch.cpp in Sources */, 94EA1D5C15E6C9B400D4171A /* PythonDataObjects.cpp in Sources */, 2698699B15E6CBD0002415FF /* OperatingSystemPython.cpp in Sources */, + 94CDEB9D15F0258500DD2A7A /* CXXFormatterFunctions.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp index 44ac2d3b1e8..446a69331d9 100644 --- a/lldb/source/API/SBModule.cpp +++ b/lldb/source/API/SBModule.cpp @@ -542,17 +542,15 @@ SBModule::GetVersion (uint32_t *versions, uint32_t num_versions) { ModuleSP module_sp (GetSP ()); if (module_sp) + return module_sp->GetVersion(versions, num_versions); + else { - ObjectFile *obj_file = module_sp->GetObjectFile(); - if (obj_file) - return obj_file->GetVersion (versions, num_versions); - } - - if (versions && num_versions) - { - for (uint32_t i=0; i<num_versions; ++i) - versions[i] = UINT32_MAX; + if (versions && num_versions) + { + for (uint32_t i=0; i<num_versions; ++i) + versions[i] = UINT32_MAX; + } + return 0; } - return 0; } diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp index 86cb89b40b3..4108da05962 100644 --- a/lldb/source/API/SBTypeSummary.cpp +++ b/lldb/source/API/SBTypeSummary.cpp @@ -99,6 +99,9 @@ SBTypeSummary::IsSummaryString() if (!IsValid()) return false; + if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback) + return false; + return !m_opaque_sp->IsScripted(); } @@ -107,6 +110,8 @@ SBTypeSummary::GetData () { if (!IsValid()) return NULL; + if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback) + return NULL; if (m_opaque_sp->IsScripted()) { ScriptSummaryFormat* script_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get(); @@ -144,7 +149,7 @@ SBTypeSummary::SetSummaryString (const char* data) { if (!IsValid()) return; - if (m_opaque_sp->IsScripted()) + if (m_opaque_sp->IsScripted() || (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)) ChangeSummaryType(false); ((StringSummaryFormat*)m_opaque_sp.get())->SetSummaryString(data); } @@ -205,6 +210,16 @@ SBTypeSummary::IsEqualTo (lldb::SBTypeSummary &rhs) { if (IsValid() == false) return !rhs.IsValid(); + + if (m_opaque_sp->GetType() != rhs.m_opaque_sp->GetType()) + return false; + + if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback) + { + lldb_private::CXXFunctionSummaryFormat *self_cxx = (lldb_private::CXXFunctionSummaryFormat*)m_opaque_sp.get(); + lldb_private::CXXFunctionSummaryFormat *other_cxx = (lldb_private::CXXFunctionSummaryFormat*)rhs.m_opaque_sp.get(); + return (self_cxx->m_impl == other_cxx->m_impl); + } if (m_opaque_sp->IsScripted() != rhs.m_opaque_sp->IsScripted()) return false; @@ -255,12 +270,20 @@ SBTypeSummary::CopyOnWrite_Impl() { if (!IsValid()) return false; + if (m_opaque_sp.unique()) return true; TypeSummaryImplSP new_sp; - if (m_opaque_sp->IsScripted()) + if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback) + { + CXXFunctionSummaryFormat* current_summary_ptr = (CXXFunctionSummaryFormat*)m_opaque_sp.get(); + new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(GetOptions(), + current_summary_ptr->m_impl, + current_summary_ptr->m_description.c_str())); + } + else if (m_opaque_sp->IsScripted()) { ScriptSummaryFormat* current_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get(); new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), @@ -284,15 +307,23 @@ SBTypeSummary::ChangeSummaryType (bool want_script) if (!IsValid()) return false; - if (want_script == m_opaque_sp->IsScripted()) - return CopyOnWrite_Impl(); - TypeSummaryImplSP new_sp; - if (want_script) - new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", "")); - else - new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), "")); + if (want_script == m_opaque_sp->IsScripted()) + { + if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback && !want_script) + new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), "")); + else + return CopyOnWrite_Impl(); + } + + if (!new_sp) + { + if (want_script) + new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", "")); + else + new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), "")); + } SetSP(new_sp); diff --git a/lldb/source/Core/FormatClasses.cpp b/lldb/source/Core/FormatClasses.cpp index 706a7a7aa83..c76a0e58ec3 100644 --- a/lldb/source/Core/FormatClasses.cpp +++ b/lldb/source/Core/FormatClasses.cpp @@ -157,6 +157,42 @@ StringSummaryFormat::GetDescription() return sstr.GetString(); } +CXXFunctionSummaryFormat::CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags& flags, + Callback impl, + const char* description) : + TypeSummaryImpl(flags), + m_impl(impl), + m_description(description ? description : "") +{ +} + +bool +CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, + std::string& dest) +{ + dest.clear(); + StreamString stream; + if (!m_impl || m_impl(*valobj,stream) == false) + return false; + dest.assign(stream.GetData()); + return true; +} + +std::string +CXXFunctionSummaryFormat::GetDescription() +{ + StreamString sstr; + sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s", m_description.c_str(),m_impl, + Cascades() ? "" : " (not cascading)", + !DoesPrintChildren() ? "" : " (show children)", + !DoesPrintValue() ? " (hide value)" : "", + IsOneliner() ? " (one-line printout)" : "", + SkipsPointers() ? " (skip pointers)" : "", + SkipsReferences() ? " (skip references)" : "", + HideNames() ? " (hide member names)" : ""); + return sstr.GetString(); +} + #ifndef LLDB_DISABLE_PYTHON diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index fb2441d7ae9..2222783bcf6 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -14,6 +14,7 @@ // Other libraries and framework includes // Project includes +#include "lldb/Core/CXXFormatterFunctions.h" #include "lldb/Core/Debugger.h" using namespace lldb; @@ -896,6 +897,18 @@ AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp, } #endif +static void +AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp, + CXXFunctionSummaryFormat::Callback funct, + const char* description, + ConstString type_name, + TypeSummaryImpl::Flags flags) +{ + lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description)); + category_sp->GetSummaryNavigator()->Add(type_name, + summary_sp); +} + #ifndef LLDB_DISABLE_PYTHON void FormatManager::LoadObjCFormatters() @@ -1025,12 +1038,13 @@ FormatManager::LoadObjCFormatters() .SetShowMembersOneLiner(false) .SetHideItemNames(false); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("NSArray"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSArrayI"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSArrayM"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("__NSCFArray"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("CFArrayRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFArray.CFArray_SummaryProvider", ConstString("CFMutableArrayRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("NSArray"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("NSMutableArray"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSArrayI"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSArrayM"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("__NSCFArray"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("CFArrayRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArray_SummaryProvider, "NSArray summary provider", ConstString("CFMutableArrayRef"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBag.CFBag_SummaryProvider", ConstString("CFBagRef"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBag.CFBag_SummaryProvider", ConstString("__CFBag"), appkit_flags); @@ -1040,31 +1054,32 @@ FormatManager::LoadObjCFormatters() AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBinaryHeap.CFBinaryHeap_SummaryProvider", ConstString("CFBinaryHeapRef"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFBinaryHeap.CFBinaryHeap_SummaryProvider", ConstString("__CFBinaryHeap"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("NSDictionary"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider2", ConstString("CFDictionaryRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider2", ConstString("CFMutableDictionaryRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSCFDictionary"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSDictionaryI"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFDictionary.CFDictionary_SummaryProvider", ConstString("__NSDictionaryM"), appkit_flags); - - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("CFStringRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("CFMutableStringRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("NSDictionary"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSCFDictionary"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryI"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryM"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<true>, "NSDictionary summary provider", ConstString("CFDictionaryRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionary_SummaryProvider<true>, "NSDictionary summary provider", ConstString("CFMutableDictionaryRef"), appkit_flags); + + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSString"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("CFStringRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("CFMutableStringRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("__NSCFConstantString"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("__NSCFString"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSCFConstantString"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSCFString"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSString_SummaryProvider, "NSString summary provider", ConstString("NSPathStore2"), appkit_flags); + AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFAttributedString_SummaryProvider", ConstString("NSAttributedString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("__NSCFConstantString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("__NSCFString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSCFConstantString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSCFString"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.CFString.CFString_SummaryProvider", ConstString("NSPathStore2"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSBundle.NSBundle_SummaryProvider", ConstString("NSBundle"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSData"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider2", ConstString("CFDataRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider2", ConstString("CFMutableDataRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSConcreteData"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("NSConcreteMutableData"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSData.NSData_SummaryProvider", ConstString("__NSCFData"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSData"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteData"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteMutableData"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<false>, "NSData summary provider", ConstString("__NSCFData"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<true>, "NSData summary provider", ConstString("CFDataRef"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSData_SummaryProvider<true>, "NSData summary provider", ConstString("CFMutableDataRef"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSException.NSException_SummaryProvider", ConstString("NSException"), appkit_flags); @@ -1073,11 +1088,11 @@ FormatManager::LoadObjCFormatters() AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNotification.NSNotification_SummaryProvider", ConstString("NSNotification"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNotification.NSNotification_SummaryProvider", ConstString("NSConcreteNotification"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSNumber"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("__NSCFBoolean"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("__NSCFNumber"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSCFBoolean"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSNumber.NSNumber_SummaryProvider", ConstString("NSCFNumber"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSNumber"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("__NSCFBoolean"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("__NSCFNumber"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSCFBoolean"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumber_SummaryProvider, "NSNumber summary provider", ConstString("NSCFNumber"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSSet.NSSet_SummaryProvider", ConstString("NSSet"), appkit_flags); AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSSet.NSSet_SummaryProvider2", ConstString("CFSetRef"), appkit_flags); diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 781853088f1..15ad72cb7ca 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1205,3 +1205,17 @@ Module::RemapSourceFile (const char *path, std::string &new_path) const return m_source_mappings.RemapPath(path, new_path); } +uint32_t +Module::GetVersion (uint32_t *versions, uint32_t num_versions) +{ + ObjectFile *obj_file = GetObjectFile(); + if (obj_file) + return obj_file->GetVersion (versions, num_versions); + + if (versions && num_versions) + { + for (uint32_t i=0; i<num_versions; ++i) + versions[i] = UINT32_MAX; + } + return 0; +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index 3db7477c031..e835a0c94af 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -75,18 +75,6 @@ public: return 0; } - virtual ConstString - GetActualTypeName(ObjCISA isa) - { - return ConstString(NULL); - } - - virtual ObjCISA - GetParentClass(ObjCISA isa) - { - return 0; - } - //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index a811710c1a8..cab4e9d9b2a 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -152,3 +152,169 @@ AppleObjCRuntimeV1::CreateObjectChecker(const char *name) return new ClangUtilityFunction(buf->contents, name); } + +// this code relies on the assumption that an Objective-C object always starts +// with an ISA at offset 0. +ObjCLanguageRuntime::ObjCISA +AppleObjCRuntimeV1::GetISA(ValueObject& valobj) +{ + if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) + return 0; + + // 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.GetValue().GetContextType() == Value::eContextTypeInvalid) + return 0; + + addr_t isa_pointer = valobj.GetPointerValue(); + + ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) + { + uint8_t pointer_size = process->GetAddressByteSize(); + + Error error; + return process->ReadUnsignedIntegerFromMemory (isa_pointer, + pointer_size, + 0, + error); + } + return 0; +} + +AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer) +{ + ObjCISA ptr_value = isa_pointer.GetValueAsUnsigned(0); + + lldb::ProcessSP process_sp = isa_pointer.GetProcessSP(); + + Initialize (ptr_value,process_sp); +} + +AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp) +{ + Initialize (isa, process_sp); +} + +void +AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp) +{ + if (!isa || !process_sp) + { + m_valid = false; + return; + } + + m_valid = true; + + Error error; + + m_isa = process_sp->ReadPointerFromMemory(isa, error); + + if (error.Fail()) + { + m_valid = false; + return; + } + + uint32_t ptr_size = process_sp->GetAddressByteSize(); + + if (!IsPointerValid(m_isa,ptr_size)) + { + m_valid = false; + return; + } + + m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error); + + if (error.Fail()) + { + m_valid = false; + return; + } + + if (!IsPointerValid(m_parent_isa,ptr_size,true)) + { + m_valid = false; + return; + } + + lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error); + + if (error.Fail()) + { + m_valid = false; + return; + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); + + size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error); + + if (error.Fail()) + { + m_valid = false; + return; + } + + if (count) + m_name = ConstString((char*)buffer_sp->GetBytes()); + else + m_name = ConstString(); + + m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error); + + if (error.Fail()) + { + m_valid = false; + return; + } + + m_process_wp = lldb::ProcessWP(process_sp); +} + +AppleObjCRuntime::ClassDescriptorSP +AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass () +{ + if (!m_valid) + return NULL; + ProcessSP process_sp = m_process_wp.lock(); + if (!process_sp) + return NULL; + return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp)); +} + +ObjCLanguageRuntime::ClassDescriptorSP +AppleObjCRuntimeV1::GetClassDescriptor (ValueObject& in_value) +{ + ObjCISA isa = GetISA(in_value); + + ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + return found->second; + + ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(in_value)); + if (descriptor && descriptor->IsValid()) + m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor; + return descriptor; +} + +ObjCLanguageRuntime::ClassDescriptorSP +AppleObjCRuntimeV1::GetClassDescriptor (ObjCISA isa) +{ + ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + return found->second; + + ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV1(isa,m_process->CalculateProcess())); + if (descriptor && descriptor->IsValid()) + m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor; + return descriptor; +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index df8b6b469ce..2a0dbad46d4 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -24,6 +24,63 @@ class AppleObjCRuntimeV1 : public AppleObjCRuntime { public: + + class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor + { + public: + ClassDescriptorV1 (ValueObject &isa_pointer); + ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp); + + virtual ConstString + GetClassName () + { + return m_name; + } + + virtual ClassDescriptorSP + GetSuperclass (); + + virtual bool + IsValid () + { + return m_valid; + } + + virtual bool + IsTagged () + { + return false; // v1 runtime does not support tagged pointers + } + + virtual uint64_t + GetInstanceSize () + { + return m_instance_size; + } + + virtual ObjCISA + GetISA () + { + return m_isa; + } + + virtual + ~ClassDescriptorV1 () + {} + + protected: + void + Initialize (ObjCISA isa, lldb::ProcessSP process_sp); + + private: + ConstString m_name; + ObjCISA m_isa; + ObjCISA m_parent_isa; + bool m_valid; + lldb::ProcessWP m_process_wp; + uint64_t m_instance_size; + }; + virtual ~AppleObjCRuntimeV1() { } // These are generic runtime functions: @@ -69,26 +126,17 @@ public: virtual bool IsValidISA(ObjCISA isa) { - return false; + return (isa != 0) && ( (isa % 2) == 0); } virtual ObjCISA - GetISA(ValueObject& valobj) - { - return 0; - } + GetISA(ValueObject& valobj); - virtual ConstString - GetActualTypeName(ObjCISA isa) - { - return ConstString(NULL); - } + virtual ClassDescriptorSP + GetClassDescriptor (ValueObject& in_value); - virtual ObjCISA - GetParentClass(ObjCISA isa) - { - return 0; - } + virtual ClassDescriptorSP + GetClassDescriptor (ObjCISA isa); protected: virtual lldb::BreakpointResolverSP diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 1e0bf4d881f..6b146d97ecd 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -104,9 +104,7 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, const ModuleSP &objc_module_sp) : AppleObjCRuntime (process), m_get_class_name_args(LLDB_INVALID_ADDRESS), - m_get_class_name_args_mutex(Mutex::eMutexTypeNormal), - m_isa_to_name_cache(), - m_isa_to_parent_cache() + m_get_class_name_args_mutex(Mutex::eMutexTypeNormal) { static const ConstString g_gdb_object_getClass("gdb_object_getClass"); m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL); @@ -587,6 +585,46 @@ AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) return (ptr & 0x01); } +ObjCLanguageRuntime::ClassDescriptorSP +AppleObjCRuntimeV2::GetClassDescriptor (ObjCISA isa) +{ + ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + return found->second; + + ClassDescriptorSP descriptor = ClassDescriptorSP(new ClassDescriptorV2(isa,m_process->CalculateProcess())); + if (descriptor && descriptor->IsValid()) + m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor; + return descriptor; +} + +ObjCLanguageRuntime::ClassDescriptorSP +AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& in_value) +{ + uint64_t ptr_value = in_value.GetValueAsUnsigned(0); + if (ptr_value == 0) + return NULL; + + ObjCISA isa = GetISA(in_value); + + ObjCLanguageRuntime::ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ObjCLanguageRuntime::ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + return found->second; + + ClassDescriptorSP descriptor; + + if (ptr_value & 1) + return ClassDescriptorSP(new ClassDescriptorV2Tagged(in_value)); // do not save tagged pointers + descriptor = ClassDescriptorSP(new ClassDescriptorV2(in_value)); + + if (descriptor && descriptor->IsValid()) + m_isa_to_descriptor_cache[descriptor->GetISA()] = descriptor; + return descriptor; +} // this code relies on the assumption that an Objective-C object always starts // with an ISA at offset 0. an ISA is effectively a pointer to an instance of @@ -641,142 +679,283 @@ AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) return g_objc_tagged_isa_name; } - ISAToNameIterator found = m_isa_to_name_cache.find(isa); - ISAToNameIterator end = m_isa_to_name_cache.end(); + ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); - if (found != end) - return found->second; + if (found != end && found->second) + return found->second->GetClassName(); + + ClassDescriptorSP descriptor(GetClassDescriptor(isa)); + if (!descriptor.get() || !descriptor->IsValid()) + return ConstString(); + ConstString class_name = descriptor->GetClassName(); + if (descriptor->IsKVO()) + { + ClassDescriptorSP superclass(descriptor->GetSuperclass()); + if (!superclass.get() || !superclass->IsValid()) + return ConstString(); + descriptor = superclass; + } + m_isa_to_descriptor_cache[isa] = descriptor; + return descriptor->GetClassName(); +} + +SymbolVendor * +AppleObjCRuntimeV2::GetSymbolVendor() +{ + if (!m_symbol_vendor_ap.get()) + m_symbol_vendor_ap.reset(new AppleObjCSymbolVendor(m_process)); + + return m_symbol_vendor_ap.get(); +} + +AppleObjCRuntimeV2::ClassDescriptorV2::ClassDescriptorV2 (ValueObject &isa_pointer) +{ + ObjCISA ptr_value = isa_pointer.GetValueAsUnsigned(0); + + lldb::ProcessSP process_sp = isa_pointer.GetProcessSP(); + + Initialize (ptr_value,process_sp); +} + +AppleObjCRuntimeV2::ClassDescriptorV2::ClassDescriptorV2 (ObjCISA isa, lldb::ProcessSP process_sp) +{ + Initialize (isa, process_sp); +} + +void +AppleObjCRuntimeV2::ClassDescriptorV2::Initialize (ObjCISA isa, lldb::ProcessSP process_sp) +{ + if (!isa || !process_sp) + { + m_valid = false; + return; + } + + m_valid = true; - uint8_t pointer_size = m_process->GetAddressByteSize(); Error error; - /* - struct class_t *isa; - struct class_t *superclass; - Cache cache; - IMP *vtable; ---> class_rw_t data; - */ - - addr_t rw_pointer = isa + (4 * pointer_size); - //printf("rw_pointer: %llx\n", rw_pointer); - uint64_t data_pointer = m_process->ReadUnsignedIntegerFromMemory(rw_pointer, - pointer_size, - 0, - error); + m_isa = process_sp->ReadPointerFromMemory(isa, error); + if (error.Fail()) { - return g_unknown; - + m_valid = false; + return; } - /* - uint32_t flags; - uint32_t version; - ---> const class_ro_t *ro; - */ - data_pointer += 8; - //printf("data_pointer: %llx\n", data_pointer); - uint64_t ro_pointer = m_process->ReadUnsignedIntegerFromMemory(data_pointer, - pointer_size, - 0, - error); + uint32_t ptr_size = process_sp->GetAddressByteSize(); + + if (!IsPointerValid(m_isa,ptr_size,false,false,true)) + { + m_valid = false; + return; + } + + lldb::addr_t data_ptr = process_sp->ReadPointerFromMemory(m_isa + 4 * ptr_size, error); + if (error.Fail()) - return g_unknown; - - /* - uint32_t flags; - uint32_t instanceStart; - uint32_t instanceSize; - #ifdef __LP64__ - uint32_t reserved; - #endif - - const uint8_t * ivarLayout; - ---> const char * name; - */ - ro_pointer += 12; - if (pointer_size == 8) - ro_pointer += 4; - ro_pointer += pointer_size; - //printf("ro_pointer: %llx\n", ro_pointer); - uint64_t name_pointer = m_process->ReadUnsignedIntegerFromMemory(ro_pointer, - pointer_size, - 0, - error); + { + m_valid = false; + return; + } + + if (!IsPointerValid(data_ptr,ptr_size,false,false,true)) + { + m_valid = false; + return; + } + + m_parent_isa = process_sp->ReadPointerFromMemory(isa + ptr_size,error); + if (error.Fail()) - return g_unknown; + { + m_valid = false; + return; + } - //printf("name_pointer: %llx\n", name_pointer); - char cstr[512]; - if (m_process->ReadCStringFromMemory(name_pointer, cstr, sizeof(cstr), error) > 0) + // sanity checks + lldb::addr_t cache_ptr = process_sp->ReadPointerFromMemory(m_isa + 2*ptr_size, error); + if (error.Fail()) { - if (::strstr(cstr, "NSKVONotify") == cstr) - { - // the ObjC runtime implements KVO by replacing the isa with a special - // NSKVONotifying_className that overrides the relevant methods - // the side effect on us is that getting the typename for a KVO-ed object - // will return the swizzled class instead of the actual one - // this swizzled class is a descendant of the real class, so just - // return the parent type and all should be fine - ConstString class_name = GetActualTypeName(GetParentClass(isa)); - m_isa_to_name_cache[isa] = class_name; - return class_name; - } - else - { - ConstString class_name = ConstString(cstr); - m_isa_to_name_cache[isa] = class_name; - return class_name; - } + m_valid = false; + return; + } + if (!IsPointerValid(cache_ptr,ptr_size,true,false,true)) + { + m_valid = false; + return; + } + lldb::addr_t vtable_ptr = process_sp->ReadPointerFromMemory(m_isa + 3*ptr_size, error); + if (error.Fail()) + { + m_valid = false; + return; + } + if (!IsPointerValid(vtable_ptr,ptr_size,true,false,true)) + { + m_valid = false; + return; } - else - return g_unknown; -} -ObjCLanguageRuntime::ObjCISA -AppleObjCRuntimeV2::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) -{ - if (!IsValidISA(isa)) - return 0; + // now construct the data object - if (isa == g_objc_Tagged_ISA) - return 0; + lldb::addr_t rot_pointer = process_sp->ReadPointerFromMemory(data_ptr + 8, error); - ISAToParentIterator found = m_isa_to_parent_cache.find(isa); - ISAToParentIterator end = m_isa_to_parent_cache.end(); + if (error.Fail()) + { + m_valid = false; + return; + } - if (found != end) - return found->second; + if (!IsPointerValid(rot_pointer,ptr_size)) + { + m_valid = false; + return; + } + + // now read from the rot + + lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(rot_pointer + (ptr_size == 8 ? 24 : 16) ,error); - uint8_t pointer_size = m_process->GetAddressByteSize(); - Error error; - /* - struct class_t *isa; ---> struct class_t *superclass; - */ - addr_t parent_pointer = isa + pointer_size; - //printf("rw_pointer: %llx\n", rw_pointer); - - uint64_t parent_isa = m_process->ReadUnsignedIntegerFromMemory(parent_pointer, - pointer_size, - 0, - error); if (error.Fail()) - return 0; + { + m_valid = false; + return; + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); - m_isa_to_parent_cache[isa] = parent_isa; + size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error); - return parent_isa; + if (error.Fail()) + { + m_valid = false; + return; + } + + if (count) + m_name = ConstString((char*)buffer_sp->GetBytes()); + else + m_name = ConstString(); + + m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(rot_pointer + 8, ptr_size, 0, error); + + m_process_wp = lldb::ProcessWP(process_sp); } -SymbolVendor * -AppleObjCRuntimeV2::GetSymbolVendor() +AppleObjCRuntime::ClassDescriptorSP +AppleObjCRuntimeV2::ClassDescriptorV2::GetSuperclass () { - if (!m_symbol_vendor_ap.get()) - m_symbol_vendor_ap.reset(new AppleObjCSymbolVendor(m_process)); + if (!m_valid) + return NULL; + ProcessSP process_sp = m_process_wp.lock(); + if (!process_sp) + return NULL; + return AppleObjCRuntime::ClassDescriptorSP(new AppleObjCRuntimeV2::ClassDescriptorV2(m_parent_isa,process_sp)); +} + +AppleObjCRuntimeV2::ClassDescriptorV2Tagged::ClassDescriptorV2Tagged (ValueObject &isa_pointer) +{ + m_valid = false; + uint64_t value = isa_pointer.GetValueAsUnsigned(0); + lldb::ProcessSP process_sp = isa_pointer.GetProcessSP(); + if (process_sp) + m_pointer_size = process_sp->GetAddressByteSize(); + else + { + m_name = ConstString(""); + m_pointer_size = 0; + return; + } - return m_symbol_vendor_ap.get(); + m_valid = true; + m_class_bits = (value & 0xE) >> 1; + lldb::TargetSP target_sp = isa_pointer.GetTargetSP(); + + LazyBool is_lion = IsLion(target_sp); + + // TODO: check for OSX version - for now assume Mtn Lion + if (is_lion == eLazyBoolCalculate) + { + // if we can't determine the matching table (e.g. we have no Foundation), + // assume this is not a valid tagged pointer + m_valid = false; + } + else if (is_lion == eLazyBoolNo) + { + switch (m_class_bits) + { + case 0: + m_name = ConstString("NSAtom"); + break; + case 3: + m_name = ConstString("NSNumber"); + break; + case 4: + m_name = ConstString("NSDateTS"); + break; + case 5: + m_name = ConstString("NSManagedObject"); + break; + case 6: + m_name = ConstString("NSDate"); + break; + default: + m_valid = false; + break; + } + } + else + { + switch (m_class_bits) + { + case 1: + m_name = ConstString("NSNumber"); + break; + case 5: + m_name = ConstString("NSManagedObject"); + break; + case 6: + m_name = ConstString("NSDate"); + break; + case 7: + m_name = ConstString("NSDateTS"); + break; + default: + m_valid = false; + break; + } + } + if (!m_valid) + m_name = ConstString(""); + else + { + m_info_bits = (value & 0xF0ULL) >> 4; + m_value_bits = (value & ~0x0000000000000000FFULL) >> 8; + } +} + +LazyBool +AppleObjCRuntimeV2::ClassDescriptorV2Tagged::IsLion (lldb::TargetSP &target_sp) +{ + if (!target_sp) + return eLazyBoolCalculate; + ModuleList& modules = target_sp->GetImages(); + for (uint32_t idx = 0; idx < modules.GetSize(); idx++) + { + lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); + if (!module_sp) + continue; + if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0) + { + uint32_t major = UINT32_MAX; + module_sp->GetVersion(&major,1); + if (major == UINT32_MAX) + return eLazyBoolCalculate; + + return (major > 900 ? eLazyBoolNo : eLazyBoolYes); + } + } + return eLazyBoolCalculate; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 057fa62a9e7..ff94b81dfac 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -27,6 +27,165 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime { public: + + class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor + { + public: + ClassDescriptorV2 (ValueObject &isa_pointer); + ClassDescriptorV2 (ObjCISA isa, lldb::ProcessSP process); + + virtual ConstString + GetClassName () + { + return m_name; + } + + virtual ClassDescriptorSP + GetSuperclass (); + + virtual bool + IsValid () + { + return m_valid; + } + + virtual bool + IsTagged () + { + return false; // we use a special class for tagged descriptors + } + + virtual uint64_t + GetInstanceSize () + { + return m_instance_size; + } + + virtual ObjCISA + GetISA () + { + return m_isa; + } + + virtual + ~ClassDescriptorV2 () + {} + + protected: + virtual bool + CheckPointer (lldb::addr_t value, + uint32_t ptr_size) + { + if (ptr_size != 8) + return true; + return ((value & 0xFFFF800000000000) == 0); + } + + void + Initialize (ObjCISA isa, lldb::ProcessSP process_sp); + + private: + ConstString m_name; + ObjCISA m_isa; + ObjCISA m_parent_isa; + bool m_valid; + lldb::ProcessWP m_process_wp; + uint64_t m_instance_size; + }; + + class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor + { + public: + ClassDescriptorV2Tagged (ValueObject &isa_pointer); + + virtual ConstString + GetClassName () + { + return m_name; + } + + virtual 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 ClassDescriptorSP(new ObjCLanguageRuntime::ClassDescriptor_Invalid()); + } + + 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 + IsTagged () + { + return true; // we use this class to describe tagged pointers + } + + virtual uint64_t + GetInstanceSize () + { + return (IsValid() ? m_pointer_size : 0); + } + + virtual ObjCISA + GetISA () + { + return 0; // tagged pointers have no ISA + } + + virtual uint64_t + GetClassBits () + { + return (IsValid() ? m_class_bits : 0); + } + + // 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 + ~ClassDescriptorV2Tagged () + {} + + protected: + // TODO make this into a smarter OS version detector + LazyBool + IsLion (lldb::TargetSP &target_sp); + + private: + ConstString m_name; + uint8_t m_pointer_size; + bool m_valid; + uint64_t m_class_bits; + uint64_t m_info_bits; + uint64_t m_value_bits; + }; + virtual ~AppleObjCRuntimeV2() { } // These are generic runtime functions: @@ -90,8 +249,11 @@ public: virtual ConstString GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa); - virtual ObjCLanguageRuntime::ObjCISA - GetParentClass(ObjCLanguageRuntime::ObjCISA isa); + virtual ClassDescriptorSP + GetClassDescriptor (ValueObject& in_value); + + virtual ClassDescriptorSP + GetClassDescriptor (ObjCISA isa); virtual SymbolVendor * GetSymbolVendor(); @@ -102,13 +264,7 @@ protected: private: - typedef std::map<ObjCLanguageRuntime::ObjCISA, ConstString> ISAToNameCache; - typedef std::map<ObjCLanguageRuntime::ObjCISA, ObjCLanguageRuntime::ObjCISA> ISAToParentCache; - - typedef ISAToNameCache::iterator ISAToNameIterator; - typedef ISAToParentCache::iterator ISAToParentIterator; - - AppleObjCRuntimeV2 (Process *process, + AppleObjCRuntimeV2 (Process *process, const lldb::ModuleSP &objc_module_sp); bool @@ -122,9 +278,6 @@ private: lldb::addr_t m_get_class_name_args; Mutex m_get_class_name_args_mutex; - ISAToNameCache m_isa_to_name_cache; - ISAToParentCache m_isa_to_parent_cache; - std::auto_ptr<SymbolVendor> m_symbol_vendor_ap; static const char *g_find_class_name_function_name; diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp index c41db3c7eb5..a404ce40c2d 100644 --- a/lldb/source/Target/ObjCLanguageRuntime.cpp +++ b/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -262,3 +262,85 @@ ObjCLanguageRuntime::ParseMethodName (const char *name, } return result; } + +bool +ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value, + uint32_t ptr_size, + bool allow_NULLs, + bool allow_tagged, + bool check_version_specific) +{ + 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::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) +{ + if (!IsValidISA(isa)) + return 0; + + ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + { + ClassDescriptorSP superclass = found->second->GetSuperclass(); + if (!superclass || !superclass->IsValid()) + return 0; + else + { + ObjCISA parent_isa = superclass->GetISA(); + m_isa_to_descriptor_cache[parent_isa] = superclass; + return parent_isa; + } + } + + ClassDescriptorSP descriptor(GetClassDescriptor(isa)); + if (!descriptor.get() || !descriptor->IsValid()) + return 0; + m_isa_to_descriptor_cache[isa] = descriptor; + ClassDescriptorSP superclass(descriptor->GetSuperclass()); + if (!superclass.get() || !superclass->IsValid()) + return 0; + ObjCISA parent_isa = superclass->GetISA(); + m_isa_to_descriptor_cache[parent_isa] = superclass; + return parent_isa; +} + +// TODO: should we have a transparent_kvo parameter here to say if we +// want to replace the KVO swizzled class with the actual user-level type? +ConstString +ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) +{ + static const ConstString g_unknown ("unknown"); + + if (!IsValidISA(isa)) + return ConstString(); + + ISAToDescriptorIterator found = m_isa_to_descriptor_cache.find(isa); + ISAToDescriptorIterator end = m_isa_to_descriptor_cache.end(); + + if (found != end && found->second) + return found->second->GetClassName(); + + ClassDescriptorSP descriptor(GetClassDescriptor(isa)); + if (!descriptor.get() || !descriptor->IsValid()) + return ConstString(); + ConstString class_name = descriptor->GetClassName(); + if (descriptor->IsKVO()) + { + ClassDescriptorSP superclass(descriptor->GetSuperclass()); + if (!superclass.get() || !superclass->IsValid()) + return ConstString(); + descriptor = superclass; + } + m_isa_to_descriptor_cache[isa] = descriptor; + return descriptor->GetClassName(); +} diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py index ad7458bd41c..2f07bc8a1f1 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py @@ -84,7 +84,6 @@ class ObjCDataFormatterTestCase(TestBase): self.rdar11106605_commands() @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") - @expectedFailurei386 @dsym_test def test_expr_with_dsym_and_run_command(self): """Test common cases of expression parser <--> formatters interaction.""" @@ -92,7 +91,6 @@ class ObjCDataFormatterTestCase(TestBase): self.expr_objc_data_formatter_commands() @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") - @expectedFailurei386 @dwarf_test def test_expr_with_dwarf_and_run_command(self): """Test common cases of expression parser <--> formatters interaction.""" |