Skip to content

Commit 0ac42fd

Browse files
committed
[lldb] Add deref support and tests to shared_ptr synthetic
Add `frame variable` dereference suppport to libc++ `std::shared_ptr`. This change allows for commands like `v *thing_sp` and `v thing_sp->m_id`. These commands now work the same way they do with raw pointers. This is done by adding an unaccounted for child member named `$$dereference$$`. Also, add API tests for `std::shared_ptr`, previously there were none. Differential Revision: https://reviews.llvm.org/D97165
1 parent 437f0bb commit 0ac42fd

File tree

5 files changed

+125
-42
lines changed

5 files changed

+125
-42
lines changed

lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,7 @@ lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
379379

380380
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
381381
LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
382-
: SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(),
383-
m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) {
382+
: SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {
384383
if (valobj_sp)
385384
Update();
386385
}
@@ -403,42 +402,23 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
403402
if (idx == 0)
404403
return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
405404

406-
if (idx > 2)
407-
return lldb::ValueObjectSP();
408-
409405
if (idx == 1) {
410-
if (!m_count_sp) {
411-
ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(
412-
ConstString("__shared_owners_"), true));
413-
if (!shared_owners_sp)
414-
return lldb::ValueObjectSP();
415-
uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
416-
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
417-
m_count_sp = CreateValueObjectFromData(
418-
"count", data, valobj_sp->GetExecutionContextRef(),
419-
shared_owners_sp->GetCompilerType());
420-
}
421-
return m_count_sp;
422-
} else /* if (idx == 2) */
423-
{
424-
if (!m_weak_count_sp) {
425-
ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(
426-
ConstString("__shared_weak_owners_"), true));
427-
if (!shared_weak_owners_sp)
428-
return lldb::ValueObjectSP();
429-
uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
430-
DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
431-
m_weak_count_sp = CreateValueObjectFromData(
432-
"count", data, valobj_sp->GetExecutionContextRef(),
433-
shared_weak_owners_sp->GetCompilerType());
406+
if (auto ptr_sp =
407+
valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) {
408+
Status status;
409+
auto value_sp = ptr_sp->Dereference(status);
410+
if (status.Success()) {
411+
auto value_type_sp =
412+
valobj_sp->GetCompilerType().GetTypeTemplateArgument(0);
413+
return value_sp->Cast(value_type_sp);
414+
}
434415
}
435-
return m_weak_count_sp;
436416
}
417+
418+
return lldb::ValueObjectSP();
437419
}
438420

439421
bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
440-
m_count_sp.reset();
441-
m_weak_count_sp.reset();
442422
m_cntrl = nullptr;
443423

444424
ValueObjectSP valobj_sp = m_backend.GetSP();
@@ -449,9 +429,6 @@ bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
449429
if (!target_sp)
450430
return false;
451431

452-
m_byte_order = target_sp->GetArchitecture().GetByteOrder();
453-
m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
454-
455432
lldb::ValueObjectSP cntrl_sp(
456433
valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
457434

@@ -469,10 +446,8 @@ size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
469446
GetIndexOfChildWithName(ConstString name) {
470447
if (name == "__ptr_")
471448
return 0;
472-
if (name == "count")
449+
if (name == "$$dereference$$")
473450
return 1;
474-
if (name == "weak_count")
475-
return 2;
476451
return UINT32_MAX;
477452
}
478453

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,6 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
105105

106106
private:
107107
ValueObject *m_cntrl;
108-
lldb::ValueObjectSP m_count_sp;
109-
lldb::ValueObjectSP m_weak_count_sp;
110-
uint8_t m_ptr_size;
111-
lldb::ByteOrder m_byte_order;
112108
};
113109

