From e2e220a805b143d9bc8544abedff30204dcf6629 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Thu, 12 Sep 2013 00:48:47 +0000 Subject: [PATCH] SVN r189964 provided a sample Python script to inspect unordered(multi){set|map} with synthetic children, contribued by Jared Grubb This checkin converts that sample script to a C++ provider built into LLDB A test case is also provided llvm-svn: 190564 --- lldb/include/lldb/Core/ValueObject.h | 17 +++ .../DataFormatters/CXXFormatterFunctions.h | 33 +++++ lldb/lldb.xcodeproj/project.pbxproj | 72 ++-------- lldb/source/Core/ValueObject.cpp | 80 +++++++++++ lldb/source/DataFormatters/FormatManager.cpp | 4 +- .../DataFormatters/LibCxxUnorderedMap.cpp | 135 ++++++++++++++++++ .../libcxx/unordered/Makefile | 8 ++ .../unordered/TestDataFormatterUnordered.py | 75 ++++++++++ .../libcxx/unordered/main.cpp | 84 +++++++++++ 9 files changed, 446 insertions(+), 62 deletions(-) create mode 100644 lldb/source/DataFormatters/LibCxxUnorderedMap.cpp create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/Makefile create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py create mode 100644 lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/main.cpp diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 30b4daaa1d9b..dd704f15438e 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -767,6 +767,23 @@ public: lldb::ValueObjectSP GetChildAtIndexPath (const std::vector< std::pair > &idxs, size_t* index_of_error = NULL); + + // this will always create the children if necessary + lldb::ValueObjectSP + GetChildAtNamePath (const std::initializer_list &names, + ConstString* name_of_error = NULL); + + lldb::ValueObjectSP + GetChildAtNamePath (const std::vector &names, + ConstString* name_of_error = NULL); + + lldb::ValueObjectSP + GetChildAtNamePath (const std::initializer_list< std::pair > &names, + ConstString* name_of_error = NULL); + + lldb::ValueObjectSP + GetChildAtNamePath (const std::vector< std::pair > &names, + ConstString* name_of_error = NULL); virtual lldb::ValueObjectSP GetChildMemberWithName (const ConstString &name, bool can_create); diff --git a/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h b/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h index 2f56c56810ab..433c2a3c407b 100644 --- a/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h +++ b/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h @@ -868,6 +868,39 @@ namespace lldb_private { SyntheticChildrenFrontEnd* LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); + class LibcxxStdUnorderedMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp); + + virtual size_t + CalculateNumChildren (); + + virtual lldb::ValueObjectSP + GetChildAtIndex (size_t idx); + + virtual bool + Update(); + + virtual bool + MightHaveChildren (); + + virtual size_t + GetIndexOfChildWithName (const ConstString &name); + + virtual + ~LibcxxStdUnorderedMapSyntheticFrontEnd (); + private: + + ValueObject* m_tree; + size_t m_num_elements; + ValueObject* m_next_element; + std::map m_children; + std::vector > m_elements_cache; + }; + + SyntheticChildrenFrontEnd* LibcxxStdUnorderedMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index da5b109952cb..17824291df4f 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -531,11 +531,11 @@ 944372DD171F6B4300E57C32 /* RegisterContextDummy.h in Headers */ = {isa = PBXBuildFile; fileRef = 944372DB171F6B4300E57C32 /* RegisterContextDummy.h */; }; 9443B122140C18C40013457C /* SBData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9443B121140C18C10013457C /* SBData.cpp */; }; 9443B123140C26AB0013457C /* SBData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9443B120140C18A90013457C /* SBData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9452573916262D0200325455 /* SBDeclaration.cpp */; }; + 9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9456F2211616644B00656F91 /* DynamicLibrary.cpp */; }; 945759671534941F005A9070 /* PlatformPOSIX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945759651534941F005A9070 /* PlatformPOSIX.cpp */; }; 945759681534941F005A9070 /* PlatformPOSIX.h in Headers */ = {isa = PBXBuildFile; fileRef = 945759661534941F005A9070 /* PlatformPOSIX.h */; }; 945E8D80152F6AB40019BCCD /* StreamGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */; }; - 9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9452573916262D0200325455 /* SBDeclaration.cpp */; }; - 9456F2241616671900656F91 /* DynamicLibrary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9456F2211616644B00656F91 /* DynamicLibrary.cpp */; }; 9461569A14E358A6003A195C /* SBTypeFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9461568A14E35621003A195C /* SBTypeFilter.cpp */; }; 9461569B14E358A6003A195C /* SBTypeFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9461568B14E35621003A195C /* SBTypeFormat.cpp */; }; 9461569C14E358A6003A195C /* SBTypeSummary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9461568C14E35621003A195C /* SBTypeSummary.cpp */; }; @@ -549,7 +549,6 @@ 947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 947A1D631616476A0017C8D1 /* CommandObjectPlugin.h */; }; 949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 949ADF021406F648004833E1 /* ValueObjectConstResultImpl.cpp */; }; 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; }; - 94E829CA152D33C1006F96A3 /* lldb-platform in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-platform */; }; 94BA8B6D176F8C9B005A91B5 /* Range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6C176F8C9B005A91B5 /* Range.cpp */; }; 94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94BA8B6F176F97CE005A91B5 /* CommandHistory.cpp */; }; 94CB255B16B069770059775D /* CXXFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB255716B069770059775D /* CXXFormatterFunctions.cpp */; }; @@ -571,7 +570,9 @@ 94D6A0AA16CEB55F00833B6E /* NSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A716CEB55F00833B6E /* NSArray.cpp */; }; 94D6A0AB16CEB55F00833B6E /* NSDictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */; }; 94D6A0AC16CEB55F00833B6E /* NSSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A916CEB55F00833B6E /* NSSet.cpp */; }; + 94E829CA152D33C1006F96A3 /* lldb-platform in Resources */ = {isa = PBXBuildFile; fileRef = 26DC6A101337FE6900FF7998 /* lldb-platform */; }; 94EA1D5C15E6C9B400D4171A /* PythonDataObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */; }; + 94EA27CE17DE91750070F505 /* LibCxxUnorderedMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.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, ); }; }; 9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; }; @@ -1573,16 +1574,16 @@ 944372DB171F6B4300E57C32 /* RegisterContextDummy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextDummy.h; path = Utility/RegisterContextDummy.h; sourceTree = ""; }; 9443B120140C18A90013457C /* SBData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBData.h; path = include/lldb/API/SBData.h; sourceTree = ""; }; 9443B121140C18C10013457C /* SBData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBData.cpp; path = source/API/SBData.cpp; sourceTree = ""; }; - 945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = ""; }; - 945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = ""; }; - 945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = ""; }; - 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = ""; }; 944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = ""; }; 9452573616262CD000325455 /* SBDeclaration.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBDeclaration.i; sourceTree = ""; }; 9452573816262CEF00325455 /* SBDeclaration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBDeclaration.h; path = include/lldb/API/SBDeclaration.h; sourceTree = ""; }; 9452573916262D0200325455 /* SBDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBDeclaration.cpp; path = source/API/SBDeclaration.cpp; sourceTree = ""; }; 9456F2211616644B00656F91 /* DynamicLibrary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLibrary.cpp; sourceTree = ""; }; 9456F2231616645A00656F91 /* DynamicLibrary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DynamicLibrary.h; path = include/lldb/Host/DynamicLibrary.h; sourceTree = ""; }; + 945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = ""; }; + 945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = ""; }; + 945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = ""; }; + 945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = ""; }; 9461568614E355F2003A195C /* SBTypeFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeFilter.h; path = include/lldb/API/SBTypeFilter.h; sourceTree = ""; }; 9461568714E355F2003A195C /* SBTypeFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeFormat.h; path = include/lldb/API/SBTypeFormat.h; sourceTree = ""; }; 9461568814E355F2003A195C /* SBTypeSummary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeSummary.h; path = include/lldb/API/SBTypeSummary.h; sourceTree = ""; }; @@ -1647,6 +1648,7 @@ 94E367CE140C4EEA001C7A5A /* python-typemaps.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-typemaps.swig"; sourceTree = ""; }; 94EA1D5A15E6C99B00D4171A /* PythonDataObjects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonDataObjects.h; path = include/lldb/Interpreter/PythonDataObjects.h; sourceTree = ""; }; 94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonDataObjects.cpp; path = source/Interpreter/PythonDataObjects.cpp; sourceTree = ""; }; + 94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxUnorderedMap.cpp; path = source/DataFormatters/LibCxxUnorderedMap.cpp; sourceTree = ""; }; 94EBAC8313D9EE26009BA64E /* PythonPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonPointer.h; path = include/lldb/Utility/PythonPointer.h; sourceTree = ""; }; 94FA3DDD1405D4E500833217 /* ValueObjectConstResultChild.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectConstResultChild.h; path = include/lldb/Core/ValueObjectConstResultChild.h; sourceTree = ""; }; 94FA3DDF1405D50300833217 /* ValueObjectConstResultChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectConstResultChild.cpp; path = source/Core/ValueObjectConstResultChild.cpp; sourceTree = ""; }; @@ -3429,60 +3431,6 @@ name = POSIX; sourceTree = ""; }; - 940DB8C416EA64D400D3C2F1 /* lldb-perf */ = { - isa = PBXGroup; - children = ( - 940DB8C616EA654E00D3C2F1 /* darwin */, - 940DB8C516EA654900D3C2F1 /* lib */, - ); - name = "lldb-perf"; - path = "tools/lldb-perf"; - sourceTree = ""; - }; - 940DB8C516EA654900D3C2F1 /* lib */ = { - isa = PBXGroup; - children = ( - 940DB8CA16EA66FB00D3C2F1 /* Gauge.h */, - 940DB8CE16EA670C00D3C2F1 /* Measurement.h */, - 940DB8D116EA671800D3C2F1 /* MemoryGauge.cpp */, - 940DB8D216EA671800D3C2F1 /* MemoryGauge.h */, - 940DB8D516EA672200D3C2F1 /* Metric.cpp */, - 940DB8D616EA672200D3C2F1 /* Metric.h */, - 940DB8D916EA672D00D3C2F1 /* TestCase.cpp */, - 940DB8DA16EA672D00D3C2F1 /* TestCase.h */, - 940DB8DD16EA673800D3C2F1 /* Timer.cpp */, - 940DB8DE16EA673800D3C2F1 /* Timer.h */, - 940DB8E116EA674000D3C2F1 /* Xcode.cpp */, - 940DB8E216EA674000D3C2F1 /* Xcode.h */, - ); - path = lib; - sourceTree = ""; - }; - 940DB8C616EA654E00D3C2F1 /* darwin */ = { - isa = PBXGroup; - children = ( - 940DB8FB16EA84BF00D3C2F1 /* formatters */, - 940DB8C716EA655400D3C2F1 /* sketch */, - ); - path = darwin; - sourceTree = ""; - }; - 940DB8C716EA655400D3C2F1 /* sketch */ = { - isa = PBXGroup; - children = ( - 940DB8E616EA709400D3C2F1 /* main.cpp */, - ); - path = sketch; - sourceTree = ""; - }; - 940DB8FB16EA84BF00D3C2F1 /* formatters */ = { - isa = PBXGroup; - children = ( - 94DB60F016EA888A00459D9E /* main.cpp */, - ); - path = formatters; - sourceTree = ""; - }; 94CB255616B0683B0059775D /* DataFormatters */ = { isa = PBXGroup; children = ( @@ -3502,6 +3450,7 @@ 94D0B10A16D5535900EA9C70 /* LibCxx.cpp */, 94CD704F16F8DF1C00CF1E42 /* LibCxxList.cpp */, 94CD705116F8F5BC00CF1E42 /* LibCxxMap.cpp */, + 94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.cpp */, 94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */, 94D6A0A716CEB55F00833B6E /* NSArray.cpp */, 94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */, @@ -4327,6 +4276,7 @@ 94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */, 262D24E613FB8710002D1960 /* RegisterContextMemory.cpp in Sources */, 26F4A21C13FBA31A0064B613 /* ThreadMemory.cpp in Sources */, + 94EA27CE17DE91750070F505 /* LibCxxUnorderedMap.cpp in Sources */, 266DFE9713FD656E00D0C574 /* OperatingSystem.cpp in Sources */, 26954EBE1401EE8B00294D09 /* DynamicRegisterInfo.cpp in Sources */, 26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */, diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index a30cc1306c6b..8bb285db05d9 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -595,6 +595,86 @@ ValueObject::GetChildAtIndexPath (const std::vector< std::pair > & return root; } +lldb::ValueObjectSP +ValueObject::GetChildAtNamePath (const std::initializer_list &names, + ConstString* name_of_error) +{ + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (ConstString name : names) + { + root = root->GetChildMemberWithName(name, true); + if (!root) + { + if (name_of_error) + *name_of_error = name; + return root; + } + } + return root; +} + +lldb::ValueObjectSP +ValueObject::GetChildAtNamePath (const std::vector &names, + ConstString* name_of_error) +{ + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (ConstString name : names) + { + root = root->GetChildMemberWithName(name, true); + if (!root) + { + if (name_of_error) + *name_of_error = name; + return root; + } + } + return root; +} + +lldb::ValueObjectSP +ValueObject::GetChildAtNamePath (const std::initializer_list< std::pair > &names, + ConstString* name_of_error) +{ + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (std::pair name : names) + { + root = root->GetChildMemberWithName(name.first, name.second); + if (!root) + { + if (name_of_error) + *name_of_error = name.first; + return root; + } + } + return root; +} + +lldb::ValueObjectSP +ValueObject::GetChildAtNamePath (const std::vector< std::pair > &names, + ConstString* name_of_error) +{ + if (names.size() == 0) + return GetSP(); + ValueObjectSP root(GetSP()); + for (std::pair name : names) + { + root = root->GetChildMemberWithName(name.first, name.second); + if (!root) + { + if (name_of_error) + *name_of_error = name.first; + return root; + } + } + return root; +} + size_t ValueObject::GetIndexOfChildWithName (const ConstString &name) { diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index eeae8bc9a19d..c4debf9c2590 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -632,7 +632,8 @@ FormatManager::LoadLibcxxFormatters() AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__1::set<.+> >(( )?&)?$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true); - + AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_synth_flags, true); + libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); @@ -650,6 +651,7 @@ FormatManager::LoadLibcxxFormatters() AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__1::set<.+>(( )?&)?$"), stl_summary_flags, true); AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__1::multiset<.+>(( )?&)?$"), stl_summary_flags, true); AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__1::multimap<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::unordered containers summary provider", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_summary_flags, true); stl_summary_flags.SetSkipPointers(true); AddStringSummary(libcxx_category_sp, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true); diff --git a/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp b/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp new file mode 100644 index 000000000000..b73d3bf852e1 --- /dev/null +++ b/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp @@ -0,0 +1,135 @@ +//===-- LibCxxUnorderedMap.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-python.h" + +#include "lldb/DataFormatters/CXXFormatterFunctions.h" + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Host/Endian.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : +SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_tree(NULL), +m_num_elements(0), +m_next_element(nullptr), +m_children(), +m_elements_cache() +{ + if (valobj_sp) + Update(); +} + +size_t +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren () +{ + if (m_num_elements != UINT32_MAX) + return m_num_elements; + return 0; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + if (idx >= CalculateNumChildren()) + return lldb::ValueObjectSP(); + if (m_tree == NULL) + return lldb::ValueObjectSP(); + + auto cached = m_children.find(idx); + if (cached != m_children.end()) + return cached->second; + + while (idx >= m_elements_cache.size()) + { + if (m_next_element == nullptr) + return lldb::ValueObjectSP(); + + Error error; + ValueObjectSP node_sp = m_next_element->Dereference(error); + if (!node_sp || error.Fail()) + return lldb::ValueObjectSP(); + + ValueObjectSP value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true); + ValueObjectSP hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true); + if (!hash_sp || !value_sp) + return lldb::ValueObjectSP(); + m_elements_cache.push_back({value_sp.get(),hash_sp->GetValueAsUnsigned(0)}); + m_next_element = node_sp->GetChildMemberWithName(ConstString("__next_"),true).get(); + if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0) + m_next_element = nullptr; + } + + std::pair val_hash = m_elements_cache[idx]; + if (!val_hash.first) + return lldb::ValueObjectSP(); + StreamString stream; + stream.Printf("[%zu]",idx); + DataExtractor data; + val_hash.first->GetData(data); + ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(); + return val_hash.first->CreateValueObjectFromData(stream.GetData(), + data, + exe_ctx, + val_hash.first->GetClangType()); +} + +bool +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() +{ + m_num_elements = UINT32_MAX; + m_next_element = nullptr; + m_elements_cache.clear(); + m_children.clear(); + ValueObjectSP table_sp = m_backend.GetChildMemberWithName(ConstString("__table_"), true); + if (!table_sp) + return false; + ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath({ConstString("__p2_"),ConstString("__first_")}); + if (!num_elements_sp) + return false; + m_num_elements = num_elements_sp->GetValueAsUnsigned(0); + m_tree = table_sp->GetChildAtNamePath({ConstString("__p1_"),ConstString("__first_"),ConstString("__next_")}).get(); + if (m_num_elements > 0) + m_next_element = table_sp->GetChildAtNamePath({ConstString("__p1_"),ConstString("__first_"),ConstString("__next_")}).get(); + return false; +} + +bool +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::~LibcxxStdUnorderedMapSyntheticFrontEnd () +{} + +SyntheticChildrenFrontEnd* +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return NULL; + return (new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)); +} diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/Makefile b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/Makefile new file mode 100644 index 000000000000..e681e094da4d --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/Makefile @@ -0,0 +1,8 @@ +LEVEL = ../../../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules + +CXXFLAGS += -stdlib=libc++ -O0 -std=c++11 +LDFLAGS += -stdlib=libc++ \ No newline at end of file diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py new file mode 100644 index 000000000000..a56655346271 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py @@ -0,0 +1,75 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class LibcxxMultiMapDataFormatterTestCase(TestBase): + + mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libcxx", "unordered") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym_and_run_command(self): + """Test data formatter commands.""" + self.buildDsym() + self.data_formatter_commands() + + @skipIfLinux # No standard locations for libc++ on Linux, so skip for now + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Test data formatter commands.""" + self.buildDwarf() + self.data_formatter_commands() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + def look_for_content_and_continue(self,var_name,substrs): + self.expect( ("frame variable %s" % var_name), substrs ) + self.runCmd("continue") + + def data_formatter_commands(self): + """Test that that file and class static variables display correctly.""" + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_source_regexp (self, "Set break point at this line.") + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd('type format clear', check=False) + self.runCmd('type summary clear', check=False) + self.runCmd('type filter clear', check=False) + self.runCmd('type synth clear', check=False) + self.runCmd("settings set target.max-children-count 256", check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.expect('image list', substrs = self.getLibcPlusPlusLibs()) + + self.look_for_content_and_continue("map",['size=5 {,''hello','world','this','is','me']) + self.look_for_content_and_continue("mmap",['size=6 {','first = 3','second = "this"','first = 2','second = "hello"']) + self.look_for_content_and_continue("iset",['size=5 {','[0] = 5','[2] = 3','[3] = 2']) + self.look_for_content_and_continue("sset",['size=5 {','[0] = "is"','[1] = "world"','[4] = "hello"']) + self.look_for_content_and_continue("imset",['size=6 {','[0] = 3','[1] = 3','[2] = 3','[4] = 2','[5] = 1']) + self.look_for_content_and_continue("smset",['size=5 {','[0] = "is"','[1] = "is"','[2] = "world"','[3] = "world"']) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/main.cpp new file mode 100644 index 000000000000..4e8a1a779c0c --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/main.cpp @@ -0,0 +1,84 @@ +#include +#ifdef _LIBCPP_INLINE_VISIBILITY +#undef _LIBCPP_INLINE_VISIBILITY +#endif +#define _LIBCPP_INLINE_VISIBILITY +#include +#include + +using std::string; + +#define intstr_map std::unordered_map +#define intstr_mmap std::unordered_multimap + +#define int_set std::unordered_set +#define str_set std::unordered_set +#define int_mset std::unordered_multiset +#define str_mset std::unordered_multiset + +int g_the_foo = 0; + +int thefoo_rw(int arg = 1) +{ + if (arg < 0) + arg = 0; + if (!arg) + arg = 1; + g_the_foo += arg; + return g_the_foo; +} + +int main() +{ + intstr_map map; + map.emplace(1,"hello"); + map.emplace(2,"world"); + map.emplace(3,"this"); + map.emplace(4,"is"); + map.emplace(5,"me"); + thefoo_rw(); // Set break point at this line. + + intstr_mmap mmap; + mmap.emplace(1,"hello"); + mmap.emplace(2,"hello"); + mmap.emplace(2,"world"); + mmap.emplace(3,"this"); + mmap.emplace(3,"this"); + mmap.emplace(3,"this"); + thefoo_rw(); // Set break point at this line. + + int_set iset; + iset.emplace(1); + iset.emplace(2); + iset.emplace(3); + iset.emplace(4); + iset.emplace(5); + thefoo_rw(); // Set break point at this line. + + str_set sset; + sset.emplace("hello"); + sset.emplace("world"); + sset.emplace("this"); + sset.emplace("is"); + sset.emplace("me"); + thefoo_rw(); // Set break point at this line. + + int_mset imset; + imset.emplace(1); + imset.emplace(2); + imset.emplace(2); + imset.emplace(3); + imset.emplace(3); + imset.emplace(3); + thefoo_rw(); // Set break point at this line. + + str_mset smset; + smset.emplace("hello"); + smset.emplace("world"); + smset.emplace("world"); + smset.emplace("is"); + smset.emplace("is"); + thefoo_rw(); // Set break point at this line. + + return 0; +} \ No newline at end of file