danilashtefan updated this revision to Diff 389597.
danilashtefan added a comment.
Unified tests added
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D114008/new/
https://reviews.llvm.org/D114008
Files:
lldb/examples/synthetic/gnu_libstdcpp.py
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/Makefile
lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/main.cpp
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/main.cpp
@@ -0,0 +1,40 @@
+#include <deque>
+
+struct Foo_small {
+ int a;
+ int b;
+ int c;
+
+ Foo_small(int a, int b, int c) : a(a), b(b), c(c) {}
+};
+
+struct Foo_large {
+ int a;
+ int b;
+ int c;
+ char d[1000] = {0};
+
+ Foo_large(int a, int b, int c) : a(a), b(b), c(c) {}
+};
+
+template <typename T> T fill(T deque) {
+ for (int i = 0; i < 100; i++) {
+ deque.push_back({i, i + 1, i + 2});
+ deque.push_front({-i, -(i + 1), -(i + 2)});
+ }
+ return deque;
+}
+
+int main() {
+ std::deque<int> empty;
+ std::deque<int> deque_1 = {1};
+ std::deque<int> deque_3 = {3, 1, 2};
+
+ std::deque<Foo_small> deque_200_small;
+ deque_200_small = fill<std::deque<Foo_small>>(deque_200_small);
+
+ std::deque<Foo_large> deque_200_large;
+ deque_200_large = fill<std::deque<Foo_large>>(deque_200_large);
+
+ return empty.size() + deque_1.front() + deque_3.front(); // break here
+}
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py
@@ -0,0 +1,55 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+USE_LIBSTDCPP = "USE_LIBSTDCPP"
+USE_LIBCPP = "USE_LIBCPP"
+
+class GenericDequeDataFormatterTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def findVariable(self, name):
+ var = self.frame().FindVariable(name)
+ self.assertTrue(var.IsValid())
+ return var
+
+ def getVariableType(self, name):
+ var = self.findVariable(name)
+ return var.GetType().GetDisplayTypeName()
+
+ def check(self, var_name, size):
+ var = self.findVariable(var_name)
+ self.assertEqual(var.GetNumChildren(), size)
+ children = []
+ for i in range(size):
+ child = var.GetChildAtIndex(i)
+ children.append(ValueCheck(value=child.GetValue()))
+ self.expect_var_path(var_name, type=self.getVariableType(var_name), children=children)
+
+ def do_test(self, stdlib_type):
+ self.build()
+ lldbutil.run_to_source_breakpoint(self, "break here",
+ lldb.SBFileSpec("main.cpp"))
+
+ self.expect_expr("empty", result_children=[])
+ self.expect_expr("deque_1", result_children=[
+ ValueCheck(name="[0]", value="1"),
+ ])
+ self.expect_expr("deque_3", result_children=[
+ ValueCheck(name="[0]", value="3"),
+ ValueCheck(name="[1]", value="1"),
+ ValueCheck(name="[2]", value="2")
+ ])
+
+ self.check("deque_200_small", 200)
+ self.check("deque_200_large", 200)
+
+ @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)
\ No newline at end of file
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -918,6 +918,11 @@
SyntheticChildrenSP(new ScriptedSyntheticChildren(
stl_deref_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
+ cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
+ RegularExpression("^std::deque<.+>(( )?&)?$"),
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(
RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
SyntheticChildrenSP(new ScriptedSyntheticChildren(
@@ -946,6 +951,10 @@
RegularExpression("^std::set<.+> >(( )?&)?$"),
TypeSummaryImplSP(
new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
+ RegularExpression("^std::deque<.+>(( )?&)?$"),
+ TypeSummaryImplSP(
+ new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
RegularExpression("^std::multimap<.+> >(( )?&)?$"),
TypeSummaryImplSP(
Index: lldb/examples/synthetic/gnu_libstdcpp.py
===================================================================
--- lldb/examples/synthetic/gnu_libstdcpp.py
+++ lldb/examples/synthetic/gnu_libstdcpp.py
@@ -8,6 +8,137 @@
# You are encouraged to look at the STL implementation for your platform
# before relying on these formatters to do the right thing for your setup
+class StdDequeSynthProvider:
+ def __init__(self, valobj, d):
+ self.valobj = valobj
+ self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
+ self.count = None
+ self.block_size = -1
+ self.element_size = -1
+ self.find_block_size()
+
+
+ def find_block_size(self):
+ # in order to use the deque we must have the block size, or else
+ # it's impossible to know what memory addresses are valid
+ self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
+ if not self.element_type.IsValid():
+ return
+ self.element_size = self.element_type.GetByteSize()
+ # The block size (i.e. number of elements per subarray) is defined in
+ # this piece of code, so we need to replicate it.
+ #
+ # #define _GLIBCXX_DEQUE_BUF_SIZE 512
+ #
+ # return (__size < _GLIBCXX_DEQUE_BUF_SIZE
+ # ? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1));
+ if self.element_size < 512:
+ self.block_size = 512 // self.element_size
+ else:
+ self.block_size = 1
+
+ def num_children(self):
+ if self.count is None:
+ return 0
+ return self.count
+
+ def has_children(self):
+ return True
+
+ def get_child_index(self, name):
+ try:
+ return int(name.lstrip('[').rstrip(']'))
+ except:
+ return -1
+
+ def get_child_at_index(self, index):
+ if index < 0 or self.count is None:
+ return None
+ if index >= self.num_children():
+ return None
+ try:
+ name = '[' + str(index) + ']'
+ # We first look for the element in the first subarray,
+ # which might be incomplete.
+ if index < self.first_node_size:
+ # The following statement is valid because self.first_elem is the pointer
+ # to the first element
+ return self.first_elem.CreateChildAtOffset(name, index * self.element_size, self.element_type)
+
+ # Now the rest of the subarrays except for maybe the last one
+ # are going to be complete, so the final expression is simpler
+ i, j = divmod(index - self.first_node_size, self.block_size)
+
+ # We first move to the beginning of the node/subarray were our element is
+ node = self.start_node.CreateChildAtOffset(
+ '',
+ (1 + i) * self.valobj.GetProcess().GetAddressByteSize(),
+ self.element_type.GetPointerType())
+ return node.CreateChildAtOffset(name, j * self.element_size, self.element_type)
+
+ except:
+ return None
+
+ def update(self):
+ logger = lldb.formatters.Logger.Logger()
+ self.count = 0
+ try:
+ # A deque is effectively a two-dim array, with fixed width.
+ # However, only a subset of this memory contains valid data
+ # since a deque may have some slack at the front and back in
+ # order to have O(1) insertion at both ends.
+ # The rows in active use are delimited by '_M_start' and
+ # '_M_finish'.
+ #
+ # To find the elements that are actually constructed, the 'start'
+ # variable tells which element in this NxM array is the 0th
+ # one.
+ if self.block_size < 0 or self.element_size < 0:
+ return False
+
+ count = 0
+
+ impl = self.valobj.GetChildMemberWithName('_M_impl')
+
+ # we calculate the size of the first node (i.e. first internal array)
+ self.start = impl.GetChildMemberWithName('_M_start')
+ self.start_node = self.start.GetChildMemberWithName('_M_node')
+ first_node_address = self.start_node.GetValueAsUnsigned(0)
+ first_node_last_elem = self.start.GetChildMemberWithName('_M_last').GetValueAsUnsigned(0)
+ self.first_elem = self.start.GetChildMemberWithName('_M_cur')
+ first_node_first_elem = self.first_elem.GetValueAsUnsigned(0)
+
+
+ finish = impl.GetChildMemberWithName('_M_finish')
+ last_node_address = finish.GetChildMemberWithName('_M_node').GetValueAsUnsigned(0)
+ last_node_first_elem = finish.GetChildMemberWithName('_M_first').GetValueAsUnsigned(0)
+ last_node_last_elem = finish.GetChildMemberWithName('_M_cur').GetValueAsUnsigned(0)
+
+ if first_node_first_elem == 0 or first_node_last_elem == 0 or first_node_first_elem > first_node_last_elem:
+ return False
+ if last_node_first_elem == 0 or last_node_last_elem == 0 or last_node_first_elem > last_node_last_elem:
+ return False
+
+
+ if last_node_address == first_node_address:
+ self.first_node_size = (last_node_last_elem - first_node_first_elem) // self.element_size
+ count += self.first_node_size
+ else:
+ self.first_node_size = (first_node_last_elem - first_node_first_elem) // self.element_size
+ count += self.first_node_size
+
+ # we calculate the size of the last node
+ finish = impl.GetChildMemberWithName('_M_finish')
+ last_node_address = finish.GetChildMemberWithName('_M_node').GetValueAsUnsigned(0)
+ count += (last_node_last_elem - last_node_first_elem) // self.element_size
+
+ # we calculate the size of the intermediate nodes
+ num_intermediate_nodes = (last_node_address - first_node_address - 1) // self.valobj.GetProcess().GetAddressByteSize()
+ count += self.block_size * num_intermediate_nodes
+ self.count = count
+ except:
+ pass
+ return False
class AbstractListSynthProvider:
def __init__(self, valobj, dict, has_prev):
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits