diff --git a/lldb/examples/synthetic/gnu_libstdcpp.py b/lldb/examples/synthetic/gnu_libstdcpp.py --- a/lldb/examples/synthetic/gnu_libstdcpp.py +++ b/lldb/examples/synthetic/gnu_libstdcpp.py @@ -9,12 +9,17 @@ # before relying on these formatters to do the right thing for your setup -class StdListSynthProvider: - - def __init__(self, valobj, dict): +class AbstractListSynthProvider: + def __init__(self, valobj, dict, has_prev): + ''' + :param valobj: The value object of the list + :param dict: A dict with metadata provided by LLDB + :param has_prev: Whether the list supports a 'prev' pointer besides a 'next' one + ''' logger = lldb.formatters.Logger.Logger() self.valobj = valobj self.count = None + self.has_prev = has_prev logger >> "Providing synthetic children for a list named " + \ str(valobj.GetName()) @@ -24,13 +29,13 @@ def is_valid(self, node): logger = lldb.formatters.Logger.Logger() - valid = self.value(self.next_node(node)) != self.node_address + valid = self.value(self.next_node(node)) != self.get_end_of_list_address() if valid: logger >> "%s is valid" % str(self.valobj.GetName()) else: logger >> "synthetic value is not valid" return valid - + def value(self, node): logger = lldb.formatters.Logger.Logger() value = node.GetValueAsUnsigned() @@ -73,26 +78,30 @@ def num_children_impl(self): logger = lldb.formatters.Logger.Logger() try: - next_val = self.next.GetValueAsUnsigned(0) - prev_val = self.prev.GetValueAsUnsigned(0) # After a std::list has been initialized, both next and prev will # be non-NULL - if next_val == 0 or prev_val == 0: - return 0 - if next_val == self.node_address: + next_val = self.next.GetValueAsUnsigned(0) + if next_val == 0: return 0 - if next_val == prev_val: - return 1 if self.has_loop(): return 0 - size = 2 + if self.has_prev: + prev_val = self.prev.GetValueAsUnsigned(0) + if prev_val == 0: + return 0 + if next_val == self.node_address: + return 0 + if next_val == prev_val: + return 1 + size = 1 current = self.next while current.GetChildMemberWithName( - '_M_next').GetValueAsUnsigned(0) != self.node_address: + '_M_next').GetValueAsUnsigned(0) != self.get_end_of_list_address(): size = size + 1 current = current.GetChildMemberWithName('_M_next') - return (size - 1) + return size except: + logger >> "Error determining the size" return 0 def get_child_index(self, name): @@ -101,7 +110,7 @@ return int(name.lstrip('[').rstrip(']')) except: return -1 - + def get_child_at_index(self, index): logger = lldb.formatters.Logger.Logger() logger >> "Fetching child " + str(index) @@ -115,9 +124,11 @@ while offset > 0: current = current.GetChildMemberWithName('_M_next') offset = offset - 1 + # C++ lists store the data of a node after its pointers. In the case of a forward list, there's just one pointer (next), and + # in the case of a double-linked list, there's an additional pointer (prev). return current.CreateChildAtOffset( '[' + str(index) + ']', - 2 * current.GetType().GetByteSize(), + (2 if self.has_prev else 1) * current.GetType().GetByteSize(), self.data_type) except: return None @@ -139,19 +150,60 @@ # later self.count = None try: - impl = self.valobj.GetChildMemberWithName('_M_impl') - self.node = impl.GetChildMemberWithName('_M_node') - self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) - self.next = self.node.GetChildMemberWithName('_M_next') - self.prev = self.node.GetChildMemberWithName('_M_prev') + self.impl = self.valobj.GetChildMemberWithName('_M_impl') self.data_type = self.extract_type() self.data_size = self.data_type.GetByteSize() + self.updateNodes() except: pass return False + ''' + Method is used to extract the list pointers into the variables (e.g self.node, self.next, and optionally to self.prev) + and is mandatory to be overriden in each AbstractListSynthProvider subclass + ''' + def updateNodes(self): + raise NotImplementedError + def has_children(self): return True + + ''' + Method is used to identify if a node traversal has reached its end + and is mandatory to be overriden in each AbstractListSynthProvider subclass + ''' + def get_end_of_list_address(self): + raise NotImplementedError + + +class StdForwardListSynthProvider(AbstractListSynthProvider): + + def __init__(self, valobj, dict): + has_prev = False + super().__init__(valobj, dict, has_prev) + + def updateNodes(self): + self.node = self.impl.GetChildMemberWithName('_M_head') + self.next = self.node.GetChildMemberWithName('_M_next') + + def get_end_of_list_address(self): + return 0 + + +class StdListSynthProvider(AbstractListSynthProvider): + + def __init__(self, valobj, dict): + has_prev = True + super().__init__(valobj, dict, has_prev) + + def updateNodes(self): + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) + self.node = self.impl.GetChildMemberWithName('_M_node') + self.prev = self.node.GetChildMemberWithName('_M_prev') + self.next = self.node.GetChildMemberWithName('_M_next') + + def get_end_of_list_address(self): + return self.node_address class StdVectorSynthProvider: diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -923,6 +923,11 @@ SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); + cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( + RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"), + SyntheticChildrenSP(new ScriptedSyntheticChildren( + stl_synth_flags, + "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( @@ -953,6 +958,10 @@ RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); + cpp_category_sp->GetRegexTypeSummariesContainer()->Add( + RegularExpression("^std::(__cxx11::)?forward_list<.+>(( )?&)?$"), + TypeSummaryImplSP( + new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/Makefile rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/Makefile rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/Makefile --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/Makefile +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/Makefile @@ -1,4 +1,3 @@ CXX_SOURCES := main.cpp -USE_LIBCPP := 1 include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/TestDataFormatterGenericForwardList.py @@ -9,8 +9,10 @@ from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil +USE_LIBSTDCPP = "USE_LIBSTDCPP" +USE_LIBCPP = "USE_LIBCPP" -class TestDataFormatterLibcxxForwardList(TestBase): +class TestDataFormatterGenericForwardList(TestBase): mydir = TestBase.compute_mydir(__file__) @@ -19,10 +21,10 @@ self.line = line_number('main.cpp', '// break here') self.namespace = 'std' - @add_test_categories(["libc++"]) - def test(self): + + def do_test(self, stdlib_type): """Test that std::forward_list is displayed correctly""" - self.build() + self.build(dictionary={stdlib_type: "1"}) lldbutil.run_to_source_breakpoint(self, '// break here', lldb.SBFileSpec("main.cpp", False)) @@ -49,3 +51,12 @@ '[3] = 4444', '[4] = 55555', '}']) + + @add_test_categories(["libstdcxx"]) + def test_libstdcpp(self): + self.do_test(USE_LIBSTDCPP) + + @add_test_categories(["libc++"]) + def test_libcpp(self): + self.do_test(USE_LIBCPP) + diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/forward_list/main.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + std::forward_list empty{}, one_elt{47}, + five_elts{1, 22, 333, 4444, 55555}; + return 0; // break here +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/main.cpp deleted file mode 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/main.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -int main() -{ - std::forward_list empty{}, one_elt{47}, five_elts{1,22,333,4444,55555}; - return 0; // break here -}