Fix libstdc++ data formatters on Ubuntu 15.10 x86_64

See http://reviews.llvm.org/D13964 for details.

llvm-svn: 250965
This commit is contained in:
Todd Fiala 2015-10-22 00:23:38 +00:00
parent a8f17871e4
commit 82ffb8e904
7 changed files with 195 additions and 29 deletions

View File

@ -13,7 +13,7 @@ class StdListSynthProvider:
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj
self.count = None
logger >> "Providing synthetic children for a map named " + str(valobj.GetName())
logger >> "Providing synthetic children for a list named " + str(valobj.GetName())
def next_node(self,node):
logger = lldb.formatters.Logger.Logger()
@ -21,11 +21,20 @@ class StdListSynthProvider:
def is_valid(self,node):
logger = lldb.formatters.Logger.Logger()
return self.value(self.next_node(node)) != self.node_address
valid = self.value(self.next_node(node)) != self.node_address
if valid:
logger >> "%s is valid" % str(self.valobj.GetName())
else:
logger >> "synthetic value is not valid"
return valid
def value(self,node):
logger = lldb.formatters.Logger.Logger()
return node.GetValueAsUnsigned()
value = node.GetValueAsUnsigned()
logger >> "synthetic value for {}: {}".format(
str(self.valobj.GetName()),
value)
return value
# Floyd's cycle-finding algorithm
# try to detect if this list has a loop
@ -49,7 +58,12 @@ class StdListSynthProvider:
def num_children(self):
logger = lldb.formatters.Logger.Logger()
if self.count == None:
if self.count is None:
# libstdc++ 6.0.21 added dedicated count field.
count_child = self.node.GetChildMemberWithName('_M_data')
if count_child and count_child.IsValid():
self.count = count_child.GetValueAsUnsigned(0)
if self.count is None:
self.count = self.num_children_impl()
return self.count
@ -117,10 +131,10 @@ class StdListSynthProvider:
self.count = None
try:
impl = self.valobj.GetChildMemberWithName('_M_impl')
node = impl.GetChildMemberWithName('_M_node')
self.node = impl.GetChildMemberWithName('_M_node')
self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
self.next = node.GetChildMemberWithName('_M_next')
self.prev = node.GetChildMemberWithName('_M_prev')
self.next = self.node.GetChildMemberWithName('_M_next')
self.prev = self.node.GetChildMemberWithName('_M_prev')
self.data_type = self.extract_type()
self.data_size = self.data_type.GetByteSize()
except:

View File

@ -545,7 +545,14 @@ LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
lldb::TypeSummaryImplSP std_string_summary_sp(new StringSummaryFormat(stl_summary_flags,
"${var._M_dataplus._M_p}"));
lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
LibStdcppStringSummaryProvider,
"libstdc++ c++11 std::string summary provider"));
lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags,
LibStdcppWStringSummaryProvider,
"libstdc++ c++11 std::wstring summary provider"));
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"),
std_string_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char>"),
@ -554,7 +561,12 @@ LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
std_string_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
std_string_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::string"),
cxx11_string_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
cxx11_string_summary_sp);
// making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*)
lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags,
"${var._M_dataplus._M_p%S}"));
@ -567,8 +579,12 @@ LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
std_wstring_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
std_wstring_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::wstring"),
cxx11_wstring_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
cxx11_wstring_summary_sp);
#ifndef LLDB_DISABLE_PYTHON
SyntheticChildren::Flags stl_synth_flags;
@ -580,9 +596,16 @@ LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
#if 0
// With only this, I get std::list showing the content, all children on the same line.
// With this and the section below, I see one child element per line.
cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::__cxx11::_List_base<.+>(( )?&)?$")),
SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
"lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
#endif
stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true);
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
@ -591,10 +614,16 @@ LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
"size=${svar%#}")));
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
"size=${svar%#}")));
#if 0
// With this, I get std::list showing one child per line. Requires the change above to get anything, though.
cpp_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::__cxx11::_List_base<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
"size=${svar%#}")));
#endif
AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
AddCXXSynthetic(cpp_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);

View File

