<rdar://problem/4529976>

Adding data formatters for iterators for std::map and std::vector (both libc++ and libstdcpp)
This does not include reverse iterators since they are both trickier (due to requirements the standard imposes on them) and much less useful

llvm-svn: 175787
This commit is contained in:
Enrico Granata 2013-02-21 19:57:10 +00:00
parent efbbbfd384
commit ea2bc0fb1f
18 changed files with 1068 additions and 342 deletions

View File

@ -992,7 +992,7 @@ public:
bool
IsCStringContainer (bool check_pointer = false);
void
size_t
ReadPointedString (Stream& s,
Error& error,
uint32_t max_length = 0,
@ -1260,7 +1260,6 @@ protected:
m_is_deref_of_parent:1,
m_is_array_item_for_pointer:1,
m_is_bitfield_for_scalar:1,
m_is_expression_path_child:1,
m_is_child_at_offset:1,
m_is_getting_summary:1,
m_did_calculate_complete_objc_class_type:1;

View File

@ -557,9 +557,101 @@ namespace lldb_private {
};
SyntheticChildrenFrontEnd* LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
}
}
class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
virtual size_t
CalculateNumChildren ();
virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);
virtual bool
Update();
virtual bool
MightHaveChildren ();
virtual size_t
GetIndexOfChildWithName (const ConstString &name);
virtual
~LibstdcppMapIteratorSyntheticFrontEnd ();
private:
ExecutionContextRef m_exe_ctx_ref;
lldb::addr_t m_pair_address;
ClangASTType m_pair_type;
EvaluateExpressionOptions m_options;
lldb::ValueObjectSP m_pair_sp;
};
SyntheticChildrenFrontEnd* LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
LibCxxMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
virtual size_t
CalculateNumChildren ();
virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);
virtual bool
Update();
virtual bool
MightHaveChildren ();
virtual size_t
GetIndexOfChildWithName (const ConstString &name);
virtual
~LibCxxMapIteratorSyntheticFrontEnd ();
private:
ValueObject *m_pair_ptr;
};
SyntheticChildrenFrontEnd* LibCxxMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
#endif
class VectorIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
ConstString item_name);
virtual size_t
CalculateNumChildren ();
virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);
virtual bool
Update();
virtual bool
MightHaveChildren ();
virtual size_t
GetIndexOfChildWithName (const ConstString &name);
virtual
~VectorIteratorSyntheticFrontEnd ();
private:
ExecutionContextRef m_exe_ctx_ref;
ConstString m_item_name;
lldb::ValueObjectSP m_item_sp;
};
SyntheticChildrenFrontEnd* LibCxxVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
SyntheticChildrenFrontEnd* LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
} // namespace formatters
} // namespace lldb_private
#endif // liblldb_CXXFormatterFunctions_h_

View File

