forked from OSchip/llvm-project
[formatters] Add a libstdcpp formatter for forward_list and refactor list formatter
This diff adds a data formatter for libstdcpp's forward_list. Besides, it refactors the existing code by extracting the common functionality between libstdcpp forward_list and list formatters into the AbstractListSynthProvider class. Reviewed By: wallace Differential Revision: https://reviews.llvm.org/D113362
This commit is contained in:
parent
af4dc633f8
commit
577c1eecf8
|
@ -9,12 +9,17 @@ import lldb.formatters.Logger
|
||||||
# before relying on these formatters to do the right thing for your setup
|
# before relying on these formatters to do the right thing for your setup
|
||||||
|
|
||||||
|
|
||||||
class StdListSynthProvider:
|
class AbstractListSynthProvider:
|
||||||
|
def __init__(self, valobj, dict, has_prev):
|
||||||
def __init__(self, valobj, dict):
|
'''
|
||||||
|
: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()
|
logger = lldb.formatters.Logger.Logger()
|
||||||
self.valobj = valobj
|
self.valobj = valobj
|
||||||
self.count = None
|
self.count = None
|
||||||
|
self.has_prev = has_prev
|
||||||
logger >> "Providing synthetic children for a list named " + \
|
logger >> "Providing synthetic children for a list named " + \
|
||||||
str(valobj.GetName())
|
str(valobj.GetName())
|
||||||
|
|
||||||
|
@ -24,13 +29,13 @@ class StdListSynthProvider:
|
||||||
|
|
||||||
def is_valid(self, node):
|
def is_valid(self, node):
|
||||||
logger = lldb.formatters.Logger.Logger()
|
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:
|
if valid:
|
||||||
logger >> "%s is valid" % str(self.valobj.GetName())
|
logger >> "%s is valid" % str(self.valobj.GetName())
|
||||||
else:
|
else:
|
||||||
logger >> "synthetic value is not valid"
|
logger >> "synthetic value is not valid"
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
def value(self, node):
|
def value(self, node):
|
||||||
logger = lldb.formatters.Logger.Logger()
|
logger = lldb.formatters.Logger.Logger()
|
||||||
value = node.GetValueAsUnsigned()
|
value = node.GetValueAsUnsigned()
|
||||||
|
@ -73,26 +78,30 @@ class StdListSynthProvider:
|
||||||
def num_children_impl(self):
|
def num_children_impl(self):
|
||||||
logger = lldb.formatters.Logger.Logger()
|
logger = lldb.formatters.Logger.Logger()
|
||||||
try:
|
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
|
# After a std::list has been initialized, both next and prev will
|
||||||
# be non-NULL
|
# be non-NULL
|
||||||
if next_val == 0 or prev_val == 0:
|
next_val = self.next.GetValueAsUnsigned(0)
|
||||||
|
if next_val == 0:
|
||||||
return 0
|
return 0
|
||||||
if next_val == self.node_address:
|
|
||||||
return 0
|
|
||||||
if next_val == prev_val:
|
|
||||||
return 1
|
|
||||||
if self.has_loop():
|
if self.has_loop():
|
||||||
return 0
|
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
|
current = self.next
|
||||||
while current.GetChildMemberWithName(
|
while current.GetChildMemberWithName(
|
||||||
'_M_next').GetValueAsUnsigned(0) != self.node_address:
|
'_M_next').GetValueAsUnsigned(0) != self.get_end_of_list_address():
|
||||||
size = size + 1
|
size = size + 1
|
||||||
current = current.GetChildMemberWithName('_M_next')
|
current = current.GetChildMemberWithName('_M_next')
|
||||||
return (size - 1)
|
return size
|
||||||
except:
|
except:
|
||||||
|
logger >> "Error determining the size"
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_child_index(self, name):
|
def get_child_index(self, name):
|
||||||
|
@ -101,7 +110,7 @@ class StdListSynthProvider:
|
||||||
return int(name.lstrip('[').rstrip(']'))
|
return int(name.lstrip('[').rstrip(']'))
|
||||||
except:
|
except:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def get_child_at_index(self, index):
|
def get_child_at_index(self, index):
|
||||||
logger = lldb.formatters.Logger.Logger()
|
logger = lldb.formatters.Logger.Logger()
|
||||||
logger >> "Fetching child " + str(index)
|
logger >> "Fetching child " + str(index)
|
||||||
|
@ -115,9 +124,11 @@ class StdListSynthProvider:
|
||||||
while offset > 0:
|
while offset > 0:
|
||||||
current = current.GetChildMemberWithName('_M_next')
|
current = current.GetChildMemberWithName('_M_next')
|
||||||
offset = offset - 1
|
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(
|
return current.CreateChildAtOffset(
|
||||||
'[' + str(index) + ']',
|
'[' + str(index) + ']',
|
||||||
2 * current.GetType().GetByteSize(),
|
(2 if self.has_prev else 1) * current.GetType().GetByteSize(),
|
||||||
self.data_type)
|
self.data_type)
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
@ -139,19 +150,60 @@ class StdListSynthProvider:
|
||||||
# later
|
# later
|
||||||
self.count = None
|
self.count = None
|
||||||
try:
|
try:
|
||||||
impl = self.valobj.GetChildMemberWithName('_M_impl')
|
self.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.data_type = self.extract_type()
|
self.data_type = self.extract_type()
|
||||||
self.data_size = self.data_type.GetByteSize()
|
self.data_size = self.data_type.GetByteSize()
|
||||||
|
self.updateNodes()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return False
|
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):
|
def has_children(self):
|
||||||
return True
|
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:
|
class StdVectorSynthProvider:
|
||||||
|
|
|
@ -923,6 +923,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
|
||||||
SyntheticChildrenSP(new ScriptedSyntheticChildren(
|
SyntheticChildrenSP(new ScriptedSyntheticChildren(
|
||||||
stl_synth_flags,
|
stl_synth_flags,
|
||||||
"lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
|
"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.SetDontShowChildren(false);
|
||||||
stl_summary_flags.SetSkipPointers(false);
|
stl_summary_flags.SetSkipPointers(false);
|
||||||
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
|
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(
|
||||||
|
@ -953,6 +958,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
|
||||||
RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
|
RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"),
|
||||||
TypeSummaryImplSP(
|
TypeSummaryImplSP(
|
||||||
new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
|
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(
|
AddCXXSynthetic(
|
||||||
cpp_category_sp,
|
cpp_category_sp,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
CXX_SOURCES := main.cpp
|
CXX_SOURCES := main.cpp
|
||||||
|
|
||||||
USE_LIBCPP := 1
|
|
||||||
include Makefile.rules
|
include Makefile.rules
|
|
@ -9,8 +9,10 @@ from lldbsuite.test.decorators import *
|
||||||
from lldbsuite.test.lldbtest import *
|
from lldbsuite.test.lldbtest import *
|
||||||
from lldbsuite.test import lldbutil
|
from lldbsuite.test import lldbutil
|
||||||
|
|
||||||
|
USE_LIBSTDCPP = "USE_LIBSTDCPP"
|
||||||
|
USE_LIBCPP = "USE_LIBCPP"
|
||||||
|
|
||||||
class TestDataFormatterLibcxxForwardList(TestBase):
|
class TestDataFormatterGenericForwardList(TestBase):
|
||||||
|
|
||||||
mydir = TestBase.compute_mydir(__file__)
|
mydir = TestBase.compute_mydir(__file__)
|
||||||
|
|
||||||
|
@ -19,10 +21,10 @@ class TestDataFormatterLibcxxForwardList(TestBase):
|
||||||
self.line = line_number('main.cpp', '// break here')
|
self.line = line_number('main.cpp', '// break here')
|
||||||
self.namespace = 'std'
|
self.namespace = 'std'
|
||||||
|
|
||||||
@add_test_categories(["libc++"])
|
|
||||||
def test(self):
|
def do_test(self, stdlib_type):
|
||||||
"""Test that std::forward_list is displayed correctly"""
|
"""Test that std::forward_list is displayed correctly"""
|
||||||
self.build()
|
self.build(dictionary={stdlib_type: "1"})
|
||||||
lldbutil.run_to_source_breakpoint(self, '// break here',
|
lldbutil.run_to_source_breakpoint(self, '// break here',
|
||||||
lldb.SBFileSpec("main.cpp", False))
|
lldb.SBFileSpec("main.cpp", False))
|
||||||
|
|
||||||
|
@ -49,3 +51,12 @@ class TestDataFormatterLibcxxForwardList(TestBase):
|
||||||
'[3] = 4444',
|
'[3] = 4444',
|
||||||
'[4] = 55555',
|
'[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)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <forward_list>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::forward_list<int> empty{}, one_elt{47},
|
||||||
|
five_elts{1, 22, 333, 4444, 55555};
|
||||||
|
return 0; // break here
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
#include <forward_list>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::forward_list<int> empty{}, one_elt{47}, five_elts{1,22,333,4444,55555};
|
|
||||||
return 0; // break here
|
|
||||||
}
|
|
Loading…
Reference in New Issue