Skip to content

Commit 89ac0c7

Browse files
committedOct 31, 2017
Add data formatter for libc++'s forward_list
Summary: This adds a data formatter for the implementation of forward_list in libc++. I've refactored the existing std::list data formatter a bit to enable more sharing of code (mainly the loop detection stuff). Reviewers: jingham, EricWF Subscribers: srhines, eugene, lldb-commits Differential Revision: https://reviews.llvm.org/D35556 llvm-svn: 316992
1 parent e443564 commit 89ac0c7

File tree

6 files changed

+249
-85
lines changed

6 files changed

+249
-85
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
LEVEL = ../../../../../make
2+
3+
CXX_SOURCES := main.cpp
4+
5+
USE_LIBCPP := 1
6+
include $(LEVEL)/Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Test lldb data formatter subsystem.
3+
"""
4+
5+
from __future__ import print_function
6+
7+
8+
import lldb
9+
from lldbsuite.test.decorators import *
10+
from lldbsuite.test.lldbtest import *
11+
from lldbsuite.test import lldbutil
12+
13+
14+
class TestDataFormatterLibcxxForwardList(TestBase):
15+
16+
mydir = TestBase.compute_mydir(__file__)
17+
18+
def setUp(self):
19+
TestBase.setUp(self)
20+
self.line = line_number('main.cpp', '// break here')
21+
ns = 'ndk' if lldbplatformutil.target_is_android() else ''
22+
self.namespace = 'std::__' + ns + '1'
23+
24+
@add_test_categories(["libc++"])
25+
def test(self):
26+
"""Test that std::forward_list is displayed correctly"""
27+
self.build()
28+
lldbutil.run_to_source_breakpoint(self, '// break here',
29+
lldb.SBFileSpec("main.cpp", False))
30+
31+
forward_list = self.namespace + '::forward_list'
32+
self.expect("frame variable empty",
33+
substrs=[forward_list,
34+
'size=0',
35+
'{}'])
36+
37+
self.expect("frame variable one_elt",
38+
substrs=[forward_list,
39+
'size=1',
40+
'{',
41+
'[0] = 47',
42+
'}'])
43+
44+
self.expect("frame variable five_elts",
45+
substrs=[forward_list,
46+
'size=5',
47+
'{',
48+
'[0] = 1',
49+
'[1] = 22',
50+
'[2] = 333',
51+
'[3] = 4444',
52+
'[4] = 55555',
53+
'}'])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <forward_list>
2+
3+
int main()
4+
{
5+
std::forward_list<int> empty{}, one_elt{47}, five_elts{1,22,333,4444,55555};
6+
return 0; // break here
7+
}

‎lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,12 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
426426
"libc++ std::vector synthetic children",
427427
ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags,
428428
true);
429+
AddCXXSynthetic(
430+
cpp_category_sp,
431+
lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
432+
"libc++ std::forward_list synthetic children",
433+
ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"),
434+
stl_synth_flags, true);
429435
AddCXXSynthetic(
430436
cpp_category_sp,
431437
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
@@ -500,6 +506,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
500506
"libc++ std::vector summary provider",
501507
ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"),
502508
stl_summary_flags, true);
509+
AddCXXSummary(cpp_category_sp,
510+
lldb_private::formatters::LibcxxContainerSummaryProvider,
511+
"libc++ std::list summary provider",
512+
ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"),
513+
stl_summary_flags, true);
503514
AddCXXSummary(cpp_category_sp,
504515
lldb_private::formatters::LibcxxContainerSummaryProvider,
505516
"libc++ std::list summary provider",

‎lldb/source/Plugins/Language/CPlusPlus/LibCxx.h

+4
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ SyntheticChildrenFrontEnd *
104104
LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,
105105
lldb::ValueObjectSP);
106106

107+
SyntheticChildrenFrontEnd *
108+
LibcxxStdForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *,
109+
lldb::ValueObjectSP);
110+
107111
SyntheticChildrenFrontEnd *
108112
LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *,
109113
lldb::ValueObjectSP);

‎lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp

+168-85
Original file line numberDiff line numberDiff line change
@@ -114,58 +114,91 @@ class ListIterator {
114114
ListEntry m_entry;
115115
};
116116

117-
} // end anonymous namespace
118-
119-
namespace lldb_private {
120-
namespace formatters {
121-
class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
117+
class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
122118
public:
123-
LibcxxStdListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
119+
size_t GetIndexOfChildWithName(const ConstString &name) override {
120+
return ExtractIndexFromString(name.GetCString());
121+
}
122+
bool MightHaveChildren() override { return true; }
123+
bool Update() override;
124124

125-
~LibcxxStdListSyntheticFrontEnd() override = default;
125+
protected:
126+
AbstractListFrontEnd(ValueObject &valobj)
127+
: SyntheticChildrenFrontEnd(valobj) {}
126128

127-
size_t CalculateNumChildren() override;
129+
size_t m_count;
130+
ValueObject *m_head;
128131

129-
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
132+
static constexpr bool g_use_loop_detect = true;
133+
size_t m_loop_detected; // The number of elements that have had loop detection
134+
// run over them.
135+
ListEntry m_slow_runner; // Used for loop detection
136+
ListEntry m_fast_runner; // Used for loop detection
137+
138+
size_t m_list_capping_size;
139+
CompilerType m_element_type;
140+
std::map<size_t, ListIterator> m_iterators;
141+
142+
bool HasLoop(size_t count);
143+
ValueObjectSP GetItem(size_t idx);
144+
};
130145

146+
class ForwardListFrontEnd : public AbstractListFrontEnd {
147+
public:
148+
ForwardListFrontEnd(ValueObject &valobj);
149+
150+
size_t CalculateNumChildren() override;
151+
ValueObjectSP GetChildAtIndex(size_t idx) override;
131152
bool Update() override;
153+
};
132154

133-
bool MightHaveChildren() override;
155+
class ListFrontEnd : public AbstractListFrontEnd {
156+
public:
157+
ListFrontEnd(lldb::ValueObjectSP valobj_sp);
134158

135-
size_t GetIndexOfChildWithName(const ConstString &name) override;
159+
~ListFrontEnd() override = default;
136160

137-
private:
138-
bool HasLoop(size_t count);
161+
size_t CalculateNumChildren() override;
139162

140-
size_t m_list_capping_size;
141-
static const bool g_use_loop_detect = true;
163+
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
142164

143-
size_t m_loop_detected; // The number of elements that have had loop detection
144-
// run over them.
145-
ListEntry m_slow_runner; // Used for loop detection
146-
ListEntry m_fast_runner; // Used for loop detection
165+
bool Update() override;
147166

167+
private:
148168
lldb::addr_t m_node_address;
149-
ValueObject *m_head;
150169
ValueObject *m_tail;
151-
CompilerType m_element_type;
152-
size_t m_count;
153-
std::map<size_t, ListIterator> m_iterators;
154170
};
155-
} // namespace formatters
156-
} // namespace lldb_private
157-
158-
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
159-
LibcxxStdListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
160-
: SyntheticChildrenFrontEnd(*valobj_sp), m_list_capping_size(0),
161-
m_loop_detected(0), m_node_address(), m_head(nullptr), m_tail(nullptr),
162-
m_element_type(), m_count(UINT32_MAX), m_iterators() {
163-
if (valobj_sp)
164-
Update();
171+
172+
} // end anonymous namespace
173+
174+
bool AbstractListFrontEnd::Update() {
175+
m_loop_detected = 0;
176+
m_count = UINT32_MAX;
177+
m_head = nullptr;
178+
m_list_capping_size = 0;
179+
m_slow_runner.SetEntry(nullptr);
180+
m_fast_runner.SetEntry(nullptr);
181+
m_iterators.clear();
182+
183+
if (m_backend.GetTargetSP())
184+
m_list_capping_size =
185+
m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
186+
if (m_list_capping_size == 0)
187+
m_list_capping_size = 255;
188+
189+
CompilerType list_type = m_backend.GetCompilerType();
190+
if (list_type.IsReferenceType())
191+
list_type = list_type.GetNonReferenceType();
192+
193+
if (list_type.GetNumTemplateArguments() == 0)
194+
return false;
195+
TemplateArgumentKind kind;
196+
m_element_type = list_type.GetTemplateArgument(0, kind);
197+
198+
return false;
165199
}
166200

167-
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(
168-
size_t count) {
201+
bool AbstractListFrontEnd::HasLoop(size_t count) {
169202
if (!g_use_loop_detect)
170203
return false;
171204
// don't bother checking for a loop if we won't actually need to jump nodes
@@ -201,8 +234,96 @@ bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(
201234
return m_slow_runner == m_fast_runner;
202235
}
203236

204-
size_t lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
205-
CalculateNumChildren() {
237+
ValueObjectSP AbstractListFrontEnd::GetItem(size_t idx) {
238+
size_t advance = idx;
239+
ListIterator current(m_head);
240+
if (idx > 0) {
241+
auto cached_iterator = m_iterators.find(idx - 1);
242+
if (cached_iterator != m_iterators.end()) {
243+
current = cached_iterator->second;
244+
advance = 1;
245+
}
246+
}
247+
ValueObjectSP value_sp = current.advance(advance);
248+
m_iterators[idx] = current;
249+
return value_sp;
250+
}
251+
252+
ForwardListFrontEnd::ForwardListFrontEnd(ValueObject &valobj)
253+
: AbstractListFrontEnd(valobj) {
254+
Update();
255+
}
256+
257+
size_t ForwardListFrontEnd::CalculateNumChildren() {
258+
if (m_count != UINT32_MAX)
259+
return m_count;
260+
261+
ListEntry current(m_head);
262+
m_count = 0;
263+
while (current && m_count < m_list_capping_size) {
264+
++m_count;
265+
current = current.next();
266+
}
267+
return m_count;
268+
}
269+
270+
ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) {
271+
if (idx >= CalculateNumChildren())
272+
return nullptr;
273+
274+
if (!m_head)
275+
return nullptr;
276+
277+
if (HasLoop(idx + 1))
278+
return nullptr;
279+
280+
ValueObjectSP current_sp = GetItem(idx);
281+
if (!current_sp)
282+
return nullptr;
283+
284+
current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
285+
if (!current_sp)
286+
return nullptr;
287+
288+
// we need to copy current_sp into a new object otherwise we will end up with
289+
// all items named __value_
290+
DataExtractor data;
291+
Status error;
292+
current_sp->GetData(data, error);
293+
if (error.Fail())
294+
return nullptr;
295+
296+
return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
297+
m_backend.GetExecutionContextRef(),
298+
m_element_type);
299+
}
300+
301+
bool ForwardListFrontEnd::Update() {
302+
AbstractListFrontEnd::Update();
303+
304+
Status err;
305+
ValueObjectSP backend_addr(m_backend.AddressOf(err));
306+
if (err.Fail() || !backend_addr)
307+
return false;
308+
309+
ValueObjectSP impl_sp(
310+
m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true));
311+
if (!impl_sp)
312+
return false;
313+
impl_sp = impl_sp->GetChildMemberWithName(ConstString("__first_"), true);
314+
if (!impl_sp)
315+
return false;
316+
m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
317+
return false;
318+
}
319+
320+
ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
321+
: AbstractListFrontEnd(*valobj_sp), m_node_address(), m_tail(nullptr) {
322+
if (valobj_sp)
323+
Update();
324+
}
325+
326+
size_t ListFrontEnd::CalculateNumChildren() {
206327
if (m_count != UINT32_MAX)
207328
return m_count;
208329
if (!m_head || !m_tail || m_node_address == 0)
@@ -239,9 +360,7 @@ size_t lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
239360
}
240361
}
241362

242-
lldb::ValueObjectSP
243-
lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex(
244-
size_t idx) {
363+
lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(size_t idx) {
245364
static ConstString g_value("__value_");
246365
static ConstString g_next("__next_");
247366

@@ -254,23 +373,10 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex(
254373
if (HasLoop(idx + 1))
255374
return lldb::ValueObjectSP();
256375

257-
size_t actual_advance = idx;
258-
259-
ListIterator current(m_head);
260-
if (idx > 0) {
261-
auto cached_iterator = m_iterators.find(idx - 1);
262-
if (cached_iterator != m_iterators.end()) {
263-
current = cached_iterator->second;
264-
actual_advance = 1;
265-
}
266-
}
267-
268-
ValueObjectSP current_sp(current.advance(actual_advance));
376+
ValueObjectSP current_sp = GetItem(idx);
269377
if (!current_sp)
270378
return lldb::ValueObjectSP();
271379

272-
m_iterators[idx] = current;
273-
274380
current_sp = current_sp->GetChildAtIndex(1, true); // get the __value_ child
275381
if (!current_sp)
276382
return lldb::ValueObjectSP();
@@ -303,23 +409,13 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex(
303409
m_element_type);
304410
}
305411

306-
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() {
307-
m_iterators.clear();
308-
m_head = m_tail = nullptr;
412+
bool ListFrontEnd::Update() {
413+
AbstractListFrontEnd::Update();
414+
m_tail = nullptr;
309415
m_node_address = 0;
310-
m_count = UINT32_MAX;
311-
m_loop_detected = 0;
312-
m_slow_runner.SetEntry(nullptr);
313-
m_fast_runner.SetEntry(nullptr);
314416

315417
Status err;
316418
ValueObjectSP backend_addr(m_backend.AddressOf(err));
317-
m_list_capping_size = 0;
318-
if (m_backend.GetTargetSP())
319-
m_list_capping_size =
320-
m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
321-
if (m_list_capping_size == 0)
322-
m_list_capping_size = 255;
323419
if (err.Fail() || !backend_addr)
324420
return false;
325421
m_node_address = backend_addr->GetValueAsUnsigned(0);
@@ -329,31 +425,18 @@ bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() {
329425
m_backend.GetChildMemberWithName(ConstString("__end_"), true));
330426
if (!impl_sp)
331427
return false;
332-
CompilerType list_type = m_backend.GetCompilerType();
333-
if (list_type.IsReferenceType())
334-
list_type = list_type.GetNonReferenceType();
335-
336-
if (list_type.GetNumTemplateArguments() == 0)
337-
return false;
338-
lldb::TemplateArgumentKind kind;
339-
m_element_type = list_type.GetTemplateArgument(0, kind);
340428
m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
341429
m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
342430
return false;
343431
}
344432

345-
bool lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
346-
MightHaveChildren() {
347-
return true;
348-
}
349-
350-
size_t lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::
351-
GetIndexOfChildWithName(const ConstString &name) {
352-
return ExtractIndexFromString(name.GetCString());
433+
SyntheticChildrenFrontEnd *formatters::LibcxxStdListSyntheticFrontEndCreator(
434+
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
435+
return (valobj_sp ? new ListFrontEnd(valobj_sp) : nullptr);
353436
}
354437

355438
SyntheticChildrenFrontEnd *
356-
lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator(
439+
formatters::LibcxxStdForwardListSyntheticFrontEndCreator(
357440
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
358-
return (valobj_sp ? new LibcxxStdListSyntheticFrontEnd(valobj_sp) : nullptr);
441+
return valobj_sp ? new ForwardListFrontEnd(*valobj_sp) : nullptr;
359442
}

0 commit comments

Comments
 (0)
Please sign in to comment.