@ -273,6 +273,15 @@ namespace lldb_private {
m_expression_paths()
{
}
TypeFilterImpl(const SyntheticChildren::Flags& flags,
const std::initializer_list<const char*> items) :
SyntheticChildren(flags),
m_expression_paths()
{
for (auto path : items)
AddExpressionPath (path);
}
void
AddExpressionPath (const char* path)
@ -305,7 +314,7 @@ namespace lldb_private {
}
void
AddExpressionPath (std::string path)
AddExpressionPath (const std::string& path)
{
bool need_add_dot = true;
if (path[0] == '.' ||
@ -320,7 +329,7 @@ namespace lldb_private {
}
bool
SetExpressionPathAtIndex (int i, std::string path)
SetExpressionPathAtIndex (int i, const std::string& path)
{
if (i >= GetCount())
return false;

View File

@ -551,6 +551,8 @@
94CB257116B0A4270059775D /* TypeSummary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB256E16B0A4260059775D /* TypeSummary.cpp */; };
94CB257216B0A4270059775D /* TypeSynthetic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB256F16B0A4270059775D /* TypeSynthetic.cpp */; };
94CB257416B1D3880059775D /* FormatCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94CB257316B1D3870059775D /* FormatCache.cpp */; };
94D0B10C16D5535900EA9C70 /* LibCxx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D0B10A16D5535900EA9C70 /* LibCxx.cpp */; };
94D0B10D16D5535900EA9C70 /* LibStdcpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */; };
94D6A0AA16CEB55F00833B6E /* NSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A716CEB55F00833B6E /* NSArray.cpp */; };
94D6A0AB16CEB55F00833B6E /* NSDictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */; };
94D6A0AC16CEB55F00833B6E /* NSSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94D6A0A916CEB55F00833B6E /* NSSet.cpp */; };
@ -1594,6 +1596,8 @@
94CB256F16B0A4270059775D /* TypeSynthetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeSynthetic.cpp; path = source/DataFormatters/TypeSynthetic.cpp; sourceTree = "<group>"; };
94CB257316B1D3870059775D /* FormatCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatCache.cpp; path = source/DataFormatters/FormatCache.cpp; sourceTree = "<group>"; };
94CB257516B1D3910059775D /* FormatCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatCache.h; path = include/lldb/DataFormatters/FormatCache.h; sourceTree = "<group>"; };
94D0B10A16D5535900EA9C70 /* LibCxx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibCxx.cpp; path = source/DataFormatters/LibCxx.cpp; sourceTree = "<group>"; };
94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LibStdcpp.cpp; path = source/DataFormatters/LibStdcpp.cpp; sourceTree = "<group>"; };
94D6A0A716CEB55F00833B6E /* NSArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSArray.cpp; path = source/DataFormatters/NSArray.cpp; sourceTree = "<group>"; };
94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSDictionary.cpp; path = source/DataFormatters/NSDictionary.cpp; sourceTree = "<group>"; };
94D6A0A916CEB55F00833B6E /* NSSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NSSet.cpp; path = source/DataFormatters/NSSet.cpp; sourceTree = "<group>"; };
@ -3370,6 +3374,8 @@
94CB256216B069800059775D /* FormatManager.h */,
94CB255A16B069770059775D /* FormatManager.cpp */,
94CB256316B069800059775D /* FormatNavigator.h */,
94D0B10A16D5535900EA9C70 /* LibCxx.cpp */,
94D0B10B16D5535900EA9C70 /* LibStdcpp.cpp */,
94D6A0A716CEB55F00833B6E /* NSArray.cpp */,
94D6A0A816CEB55F00833B6E /* NSDictionary.cpp */,
94D6A0A916CEB55F00833B6E /* NSSet.cpp */,
@ -3947,6 +3953,7 @@
2689004B13353E0400698AC0 /* Section.cpp in Sources */,
2689004C13353E0400698AC0 /* SourceManager.cpp in Sources */,
2689004D13353E0400698AC0 /* State.cpp in Sources */,
94D0B10D16D5535900EA9C70 /* LibStdcpp.cpp in Sources */,
2689004E13353E0400698AC0 /* Stream.cpp in Sources */,
2689004F13353E0400698AC0 /* StreamFile.cpp in Sources */,
2689005013353E0400698AC0 /* StreamString.cpp in Sources */,
@ -4039,6 +4046,7 @@
268900C213353E5F00698AC0 /* DWARFDebugPubnamesSet.cpp in Sources */,
268900C313353E5F00698AC0 /* DWARFDebugRanges.cpp in Sources */,
268900C413353E5F00698AC0 /* DWARFDefines.cpp in Sources */,
94D0B10C16D5535900EA9C70 /* LibCxx.cpp in Sources */,
268900C513353E5F00698AC0 /* DWARFDIECollection.cpp in Sources */,
268900C613353E5F00698AC0 /* DWARFFormValue.cpp in Sources */,
268900C713353E5F00698AC0 /* DWARFLocationDescription.cpp in Sources */,

View File