@ -14,6 +14,7 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/VectorIterator.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
@ -256,3 +257,117 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithNa
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
{
}
bool
lldb_private::formatters::LibStdcppStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
const bool scalar_is_load_addr = true;
AddressType addr_type;
lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
if (addr_of_string != LLDB_INVALID_ADDRESS)
{
switch (addr_type)
{
case eAddressTypeLoad:
{
ProcessSP process_sp(valobj.GetProcessSP());
if (!process_sp)
return false;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
Error error;
lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
return false;
options.SetLocation(addr_of_data);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetNeedsZeroTermination(false);
options.SetBinaryZeroIsTerminator(true);
lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
if (error.Fail())
return false;
options.SetSourceSize(size_of_data);
if (!StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options))
{
stream.Printf("Summary Unavailable");
return true;
}
else
return true;
}
break;
case eAddressTypeHost:
break;
case eAddressTypeInvalid:
case eAddressTypeFile:
break;
}
}
return false;
}
bool
lldb_private::formatters::LibStdcppWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
{
const bool scalar_is_load_addr = true;
AddressType addr_type;
lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
if (addr_of_string != LLDB_INVALID_ADDRESS)
{
switch (addr_type)
{
case eAddressTypeLoad:
{
ProcessSP process_sp(valobj.GetProcessSP());
if (!process_sp)
return false;
CompilerType wchar_compiler_type = valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
if (!wchar_compiler_type)
return false;
const uint32_t wchar_size = wchar_compiler_type.GetBitSize(nullptr); // Safe to pass NULL for exe_scope here
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
Error error;
lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
return false;
options.SetLocation(addr_of_data);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
options.SetNeedsZeroTermination(false);
options.SetBinaryZeroIsTerminator(false);
lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
if (error.Fail())
return false;
options.SetSourceSize(size_of_data);
options.SetPrefixToken("L");
switch (wchar_size)
{
case 8:
return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options);
case 16:
return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options);
case 32:
return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32>(options);
default:
stream.Printf("size for wchar_t is not valid");
return true;
}
return true;
}
break;
case eAddressTypeHost:
break;
case eAddressTypeInvalid:
case eAddressTypeFile:
break;
}
}
return false;
}

View File

@ -18,6 +18,12 @@
namespace lldb_private {
namespace formatters
{
bool
LibStdcppStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); // libcstdc++ c++11 std::string
bool
LibStdcppWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); // libcstdc++ c++11 std::wstring
SyntheticChildrenFrontEnd* LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
SyntheticChildrenFrontEnd* LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);

View File

@ -15,6 +15,7 @@ typedef std::list<int> int_list;
int main()
{
#ifdef LLDB_USING_LIBCPP
int_list *numbers_list = new int_list{1,2,3,4,5,6,7,8,9,10};
auto *third_elem = numbers_list->__end_.__next_->__next_->__next_; // Set break point at this line.
@ -22,6 +23,7 @@ int main()
auto *fifth_elem = third_elem->__next_->__next_;
assert(fifth_elem->__value_ == 5);
fifth_elem->__next_ = third_elem;
#endif
// Any attempt to free the list will probably crash the program. Let's just leak it.
return 0; // Set second break point at this line.

View File

@ -47,21 +47,21 @@ class StdStringDataFormatterTestCase(TestBase):
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
self.expect("frame variable",
substrs = ['(std::wstring) s = L"hello world! מזל טוב!"',
'(std::wstring) S = L"!!!!"',
'(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
'(std::string) q = "hello world"',
'(std::string) Q = "quite a long std::strin with lots of info inside it"'])
var_s = self.frame().FindVariable('s')
var_S = self.frame().FindVariable('S')
var_mazeltov = self.frame().FindVariable('mazeltov')
var_q = self.frame().FindVariable('q')
var_Q = self.frame().FindVariable('Q')
self.runCmd("n")
self.assertTrue(var_s.GetSummary() == 'L"hello world! מזל טוב!"', "s summary wrong")
self.assertTrue(var_S.GetSummary() == 'L"!!!!"', "S summary wrong")
self.assertTrue(var_mazeltov.GetSummary() == 'L"מזל טוב"', "mazeltov summary wrong")
self.assertTrue(var_q.GetSummary() == '"hello world"', "q summary wrong")
self.assertTrue(var_Q.GetSummary() == '"quite a long std::strin with lots of info inside it"', "Q summary wrong")
self.expect("frame variable",
substrs = ['(std::wstring) s = L"hello world! מזל טוב!"',
'(std::wstring) S = L"!!!!!"',
'(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
'(std::string) q = "hello world"',
'(std::string) Q = "quite a long std::strin with lots of info inside it"'])
self.runCmd("next")
self.assertTrue(var_S.GetSummary() == 'L"!!!!!"', "new S summary wrong")
if __name__ == '__main__':
import atexit

View File

@ -296,12 +296,12 @@ ifeq (1,$(USE_LIBCPP))
ifeq "$(OS)" "Linux"
# This is the default install location on Ubuntu 14.04
ifneq ($(wildcard /usr/include/c++/v1/.),)
CXXFLAGS += -stdlib=libc++
CXXFLAGS += -stdlib=libc++ -DLLDB_USING_LIBCPP
LDFLAGS += -stdlib=libc++
CXXFLAGS += -I/usr/include/c++/v1
endif
else
CXXFLAGS += -stdlib=libc++
CXXFLAGS += -stdlib=libc++ -DLLDB_USING_LIBCPP
LDFLAGS += -stdlib=libc++
endif
endif