[DataFormatters] Add formatter for libc++ std::unique_ptr

This adds a formatter for libc++ std::unique_ptr.

I also refactored GetValueOfCompressedPair(...) out of LibCxxList.cpp since I need the same functionality and it made sense to share it.

Differential Revision: https://reviews.llvm.org/D76476
This commit is contained in:
shafik 2020-03-23 11:42:41 -07:00
parent 1b9cd51d55
commit a567d6809e
9 changed files with 220 additions and 11 deletions

View File

@ -56,6 +56,8 @@ size_t ExtractIndexFromString(const char *item_name);
lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj);
lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair);
time_t GetOSXEpoch();
struct InferiorSizedWord {

View File

@ -142,3 +142,14 @@ 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;
}

View File

@ -611,6 +611,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"shared_ptr synthetic children",
ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"),
stl_synth_flags, true);
ConstString libcxx_std_unique_ptr_regex(
"^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$");
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
"unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
@ -715,6 +724,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::weak_ptr summary provider",
ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"),
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
"libc++ std::unique_ptr summary provider",
libcxx_std_unique_ptr_regex, stl_summary_flags, true);
AddCXXSynthetic(
cpp_category_sp,

View File

@ -144,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
return true;
}
bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
if (!valobj_sp)
return false;
ValueObjectSP ptr_sp(
valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
if (!ptr_sp)
return false;
ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
if (!ptr_sp)
return false;
if (ptr_sp->GetValueAsUnsigned(0) == 0) {
stream.Printf("nullptr");
return true;
} else {
bool print_pointee = false;
Status error;
ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
if (pointee_sp && error.Success()) {
if (pointee_sp->DumpPrintableRepresentation(
stream, ValueObject::eValueObjectRepresentationStyleSummary,
lldb::eFormatInvalid,
ValueObject::PrintableRepresentationSpecialCases::eDisable,
false))
print_pointee = true;
}
if (!print_pointee)
stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
}
return true;
}
/*
(lldb) fr var ibeg --raw --ptr-depth 1
(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
@ -449,6 +486,67 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
: nullptr);
}
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_compressed_pair_sp() {
if (valobj_sp)
Update();
}
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
~LibcxxUniquePtrSyntheticFrontEnd() = default;
SyntheticChildrenFrontEnd *
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)
: nullptr);
}
size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
CalculateNumChildren() {
return (m_compressed_pair_sp ? 1 : 0);
}
lldb::ValueObjectSP
lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
if (!m_compressed_pair_sp)
return lldb::ValueObjectSP();
if (idx != 0)
return lldb::ValueObjectSP();
return m_compressed_pair_sp;
}
bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
ValueObjectSP ptr_sp(
valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
if (!ptr_sp)
return false;
m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
return false;
}
bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
MightHaveChildren() {
return true;
}
size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name) {
if (name == "__value_")
return 0;
return UINT32_MAX;
}
bool lldb_private::formatters::LibcxxContainerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
if (valobj.IsPointerType()) {

View File

@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider(
const TypeSummaryOptions
&options); // libc++ std::shared_ptr<> and std::weak_ptr<>
// libc++ std::unique_ptr<>
bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);
bool LibcxxFunctionSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options); // libc++ std::function<>
@ -107,6 +111,26 @@ private:
lldb::ByteOrder m_byte_order;
};
class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
size_t CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
bool Update() override;
bool MightHaveChildren() override;
size_t GetIndexOfChildWithName(ConstString name) override;
~LibcxxUniquePtrSyntheticFrontEnd() override;
private:
lldb::ValueObjectSP m_compressed_pair_sp;
};
SyntheticChildrenFrontEnd *
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
@ -115,6 +139,10 @@ SyntheticChildrenFrontEnd *
LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

View File

@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) {
m_element_type);
}
static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) {
ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true);
if (! value) {
// pre-r300140 member name
value = pair.GetChildMemberWithName(ConstString("__first_"), true);
}
return value;
}
bool ForwardListFrontEnd::Update() {
AbstractListFrontEnd::Update();
@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() {
m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true));
if (!impl_sp)
return false;
impl_sp = GetValueOfCompressedPair(*impl_sp);
impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp);
if (!impl_sp)
return false;
m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() {
ValueObjectSP size_alloc(
m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
if (size_alloc) {
ValueObjectSP value = GetValueOfCompressedPair(*size_alloc);
ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc);
if (value) {
m_count = value->GetValueAsUnsigned(UINT32_MAX);
}

View File

@ -0,0 +1,6 @@
CXX_SOURCES := main.cpp
USE_LIBCPP := 1
CXXFLAGS_EXTRAS := -std=c++14
include Makefile.rules

View File

@ -0,0 +1,47 @@
"""
Test lldb data formatter for libc++ std::unique_ptr.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class LibcxUniquePtrDataFormatterTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@add_test_categories(["libc++"])
def test_with_run_command(self):
"""Test that that file and class static variables display correctly."""
self.build()
(self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here',
lldb.SBFileSpec("main.cpp", False))
self.expect("frame variable up_empty",
substrs=['(std::unique_ptr<int, std::default_delete<int> >) up_empty = nullptr {',
'__value_ = ',
'}'])
self.expect("frame variable up_int",
substrs=['(std::unique_ptr<int, std::default_delete<int> >) up_int = 10 {',
'__value_ = ',
'}'])
self.expect("frame variable up_int_ref",
substrs=['(std::unique_ptr<int, std::default_delete<int> > &) up_int_ref = 10: {',
'__value_ = ',
'}'])
self.expect("frame variable up_int_ref_ref",
substrs=['(std::unique_ptr<int, std::default_delete<int> > &&) up_int_ref_ref = 10: {',
'__value_ = ',
'}'])
self.expect("frame variable up_str",
substrs=['up_str = "hello" {',
'__value_ = ',
'}'])

View File

@ -0,0 +1,13 @@
#include <cstdio>
#include <memory>
#include <string>
int main() {
std::unique_ptr<int> up_empty;
std::unique_ptr<int> up_int = std::make_unique<int>(10);
std::unique_ptr<std::string> up_str = std::make_unique<std::string>("hello");
std::unique_ptr<int> &up_int_ref = up_int;
std::unique_ptr<int> &&up_int_ref_ref = std::make_unique<int>(10);
return 0; // break here
}