@ -96,7 +96,6 @@ ValueObject::ValueObject (ValueObject &parent) :
m_is_deref_of_parent (false),
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
m_is_expression_path_child(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
m_did_calculate_complete_objc_class_type(false)
@ -141,7 +140,6 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope,
m_is_deref_of_parent (false),
m_is_array_item_for_pointer(false),
m_is_bitfield_for_scalar(false),
m_is_expression_path_child(false),
m_is_child_at_offset(false),
m_is_getting_summary(false),
m_did_calculate_complete_objc_class_type(false)
@ -1040,7 +1038,7 @@ strlen_or_inf (const char* str,
return len;
}
void
size_t
ValueObject::ReadPointedString (Stream& s,
Error& error,
uint32_t max_length,
@ -1053,6 +1051,9 @@ ValueObject::ReadPointedString (Stream& s,
if (target && max_length == 0)
max_length = target->GetMaximumSizeOfStringSummary();
size_t bytes_read = 0;
size_t total_bytes_read = 0;
clang_type_t clang_type = GetClangType();
clang_type_t elem_or_pointee_clang_type;
const Flags type_flags (GetTypeInfo (&elem_or_pointee_clang_type));
@ -1090,7 +1091,6 @@ ValueObject::ReadPointedString (Stream& s,
{
Address cstr_so_addr (cstr_address);
DataExtractor data;
size_t bytes_read = 0;
if (cstr_len > 0 && honor_array)
{
// I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
@ -1099,6 +1099,7 @@ ValueObject::ReadPointedString (Stream& s,
if ((bytes_read = data.GetByteSize()) > 0)
{
total_bytes_read = bytes_read;
s << '"';
data.Dump (&s,
0, // Start offset in "data"
@ -1127,6 +1128,7 @@ ValueObject::ReadPointedString (Stream& s,
// but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0)
{
total_bytes_read += bytes_read;
const char *cstr = data.PeekCStr(0);
size_t len = strlen_or_inf (cstr, k_max_buf_size, k_max_buf_size+1);
if (len > k_max_buf_size)
@ -1183,6 +1185,7 @@ ValueObject::ReadPointedString (Stream& s,
error.SetErrorString("impossible to read a string from this object");
s << "<not a string object>";
}
return total_bytes_read;
}
const char *
@ -2107,9 +2110,9 @@ ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_cr
// Cache the value if we got one back...
if (synthetic_child_sp.get())
{
// FIXME: this causes a "real" child to end up with its name changed to the contents of expression
AddSyntheticChild(name_const_string, synthetic_child_sp.get());
synthetic_child_sp->SetName(ConstString(SkipLeadingExpressionPathSeparators(expression)));
synthetic_child_sp->m_is_expression_path_child = true;
}
}
return synthetic_child_sp;
@ -2336,8 +2339,8 @@ ValueObject::GetValueForExpressionPath(const char* expression,
{
const char* dummy_first_unparsed;
ExpressionPathScanEndReason dummy_reason_to_stop;
ExpressionPathEndResultType dummy_final_value_type;
ExpressionPathScanEndReason dummy_reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnknown;
ExpressionPathEndResultType dummy_final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression,

View File

@ -550,10 +550,11 @@ lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stre
if (!location_sp)
return false;
Error error;
location_sp->ReadPointedString(stream,
error,
0, // max length is decided by the settings
false); // do not honor array (terminates on first 0 byte even for a char[])
if (location_sp->ReadPointedString(stream,
error,
0, // max length is decided by the settings
false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
stream.Printf("\"\""); // if nothing was read, print an empty string
return error.Success();
}
@ -1073,320 +1074,70 @@ lldb_private::formatters::ExtractIndexFromString (const char* item_name)
return idx;
}
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_exe_ctx_ref(),
m_count(0),
m_base_data_address(0),
m_options()
{
if (valobj_sp)
Update();
m_options.SetCoerceToId(false)
.SetUnwindOnError(true)
.SetKeepInMemory(true)
.SetUseDynamic(lldb::eDynamicCanRunTarget);
}
size_t
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
{
return m_count;
}
lldb::ValueObjectSP
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (idx >= m_count)
return ValueObjectSP();
if (m_base_data_address == 0 || m_count == 0)
return ValueObjectSP();
size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
lldb::addr_t byte_location = m_base_data_address + byte_idx;
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (!process_sp)
return ValueObjectSP();
uint8_t byte = 0;
uint8_t mask = 0;
Error err;
size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
if (err.Fail() || bytes_read == 0)
return ValueObjectSP();
switch (bit_index)
{
case 0:
mask = 1; break;
case 1:
mask = 2; break;
case 2:
mask = 4; break;
case 3:
mask = 8; break;
case 4:
mask = 16; break;
case 5:
mask = 32; break;
case 6:
mask = 64; break;
case 7:
mask = 128; break;
default:
return ValueObjectSP();
}
bool bit_set = ((byte & mask) != 0);
Target& target(process_sp->GetTarget());
ValueObjectSP retval_sp;
if (bit_set)
target.EvaluateExpression("(bool)true", NULL, retval_sp);
else
target.EvaluateExpression("(bool)false", NULL, retval_sp);
StreamString name; name.Printf("[%zu]",idx);
if (retval_sp)
retval_sp->SetName(ConstString(name.GetData()));
return retval_sp;
}
/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
__begin_ = 0x00000001001000e0
__size_ = 56
__cap_alloc_ = {
std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = {
__first_ = 1
}
}
}*/
bool
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
if (!size_sp)
return false;
m_count = size_sp->GetValueAsUnsigned(0);
if (!m_count)
return true;
ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
if (!begin_sp)
{
m_count = 0;
return false;
}
m_base_data_address = begin_sp->GetValueAsUnsigned(0);
if (!m_base_data_address)
{
m_count = 0;
return false;
}
return true;
}
bool
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (!m_count || !m_base_data_address)
return UINT32_MAX;
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd ()
{}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp));
}
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
ConstString item_name) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_exe_ctx_ref(),
m_count(0),
m_base_data_address(0),
m_options()
m_item_name(item_name),
m_item_sp()
{
if (valobj_sp)
Update();
m_options.SetCoerceToId(false)
.SetUnwindOnError(true)
.SetKeepInMemory(true)
.SetUseDynamic(lldb::eDynamicCanRunTarget);
}
size_t
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
{
return m_count;
}
lldb::ValueObjectSP
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (idx >= m_count)
return ValueObjectSP();
if (m_base_data_address == 0 || m_count == 0)
return ValueObjectSP();
size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
lldb::addr_t byte_location = m_base_data_address + byte_idx;
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (!process_sp)
return ValueObjectSP();
uint8_t byte = 0;
uint8_t mask = 0;
Error err;
size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
if (err.Fail() || bytes_read == 0)
return ValueObjectSP();
switch (bit_index)
{
case 0:
mask = 1; break;
case 1:
mask = 2; break;
case 2:
mask = 4; break;
case 3:
mask = 8; break;
case 4:
mask = 16; break;
case 5:
mask = 32; break;
case 6:
mask = 64; break;
case 7:
mask = 128; break;
default:
return ValueObjectSP();
}
bool bit_set = ((byte & mask) != 0);
Target& target(process_sp->GetTarget());
ValueObjectSP retval_sp;
if (bit_set)
target.EvaluateExpression("(bool)true", NULL, retval_sp);
else
target.EvaluateExpression("(bool)false", NULL, retval_sp);
StreamString name; name.Printf("[%zu]",idx);
if (retval_sp)
retval_sp->SetName(ConstString(name.GetData()));
return retval_sp;
}
/*((std::vector<std::allocator<bool> >) vBool = {
(std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = {
(std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = {
(std::_Bit_iterator) _M_start = {
(std::_Bit_iterator_base) std::_Bit_iterator_base = {
(_Bit_type *) _M_p = 0x0016b160
(unsigned int) _M_offset = 0
}
}
(std::_Bit_iterator) _M_finish = {
(std::_Bit_iterator_base) std::_Bit_iterator_base = {
(_Bit_type *) _M_p = 0x0016b16c
(unsigned int) _M_offset = 16
}
}
(_Bit_type *) _M_end_of_storage = 0x0016b170
}
}
}
*/
bool
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::Update()
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
if (!item_ptr)
return false;
if (item_ptr->GetValueAsUnsigned(0) == 0)
return false;
Error err;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true));
if (!m_impl_sp)
return false;
ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true));
ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true));
ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp;
if (!m_start_sp || !m_finish_sp)
return false;
start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true);
finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true);
finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true);
if (!start_p_sp || !finish_offset_sp || !finish_p_sp)
return false;
m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType())));
if (err.Fail())
m_item_sp.reset();
return (m_item_sp.get() != NULL);
}
m_base_data_address = start_p_sp->GetValueAsUnsigned(0);
if (!m_base_data_address)
return false;
lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0));
if (!end_data_address)
return false;
if (end_data_address < m_base_data_address)
return false;
else
m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8;
size_t
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
{
return 1;
}
return true;
lldb::ValueObjectSP
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (idx == 0)
return m_item_sp;
return lldb::ValueObjectSP();
}
bool
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren ()
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (!m_count || !m_base_data_address)
return UINT32_MAX;
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
if (name == ConstString("item"))
return 0;
return UINT32_MAX;
}
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd ()
{}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
{
if (!valobj_sp)
return NULL;
return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp));
}
template bool