114110
class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CXX_SOURCES := main.cpp
2+
3+
USE_LIBCPP := 1
4+
5+
CXXFLAGS_EXTRAS := -std=c++14
6+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""
2+
Test lldb data formatter for libc++ std::shared_ptr.
3+
"""
4+
5+
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
12+
class TestCase(TestBase):
13+
14+
mydir = TestBase.compute_mydir(__file__)
15+
16+
@add_test_categories(["libc++"])
17+
def test_shared_ptr_variables(self):
18+
"""Test `frame variable` output for `std::shared_ptr` types."""
19+
self.build()
20+
21+
lldbutil.run_to_source_breakpoint(
22+
self, "// break here", lldb.SBFileSpec("main.cpp")
23+
)
24+
25+
valobj = self.expect_var_path(
26+
"sp_empty",
27+
type="std::shared_ptr<int>",
28+
summary="nullptr",
29+
children=[ValueCheck(name="__ptr_")],
30+
)
31+
self.assertEqual(
32+
valobj.child[0].GetValueAsUnsigned(lldb.LLDB_INVALID_ADDRESS), 0
33+
)
34+
35+
self.expect(
36+
"frame variable *sp_empty", substrs=["(int) *sp_empty = <parent is NULL>"]
37+
)
38+
39+
valobj = self.expect_var_path(
40+
"sp_int",
41+
type="std::shared_ptr<int>",
42+
children=[ValueCheck(name="__ptr_")],
43+
)
44+
self.assertRegex(valobj.summary, r"^10( strong=1)? weak=1$")
45+
self.assertNotEqual(valobj.child[0].unsigned, 0)
46+
47+
valobj = self.expect_var_path(
48+
"sp_int_ref",
49+
type="std::shared_ptr<int> &",
50+
children=[ValueCheck(name="__ptr_")],
51+
)
52+
self.assertRegex(valobj.summary, r"^10( strong=1)? weak=1$")
53+
self.assertNotEqual(valobj.child[0].unsigned, 0)
54+
55+
valobj = self.expect_var_path(
56+
"sp_int_ref_ref",
57+
type="std::shared_ptr<int> &&",
58+
children=[ValueCheck(name="__ptr_")],
59+
)
60+
self.assertRegex(valobj.summary, r"^10( strong=1)? weak=1$")
61+
self.assertNotEqual(valobj.child[0].unsigned, 0)
62+
63+
valobj = self.expect_var_path(
64+
"sp_str",
65+
type="std::shared_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >",
66+
children=[ValueCheck(name="__ptr_", summary='"hello"')],
67+
)
68+
self.assertRegex(valobj.summary, r'^"hello"( strong=1)? weak=1$')
69+
70+
valobj = self.expect_var_path("sp_user", type="std::shared_ptr<User>")
71+
self.assertRegex(
72+
valobj.summary,
73+
"^std(::__1)?::shared_ptr<User>::element_type @ 0x0*[1-9a-f][0-9a-f]+( strong=1)? weak=1",
74+
)
75+
self.assertNotEqual(valobj.child[0].unsigned, 0)
76+
77+
valobj = self.expect_var_path(
78+
"*sp_user",
79+
type="User",
80+
children=[
81+
ValueCheck(name="id", value="30"),
82+
ValueCheck(name="name", summary='"steph"'),
83+
],
84+
)
85+
self.assertEqual(str(valobj), '(User) *__ptr_ = (id = 30, name = "steph")')
86+
87+
self.expect_var_path("sp_user->id", type="int", value="30")
88+
self.expect_var_path("sp_user->name", type="std::string", summary='"steph"')
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <memory>
2+
#include <string>
3+
4+
struct User {
5+
int id = 30;
6+
std::string name = "steph";
7+
};
8+
9+
int main() {
10+
std::shared_ptr<int> sp_empty;
11+
std::shared_ptr<int> sp_int = std::make_shared<int>(10);
12+
std::shared_ptr<std::string> sp_str = std::make_shared<std::string>("hello");
13+
std::shared_ptr<int> &sp_int_ref = sp_int;
14+
std::shared_ptr<int> &&sp_int_ref_ref = std::make_shared<int>(10);
15+
std::shared_ptr<User> sp_user = std::make_shared<User>();
16+
17+
return 0; // break here
18+
}

0 commit comments

Comments
 (0)