[Lldb-commits] [lldb] d366da9 - [lldb] Make the libcxx unique_ptr prettyprinter support custom deleters.
Jorge Gorbe Moya via lldb-commits
lldb-commits at lists.llvm.org
Mon May 1 13:08:20 PDT 2023
Author: Jorge Gorbe Moya
Date: 2023-05-01T13:08:04-07:00
New Revision: d366da97bd24ddfb91c9f260fa0aaf105d947652
URL: https://github.com/llvm/llvm-project/commit/d366da97bd24ddfb91c9f260fa0aaf105d947652
DIFF: https://github.com/llvm/llvm-project/commit/d366da97bd24ddfb91c9f260fa0aaf105d947652.diff
LOG: [lldb] Make the libcxx unique_ptr prettyprinter support custom deleters.
The unique_ptr prettyprinter calls `GetValueOfLibCXXCompressedPair`,
which looks for a `__value_` child. However, when the second value in
the compressed pair is not an empty class, there are two `__value_`
children because `__compressed_pair` derives twice from
`__compressed_pair_elem`, one for each member of the pair. And then the
lookup fails because it's ambiguous.
This patch makes the following changes:
- Rename `GetValueOfLibCXXCompressedPair` to
`GetFirstValueOfLibCXXCompressedPair`, and add a similar function to
get the second value. Put both functions in
Plugin/Language/CPlusPlus/LibCxx.cpp because it seems inappropriate to
have libcxx-specific helpers separate from all the libcxx-dependent
code.
- Read the second value of the `__ptr_` pair and display a "deleter"
child in the unique_ptr synthetic child provider, when available.
- Add a test case for the non-empty deleter case.
Differential Revision: https://reviews.llvm.org/D148662
Added:
Modified:
lldb/include/lldb/DataFormatters/FormattersHelpers.h
lldb/source/DataFormatters/FormattersHelpers.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h
index e9af6656e3d7d..a2e8521d96651 100644
--- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h
+++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h
@@ -58,8 +58,6 @@ size_t ExtractIndexFromString(const char *item_name);
Address GetArrayAddressOrPointerValue(ValueObject &valobj);
-lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair);
-
time_t GetOSXEpoch();
struct InferiorSizedWord {
diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp
index 87da31769ff12..085ed3d0a2f29 100644
--- a/lldb/source/DataFormatters/FormattersHelpers.cpp
+++ b/lldb/source/DataFormatters/FormattersHelpers.cpp
@@ -126,14 +126,3 @@ lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) {
return data_addr;
}
-
-lldb::ValueObjectSP
-lldb_private::formatters::GetValueOfLibCXXCompressedPair(ValueObject &pair) {
- ValueObjectSP value =
- pair.GetChildMemberWithName(ConstString("__value_"), true);
- if (!value) {
- // pre-r300140 member name
- value = pair.GetChildMemberWithName(ConstString("__first_"), true);
- }
- return value;
-}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index faa33ecefc2d0..236a8129eeb34 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -46,6 +46,38 @@ lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
return {};
}
+lldb::ValueObjectSP
+lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(
+ ValueObject &pair) {
+ ValueObjectSP value;
+ ValueObjectSP first_child = pair.GetChildAtIndex(0, true);
+ if (first_child)
+ value = first_child->GetChildMemberWithName(ConstString("__value_"), true);
+ if (!value) {
+ // pre-r300140 member name
+ value = pair.GetChildMemberWithName(ConstString("__first_"), true);
+ }
+ return value;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
+ ValueObject &pair) {
+ ValueObjectSP value;
+ if (pair.GetNumChildren() > 1) {
+ ValueObjectSP second_child = pair.GetChildAtIndex(1, true);
+ if (second_child) {
+ value =
+ second_child->GetChildMemberWithName(ConstString("__value_"), true);
+ }
+ }
+ if (!value) {
+ // pre-r300140 member name
+ value = pair.GetChildMemberWithName(ConstString("__second_"), true);
+ }
+ return value;
+}
+
bool lldb_private::formatters::LibcxxOptionalSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
@@ -170,7 +202,7 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
if (!ptr_sp)
return false;
- ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
+ ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
if (!ptr_sp)
return false;
@@ -658,7 +690,9 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(
size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
CalculateNumChildren() {
- return (m_value_ptr_sp ? 1 : 0);
+ if (m_value_ptr_sp)
+ return m_deleter_sp ? 2 : 1;
+ return 0;
}
lldb::ValueObjectSP
@@ -670,7 +704,10 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(
if (idx == 0)
return m_value_ptr_sp;
- if (idx == 1) {
+ if (idx == 1)
+ return m_deleter_sp;
+
+ if (idx == 2) {
Status status;
auto value_sp = m_value_ptr_sp->Dereference(status);
if (status.Success()) {
@@ -691,7 +728,15 @@ bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
if (!ptr_sp)
return false;
- m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
+ // Retrieve the actual pointer and the deleter, and clone them to give them
+ // user-friendly names.
+ ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+ if (value_pointer_sp)
+ m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
+
+ ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
+ if (deleter_sp)
+ m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
return false;
}
@@ -703,10 +748,12 @@ bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name) {
- if (name == "__value_")
+ if (name == "pointer")
return 0;
- if (name == "$$dereference$$")
+ if (name == "deleter")
return 1;
+ if (name == "$$dereference$$")
+ return 2;
return UINT32_MAX;
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 9ab22153a92a8..2dae71b24419d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -23,6 +23,10 @@ lldb::ValueObjectSP
GetChildMemberWithName(ValueObject &obj,
llvm::ArrayRef<ConstString> alternative_names);
+lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
+lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
+
+
bool LibcxxStringSummaryProviderASCII(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &summary_options); // libc++ std::string
@@ -200,6 +204,7 @@ class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
private:
lldb::ValueObjectSP m_value_ptr_sp;
+ lldb::ValueObjectSP m_deleter_sp;
};
SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index a1953a1c7a227..3ae26a3012ac8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -300,7 +300,7 @@ bool ForwardListFrontEnd::Update() {
m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true));
if (!impl_sp)
return false;
- impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp);
+ impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
if (!impl_sp)
return false;
m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
@@ -321,7 +321,7 @@ size_t ListFrontEnd::CalculateNumChildren() {
ValueObjectSP size_alloc(
m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
if (size_alloc) {
- ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc);
+ ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_alloc);
if (value) {
m_count = value->GetValueAsUnsigned(UINT32_MAX);
}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
index cc147de4ff481..a2d16375f1b86 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
@@ -40,7 +40,7 @@ def test_unique_ptr_variables(self):
"up_empty",
type=self.make_expected_type("int"),
summary="nullptr",
- children=[ValueCheck(name="__value_")],
+ children=[ValueCheck(name="pointer")],
)
self.assertEqual(
valobj.child[0].GetValueAsUnsigned(lldb.LLDB_INVALID_ADDRESS), 0
@@ -54,7 +54,7 @@ def test_unique_ptr_variables(self):
"up_int",
type=self.make_expected_type("int"),
summary="10",
- children=[ValueCheck(name="__value_")],
+ children=[ValueCheck(name="pointer")],
)
self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -62,7 +62,7 @@ def test_unique_ptr_variables(self):
"up_int_ref",
type=self.make_expected_type("int", qualifiers="&"),
summary="10",
- children=[ValueCheck(name="__value_")],
+ children=[ValueCheck(name="pointer")],
)
self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -70,7 +70,7 @@ def test_unique_ptr_variables(self):
"up_int_ref_ref",
type=self.make_expected_type("int", qualifiers="&&"),
summary="10",
- children=[ValueCheck(name="__value_")],
+ children=[ValueCheck(name="pointer")],
)
self.assertNotEqual(valobj.child[0].unsigned, 0)
@@ -78,7 +78,7 @@ def test_unique_ptr_variables(self):
"up_str",
type=self.make_expected_basic_string_ptr(),
summary='"hello"',
- children=[ValueCheck(name="__value_", summary='"hello"')],
+ children=[ValueCheck(name="pointer", summary='"hello"')],
)
valobj = self.expect_var_path(
@@ -95,7 +95,20 @@ def test_unique_ptr_variables(self):
ValueCheck(name="name", summary='"steph"'),
],
)
- self.assertEqual(str(valobj), '(User) *__value_ = (id = 30, name = "steph")')
+ self.assertEqual(str(valobj), '(User) *pointer = (id = 30, name = "steph")')
+
+ valobj = self.expect_var_path(
+ "up_non_empty_deleter",
+ type="std::unique_ptr<int, NonEmptyIntDeleter>",
+ summary="1234",
+ children=[
+ ValueCheck(name="pointer"),
+ ValueCheck(name="deleter", children=[
+ ValueCheck(name="dummy_", value="9999")
+ ]),
+ ],
+ )
+ self.assertNotEqual(valobj.child[0].unsigned, 0)
self.expect_var_path("up_user->id", type="int", value="30")
self.expect_var_path("up_user->name", type="std::string", summary='"steph"')
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
index 5201b2a6e9cb3..ab65d95b248ef 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
@@ -6,6 +6,15 @@ struct User {
std::string name = "steph";
};
+// libc++ stores unique_ptr data in a compressed pair, which has a specialized
+// representation when the type of the second element is an empty class. So
+// we need a deleter class with a dummy data member to trigger the other path.
+struct NonEmptyIntDeleter {
+ void operator()(int* ptr) { delete ptr; }
+
+ int dummy_ = 9999;
+};
+
int main() {
std::unique_ptr<int> up_empty;
std::unique_ptr<int> up_int = std::make_unique<int>(10);
@@ -13,6 +22,8 @@ int main() {
std::unique_ptr<int> &up_int_ref = up_int;
std::unique_ptr<int> &&up_int_ref_ref = std::make_unique<int>(10);
std::unique_ptr<User> up_user = std::make_unique<User>();
+ auto up_non_empty_deleter =
+ std::unique_ptr<int, NonEmptyIntDeleter>(new int(1234));
return 0; // break here
}
More information about the lldb-commits
mailing list