View File

@ -443,12 +443,16 @@ static void
AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
const char* string,
ConstString type_name,
TypeSummaryImpl::Flags flags)
TypeSummaryImpl::Flags flags,
bool regex = false)
{
lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags,
string));
category_sp->GetSummaryNavigator()->Add(type_name,
summary_sp);
if (regex)
{}
else
category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
}
#ifndef LLDB_DISABLE_PYTHON
@ -456,7 +460,8 @@ static void
AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp,
const char* funct_name,
ConstString type_name,
TypeSummaryImpl::Flags flags)
TypeSummaryImpl::Flags flags,
bool regex = false)
{
std::string code(" ");
@ -465,8 +470,10 @@ AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp,
lldb::TypeSummaryImplSP summary_sp(new ScriptSummaryFormat(flags,
funct_name,
code.c_str()));
category_sp->GetSummaryNavigator()->Add(type_name,
summary_sp);
if (regex)
{}
else
category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
}
#endif
@ -476,11 +483,14 @@ AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
CXXFunctionSummaryFormat::Callback funct,
const char* description,
ConstString type_name,
TypeSummaryImpl::Flags flags)
TypeSummaryImpl::Flags flags,
bool regex = false)
{
lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description));
category_sp->GetSummaryNavigator()->Add(type_name,
summary_sp);
if (regex)
{}
else
category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
}
#endif
@ -489,10 +499,14 @@ static void AddCXXSynthetic (TypeCategoryImpl::SharedPointer category_sp,
CXXSyntheticChildren::CreateFrontEndCallback generator,
const char* description,
ConstString type_name,
ScriptedSyntheticChildren::Flags flags)
ScriptedSyntheticChildren::Flags flags,
bool regex = false)
{
lldb::SyntheticChildrenSP synth_sp(new CXXSyntheticChildren(flags,description,generator));
category_sp->GetSyntheticNavigator()->Add(type_name,synth_sp);
if (regex)
category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), synth_sp);
else
category_sp->GetSyntheticNavigator()->Add(type_name,synth_sp);
}
#endif
@ -561,6 +575,10 @@ FormatManager::LoadLibStdcppFormatters()
gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
"size=${svar%#}")));
AddCXXSynthetic(gnu_category_sp, lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true);
AddCXXSynthetic(gnu_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true);
gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::vector<std::allocator<bool> >"),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
@ -634,9 +652,13 @@ FormatManager::LoadLibcxxFormatters()
libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::deque<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::shared_ptr<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})")));
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}")));
libcxx_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::__1::weak_ptr<.+>(( )?&)?$")),
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})")));
TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}")));
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true);
AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true);
// this summary prevails on the regex std::vector<> because we do exact matches before regex ones
libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::vector<std::__1::allocator<bool> >"),
@ -644,7 +666,7 @@ FormatManager::LoadLibcxxFormatters()
libcxx_category_sp->GetSyntheticNavigator()->Add(ConstString("std::__1::vector<std::__1::allocator<bool> >"),
SyntheticChildrenSP(new CXXSyntheticChildren(stl_synth_flags,"libc++ std::vector<bool> synthetic children",lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator)));
#endif
}

