<rdar://problem/14071463>

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
This commit is contained in:
Enrico Granata 2013-09-12 00:48:47 +00:00
parent 872ac4b5f0
commit e2e220a805
9 changed files with 446 additions and 62 deletions

View File

@ -768,6 +768,23 @@ public:
GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs,
size_t* index_of_error = NULL);
// this will always create the children if necessary
lldb::ValueObjectSP
GetChildAtNamePath (const std::initializer_list<ConstString> &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::vector<ConstString> &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::initializer_list< std::pair<ConstString, bool> > &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::vector< std::pair<ConstString, bool> > &names,
ConstString* name_of_error = NULL);
virtual lldb::ValueObjectSP
GetChildMemberWithName (const ConstString &name, bool can_create);

View File

@ -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<size_t,lldb::ValueObjectSP> m_children;
std::vector<std::pair<ValueObject*, uint64_t> > m_elements_cache;
};
SyntheticChildrenFrontEnd* LibcxxStdUnorderedMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
} // namespace formatters
} // namespace lldb_private

View File

@ -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 = "<group>"; };
9443B120140C18A90013457C /* SBData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBData.h; path = include/lldb/API/SBData.h; sourceTree = "<group>"; };
9443B121140C18C10013457C /* SBData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBData.cpp; path = source/API/SBData.cpp; sourceTree = "<group>"; };
945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = "<group>"; };
945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = "<group>"; };
945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = "<group>"; };
945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = "<group>"; };
944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = "<group>"; };
9452573616262CD000325455 /* SBDeclaration.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBDeclaration.i; sourceTree = "<group>"; };
9452573816262CEF00325455 /* SBDeclaration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBDeclaration.h; path = include/lldb/API/SBDeclaration.h; sourceTree = "<group>"; };
9452573916262D0200325455 /* SBDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBDeclaration.cpp; path = source/API/SBDeclaration.cpp; sourceTree = "<group>"; };
9456F2211616644B00656F91 /* DynamicLibrary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicLibrary.cpp; sourceTree = "<group>"; };
9456F2231616645A00656F91 /* DynamicLibrary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DynamicLibrary.h; path = include/lldb/Host/DynamicLibrary.h; sourceTree = "<group>"; };
945759651534941F005A9070 /* PlatformPOSIX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformPOSIX.cpp; path = POSIX/PlatformPOSIX.cpp; sourceTree = "<group>"; };
945759661534941F005A9070 /* PlatformPOSIX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformPOSIX.h; path = POSIX/PlatformPOSIX.h; sourceTree = "<group>"; };
945E8D7D152F6AA80019BCCD /* StreamGDBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamGDBRemote.h; path = include/lldb/Core/StreamGDBRemote.h; sourceTree = "<group>"; };
945E8D7F152F6AB40019BCCD /* StreamGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamGDBRemote.cpp; path = source/Core/StreamGDBRemote.cpp; sourceTree = "<group>"; };
9461568614E355F2003A195C /* SBTypeFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeFilter.h; path = include/lldb/API/SBTypeFilter.h; sourceTree = "<group>"; };
9461568714E355F2003A195C /* SBTypeFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeFormat.h; path = include/lldb/API/SBTypeFormat.h; sourceTree = "<group>"; };
9461568814E355F2003A195C /* SBTypeSummary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeSummary.h; path = include/lldb/API/SBTypeSummary.h; sourceTree = "<group>"; };
@ -1647,6 +1648,7 @@
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>"; };
94EA1D5B15E6C9B400D4171A /* PythonDataObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PythonDataObjects.cpp; path = source/Interpreter/PythonDataObjects.cpp; sourceTree = "<group>"; };
94EA27CD17DE91750070F505 /* LibCxxUnorderedMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxxUnorderedMap.cpp; path = source/DataFormatters/LibCxxUnorderedMap.cpp; sourceTree = "<group>"; };
94EBAC8313D9EE26009BA64E /* PythonPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonPointer.h; path = include/lldb/Utility/PythonPointer.h; sourceTree = "<group>"; };
94FA3DDD1405D4E500833217 /* ValueObjectConstResultChild.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectConstResultChild.h; path = include/lldb/Core/ValueObjectConstResultChild.h; sourceTree = "<group>"; };
94FA3DDF1405D50300833217 /* ValueObjectConstResultChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectConstResultChild.cpp; path = source/Core/ValueObjectConstResultChild.cpp; sourceTree = "<group>"; };
@ -3429,60 +3431,6 @@
name = POSIX;
sourceTree = "<group>";
};
940DB8C416EA64D400D3C2F1 /* lldb-perf */ = {
isa = PBXGroup;
children = (
940DB8C616EA654E00D3C2F1 /* darwin */,
940DB8C516EA654900D3C2F1 /* lib */,
);
name = "lldb-perf";
path = "tools/lldb-perf";
sourceTree = "<group>";
};
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 = "<group>";
};
940DB8C616EA654E00D3C2F1 /* darwin */ = {
isa = PBXGroup;
children = (
940DB8FB16EA84BF00D3C2F1 /* formatters */,
940DB8C716EA655400D3C2F1 /* sketch */,
);
path = darwin;
sourceTree = "<group>";
};
940DB8C716EA655400D3C2F1 /* sketch */ = {
isa = PBXGroup;
children = (
940DB8E616EA709400D3C2F1 /* main.cpp */,
);
path = sketch;
sourceTree = "<group>";
};
940DB8FB16EA84BF00D3C2F1 /* formatters */ = {
isa = PBXGroup;
children = (
94DB60F016EA888A00459D9E /* main.cpp */,
);
path = formatters;
sourceTree = "<group>";
};
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 */,

View File

@ -595,6 +595,86 @@ ValueObject::GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &
return root;
}
lldb::ValueObjectSP
ValueObject::GetChildAtNamePath (const std::initializer_list<ConstString> &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<ConstString> &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<ConstString, bool> > &names,
ConstString* name_of_error)
{
if (names.size() == 0)
return GetSP();
ValueObjectSP root(GetSP());
for (std::pair<ConstString, bool> 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<ConstString, bool> > &names,
ConstString* name_of_error)
{
if (names.size() == 0)
return GetSP();
ValueObjectSP root(GetSP());
for (std::pair<ConstString, bool> 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)
{

View File

@ -632,6 +632,7 @@ 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,
@ -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);

View File

@ -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<ValueObject*, uint64_t> 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));
}

View File

@ -0,0 +1,8 @@
LEVEL = ../../../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules
CXXFLAGS += -stdlib=libc++ -O0 -std=c++11
LDFLAGS += -stdlib=libc++

View File

@ -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()

View File

@ -0,0 +1,84 @@
#include <string>
#ifdef _LIBCPP_INLINE_VISIBILITY
#undef _LIBCPP_INLINE_VISIBILITY
#endif
#define _LIBCPP_INLINE_VISIBILITY
#include <unordered_map>
#include <unordered_set>
using std::string;
#define intstr_map std::unordered_map<int, string>
#define intstr_mmap std::unordered_multimap<int, string>
#define int_set std::unordered_set<int>
#define str_set std::unordered_set<string>
#define int_mset std::unordered_multiset<int>
#define str_mset std::unordered_multiset<string>
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;
}