View File

@ -0,0 +1,285 @@
//===-- LibCxx.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_exe_ctx_ref(),
m_count(0),
m_base_data_address(0),
m_options()
{
if (valobj_sp)
Update();
m_options.SetCoerceToId(false)
.SetUnwindOnError(true)
.SetKeepInMemory(true)
.SetUseDynamic(lldb::eDynamicCanRunTarget);
}
size_t
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
{
return m_count;
}
lldb::ValueObjectSP
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (idx >= m_count)
return ValueObjectSP();
if (m_base_data_address == 0 || m_count == 0)
return ValueObjectSP();
size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
lldb::addr_t byte_location = m_base_data_address + byte_idx;
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (!process_sp)
return ValueObjectSP();
uint8_t byte = 0;
uint8_t mask = 0;
Error err;
size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
if (err.Fail() || bytes_read == 0)
return ValueObjectSP();
switch (bit_index)
{
case 0:
mask = 1; break;
case 1:
mask = 2; break;
case 2:
mask = 4; break;
case 3:
mask = 8; break;
case 4:
mask = 16; break;
case 5:
mask = 32; break;
case 6:
mask = 64; break;
case 7:
mask = 128; break;
default:
return ValueObjectSP();
}
bool bit_set = ((byte & mask) != 0);
Target& target(process_sp->GetTarget());
ValueObjectSP retval_sp;
if (bit_set)
target.EvaluateExpression("(bool)true", NULL, retval_sp);
else
target.EvaluateExpression("(bool)false", NULL, retval_sp);
StreamString name; name.Printf("[%zu]",idx);
if (retval_sp)
retval_sp->SetName(ConstString(name.GetData()));
return retval_sp;
}
/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
__begin_ = 0x00000001001000e0
__size_ = 56
__cap_alloc_ = {
std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = {
__first_ = 1
}
}
}*/
bool
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
if (!size_sp)
return false;
m_count = size_sp->GetValueAsUnsigned(0);
if (!m_count)
return true;
ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
if (!begin_sp)
{
m_count = 0;
return false;
}
m_base_data_address = begin_sp->GetValueAsUnsigned(0);
if (!m_base_data_address)
{
m_count = 0;
return false;
}
return true;
}
bool
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (!m_count || !m_base_data_address)
return UINT32_MAX;
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd ()
{}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp));
}
/*
(lldb) fr var ibeg --raw --ptr-depth 1
(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
__i_ = {
__ptr_ = 0x0000000100103870 {
std::__1::__tree_node_base<void *> = {
std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
__left_ = 0x0000000000000000
}
__right_ = 0x0000000000000000
__parent_ = 0x00000001001038b0
__is_black_ = true
}
__value_ = {
first = 0
second = { std::string }
*/
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::LibCxxMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_pair_ptr()
{
if (valobj_sp)
Update();
}
bool
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
TargetSP target_sp(valobj_sp->GetTargetSP());
if (!target_sp)
return false;
if (!valobj_sp)
return false;
// this must be a ValueObject* because it is a child of the ValueObject we are producing children for
// it if were a ValueObjectSP, we would end up with a loop (iterator -> synthetic -> child -> parent == iterator)
// and that would in turn leak memory by never allowing the ValueObjects to die and free their memory
m_pair_ptr = valobj_sp->GetValueForExpressionPath(".__i_.__ptr_->__value_",
NULL,
NULL,
NULL,
ValueObject::GetValueForExpressionPathOptions().DontCheckDotVsArrowSyntax().DontAllowSyntheticChildren(),
NULL).get();
return (m_pair_ptr != NULL);
}
size_t
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
{
return 2;
}
lldb::ValueObjectSP
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (!m_pair_ptr)
return lldb::ValueObjectSP();
return m_pair_ptr->GetChildAtIndex(idx, true);
}
bool
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (name == ConstString("first"))
return 0;
if (name == ConstString("second"))
return 1;
return UINT32_MAX;
}
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::~LibCxxMapIteratorSyntheticFrontEnd ()
{
// this will be deleted when its parent dies (since it's a child object)
//delete m_pair_ptr;
}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp));
}
/*
(lldb) fr var ibeg --raw --ptr-depth 1 -T
(std::__1::__wrap_iter<int *>) ibeg = {
(std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
(int) *__i = 1
}
}
*/
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
static ConstString g_item_name;
if (!g_item_name)
g_item_name.SetCString("__i");
if (!valobj_sp)
return NULL;
return (new VectorIteratorSyntheticFrontEnd(valobj_sp,g_item_name));
}

View File

@ -0,0 +1,331 @@
//===-- LibStdcpp.cpp ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_exe_ctx_ref(),
m_count(0),
m_base_data_address(0),
m_options()
{
if (valobj_sp)
Update();
m_options.SetCoerceToId(false)
.SetUnwindOnError(true)
.SetKeepInMemory(true)
.SetUseDynamic(lldb::eDynamicCanRunTarget);
}
size_t
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
{
return m_count;
}
lldb::ValueObjectSP
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (idx >= m_count)
return ValueObjectSP();
if (m_base_data_address == 0 || m_count == 0)
return ValueObjectSP();
size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
lldb::addr_t byte_location = m_base_data_address + byte_idx;
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (!process_sp)
return ValueObjectSP();
uint8_t byte = 0;
uint8_t mask = 0;
Error err;
size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
if (err.Fail() || bytes_read == 0)
return ValueObjectSP();
switch (bit_index)
{
case 0:
mask = 1; break;
case 1:
mask = 2; break;
case 2:
mask = 4; break;
case 3:
mask = 8; break;
case 4:
mask = 16; break;
case 5:
mask = 32; break;
case 6:
mask = 64; break;
case 7:
mask = 128; break;
default:
return ValueObjectSP();
}
bool bit_set = ((byte & mask) != 0);
Target& target(process_sp->GetTarget());
ValueObjectSP retval_sp;
if (bit_set)
target.EvaluateExpression("(bool)true", NULL, retval_sp);
else
target.EvaluateExpression("(bool)false", NULL, retval_sp);
StreamString name; name.Printf("[%zu]",idx);
if (retval_sp)
retval_sp->SetName(ConstString(name.GetData()));
return retval_sp;
}
/*((std::vector<std::allocator<bool> >) vBool = {
(std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = {
(std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = {
(std::_Bit_iterator) _M_start = {
(std::_Bit_iterator_base) std::_Bit_iterator_base = {
(_Bit_type *) _M_p = 0x0016b160
(unsigned int) _M_offset = 0
}
}
(std::_Bit_iterator) _M_finish = {
(std::_Bit_iterator_base) std::_Bit_iterator_base = {
(_Bit_type *) _M_p = 0x0016b16c
(unsigned int) _M_offset = 16
}
}
(_Bit_type *) _M_end_of_storage = 0x0016b170
}
}
}
*/
bool
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true));
if (!m_impl_sp)
return false;
ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true));
ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true));
ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp;
if (!m_start_sp || !m_finish_sp)
return false;
start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true);
finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true);
finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true);
if (!start_p_sp || !finish_offset_sp || !finish_p_sp)
return false;
m_base_data_address = start_p_sp->GetValueAsUnsigned(0);
if (!m_base_data_address)
return false;
lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0));
if (!end_data_address)
return false;
if (end_data_address < m_base_data_address)
return false;
else
m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8;
return true;
}
bool
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (!m_count || !m_base_data_address)
return UINT32_MAX;
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd ()
{}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp));
}
/*
(std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) ibeg = {
(_Base_ptr) _M_node = 0x0000000100103910 {
(std::_Rb_tree_color) _M_color = _S_black
(std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
(std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
(std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
}
}
*/
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp.get()),
m_exe_ctx_ref(),
m_pair_address(0),
m_pair_type(),
m_options(),
m_pair_sp()
{
if (valobj_sp)
Update();
m_options.SetCoerceToId(false)
.SetUnwindOnError(true)
.SetKeepInMemory(true)
.SetUseDynamic(lldb::eDynamicCanRunTarget);
}
bool
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::Update()
{
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
TargetSP target_sp(valobj_sp->GetTargetSP());
if (!target_sp)
return false;
bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
if (!_M_node_sp)
return false;
m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
if (m_pair_address == 0)
return false;
m_pair_address += (is_64bit ? 32 : 16);
ClangASTType my_type(valobj_sp->GetClangAST(),valobj_sp->GetClangType());
if (ClangASTContext::GetNumTemplateArguments(valobj_sp->GetClangAST(),valobj_sp->GetClangType()) >= 1)
{
TemplateArgumentKind kind;
clang_type_t pair_type = ClangASTContext::GetTemplateArgument(valobj_sp->GetClangAST(),valobj_sp->GetClangType(), 0, kind);
if (kind != eTemplateArgumentKindType && kind != eTemplateArgumentKindTemplate && kind != eTemplateArgumentKindTemplateExpansion)
return false;
m_pair_type = ClangASTType(valobj_sp->GetClangAST(),pair_type);
}
else
return false;
return true;
}
size_t
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
{
return 2;
}
lldb::ValueObjectSP
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
{
if (m_pair_address == 0)
return lldb::ValueObjectSP();
if (m_pair_type.GetASTContext() == NULL ||
m_pair_type.GetOpaqueQualType() == NULL)
return lldb::ValueObjectSP();
if (!m_pair_sp)
m_pair_sp = ValueObject::CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type);
if (m_pair_sp)
return m_pair_sp->GetChildAtIndex(idx, true);
return lldb::ValueObjectSP();
}
bool
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren ()
{
return true;
}
size_t
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
{
if (name == ConstString("first"))
return 0;
if (name == ConstString("second"))
return 1;
return UINT32_MAX;
}
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::~LibstdcppMapIteratorSyntheticFrontEnd ()
{}
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp));
}
/*
(lldb) fr var ibeg --ptr-depth 1
(__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) ibeg = {
_M_current = 0x00000001001037a0 {
*_M_current = 1
}
}
*/
SyntheticChildrenFrontEnd*
lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
static ConstString g_item_name;
if (!g_item_name)
g_item_name.SetCString("_M_current");
if (!valobj_sp)
return NULL;
return (new VectorIteratorSyntheticFrontEnd(valobj_sp,g_item_name));
}

View File

@ -7,12 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/lldb-python.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "llvm/Support/ConvertUTF.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
@ -144,8 +140,6 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
m_data_32 = NULL;
delete m_data_64;
m_data_64 = NULL;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
@ -245,8 +239,6 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
m_data_ptr = 0;
m_children.clear();
ValueObjectSP valobj_sp = m_backend.GetSP();
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();

View File

@ -7,12 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/lldb-python.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "llvm/Support/ConvertUTF.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
@ -245,8 +241,6 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
@ -393,8 +387,6 @@ lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
m_data_64 = NULL;
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();

View File

@ -7,12 +7,8 @@
//
//===----------------------------------------------------------------------===//
#include "lldb/lldb-python.h"
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
#include "llvm/Support/ConvertUTF.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Stream.h"
@ -201,8 +197,6 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::Update()
ValueObjectSP valobj_sp = m_backend.GetSP();
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
@ -345,8 +339,6 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::Update()
m_data_64 = NULL;
if (!valobj_sp)
return false;
if (valobj_sp->IsDynamic())
valobj_sp = valobj_sp->GetStaticValue();
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();

View File

@ -0,0 +1,8 @@
LEVEL = ../../../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules
CXXFLAGS += -stdlib=libc++ -O0
LDFLAGS += -stdlib=libc++

View File

@ -0,0 +1,78 @@
"""
Test lldb data formatter subsystem.
"""
import os, time
import unittest2
import lldb
from lldbtest import *
import lldbutil
class LibcxxIteratorDataFormatterTestCase(TestBase):
mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libcxx", "iterator")
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@dsym_test
def test_with_dsym_and_run_command(self):
"""Test data formatter commands."""
self.buildDsym()
self.data_formatter_commands()
@skipOnLinux # No standard locations for libc++ on Linux, so skip for now
@dwarf_test
def test_with_dwarf_and_run_command(self):
"""Test data formatter commands."""
self.buildDwarf()
self.data_formatter_commands()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break at.
self.line = line_number('main.cpp', '// Set break point at this line.')
def data_formatter_commands(self):
"""Test that libc++ iterators format properly."""
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['stopped',
'stop reason = breakpoint'])
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd('type format clear', check=False)
self.runCmd('type summary clear', check=False)
self.runCmd('type filter clear', check=False)
self.runCmd('type synth clear', check=False)
self.runCmd("settings set target.max-children-count 256", check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
self.expect('image list',substrs=['libc++.1.dylib','libc++abi.dylib'])
self.expect('frame variable ivI', substrs = ['item = 3'])
self.expect('expr ivI', substrs = ['item = 3'])
self.expect('frame variable iimI', substrs = ['first = 0','second = 12'])
self.expect('expr iimI', substrs = ['first = 0','second = 12'])
self.expect('frame variable simI', substrs = ['first = "world"','second = 42'])
self.expect('expr simI', substrs = ['first = "world"','second = 42'])
self.expect('frame variable svI', substrs = ['item = "hello"'])
self.expect('expr svI', substrs = ['item = "hello"'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,42 @@
#include <string>
#ifdef _LIBCPP_INLINE_VISIBILITY
#undef _LIBCPP_INLINE_VISIBILITY
#endif
#define _LIBCPP_INLINE_VISIBILITY
#include <map>
#include <vector>
typedef std::map<int, int> intint_map;
typedef std::map<std::string, int> strint_map;
typedef std::vector<int> int_vector;
typedef std::vector<std::string> string_vector;
typedef intint_map::iterator iimter;
typedef strint_map::iterator simter;
typedef int_vector::iterator ivter;
typedef string_vector::iterator svter;
int main()
{
intint_map iim;
iim[0] = 12;
strint_map sim;
sim["world"] = 42;
int_vector iv;
iv.push_back(3);
string_vector sv;
sv.push_back("hello");
iimter iimI = iim.begin();
simter simI = sim.begin();
ivter ivI = iv.begin();
svter svI = sv.begin();
return 0; // Set break point at this line.
}

View File

@ -0,0 +1,8 @@
LEVEL = ../../../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules
CXXFLAGS += -stdlib=libstdc++ -O0
LDFLAGS += -stdlib=libstdc++

View File

@ -0,0 +1,76 @@
"""
Test lldb data formatter subsystem.
"""
import os, time
import unittest2
import lldb
from lldbtest import *
import lldbutil
class StdIteratorDataFormatterTestCase(TestBase):
mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libstdcpp", "iterator")
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@dsym_test
def test_with_dsym_and_run_command(self):
"""Test data formatter commands."""
self.buildDsym()
self.data_formatter_commands()
@skipOnLinux #PR-15256: assertion failure in RecordLayoutBuilder::updateExternalFieldOffset
@dwarf_test
def test_with_dwarf_and_run_command(self):
"""Test data formatter commands."""
self.buildDwarf()
self.data_formatter_commands()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break at.
self.line = line_number('main.cpp', '// Set break point at this line.')
def data_formatter_commands(self):
"""Test that libstdcpp iterators format properly."""
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['stopped',
'stop reason = breakpoint'])
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd('type format clear', check=False)
self.runCmd('type summary clear', check=False)
self.runCmd('type filter clear', check=False)
self.runCmd('type synth clear', check=False)
self.runCmd("settings set target.max-children-count 256", check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
self.expect('frame variable ivI', substrs = ['item = 3'])
self.expect('expr ivI', substrs = ['item = 3'])
self.expect('frame variable iimI', substrs = ['first = 0','second = 12'])
self.expect('expr iimI', substrs = ['first = 0','second = 12'])
self.expect('frame variable simI', substrs = ['first = "world"','second = 42'])
self.expect('expr simI', substrs = ['first = "world"','second = 42'])
self.expect('frame variable svI', substrs = ['item = "hello"'])
self.expect('expr svI', substrs = ['item = "hello"'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,38 @@
#include <string>
#include <map>
#include <vector>
typedef std::map<int, int> intint_map;
typedef std::map<std::string, int> strint_map;
typedef std::vector<int> int_vector;
typedef std::vector<std::string> string_vector;
typedef intint_map::iterator iimter;
typedef strint_map::iterator simter;
typedef int_vector::iterator ivter;
typedef string_vector::iterator svter;
int main()
{
intint_map iim;
iim[0] = 12;
strint_map sim;
sim["world"] = 42;
int_vector iv;
iv.push_back(3);
string_vector sv;
sv.push_back("hello");
iimter iimI = iim.begin();
simter simI = sim.begin();
ivter ivI = iv.begin();
svter svI = sv.begin();
return 0; // Set break point at this line.
}