diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 |
commit | 205afe679855a4ce8149cdaa94d3f0868ce796dc (patch) | |
tree | 09bc83f73246ee3c7a779605cd0122093d2a8a19 /source/DataFormatters | |
parent | 0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (diff) |
Notes
Diffstat (limited to 'source/DataFormatters')
25 files changed, 2790 insertions, 764 deletions
diff --git a/source/DataFormatters/CF.cpp b/source/DataFormatters/CF.cpp index e131b68096fd4..483419e5ac3fb 100644 --- a/source/DataFormatters/CF.cpp +++ b/source/DataFormatters/CF.cpp @@ -26,7 +26,7 @@ using namespace lldb_private; using namespace lldb_private::formatters; bool -lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { time_t epoch = GetOSXEpoch(); epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0); @@ -41,7 +41,7 @@ lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, St } bool -lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -105,7 +105,7 @@ lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& str } bool -lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -235,7 +235,7 @@ lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Strea } bool -lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp index ae5b35fd2b1cb..04cdadf5a98fe 100644 --- a/source/DataFormatters/CXXFormatterFunctions.cpp +++ b/source/DataFormatters/CXXFormatterFunctions.cpp @@ -10,6 +10,8 @@ #include "lldb/lldb-python.h" #include "lldb/DataFormatters/CXXFormatterFunctions.h" +#include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/DataFormatters/TypeSummary.h" #include "llvm/Support/ConvertUTF.h" @@ -20,10 +22,16 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/ProcessStructReader.h" + #include <algorithm> +#if __ANDROID_NDK__ +#include <sys/types.h> +#endif using namespace lldb; using namespace lldb_private; @@ -187,283 +195,53 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, return valobj_sp; } -// use this call if you already have an LLDB-side buffer for the data -template<typename SourceDataType> -static bool -DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, - const SourceDataType*, - UTF8**, - UTF8*, - ConversionFlags), - DataExtractor& data, - Stream& stream, - char prefix_token = '@', - char quote = '"', - uint32_t sourceSize = 0) +bool +lldb_private::formatters::FunctionPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { - if (prefix_token != 0) - stream.Printf("%c",prefix_token); - if (quote != 0) - stream.Printf("%c",quote); - if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) + std::string destination; + StreamString sstr; + AddressType func_ptr_address_type = eAddressTypeInvalid; + addr_t func_ptr_address = valobj.GetPointerValue (&func_ptr_address_type); + if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS) { - const int bufferSPSize = data.GetByteSize(); - if (sourceSize == 0) - { - const int origin_encoding = 8*sizeof(SourceDataType); - sourceSize = bufferSPSize/(origin_encoding / 4); - } - - SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart(); - SourceDataType *data_end_ptr = data_ptr + sourceSize; - - while (data_ptr < data_end_ptr) + switch (func_ptr_address_type) { - if (!*data_ptr) - { - data_end_ptr = data_ptr; + case eAddressTypeInvalid: + case eAddressTypeFile: + case eAddressTypeHost: break; + + case eAddressTypeLoad: + { + ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); + + Address so_addr; + Target *target = exe_ctx.GetTargetPtr(); + if (target && target->GetSectionLoadList().IsEmpty() == false) + { + if (target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address, so_addr)) + { + so_addr.Dump (&sstr, + exe_ctx.GetBestExecutionContextScope(), + Address::DumpStyleResolvedDescription, + Address::DumpStyleSectionNameOffset); + } + } } - data_ptr++; - } - - data_ptr = (SourceDataType*)data.GetDataStart(); - - lldb::DataBufferSP utf8_data_buffer_sp; - UTF8* utf8_data_ptr = nullptr; - UTF8* utf8_data_end_ptr = nullptr; - - if (ConvertFunction) - { - utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0)); - utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); - utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize(); - ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); - utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr - } - else - { - // just copy the pointers - the cast is necessary to make the compiler happy - // but this should only happen if we are reading UTF8 data - utf8_data_ptr = (UTF8*)data_ptr; - utf8_data_end_ptr = (UTF8*)data_end_ptr; - } - - // since we tend to accept partial data (and even partially malformed data) - // we might end up with no NULL terminator before the end_ptr - // hence we need to take a slower route and ensure we stay within boundaries - for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++) - { - if (!*utf8_data_ptr) break; - stream.Printf("%c",*utf8_data_ptr); } } - if (quote != 0) - stream.Printf("%c",quote); - return true; -} - -template<typename SourceDataType> -class ReadUTFBufferAndDumpToStreamOptions -{ -public: - typedef ConversionResult (*ConvertFunctionType) (const SourceDataType**, - const SourceDataType*, - UTF8**, - UTF8*, - ConversionFlags); - - ReadUTFBufferAndDumpToStreamOptions () : - m_conversion_function(NULL), - m_location(0), - m_process_sp(), - m_stream(NULL), - m_prefix_token('@'), - m_quote('"'), - m_source_size(0), - m_needs_zero_termination(true) - { - } - - ReadUTFBufferAndDumpToStreamOptions& - SetConversionFunction (ConvertFunctionType f) - { - m_conversion_function = f; - return *this; - } - - ConvertFunctionType - GetConversionFunction () const - { - return m_conversion_function; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetLocation (uint64_t l) - { - m_location = l; - return *this; - } - - uint64_t - GetLocation () const - { - return m_location; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetProcessSP (ProcessSP p) - { - m_process_sp = p; - return *this; - } - - ProcessSP - GetProcessSP () const - { - return m_process_sp; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetStream (Stream* s) - { - m_stream = s; - return *this; - } - - Stream* - GetStream () const - { - return m_stream; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetPrefixToken (char p) - { - m_prefix_token = p; - return *this; - } - - char - GetPrefixToken () const - { - return m_prefix_token; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetQuote (char q) - { - m_quote = q; - return *this; - } - - char - GetQuote () const - { - return m_quote; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetSourceSize (uint32_t s) - { - m_source_size = s; - return *this; - } - - uint32_t - GetSourceSize () const - { - return m_source_size; - } - - ReadUTFBufferAndDumpToStreamOptions& - SetNeedsZeroTermination (bool z) + if (sstr.GetSize() > 0) { - m_needs_zero_termination = z; - return *this; - } - - bool - GetNeedsZeroTermination () const - { - return m_needs_zero_termination; - } - -private: - ConvertFunctionType m_conversion_function; - uint64_t m_location; - ProcessSP m_process_sp; - Stream* m_stream; - char m_prefix_token; - char m_quote; - uint32_t m_source_size; - bool m_needs_zero_termination; -}; - -template<typename SourceDataType> -static bool -ReadUTFBufferAndDumpToStream (const ReadUTFBufferAndDumpToStreamOptions<SourceDataType>& options) -{ - if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS) - return false; - - ProcessSP process_sp(options.GetProcessSP()); - - if (!process_sp) - return false; - - const int type_width = sizeof(SourceDataType); - const int origin_encoding = 8 * type_width ; - if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) - return false; - // if not UTF8, I need a conversion function to return proper UTF8 - if (origin_encoding != 8 && !options.GetConversionFunction()) - return false; - - if (!options.GetStream()) - return false; - - uint32_t sourceSize = options.GetSourceSize(); - bool needs_zero_terminator = options.GetNeedsZeroTermination(); - - if (!sourceSize) - { - sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); - needs_zero_terminator = true; + stream.Printf("(%s)", sstr.GetData()); + return true; } else - sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary()); - - const int bufferSPSize = sourceSize * type_width; - - lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); - - if (!buffer_sp->GetBytes()) return false; - - Error error; - char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes()); - - size_t data_read = 0; - if (needs_zero_terminator) - data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width); - else - data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error); - - if (error.Fail() || data_read == 0) - { - options.GetStream()->Printf("unable to read data"); - return true; - } - - DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); - - return DumpUTFBufferToStream(options.GetConversionFunction(), data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize); } bool -lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -474,14 +252,13 @@ lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stre if (!valobj_addr) return false; - ReadUTFBufferAndDumpToStreamOptions<UTF16> options; + ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(valobj_addr); - options.SetConversionFunction(ConvertUTF16toUTF8); options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetPrefixToken('u'); - if (!ReadUTFBufferAndDumpToStream(options)) + if (!ReadStringAndDumpToStream<StringElementType::UTF16>(options)) { stream.Printf("Summary Unavailable"); return true; @@ -491,7 +268,7 @@ lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stre } bool -lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -502,14 +279,13 @@ lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stre if (!valobj_addr) return false; - ReadUTFBufferAndDumpToStreamOptions<UTF32> options; + ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(valobj_addr); - options.SetConversionFunction(ConvertUTF32toUTF8); options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetPrefixToken('U'); - if (!ReadUTFBufferAndDumpToStream(options)) + if (!ReadStringAndDumpToStream<StringElementType::UTF32>(options)) { stream.Printf("Summary Unavailable"); return true; @@ -519,7 +295,7 @@ lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stre } bool -lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -543,45 +319,20 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar); const uint32_t wchar_size = wchar_clang_type.GetBitSize(); + ReadStringAndDumpToStreamOptions options(valobj); + options.SetLocation(data_addr); + options.SetProcessSP(process_sp); + options.SetStream(&stream); + options.SetPrefixToken('L'); + switch (wchar_size) { case 8: - { - // utf 8 - - ReadUTFBufferAndDumpToStreamOptions<UTF8> options; - options.SetLocation(data_addr); - options.SetConversionFunction(nullptr); - options.SetProcessSP(process_sp); - options.SetStream(&stream); - options.SetPrefixToken('L'); - - return ReadUTFBufferAndDumpToStream(options); - } + return ReadStringAndDumpToStream<StringElementType::UTF8>(options); case 16: - { - // utf 16 - ReadUTFBufferAndDumpToStreamOptions<UTF16> options; - options.SetLocation(data_addr); - options.SetConversionFunction(ConvertUTF16toUTF8); - options.SetProcessSP(process_sp); - options.SetStream(&stream); - options.SetPrefixToken('L'); - - return ReadUTFBufferAndDumpToStream(options); - } + return ReadStringAndDumpToStream<StringElementType::UTF16>(options); case 32: - { - // utf 32 - ReadUTFBufferAndDumpToStreamOptions<UTF32> options; - options.SetLocation(data_addr); - options.SetConversionFunction(ConvertUTF32toUTF8); - options.SetProcessSP(process_sp); - options.SetStream(&stream); - options.SetPrefixToken('L'); - - return ReadUTFBufferAndDumpToStream(options); - } + return ReadStringAndDumpToStream<StringElementType::UTF32>(options); default: stream.Printf("size for wchar_t is not valid"); return true; @@ -590,7 +341,7 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea } bool -lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { DataExtractor data; Error error; @@ -604,11 +355,18 @@ lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& st if (!value.empty()) stream.Printf("%s ", value.c_str()); - return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1); + ReadBufferAndDumpToStreamOptions options(valobj); + options.SetData(data); + options.SetStream(&stream); + options.SetPrefixToken('u'); + options.SetQuote('\''); + options.SetSourceSize(1); + + return ReadBufferAndDumpToStream<StringElementType::UTF16>(options); } bool -lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { DataExtractor data; Error error; @@ -622,11 +380,18 @@ lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& st if (!value.empty()) stream.Printf("%s ", value.c_str()); - return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1); + ReadBufferAndDumpToStreamOptions options(valobj); + options.SetData(data); + options.SetStream(&stream); + options.SetPrefixToken('U'); + options.SetQuote('\''); + options.SetSourceSize(1); + + return ReadBufferAndDumpToStream<StringElementType::UTF32>(options); } bool -lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions&) { DataExtractor data; Error error; @@ -635,55 +400,14 @@ lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& str if (error.Fail()) return false; - clang::ASTContext* ast = valobj.GetClangType().GetASTContext(); - - if (!ast) - return false; - - ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar); - const uint32_t wchar_size = wchar_clang_type.GetBitSize(); - std::string value; + ReadBufferAndDumpToStreamOptions options(valobj); + options.SetData(data); + options.SetStream(&stream); + options.SetPrefixToken('L'); + options.SetQuote('\''); + options.SetSourceSize(1); - switch (wchar_size) - { - case 8: - // utf 8 - valobj.GetValueAsCString(lldb::eFormatChar, value); - if (!value.empty()) - stream.Printf("%s ", value.c_str()); - return DumpUTFBufferToStream<UTF8>(nullptr, - data, - stream, - 'L', - '\'', - 1); - case 16: - // utf 16 - valobj.GetValueAsCString(lldb::eFormatUnicode16, value); - if (!value.empty()) - stream.Printf("%s ", value.c_str()); - return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8, - data, - stream, - 'L', - '\'', - 1); - case 32: - // utf 32 - valobj.GetValueAsCString(lldb::eFormatUnicode32, value); - if (!value.empty()) - stream.Printf("%s ", value.c_str()); - return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8, - data, - stream, - 'L', - '\'', - 1); - default: - stream.Printf("size for wchar_t is not valid"); - return true; - } - return true; + return ReadBufferAndDumpToStream<StringElementType::UTF16>(options); } // the field layout in a libc++ string (cap, side, data or data, size, cap) @@ -769,7 +493,7 @@ ExtractLibcxxStringInfo (ValueObject& valobj, } bool -lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { uint64_t size = 0; ValueObjectSP location_sp((ValueObject*)nullptr); @@ -782,34 +506,45 @@ lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Str } if (!location_sp) return false; - return WCharStringSummaryProvider(*location_sp.get(), stream); + return WCharStringSummaryProvider(*location_sp.get(), stream, options); } bool -lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options) { uint64_t size = 0; ValueObjectSP location_sp((ValueObject*)nullptr); + if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) return false; + if (size == 0) { stream.Printf("\"\""); return true; } + if (!location_sp) return false; - Error error; - 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(); + + DataExtractor extractor; + if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) + size = std::min<decltype(size)>(size, valobj.GetTargetSP()->GetMaximumSizeOfStringSummary()); + location_sp->GetPointeeData(extractor, 0, size); + + ReadBufferAndDumpToStreamOptions options(valobj); + options.SetData(extractor); // none of this matters for a string - pass some defaults + options.SetStream(&stream); + options.SetPrefixToken(0); + options.SetQuote('"'); + options.SetSourceSize(size); + lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options); + + return true; } bool -lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -886,7 +621,7 @@ lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildre template<bool needs_at> bool -lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -1037,8 +772,28 @@ lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::C return true; } +static ClangASTType +GetNSPathStore2Type (Target &target) +{ + static ConstString g_type_name("__lldb_autogen_nspathstore2"); + + ClangASTContext *ast_ctx = target.GetScratchClangASTContext(); + + if (!ast_ctx) + return ClangASTType(); + + ClangASTType voidstar = ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType(); + ClangASTType uint32 = ast_ctx->GetIntTypeFromBitSize(32, false); + + return ast_ctx->GetOrCreateStructForIdentifier(g_type_name, { + {"isa",voidstar}, + {"lengthAndRef",uint32}, + {"buffer",voidstar} + }); +} + bool -lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -1131,8 +886,7 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& return false; if (has_explicit_length && is_unicode) { - ReadUTFBufferAndDumpToStreamOptions<UTF16> options; - options.SetConversionFunction(ConvertUTF16toUTF8); + ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(location); options.SetProcessSP(process_sp); options.SetStream(&stream); @@ -1140,10 +894,21 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& options.SetQuote('"'); options.SetSourceSize(explicit_length); options.SetNeedsZeroTermination(false); - return ReadUTFBufferAndDumpToStream (options); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::UTF16>(options); } else - return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream, explicit_length); + { + ReadStringAndDumpToStreamOptions options(valobj); + options.SetLocation(location+1); + options.SetProcessSP(process_sp); + options.SetStream(&stream); + options.SetPrefixToken('@'); + options.SetSourceSize(explicit_length); + options.SetNeedsZeroTermination(false); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::ASCII>(options); + } } else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable) { @@ -1169,8 +934,7 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& if (error.Fail()) return false; } - ReadUTFBufferAndDumpToStreamOptions<UTF16> options; - options.SetConversionFunction(ConvertUTF16toUTF8); + ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(location); options.SetProcessSP(process_sp); options.SetStream(&stream); @@ -1178,13 +942,16 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& options.SetQuote('"'); options.SetSourceSize(explicit_length); options.SetNeedsZeroTermination(has_explicit_length == false); - return ReadUTFBufferAndDumpToStream (options); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::UTF16> (options); } else if (is_special) { - uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8); - ReadUTFBufferAndDumpToStreamOptions<UTF16> options; - options.SetConversionFunction(ConvertUTF16toUTF8); + ProcessStructReader reader(valobj.GetProcessSP().get(), valobj.GetValueAsUnsigned(0), GetNSPathStore2Type(*valobj.GetTargetSP())); + explicit_length = reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20; + lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4; + + ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(location); options.SetProcessSP(process_sp); options.SetStream(&stream); @@ -1192,14 +959,22 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& options.SetQuote('"'); options.SetSourceSize(explicit_length); options.SetNeedsZeroTermination(has_explicit_length == false); - return ReadUTFBufferAndDumpToStream (options); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::UTF16> (options); } else if (is_inline) { uint64_t location = valobj_addr + 2*ptr_size; if (!has_explicit_length) location++; - return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length); + ReadStringAndDumpToStreamOptions options(valobj); + options.SetLocation(location); + options.SetProcessSP(process_sp); + options.SetStream(&stream); + options.SetPrefixToken('@'); + options.SetSourceSize(explicit_length); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::ASCII>(options); } else { @@ -1209,16 +984,19 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& return false; if (has_explicit_length && !has_null) explicit_length++; // account for the fact that there is no NULL and we need to have one added - return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length); + ReadStringAndDumpToStreamOptions options(valobj); + options.SetLocation(location); + options.SetProcessSP(process_sp); + options.SetPrefixToken('@'); + options.SetStream(&stream); + options.SetSourceSize(explicit_length); + options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); + return ReadStringAndDumpToStream<StringElementType::ASCII>(options); } - - stream.Printf("class name = %s",class_name); - return true; - } bool -lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { TargetSP target_sp(valobj.GetTargetSP()); if (!target_sp) @@ -1241,38 +1019,38 @@ lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type)); child_sp->GetValueAsUnsigned(0); if (child_sp) - return NSStringSummaryProvider(*child_sp, stream); + return NSStringSummaryProvider(*child_sp, stream, options); return false; } bool -lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { - return NSAttributedStringSummaryProvider(valobj, stream); + return NSAttributedStringSummaryProvider(valobj, stream, options); } bool -lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { stream.Printf("%s",valobj.GetObjectDescription()); return true; } bool -lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { const uint32_t type_info = valobj.GetClangType().GetTypeInfo(); ValueObjectSP real_guy_sp = valobj.GetSP(); - if (type_info & ClangASTType::eTypeIsPointer) + if (type_info & eTypeIsPointer) { Error err; real_guy_sp = valobj.Dereference(err); if (err.Fail() || !real_guy_sp) return false; } - else if (type_info & ClangASTType::eTypeIsReference) + else if (type_info & eTypeIsReference) { real_guy_sp = valobj.GetChildAtIndex(0, true); if (!real_guy_sp) @@ -1290,7 +1068,7 @@ lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& template <bool is_sel_ptr> bool -lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { lldb::ValueObjectSP valobj_sp; @@ -1398,7 +1176,7 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update() return false; Error err; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); - m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetClangType().GetPointeeType()); + m_item_sp = CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetClangType().GetPointeeType()); if (err.Fail()) m_item_sp.reset(); return false; @@ -1437,13 +1215,13 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSynthe } template bool -lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ; +lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ; template bool -lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ; +lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ; template bool -lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ; +lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ; template bool -lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ; +lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ; diff --git a/source/DataFormatters/Cocoa.cpp b/source/DataFormatters/Cocoa.cpp index 8e92de4ddaa45..137fd4f483ccc 100644 --- a/source/DataFormatters/Cocoa.cpp +++ b/source/DataFormatters/Cocoa.cpp @@ -26,7 +26,7 @@ using namespace lldb_private; using namespace lldb_private::formatters; bool -lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -60,7 +60,7 @@ lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true)); StreamString summary_stream; - bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); + bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options); if (was_nsstring_ok && summary_stream.GetSize() > 0) { stream.Printf("%s",summary_stream.GetData()); @@ -73,7 +73,7 @@ lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& } bool -lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -106,7 +106,7 @@ lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true)); StreamString summary_stream; - bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); + bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options); if (was_nsstring_ok && summary_stream.GetSize() > 0) { stream.Printf("%s",summary_stream.GetData()); @@ -117,7 +117,7 @@ lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream } bool -lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -150,7 +150,7 @@ lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, St uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType(), true)); StreamString summary_stream; - bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); + bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options); if (was_nsstring_ok && summary_stream.GetSize() > 0) { stream.Printf("%s",summary_stream.GetData()); @@ -163,7 +163,7 @@ lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, St } bool -lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -212,7 +212,7 @@ lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream } bool -lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -290,7 +290,7 @@ lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream } bool -lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -413,7 +413,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& } bool -lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -453,7 +453,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str if (text->GetValueAsUnsigned(0) == 0) return false; StreamString summary; - if (!NSStringSummaryProvider(*text, summary)) + if (!NSStringSummaryProvider(*text, summary, options)) return false; if (base && base->GetValueAsUnsigned(0)) { @@ -461,7 +461,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str summary.GetString().resize(summary.GetSize()-1); summary.Printf(" -- "); StreamString base_summary; - if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0) + if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0) summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); } if (summary.GetSize()) @@ -478,7 +478,7 @@ lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& str } bool -lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -552,7 +552,7 @@ lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& st // vendor decides to get creative time_t epoch = GetOSXEpoch(); epoch = epoch + (time_t)date_value; - tm *tm_date = localtime(&epoch); + tm *tm_date = gmtime(&epoch); if (!tm_date) return false; std::string buffer(1024,0); diff --git a/source/DataFormatters/DataVisualization.cpp b/source/DataFormatters/DataVisualization.cpp index c2c2206f34492..7ef0be50efe08 100644 --- a/source/DataFormatters/DataVisualization.cpp +++ b/source/DataFormatters/DataVisualization.cpp @@ -101,6 +101,18 @@ DataVisualization::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp) } #endif +lldb::TypeValidatorImplSP +DataVisualization::GetValidator (ValueObject& valobj, lldb::DynamicValueType use_dynamic) +{ + return GetFormatManager().GetValidator(valobj, use_dynamic); +} + +lldb::TypeValidatorImplSP +DataVisualization::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp) +{ + return GetFormatManager().GetValidatorForType(type_sp); +} + bool DataVisualization::AnyMatches (ConstString type_name, TypeCategoryImpl::FormatCategoryItems items, @@ -184,6 +196,18 @@ DataVisualization::Categories::Disable (const lldb::TypeCategoryImplSP& category } void +DataVisualization::Categories::EnableStar () +{ + GetFormatManager().EnableAllCategories (); +} + +void +DataVisualization::Categories::DisableStar () +{ + GetFormatManager().DisableAllCategories(); +} + +void DataVisualization::Categories::LoopThrough (FormatManager::CategoryCallback callback, void* callback_baton) { GetFormatManager().LoopThroughCategories(callback, callback_baton); diff --git a/source/DataFormatters/FormatCache.cpp b/source/DataFormatters/FormatCache.cpp index 3721f182f91e7..aaa4bc1f958ab 100644 --- a/source/DataFormatters/FormatCache.cpp +++ b/source/DataFormatters/FormatCache.cpp @@ -25,16 +25,20 @@ FormatCache::Entry::Entry () : m_format_cached(false), m_summary_cached(false), m_synthetic_cached(false), +m_validator_cached(false), m_format_sp(), m_summary_sp(), -m_synthetic_sp() +m_synthetic_sp(), +m_validator_sp() {} FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp) : m_summary_cached(false), m_synthetic_cached(false), +m_validator_cached(false), m_summary_sp(), -m_synthetic_sp() +m_synthetic_sp(), +m_validator_sp() { SetFormat (format_sp); } @@ -42,8 +46,10 @@ m_synthetic_sp() FormatCache::Entry::Entry (lldb::TypeSummaryImplSP summary_sp) : m_format_cached(false), m_synthetic_cached(false), +m_validator_cached(false), m_format_sp(), -m_synthetic_sp() +m_synthetic_sp(), +m_validator_sp() { SetSummary (summary_sp); } @@ -51,17 +57,31 @@ m_synthetic_sp() FormatCache::Entry::Entry (lldb::SyntheticChildrenSP synthetic_sp) : m_format_cached(false), m_summary_cached(false), +m_validator_cached(false), m_format_sp(), -m_summary_sp() +m_summary_sp(), +m_validator_sp() { SetSynthetic (synthetic_sp); } -FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp, lldb::TypeSummaryImplSP summary_sp, lldb::SyntheticChildrenSP synthetic_sp) +FormatCache::Entry::Entry (lldb::TypeValidatorImplSP validator_sp) : +m_format_cached(false), +m_summary_cached(false), +m_synthetic_cached(false), +m_format_sp(), +m_summary_sp(), +m_synthetic_sp() +{ + SetValidator (validator_sp); +} + +FormatCache::Entry::Entry (lldb::TypeFormatImplSP format_sp, lldb::TypeSummaryImplSP summary_sp, lldb::SyntheticChildrenSP synthetic_sp, lldb::TypeValidatorImplSP validator_sp) { SetFormat (format_sp); SetSummary (summary_sp); SetSynthetic (synthetic_sp); + SetValidator (validator_sp); } bool @@ -82,6 +102,12 @@ FormatCache::Entry::IsSyntheticCached () return m_synthetic_cached; } +bool +FormatCache::Entry::IsValidatorCached () +{ + return m_validator_cached; +} + lldb::TypeFormatImplSP FormatCache::Entry::GetFormat () { @@ -100,6 +126,12 @@ FormatCache::Entry::GetSynthetic () return m_synthetic_sp; } +lldb::TypeValidatorImplSP +FormatCache::Entry::GetValidator () +{ + return m_validator_sp; +} + void FormatCache::Entry::SetFormat (lldb::TypeFormatImplSP format_sp) { @@ -121,6 +153,13 @@ FormatCache::Entry::SetSynthetic (lldb::SyntheticChildrenSP synthetic_sp) m_synthetic_sp = synthetic_sp; } +void +FormatCache::Entry::SetValidator (lldb::TypeValidatorImplSP validator_sp) +{ + m_validator_cached = true; + m_validator_sp = validator_sp; +} + FormatCache::FormatCache () : m_map(), m_mutex (Mutex::eMutexTypeRecursive) @@ -201,6 +240,26 @@ FormatCache::GetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& sy return false; } +bool +FormatCache::GetValidator (const ConstString& type,lldb::TypeValidatorImplSP& validator_sp) +{ + Mutex::Locker lock(m_mutex); + auto entry = GetEntry(type); + if (entry.IsValidatorCached()) + { +#ifdef LLDB_CONFIGURATION_DEBUG + m_cache_hits++; +#endif + validator_sp = entry.GetValidator(); + return true; + } +#ifdef LLDB_CONFIGURATION_DEBUG + m_cache_misses++; +#endif + validator_sp.reset(); + return false; +} + void FormatCache::SetFormat (const ConstString& type,lldb::TypeFormatImplSP& format_sp) { @@ -223,6 +282,13 @@ FormatCache::SetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& sy } void +FormatCache::SetValidator (const ConstString& type,lldb::TypeValidatorImplSP& validator_sp) +{ + Mutex::Locker lock(m_mutex); + GetEntry(type).SetValidator(validator_sp); +} + +void FormatCache::Clear () { Mutex::Locker lock(m_mutex); diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp index 28d108f2410a3..01799cef5e4ee 100644 --- a/source/DataFormatters/FormatManager.cpp +++ b/source/DataFormatters/FormatManager.cpp @@ -447,6 +447,32 @@ FormatManager::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_s } #endif +lldb::TypeValidatorImplSP +FormatManager::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp) +{ + if (!type_sp) + return lldb::TypeValidatorImplSP(); + lldb::TypeValidatorImplSP validator_chosen_sp; + uint32_t num_categories = m_categories_map.GetCount(); + lldb::TypeCategoryImplSP category_sp; + uint32_t prio_category = UINT32_MAX; + for (uint32_t category_id = 0; + category_id < num_categories; + category_id++) + { + category_sp = GetCategoryAtIndex(category_id); + if (category_sp->IsEnabled() == false) + continue; + lldb::TypeValidatorImplSP validator_current_sp(category_sp->GetValidatorForType(type_sp).get()); + if (validator_current_sp && (validator_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) + { + prio_category = category_sp->GetEnabledPosition(); + validator_chosen_sp = validator_current_sp; + } + } + return validator_chosen_sp; +} + lldb::TypeCategoryImplSP FormatManager::GetCategory (const ConstString& category_name, bool can_create) @@ -501,10 +527,9 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj) if (valobj.GetTargetSP().get() && valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries() == false) return false; // then don't oneline - // if this object has a summary, don't try to do anything special to it - // if the user wants one-liner, they can ask for it in summary :) + // if this object has a summary, then ask the summary if (valobj.GetSummaryFormat().get() != nullptr) - return false; + return valobj.GetSummaryFormat()->IsOneLiner(); // no children, no party if (valobj.GetNumChildren() == 0) @@ -516,6 +541,7 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj) idx < valobj.GetNumChildren(); idx++) { + bool is_synth_val = false; ValueObjectSP child_sp(valobj.GetChildAtIndex(idx, true)); // something is wrong here - bail out if (!child_sp) @@ -523,7 +549,17 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj) // if we decided to define synthetic children for a type, we probably care enough // to show them, but avoid nesting children in children if (child_sp->GetSyntheticChildren().get() != nullptr) - return false; + { + ValueObjectSP synth_sp(child_sp->GetSyntheticValue()); + // wait.. wat? just get out of here.. + if (!synth_sp) + return false; + // but if we only have them to provide a value, keep going + if (synth_sp->MightHaveChildren() == false && synth_sp->DoesProvideSyntheticValue()) + is_synth_val = true; + else + return false; + } total_children_name_len += child_sp->GetName().GetLength(); @@ -547,7 +583,7 @@ FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj) // ...and no summary... // (if it had a summary and the summary wanted children, we would have bailed out anyway // so this only makes us bail out if this has no summary and we would then print children) - if (!child_sp->GetSummaryFormat()) + if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do that if not a synthetic valued child return false; // then bail out } } @@ -756,6 +792,63 @@ FormatManager::GetSyntheticChildren (ValueObject& valobj, } #endif +lldb::TypeValidatorImplSP +FormatManager::GetValidator (ValueObject& valobj, + lldb::DynamicValueType use_dynamic) +{ + TypeValidatorImplSP retval; + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + ConstString valobj_type(GetTypeForCache(valobj, use_dynamic)); + if (valobj_type) + { + if (log) + log->Printf("\n\n[FormatManager::GetValidator] Looking into cache for type %s", valobj_type.AsCString("<invalid>")); + if (m_format_cache.GetValidator(valobj_type,retval)) + { + if (log) + { + log->Printf("[FormatManager::GetValidator] Cache search success. Returning."); + if (log->GetDebug()) + log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); + } + return retval; + } + if (log) + log->Printf("[FormatManager::GetValidator] Cache search failed. Going normal route"); + } + retval = m_categories_map.GetValidator(valobj, use_dynamic); + if (!retval) + { + if (log) + log->Printf("[FormatManager::GetValidator] Search failed. Giving hardcoded a chance."); + retval = GetHardcodedValidator(valobj, use_dynamic); + } + else if (valobj_type) + { + if (log) + log->Printf("[FormatManager::GetValidator] Caching %p for type %s", + static_cast<void*>(retval.get()), + valobj_type.AsCString("<invalid>")); + m_format_cache.SetValidator(valobj_type,retval); + } + if (log && log->GetDebug()) + log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); + return retval; +} + +lldb::TypeValidatorImplSP +FormatManager::GetHardcodedValidator (ValueObject& valobj, + lldb::DynamicValueType use_dynamic) +{ + for (const auto& candidate: m_hardcoded_validators) + { + auto result = candidate(valobj,use_dynamic,*this); + if (result) + return result; + } + return nullptr; +} + FormatManager::FormatManager() : m_format_cache(), m_named_summaries_map(this), @@ -773,7 +866,8 @@ FormatManager::FormatManager() : m_appkit_category_name(ConstString("AppKit")), m_hardcoded_formats(), m_hardcoded_summaries(), - m_hardcoded_synthetics() + m_hardcoded_synthetics(), + m_hardcoded_validators() { LoadSystemFormatters(); @@ -825,6 +919,21 @@ AddStringSummary(TypeCategoryImpl::SharedPointer category_sp, category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp); } +static void +AddOneLineSummary (TypeCategoryImpl::SharedPointer category_sp, + ConstString type_name, + TypeSummaryImpl::Flags flags, + bool regex = false) +{ + flags.SetShowMembersOneLiner(true); + lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags, "")); + + if (regex) + category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); + else + category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp); +} + #ifndef LLDB_DISABLE_PYTHON static void AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp, @@ -945,13 +1054,6 @@ FormatManager::LoadLibStdcppFormatters() 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->GetTypeSummariesContainer()->Add(ConstString("std::vector<std::allocator<bool> >"), - TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - - gnu_category_sp->GetTypeSyntheticsContainer()->Add(ConstString("std::vector<std::allocator<bool> >"), - SyntheticChildrenSP(new CXXSyntheticChildren(stl_synth_flags,"libc++ std::vector<bool> synthetic children",lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator))); - #endif } @@ -998,6 +1100,7 @@ FormatManager::LoadLibcxxFormatters() AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_synth_flags, true); + AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, true); libcxx_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, @@ -1124,6 +1227,10 @@ FormatManager::LoadObjCFormatters() .SetHideItemNames(false); TypeCategoryImpl::SharedPointer objc_category_sp = GetCategory(m_objc_category_name); + TypeCategoryImpl::SharedPointer appkit_category_sp = GetCategory(m_appkit_category_name); + TypeCategoryImpl::SharedPointer corefoundation_category_sp = GetCategory(m_corefoundation_category_name); + TypeCategoryImpl::SharedPointer coregraphics_category_sp = GetCategory(m_coregraphics_category_name); + TypeCategoryImpl::SharedPointer coreservices_category_sp = GetCategory(m_coreservices_category_name); lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider,"")); objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL"), @@ -1159,8 +1266,6 @@ FormatManager::LoadObjCFormatters() ConstString("__block_literal_generic"), objc_flags); - TypeCategoryImpl::SharedPointer corefoundation_category_sp = GetCategory(m_corefoundation_category_name); - AddStringSummary(corefoundation_category_sp, "${var.years} years, ${var.months} months, ${var.days} days, ${var.hours} hours, ${var.minutes} minutes ${var.seconds} seconds", ConstString("CFGregorianUnits"), @@ -1169,43 +1274,35 @@ FormatManager::LoadObjCFormatters() "location=${var.location} length=${var.length}", ConstString("CFRange"), objc_flags); - AddStringSummary(corefoundation_category_sp, - "(x=${var.x}, y=${var.y})", - ConstString("NSPoint"), - objc_flags); - AddStringSummary(corefoundation_category_sp, + + AddStringSummary(appkit_category_sp, "location=${var.location}, length=${var.length}", ConstString("NSRange"), objc_flags); - AddStringSummary(corefoundation_category_sp, - "${var.origin}, ${var.size}", - ConstString("NSRect"), - objc_flags); - AddStringSummary(corefoundation_category_sp, + AddStringSummary(appkit_category_sp, "(${var.origin}, ${var.size}), ...", ConstString("NSRectArray"), objc_flags); - AddStringSummary(objc_category_sp, - "(width=${var.width}, height=${var.height})", - ConstString("NSSize"), - objc_flags); - - TypeCategoryImpl::SharedPointer coregraphics_category_sp = GetCategory(m_coregraphics_category_name); - - AddStringSummary(coregraphics_category_sp, - "(width=${var.width}, height=${var.height})", - ConstString("CGSize"), - objc_flags); - AddStringSummary(coregraphics_category_sp, - "(x=${var.x}, y=${var.y})", - ConstString("CGPoint"), - objc_flags); - AddStringSummary(coregraphics_category_sp, - "origin=${var.origin} size=${var.size}", - ConstString("CGRect"), - objc_flags); - TypeCategoryImpl::SharedPointer coreservices_category_sp = GetCategory(m_coreservices_category_name); + AddOneLineSummary (appkit_category_sp, + ConstString("NSPoint"), + objc_flags); + AddOneLineSummary (appkit_category_sp, + ConstString("NSSize"), + objc_flags); + AddOneLineSummary (appkit_category_sp, + ConstString("NSRect"), + objc_flags); + + AddOneLineSummary (coregraphics_category_sp, + ConstString("CGSize"), + objc_flags); + AddOneLineSummary (coregraphics_category_sp, + ConstString("CGPoint"), + objc_flags); + AddOneLineSummary (coregraphics_category_sp, + ConstString("CGRect"), + objc_flags); AddStringSummary(coreservices_category_sp, "red=${var.red} green=${var.green} blue=${var.blue}", @@ -1236,8 +1333,6 @@ FormatManager::LoadObjCFormatters() ConstString("HIRect"), objc_flags); - TypeCategoryImpl::SharedPointer appkit_category_sp = GetCategory(m_appkit_category_name); - TypeSummaryImpl::Flags appkit_flags; appkit_flags.SetCascades(true) .SetSkipPointers(false) @@ -1307,6 +1402,8 @@ FormatManager::LoadObjCFormatters() AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSOrderedSet synthetic children", ConstString("NSOrderedSet"), ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetI synthetic children", ConstString("__NSOrderedSetI"), ScriptedSyntheticChildren::Flags()); AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSOrderedSetM synthetic children", ConstString("__NSOrderedSetM"), ScriptedSyntheticChildren::Flags()); + + AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSIndexPathSyntheticFrontEndCreator, "NSIndexPath synthetic children", ConstString("NSIndexPath"), ScriptedSyntheticChildren::Flags()); AddCXXSummary(corefoundation_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("CFBagRef"), appkit_flags); AddCXXSummary(corefoundation_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("__CFBag"), appkit_flags); @@ -1471,8 +1568,22 @@ FormatManager::LoadHardcodedFormatters() } { // insert code to load summaries here + m_hardcoded_summaries.push_back( + [](lldb_private::ValueObject& valobj, + lldb::DynamicValueType, + FormatManager&) -> TypeSummaryImpl::SharedPointer { + static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags(), lldb_private::formatters::FunctionPointerSummaryProvider, "Function pointer summary provider")); + if (valobj.GetClangType().IsFunctionPointerType()) + { + return formatter_sp; + } + return nullptr; + }); } { // insert code to load synthetics here } + { + // insert code to load validators here + } } diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp index 174202661f039..26bbcf91242f1 100644 --- a/source/DataFormatters/LibCxx.cpp +++ b/source/DataFormatters/LibCxx.cpp @@ -27,7 +27,7 @@ using namespace lldb_private; using namespace lldb_private::formatters; bool -lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); if (!valobj_sp) @@ -143,7 +143,7 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si if (bit_set && buffer_sp && buffer_sp->GetBytes()) *(buffer_sp->GetBytes()) = 1; // regardless of endianness, anything non-zero is true StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); - ValueObjectSP retval_sp(ValueObject::CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type)); + ValueObjectSP retval_sp(CreateValueObjectFromData(name.GetData(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()), m_exe_ctx_ref, m_bool_type)); if (retval_sp) m_children[idx] = retval_sp; return retval_sp; @@ -378,7 +378,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (siz return lldb::ValueObjectSP(); uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); DataExtractor data(&count, 8, m_byte_order, m_ptr_size); - m_count_sp = ValueObject::CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_owners_sp->GetClangType()); + m_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_owners_sp->GetClangType()); } return m_count_sp; } @@ -391,7 +391,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (siz return lldb::ValueObjectSP(); uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); DataExtractor data(&count, 8, m_byte_order, m_ptr_size); - m_weak_count_sp = ValueObject::CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_weak_owners_sp->GetClangType()); + m_weak_count_sp = CreateValueObjectFromData("count", data, valobj_sp->GetExecutionContextRef(), shared_weak_owners_sp->GetClangType()); } return m_weak_count_sp; } @@ -450,111 +450,8 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator (CXXSyntheticC return (new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)); } -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : - SyntheticChildrenFrontEnd(*valobj_sp.get()), - m_start(NULL), - m_finish(NULL), - m_element_type(), - m_element_size(0), - m_children() -{ - if (valobj_sp) - Update(); -} - -size_t -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren () -{ - if (!m_start || !m_finish) - return 0; - uint64_t start_val = m_start->GetValueAsUnsigned(0); - uint64_t finish_val = m_finish->GetValueAsUnsigned(0); - - if (start_val == 0 || finish_val == 0) - return 0; - - if (start_val >= finish_val) - return 0; - - size_t num_children = (finish_val - start_val); - if (num_children % m_element_size) - return 0; - return num_children/m_element_size; -} - -lldb::ValueObjectSP -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (size_t idx) -{ - if (!m_start || !m_finish) - return lldb::ValueObjectSP(); - - auto cached = m_children.find(idx); - if (cached != m_children.end()) - return cached->second; - - uint64_t offset = idx * m_element_size; - offset = offset + m_start->GetValueAsUnsigned(0); - StreamString name; - name.Printf("[%" PRIu64 "]", (uint64_t)idx); - ValueObjectSP child_sp = ValueObject::CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type); - m_children[idx] = child_sp; - return child_sp; -} - -bool -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() -{ - m_start = m_finish = NULL; - m_children.clear(); - ValueObjectSP data_type_finder_sp(m_backend.GetChildMemberWithName(ConstString("__end_cap_"),true)); - if (!data_type_finder_sp) - return false; - data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(ConstString("__first_"),true); - if (!data_type_finder_sp) - return false; - m_element_type = data_type_finder_sp->GetClangType().GetPointeeType(); - m_element_size = m_element_type.GetByteSize(); - - if (m_element_size > 0) - { - // store raw pointers or end up with a circular dependency - m_start = m_backend.GetChildMemberWithName(ConstString("__begin_"),true).get(); - m_finish = m_backend.GetChildMemberWithName(ConstString("__end_"),true).get(); - } - return false; -} - -bool -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::MightHaveChildren () -{ - return true; -} - -size_t -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) -{ - if (!m_start || !m_finish) - return UINT32_MAX; - return ExtractIndexFromString(name.GetCString()); -} - -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::~LibcxxStdVectorSyntheticFrontEnd () -{ - // these need to stay around because they are child objects who will follow their parent's life cycle - // delete m_start; - // delete m_finish; -} - -SyntheticChildrenFrontEnd* -lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) -{ - if (!valobj_sp) - return NULL; - return (new LibcxxStdVectorSyntheticFrontEnd(valobj_sp)); -} - bool -lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { if (valobj.IsPointerType()) { diff --git a/source/DataFormatters/LibCxxInitializerList.cpp b/source/DataFormatters/LibCxxInitializerList.cpp new file mode 100644 index 0000000000000..e76b0bec95ce2 --- /dev/null +++ b/source/DataFormatters/LibCxxInitializerList.cpp @@ -0,0 +1,145 @@ +//===-- LibCxxInitializerList.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/lldb-python.h" + +#include "lldb/DataFormatters/CXXFormatterFunctions.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/ValueObject.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { + namespace formatters { + class LibcxxInitializerListSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxInitializerListSyntheticFrontEnd (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 + ~LibcxxInitializerListSyntheticFrontEnd (); + private: + ValueObject* m_start; + ClangASTType m_element_type; + uint32_t m_element_size; + size_t m_num_elements; + std::map<size_t,lldb::ValueObjectSP> m_children; + }; + } +} + +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::LibcxxInitializerListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : +SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_start(NULL), +m_element_type(), +m_element_size(0), +m_num_elements(0), +m_children() +{ + if (valobj_sp) + Update(); +} + +size_t +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren () +{ + static ConstString g___size_("__size_"); + m_num_elements = 0; + ValueObjectSP size_sp(m_backend.GetChildMemberWithName(g___size_, true)); + if (size_sp) + m_num_elements = size_sp->GetValueAsUnsigned(0); + return m_num_elements; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + if (!m_start) + return lldb::ValueObjectSP(); + + auto cached = m_children.find(idx); + if (cached != m_children.end()) + return cached->second; + + uint64_t offset = idx * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + ValueObjectSP child_sp = CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type); + m_children[idx] = child_sp; + return child_sp; +} + +bool +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() +{ + static ConstString g___begin_("__begin_"); + + m_start = nullptr; + m_num_elements = 0; + m_children.clear(); + lldb::TemplateArgumentKind kind; + m_element_type = m_backend.GetClangType().GetTemplateArgument(0, kind); + if (kind != lldb::eTemplateArgumentKindType || false == m_element_type.IsValid()) + return false; + + m_element_size = m_element_type.GetByteSize(); + + if (m_element_size > 0) + m_start = m_backend.GetChildMemberWithName(g___begin_,true).get(); // store raw pointers or end up with a circular dependency + + return false; +} + +bool +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + if (!m_start) + return UINT32_MAX; + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::~LibcxxInitializerListSyntheticFrontEnd () +{ + // this needs to stay around because it's a child object who will follow its parent's life cycle + // delete m_start; +} + +lldb_private::SyntheticChildrenFrontEnd* +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return NULL; + return (new LibcxxInitializerListSyntheticFrontEnd(valobj_sp)); +} + diff --git a/source/DataFormatters/LibCxxList.cpp b/source/DataFormatters/LibCxxList.cpp index 7d6db1a0ccd44..5bb6ce07480f5 100644 --- a/source/DataFormatters/LibCxxList.cpp +++ b/source/DataFormatters/LibCxxList.cpp @@ -25,6 +25,47 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +namespace lldb_private { + namespace formatters { + class LibcxxStdListSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdListSyntheticFrontEnd (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 + ~LibcxxStdListSyntheticFrontEnd (); + private: + bool + HasLoop(size_t); + + size_t m_list_capping_size; + static const bool g_use_loop_detect = true; + size_t m_loop_detected; + lldb::addr_t m_node_address; + ValueObject* m_head; + ValueObject* m_tail; + ClangASTType m_element_type; + size_t m_count; + std::map<size_t,lldb::ValueObjectSP> m_children; + }; + } +} + class ListEntry { public: @@ -150,6 +191,7 @@ private: lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_list_capping_size(0), +m_loop_detected(0), m_node_address(), m_head(NULL), m_tail(NULL), @@ -162,14 +204,15 @@ m_children() } bool -lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop() +lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop(size_t count) { if (g_use_loop_detect == false) return false; // don't bother checking for a loop if we won't actually need to jump nodes if (m_count < 2) return false; - auto steps_left = m_count; + auto steps_left = std::min(count,m_count); + auto steps_left_save = steps_left; ListEntry slow(m_head); ListEntry fast(m_head); while (steps_left-- > 0) @@ -185,6 +228,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop() if (slow == fast) return true; } + m_loop_detected = steps_left_save; return false; } @@ -206,9 +250,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ( } if (m_count != UINT32_MAX) { - if (!HasLoop()) - return m_count; - return m_count = 0; + return m_count; } else { @@ -220,8 +262,6 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ( return 0; if (next_val == prev_val) return 1; - if (HasLoop()) - return 0; uint64_t size = 2; ListEntry current(m_head); while (current.next() && current.next().value() != m_node_address) @@ -248,6 +288,10 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_ if (cached != m_children.end()) return cached->second; + if (m_loop_detected <= idx) + if (HasLoop(idx)) + return lldb::ValueObjectSP(); + ListIterator current(m_head); ValueObjectSP current_sp(current.advance(idx)); if (!current_sp) @@ -264,7 +308,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_ StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); - return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); + return (m_children[idx] = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); } bool @@ -273,6 +317,7 @@ lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update() m_head = m_tail = NULL; m_node_address = 0; m_count = UINT32_MAX; + m_loop_detected = false; Error err; ValueObjectSP backend_addr(m_backend.AddressOf(err)); m_list_capping_size = 0; diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp index e665f29622d81..82e747e2db088 100644 --- a/source/DataFormatters/LibCxxMap.cpp +++ b/source/DataFormatters/LibCxxMap.cpp @@ -25,40 +25,84 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +namespace lldb_private { + namespace formatters { + class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdMapSyntheticFrontEnd (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 + ~LibcxxStdMapSyntheticFrontEnd (); + private: + bool + GetDataType(); + + void + GetValueOffset (const lldb::ValueObjectSP& node); + + ValueObject* m_tree; + ValueObject* m_root_node; + ClangASTType m_element_type; + uint32_t m_skip_size; + size_t m_count; + std::map<size_t,lldb::ValueObjectSP> m_children; + }; + } +} + class MapEntry { public: MapEntry () {} - MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} + explicit MapEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} MapEntry (const MapEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {} - MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} + explicit MapEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} ValueObjectSP - left () + left () const { + static ConstString g_left("__left_"); if (!m_entry_sp) return m_entry_sp; - return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true); + return m_entry_sp->GetChildMemberWithName(g_left, true); } ValueObjectSP - right () + right () const { + static ConstString g_right("__right_"); if (!m_entry_sp) return m_entry_sp; - return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true); + return m_entry_sp->GetChildMemberWithName(g_right, true); } ValueObjectSP - parent () + parent () const { + static ConstString g_parent("__parent_"); if (!m_entry_sp) return m_entry_sp; - return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true); + return m_entry_sp->GetChildMemberWithName(g_parent, true); } uint64_t - value () + value () const { if (!m_entry_sp) return 0; @@ -66,7 +110,7 @@ public: } bool - error () + error () const { if (!m_entry_sp) return true; @@ -74,13 +118,13 @@ public: } bool - null() + null() const { return (value() == 0); } ValueObjectSP - GetEntry () + GetEntry () const { return m_entry_sp; } @@ -119,27 +163,18 @@ public: ValueObjectSP advance (size_t count) { + ValueObjectSP fail(nullptr); if (m_error) - return lldb::ValueObjectSP(); - if (count == 0) - return m_entry.GetEntry(); - if (count == 1) - { - next (); - return m_entry.GetEntry(); - } + return fail; size_t steps = 0; while (count > 0) { - if (m_error) - return lldb::ValueObjectSP(); - next (); - count--; - if (m_entry.null()) - return lldb::ValueObjectSP(); - steps++; - if (steps > m_max_depth) - return lldb::ValueObjectSP(); + next(); + count--, steps++; + if (m_error || + m_entry.null() || + (steps > m_max_depth)) + return fail; } return m_entry.GetEntry(); } @@ -147,16 +182,39 @@ protected: void next () { - m_entry.SetEntry(increment(m_entry.GetEntry())); + if (m_entry.null()) + return; + MapEntry right(m_entry.right()); + if (right.null() == false) + { + m_entry = tree_min(std::move(right)); + return; + } + size_t steps = 0; + while (!is_left_child(m_entry)) + { + if (m_entry.error()) + { + m_error = true; + return; + } + m_entry.SetEntry(m_entry.parent()); + steps++; + if (steps > m_max_depth) + { + m_entry = MapEntry(); + return; + } + } + m_entry = MapEntry(m_entry.parent()); } private: - ValueObjectSP - tree_min (ValueObjectSP x_sp) + MapEntry + tree_min (MapEntry&& x) { - MapEntry x(x_sp); if (x.null()) - return ValueObjectSP(); + return MapEntry(); MapEntry left(x.left()); size_t steps = 0; while (left.null() == false) @@ -164,42 +222,20 @@ private: if (left.error()) { m_error = true; - return lldb::ValueObjectSP(); + return MapEntry(); } - x.SetEntry(left.GetEntry()); + x = left; left.SetEntry(x.left()); steps++; if (steps > m_max_depth) - return lldb::ValueObjectSP(); - } - return x.GetEntry(); - } - - ValueObjectSP - tree_max (ValueObjectSP x_sp) - { - MapEntry x(x_sp); - if (x.null()) - return ValueObjectSP(); - MapEntry right(x.right()); - size_t steps = 0; - while (right.null() == false) - { - if (right.error()) - return lldb::ValueObjectSP(); - x.SetEntry(right.GetEntry()); - right.SetEntry(x.right()); - steps++; - if (steps > m_max_depth) - return lldb::ValueObjectSP(); + return MapEntry(); } - return x.GetEntry(); + return x; } - + bool - is_left_child (ValueObjectSP x_sp) + is_left_child (const MapEntry& x) { - MapEntry x(x_sp); if (x.null()) return false; MapEntry rhs(x.parent()); @@ -207,31 +243,6 @@ private: return x.value() == rhs.value(); } - ValueObjectSP - increment (ValueObjectSP x_sp) - { - MapEntry node(x_sp); - if (node.null()) - return ValueObjectSP(); - MapEntry right(node.right()); - if (right.null() == false) - return tree_min(right.GetEntry()); - size_t steps = 0; - while (!is_left_child(node.GetEntry())) - { - if (node.error()) - { - m_error = true; - return lldb::ValueObjectSP(); - } - node.SetEntry(node.parent()); - steps++; - if (steps > m_max_depth) - return lldb::ValueObjectSP(); - } - return node.parent(); - } - MapEntry m_entry; size_t m_max_depth; bool m_error; @@ -302,6 +313,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const l lldb::ValueObjectSP lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx) { + static ConstString g___cc("__cc"); + static ConstString g___nc("__nc"); + + if (idx >= CalculateNumChildren()) return lldb::ValueObjectSP(); if (m_tree == NULL || m_root_node == NULL) @@ -375,7 +390,31 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t } StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); - return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type)); + auto potential_child_sp = CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type); + if (potential_child_sp) + { + switch (potential_child_sp->GetNumChildren()) + { + case 1: + { + auto child0_sp = potential_child_sp->GetChildAtIndex(0, true); + if (child0_sp && child0_sp->GetName() == g___cc) + potential_child_sp = child0_sp; + break; + } + case 2: + { + auto child0_sp = potential_child_sp->GetChildAtIndex(0, true); + auto child1_sp = potential_child_sp->GetChildAtIndex(1, true); + if (child0_sp && child0_sp->GetName() == g___cc && + child1_sp && child1_sp->GetName() == g___nc) + potential_child_sp = child0_sp; + break; + } + } + potential_child_sp->SetName(ConstString(name.GetData())); + } + return (m_children[idx] = potential_child_sp); } bool diff --git a/source/DataFormatters/LibCxxUnorderedMap.cpp b/source/DataFormatters/LibCxxUnorderedMap.cpp index bf68f20955b54..da2a88966f5ed 100644 --- a/source/DataFormatters/LibCxxUnorderedMap.cpp +++ b/source/DataFormatters/LibCxxUnorderedMap.cpp @@ -25,6 +25,41 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +namespace lldb_private { + namespace formatters { + class LibcxxStdUnorderedMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdUnorderedMapSyntheticFrontEnd (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 + ~LibcxxStdUnorderedMapSyntheticFrontEnd (); + private: + + ValueObject* m_tree; + size_t m_num_elements; + ValueObject* m_next_element; + std::map<size_t,lldb::ValueObjectSP> m_children; + std::vector<std::pair<ValueObject*, uint64_t> > m_elements_cache; + }; + } +} + lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::LibcxxStdUnorderedMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_tree(NULL), diff --git a/source/DataFormatters/LibCxxVector.cpp b/source/DataFormatters/LibCxxVector.cpp new file mode 100644 index 0000000000000..26c62afbed2b9 --- /dev/null +++ b/source/DataFormatters/LibCxxVector.cpp @@ -0,0 +1,157 @@ +//===-- LibCxxVector.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/lldb-python.h" + +#include "lldb/DataFormatters/CXXFormatterFunctions.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/ValueObject.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { + namespace formatters { + class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + LibcxxStdVectorSyntheticFrontEnd (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 + ~LibcxxStdVectorSyntheticFrontEnd (); + private: + ValueObject* m_start; + ValueObject* m_finish; + ClangASTType m_element_type; + uint32_t m_element_size; + std::map<size_t,lldb::ValueObjectSP> m_children; + }; + } +} + +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : +SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_start(NULL), +m_finish(NULL), +m_element_type(), +m_element_size(0), +m_children() +{ + if (valobj_sp) + Update(); +} + +size_t +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren () +{ + if (!m_start || !m_finish) + return 0; + uint64_t start_val = m_start->GetValueAsUnsigned(0); + uint64_t finish_val = m_finish->GetValueAsUnsigned(0); + + if (start_val == 0 || finish_val == 0) + return 0; + + if (start_val >= finish_val) + return 0; + + size_t num_children = (finish_val - start_val); + if (num_children % m_element_size) + return 0; + return num_children/m_element_size; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (size_t idx) +{ + if (!m_start || !m_finish) + return lldb::ValueObjectSP(); + + auto cached = m_children.find(idx); + if (cached != m_children.end()) + return cached->second; + + uint64_t offset = idx * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + ValueObjectSP child_sp = CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type); + m_children[idx] = child_sp; + return child_sp; +} + +bool +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() +{ + m_start = m_finish = NULL; + m_children.clear(); + ValueObjectSP data_type_finder_sp(m_backend.GetChildMemberWithName(ConstString("__end_cap_"),true)); + if (!data_type_finder_sp) + return false; + data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(ConstString("__first_"),true); + if (!data_type_finder_sp) + return false; + m_element_type = data_type_finder_sp->GetClangType().GetPointeeType(); + m_element_size = m_element_type.GetByteSize(); + + if (m_element_size > 0) + { + // store raw pointers or end up with a circular dependency + m_start = m_backend.GetChildMemberWithName(ConstString("__begin_"),true).get(); + m_finish = m_backend.GetChildMemberWithName(ConstString("__end_"),true).get(); + } + return false; +} + +bool +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::MightHaveChildren () +{ + return true; +} + +size_t +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + if (!m_start || !m_finish) + return UINT32_MAX; + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::~LibcxxStdVectorSyntheticFrontEnd () +{ + // these need to stay around because they are child objects who will follow their parent's life cycle + // delete m_start; + // delete m_finish; +} + +lldb_private::SyntheticChildrenFrontEnd* +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) +{ + if (!valobj_sp) + return NULL; + return (new LibcxxStdVectorSyntheticFrontEnd(valobj_sp)); +} + diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp index f2d617323cca5..b8f031ceeb2fd 100644 --- a/source/DataFormatters/LibStdcpp.cpp +++ b/source/DataFormatters/LibStdcpp.cpp @@ -276,7 +276,7 @@ lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex if (m_pair_address != 0 && m_pair_type) { if (!m_pair_sp) - m_pair_sp = ValueObject::CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type); + m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type); if (m_pair_sp) return m_pair_sp->GetChildAtIndex(idx, true); } diff --git a/source/DataFormatters/NSArray.cpp b/source/DataFormatters/NSArray.cpp index 16635381f94fd..e242155f4fef9 100644 --- a/source/DataFormatters/NSArray.cpp +++ b/source/DataFormatters/NSArray.cpp @@ -228,7 +228,7 @@ namespace lldb_private { } bool -lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -341,10 +341,10 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx object_at_idx += (pyhs_idx * m_ptr_size); StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); - lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), - object_at_idx, - m_exe_ctx_ref, - m_id_type); + lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(), + object_at_idx, + m_exe_ctx_ref, + m_id_type); m_children.push_back(retval_sp); return retval_sp; } @@ -604,7 +604,10 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx return lldb::ValueObjectSP(); StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); - lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type); + lldb::ValueObjectSP retval_sp = CreateValueObjectFromAddress(idx_name.GetData(), + object_at_idx, + m_exe_ctx_ref, + m_id_type); m_children.push_back(retval_sp); return retval_sp; } @@ -624,7 +627,7 @@ SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCre ClangASTType valobj_type(valobj_sp->GetClangType()); Flags flags(valobj_type.GetTypeInfo()); - if (flags.IsClear(ClangASTType::eTypeIsPointer)) + if (flags.IsClear(eTypeIsPointer)) { Error error; valobj_sp = valobj_sp->AddressOf(error); diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp index ddd1e2e7ca90c..fdac05192c467 100644 --- a/source/DataFormatters/NSDictionary.cpp +++ b/source/DataFormatters/NSDictionary.cpp @@ -36,52 +36,167 @@ GetLLDBNSPairType (TargetSP target_sp) if (target_ast_context) { - clang::ASTContext *ast = target_ast_context->getASTContext(); + ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); - if (ast) + clang_type = target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(g___lldb_autogen_nspair); + + if (!clang_type) { - const char* type_name = "__lldb_autogen_nspair"; + clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, lldb::eLanguageTypeC); - clang::IdentifierInfo &myIdent = ast->Idents.get(type_name); - clang::DeclarationName myName = ast->DeclarationNames.getIdentifier(&myIdent); - - clang::DeclContext::lookup_const_result result = ast->getTranslationUnitDecl()->lookup(myName); - - for (clang::NamedDecl *named_decl : result) - { - if (const clang::CXXRecordDecl *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(named_decl)) - { - clang_type.SetClangType(ast, clang::QualType(record_decl->getTypeForDecl(), 0)); - break; - } - else - { - // somebody else (the user?) has defined a type with the magic name already - fail!!! - return clang_type; - } - } - - if (!clang_type) + if (clang_type) { - clang_type = target_ast_context->CreateRecordType(NULL, lldb::eAccessPublic, type_name, clang::TTK_Struct, lldb::eLanguageTypeC); - - if (clang_type) - { - clang_type.StartTagDeclarationDefinition(); - ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID); - clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0); - clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0); - clang_type.CompleteTagDeclarationDefinition(); - } + clang_type.StartTagDeclarationDefinition(); + ClangASTType id_clang_type = target_ast_context->GetBasicType (eBasicTypeObjCID); + clang_type.AddFieldToRecordType("key", id_clang_type, lldb::eAccessPublic, 0); + clang_type.AddFieldToRecordType("value", id_clang_type, lldb::eAccessPublic, 0); + clang_type.CompleteTagDeclarationDefinition(); } } } return clang_type; } +namespace lldb_private { + namespace formatters { + class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + private: + struct DataDescriptor_32 + { + uint32_t _used : 26; + uint32_t _szidx : 6; + }; + struct DataDescriptor_64 + { + uint64_t _used : 58; + uint32_t _szidx : 6; + }; + + struct DictionaryItemDescriptor + { + lldb::addr_t key_ptr; + lldb::addr_t val_ptr; + lldb::ValueObjectSP valobj_sp; + }; + + public: + NSDictionaryISyntheticFrontEnd (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 + ~NSDictionaryISyntheticFrontEnd (); + private: + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + lldb::ByteOrder m_order; + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + lldb::addr_t m_data_ptr; + ClangASTType m_pair_type; + std::vector<DictionaryItemDescriptor> m_children; + }; + + class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + private: + struct DataDescriptor_32 + { + uint32_t _used : 26; + uint32_t _kvo : 1; + uint32_t _size; + uint32_t _mutations; + uint32_t _objs_addr; + uint32_t _keys_addr; + }; + struct DataDescriptor_64 + { + uint64_t _used : 58; + uint32_t _kvo : 1; + uint64_t _size; + uint64_t _mutations; + uint64_t _objs_addr; + uint64_t _keys_addr; + }; + struct DictionaryItemDescriptor + { + lldb::addr_t key_ptr; + lldb::addr_t val_ptr; + lldb::ValueObjectSP valobj_sp; + }; + public: + NSDictionaryMSyntheticFrontEnd (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 + ~NSDictionaryMSyntheticFrontEnd (); + private: + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + lldb::ByteOrder m_order; + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + ClangASTType m_pair_type; + std::vector<DictionaryItemDescriptor> m_children; + }; + + class NSDictionaryCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + NSDictionaryCodeRunningSyntheticFrontEnd (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 + ~NSDictionaryCodeRunningSyntheticFrontEnd (); + }; + } +} + template<bool name_entries> bool -lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -407,7 +522,10 @@ lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_ StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); DataExtractor data(buffer_sp, m_order, m_ptr_size); - dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type); + dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_pair_type); } return dict_item.valobj_sp; } @@ -571,13 +689,16 @@ lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_ StreamString idx_name; idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); DataExtractor data(buffer_sp, m_order, m_ptr_size); - dict_item.valobj_sp = ValueObject::CreateValueObjectFromData(idx_name.GetData(), data, m_exe_ctx_ref, m_pair_type); + dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_pair_type); } return dict_item.valobj_sp; } template bool -lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ; +lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ; template bool -lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ; +lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ; diff --git a/source/DataFormatters/NSIndexPath.cpp b/source/DataFormatters/NSIndexPath.cpp new file mode 100644 index 0000000000000..ee9583ef4cc1a --- /dev/null +++ b/source/DataFormatters/NSIndexPath.cpp @@ -0,0 +1,309 @@ +//===-- NSIndexPath.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/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Symbol/ClangASTContext.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd +{ +public: + NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : + SyntheticChildrenFrontEnd (*valobj_sp.get()), + m_ptr_size(0), + m_ast_ctx(nullptr), + m_uint_star_type() + { + m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize(); + } + + virtual size_t + CalculateNumChildren () + { + return m_impl.GetNumIndexes(); + } + + virtual lldb::ValueObjectSP + GetChildAtIndex (size_t idx) + { + return m_impl.GetIndexAtIndex(idx, m_uint_star_type); + } + + virtual bool + Update() + { + m_impl.m_mode = Mode::Invalid; + + m_ast_ctx = ClangASTContext::GetASTContext(m_backend.GetClangType().GetASTContext()); + if (!m_ast_ctx) + return false; + + m_uint_star_type = m_ast_ctx->GetPointerSizedIntType(false); + + static ConstString g__indexes("_indexes"); + static ConstString g__length("_length"); + + ProcessSP process_sp = m_backend.GetProcessSP(); + if (!process_sp) + return false; + + ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); + + if (!runtime) + return false; + + ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend)); + + if (!descriptor.get() || !descriptor->IsValid()) + return false; + + uint64_t info_bits(0),value_bits(0),payload(0); + + if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) + { + m_impl.m_mode = Mode::Inlined; + m_impl.m_inlined.SetIndexes(payload, *process_sp); + } + else + { + ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id; + ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id; + + bool has_indexes(false),has_length(false); + + for (size_t x = 0; + x < descriptor->GetNumIVars(); + x++) + { + const auto& ivar = descriptor->GetIVarAtIndex(x); + if (ivar.m_name == g__indexes) + { + _indexes_id = ivar; + has_indexes = true; + } + else if (ivar.m_name == g__length) + { + _length_id = ivar; + has_length = true; + } + + if (has_length && has_indexes) + break; + } + + if (has_length && has_indexes) + { + m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset, + m_uint_star_type.GetPointerType(), + true).get(); + ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset, + m_uint_star_type, + true)); + if (length_sp) + { + m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0); + if (m_impl.m_outsourced.m_indexes) + m_impl.m_mode = Mode::Outsourced; + } + } + } + return false; + } + + virtual bool + MightHaveChildren () + { + if (m_impl.m_mode == Mode::Invalid) + return false; + return true; + } + + virtual size_t + GetIndexOfChildWithName (const ConstString &name) + { + const char* item_name = name.GetCString(); + uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; + } + + virtual lldb::ValueObjectSP + GetSyntheticValue () { return nullptr; } + + virtual + ~NSIndexPathSyntheticFrontEnd () {} + +protected: + ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp; + + enum class Mode { + Inlined, + Outsourced, + Invalid + }; + + struct Impl { + Mode m_mode; + + size_t + GetNumIndexes () + { + switch (m_mode) + { + case Mode::Inlined: + return m_inlined.GetNumIndexes(); + case Mode::Outsourced: + return m_outsourced.m_count; + default: + return 0; + } + } + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx, const ClangASTType& desired_type) + { + if (idx >= GetNumIndexes()) + return nullptr; + switch (m_mode) + { + default: return nullptr; + case Mode::Inlined: + return m_inlined.GetIndexAtIndex (idx, desired_type); + case Mode::Outsourced: + return m_outsourced.GetIndexAtIndex (idx); + } + } + + struct InlinedIndexes { + public: + void SetIndexes(uint64_t value, Process& p) + { + m_indexes = value; + _lengthForInlinePayload(p.GetAddressByteSize()); + m_process = &p; + } + + size_t + GetNumIndexes () + { + return m_count; + } + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx, const ClangASTType& desired_type) + { + std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx)); + if (!value.second) + return nullptr; + Value v; + if (m_ptr_size == 8) + { + Scalar scalar( (unsigned long long)value.first ); + v = Value(scalar); + } + else + { + Scalar scalar( (unsigned int)value.first ); + v = Value(scalar); + } + v.SetClangType(desired_type); + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData())); + } + + private: + uint64_t m_indexes; + size_t m_count; + uint32_t m_ptr_size; + Process *m_process; + + // cfr. Foundation for the details of this code + size_t _lengthForInlinePayload(uint32_t ptr_size) { + m_ptr_size = ptr_size; + if (m_ptr_size == 8) + m_count = ((m_indexes >> 3) & 0x7); + else + m_count = ((m_indexes >> 3) & 0x3); + return m_count; + } + + std::pair<uint64_t, bool> + _indexAtPositionForInlinePayload(size_t pos) { + if (m_ptr_size == 8) + { + switch (pos) { + case 5: return {((m_indexes >> 51) & 0x1ff),true}; + case 4: return {((m_indexes >> 42) & 0x1ff),true}; + case 3: return {((m_indexes >> 33) & 0x1ff),true}; + case 2: return {((m_indexes >> 24) & 0x1ff),true}; + case 1: return {((m_indexes >> 15) & 0x1ff),true}; + case 0: return {((m_indexes >> 6) & 0x1ff),true}; + } + } + else + { + switch (pos) { + case 2: return {((m_indexes >> 23) & 0x1ff),true}; + case 1: return {((m_indexes >> 14) & 0x1ff),true}; + case 0: return {((m_indexes >> 5) & 0x1ff),true}; + } + } + return {0,false}; + } + + }; + struct OutsourcedIndexes { + ValueObject *m_indexes; + size_t m_count; + + lldb::ValueObjectSP + GetIndexAtIndex (size_t idx) + { + if (m_indexes) + { + ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMemberFromPointer(idx, true)); + return index_sp; + } + return nullptr; + } + }; + + union { + struct InlinedIndexes m_inlined; + struct OutsourcedIndexes m_outsourced; + }; + } m_impl; + + uint32_t m_ptr_size; + ClangASTContext* m_ast_ctx; + ClangASTType m_uint_star_type; +}; + +namespace lldb_private { + namespace formatters { + + SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) + { + if (valobj_sp) + return new NSIndexPathSyntheticFrontEnd(valobj_sp); + return nullptr; + } + } +} diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp index 3c7c003ed95ac..194d1bd29ea13 100644 --- a/source/DataFormatters/NSSet.cpp +++ b/source/DataFormatters/NSSet.cpp @@ -25,9 +25,165 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +namespace lldb_private { + namespace formatters { + class NSSetISyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + private: + struct DataDescriptor_32 + { + uint32_t _used : 26; + uint32_t _szidx : 6; + }; + struct DataDescriptor_64 + { + uint64_t _used : 58; + uint32_t _szidx : 6; + }; + + struct SetItemDescriptor + { + lldb::addr_t item_ptr; + lldb::ValueObjectSP valobj_sp; + }; + + public: + NSSetISyntheticFrontEnd (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 + ~NSSetISyntheticFrontEnd (); + private: + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + lldb::addr_t m_data_ptr; + std::vector<SetItemDescriptor> m_children; + }; + + class NSOrderedSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + private: + + public: + NSOrderedSetSyntheticFrontEnd (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 + ~NSOrderedSetSyntheticFrontEnd (); + private: + uint32_t m_count; + std::map<uint32_t,lldb::ValueObjectSP> m_children; + }; + + class NSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + private: + struct DataDescriptor_32 + { + uint32_t _used : 26; + uint32_t _size; + uint32_t _mutations; + uint32_t _objs_addr; + }; + struct DataDescriptor_64 + { + uint64_t _used : 58; + uint64_t _size; + uint64_t _mutations; + uint64_t _objs_addr; + }; + struct SetItemDescriptor + { + lldb::addr_t item_ptr; + lldb::ValueObjectSP valobj_sp; + }; + public: + NSSetMSyntheticFrontEnd (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 + ~NSSetMSyntheticFrontEnd (); + private: + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + std::vector<SetItemDescriptor> m_children; + }; + + class NSSetCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd + { + public: + NSSetCodeRunningSyntheticFrontEnd (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 + ~NSSetCodeRunningSyntheticFrontEnd (); + }; + } +} + template<bool cf_style> bool -lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream) +lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options) { ProcessSP process_sp = valobj.GetProcessSP(); if (!process_sp) @@ -313,10 +469,10 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx) process_sp->GetAddressByteSize()); set_item.valobj_sp = - ValueObject::CreateValueObjectFromData(idx_name.GetData(), - data, - m_exe_ctx_ref, - m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); + CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); } return set_item.valobj_sp; } @@ -481,10 +637,10 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) process_sp->GetAddressByteSize()); set_item.valobj_sp = - ValueObject::CreateValueObjectFromData(idx_name.GetData(), - data, - m_exe_ctx_ref, - m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); + CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); } return set_item.valobj_sp; } @@ -557,7 +713,7 @@ lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticF } template bool -lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream); +lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); template bool -lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream); +lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options); diff --git a/source/DataFormatters/StringPrinter.cpp b/source/DataFormatters/StringPrinter.cpp new file mode 100644 index 0000000000000..3af5931ad716f --- /dev/null +++ b/source/DataFormatters/StringPrinter.cpp @@ -0,0 +1,650 @@ +//===-- StringPrinter.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/StringPrinter.h" + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "llvm/Support/ConvertUTF.h" + +#include <ctype.h> +#include <functional> +#include <locale> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +// I can't use a std::unique_ptr for this because the Deleter is a template argument there +// and I want the same type to represent both pointers I want to free and pointers I don't need +// to free - which is what this class essentially is +// It's very specialized to the needs of this file, and not suggested for general use +template <typename T = uint8_t, typename U = char, typename S = size_t> +struct StringPrinterBufferPointer +{ +public: + + typedef std::function<void(const T*)> Deleter; + + StringPrinterBufferPointer (std::nullptr_t ptr) : + m_data(nullptr), + m_size(0), + m_deleter() + {} + + StringPrinterBufferPointer(const T* bytes, S size, Deleter deleter = nullptr) : + m_data(bytes), + m_size(size), + m_deleter(deleter) + {} + + StringPrinterBufferPointer(const U* bytes, S size, Deleter deleter = nullptr) : + m_data((T*)bytes), + m_size(size), + m_deleter(deleter) + {} + + StringPrinterBufferPointer(StringPrinterBufferPointer&& rhs) : + m_data(rhs.m_data), + m_size(rhs.m_size), + m_deleter(rhs.m_deleter) + { + rhs.m_data = nullptr; + } + + StringPrinterBufferPointer(const StringPrinterBufferPointer& rhs) : + m_data(rhs.m_data), + m_size(rhs.m_size), + m_deleter(rhs.m_deleter) + { + rhs.m_data = nullptr; // this is why m_data has to be mutable + } + + const T* + GetBytes () const + { + return m_data; + } + + const S + GetSize () const + { + return m_size; + } + + ~StringPrinterBufferPointer () + { + if (m_data && m_deleter) + m_deleter(m_data); + m_data = nullptr; + } + + StringPrinterBufferPointer& + operator = (const StringPrinterBufferPointer& rhs) + { + if (m_data && m_deleter) + m_deleter(m_data); + m_data = rhs.m_data; + m_size = rhs.m_size; + m_deleter = rhs.m_deleter; + rhs.m_data = nullptr; + return *this; + } + +private: + mutable const T* m_data; + size_t m_size; + Deleter m_deleter; +}; + +// we define this for all values of type but only implement it for those we care about +// that's good because we get linker errors for any unsupported type +template <StringElementType type> +static StringPrinterBufferPointer<> +GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next); + +// mimic isprint() for Unicode codepoints +static bool +isprint(char32_t codepoint) +{ + if (codepoint <= 0x1F || codepoint == 0x7F) // C0 + { + return false; + } + if (codepoint >= 0x80 && codepoint <= 0x9F) // C1 + { + return false; + } + if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators + { + return false; + } + if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control + { + return false; + } + if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials + { + return false; + } + return true; +} + +template <> +StringPrinterBufferPointer<> +GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) +{ + StringPrinterBufferPointer<> retval = {nullptr}; + + switch (*buffer) + { + case 0: + retval = {"\\0",2}; + break; + case '\a': + retval = {"\\a",2}; + break; + case '\b': + retval = {"\\b",2}; + break; + case '\f': + retval = {"\\f",2}; + break; + case '\n': + retval = {"\\n",2}; + break; + case '\r': + retval = {"\\r",2}; + break; + case '\t': + retval = {"\\t",2}; + break; + case '\v': + retval = {"\\v",2}; + break; + case '\"': + retval = {"\\\"",2}; + break; + case '\\': + retval = {"\\\\",2}; + break; + default: + if (isprint(*buffer)) + retval = {buffer,1}; + else + { + retval = { new uint8_t[5],4,[] (const uint8_t* c) {delete[] c;} }; + sprintf((char*)retval.GetBytes(),"\\x%02x",*buffer); + break; + } + } + + next = buffer + 1; + return retval; +} + +static char32_t +ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1) +{ + return (c0-192)*64+(c1-128); +} +static char32_t +ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2) +{ + return (c0-224)*4096+(c1-128)*64+(c2-128); +} +static char32_t +ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3) +{ + return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128); +} + +template <> +StringPrinterBufferPointer<> +GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) +{ + StringPrinterBufferPointer<> retval {nullptr}; + + unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer); + + if (1+buffer_end-buffer < utf8_encoded_len) + { + // I don't have enough bytes - print whatever I have left + retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)}; + next = buffer_end+1; + return retval; + } + + char32_t codepoint = 0; + switch (utf8_encoded_len) + { + case 1: + // this is just an ASCII byte - ask ASCII + return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); + case 2: + codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1)); + break; + case 3: + codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2)); + break; + case 4: + codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3)); + break; + default: + // this is probably some bogus non-character thing + // just print it as-is and hope to sync up again soon + retval = {buffer,1}; + next = buffer+1; + return retval; + } + + if (codepoint) + { + switch (codepoint) + { + case 0: + retval = {"\\0",2}; + break; + case '\a': + retval = {"\\a",2}; + break; + case '\b': + retval = {"\\b",2}; + break; + case '\f': + retval = {"\\f",2}; + break; + case '\n': + retval = {"\\n",2}; + break; + case '\r': + retval = {"\\r",2}; + break; + case '\t': + retval = {"\\t",2}; + break; + case '\v': + retval = {"\\v",2}; + break; + case '\"': + retval = {"\\\"",2}; + break; + case '\\': + retval = {"\\\\",2}; + break; + default: + if (isprint(codepoint)) + retval = {buffer,utf8_encoded_len}; + else + { + retval = { new uint8_t[11],10,[] (const uint8_t* c) {delete[] c;} }; + sprintf((char*)retval.GetBytes(),"\\U%08x",codepoint); + break; + } + } + + next = buffer + utf8_encoded_len; + return retval; + } + + // this should not happen - but just in case.. try to resync at some point + retval = {buffer,1}; + next = buffer+1; + return retval; +} + +// Given a sequence of bytes, this function returns: +// a sequence of bytes to actually print out + a length +// the following unscanned position of the buffer is in next +static StringPrinterBufferPointer<> +GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) +{ + if (!buffer) + return {nullptr}; + + switch (type) + { + case StringElementType::ASCII: + return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); + case StringElementType::UTF8: + return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next); + default: + return {nullptr}; + } +} + +// use this call if you already have an LLDB-side buffer for the data +template<typename SourceDataType> +static bool +DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, + const SourceDataType*, + UTF8**, + UTF8*, + ConversionFlags), + const DataExtractor& data, + Stream& stream, + char prefix_token, + char quote, + uint32_t sourceSize, + bool escapeNonPrintables) +{ + if (prefix_token != 0) + stream.Printf("%c",prefix_token); + if (quote != 0) + stream.Printf("%c",quote); + if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) + { + const int bufferSPSize = data.GetByteSize(); + if (sourceSize == 0) + { + const int origin_encoding = 8*sizeof(SourceDataType); + sourceSize = bufferSPSize/(origin_encoding / 4); + } + + SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart(); + SourceDataType *data_end_ptr = data_ptr + sourceSize; + + while (data_ptr < data_end_ptr) + { + if (!*data_ptr) + { + data_end_ptr = data_ptr; + break; + } + data_ptr++; + } + + data_ptr = (SourceDataType*)data.GetDataStart(); + + lldb::DataBufferSP utf8_data_buffer_sp; + UTF8* utf8_data_ptr = nullptr; + UTF8* utf8_data_end_ptr = nullptr; + + if (ConvertFunction) + { + utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0)); + utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); + utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize(); + ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); + utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr + } + else + { + // just copy the pointers - the cast is necessary to make the compiler happy + // but this should only happen if we are reading UTF8 data + utf8_data_ptr = (UTF8*)data_ptr; + utf8_data_end_ptr = (UTF8*)data_end_ptr; + } + + // since we tend to accept partial data (and even partially malformed data) + // we might end up with no NULL terminator before the end_ptr + // hence we need to take a slower route and ensure we stay within boundaries + for (;utf8_data_ptr < utf8_data_end_ptr;) + { + if (!*utf8_data_ptr) + break; + + if (escapeNonPrintables) + { + uint8_t* next_data = nullptr; + auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data); + auto printable_bytes = printable.GetBytes(); + auto printable_size = printable.GetSize(); + if (!printable_bytes || !next_data) + { + // GetPrintable() failed on us - print one byte in a desperate resync attempt + printable_bytes = utf8_data_ptr; + printable_size = 1; + next_data = utf8_data_ptr+1; + } + for (unsigned c = 0; c < printable_size; c++) + stream.Printf("%c", *(printable_bytes+c)); + utf8_data_ptr = (uint8_t*)next_data; + } + else + { + stream.Printf("%c",*utf8_data_ptr); + utf8_data_ptr++; + } + } + } + if (quote != 0) + stream.Printf("%c",quote); + return true; +} + +lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) : + ReadStringAndDumpToStreamOptions() +{ + SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); +} + +lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) : + ReadBufferAndDumpToStreamOptions() +{ + SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); +} + + +namespace lldb_private +{ + +namespace formatters +{ + +template <> +bool +ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options) +{ + assert(options.GetStream() && "need a Stream to print the string to"); + Error my_error; + size_t my_data_read; + + ProcessSP process_sp(options.GetProcessSP()); + + if (process_sp.get() == nullptr || options.GetLocation() == 0) + return false; + + size_t size; + + if (options.GetSourceSize() == 0) + size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + else if (!options.GetIgnoreMaxLength()) + size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary()); + else + size = options.GetSourceSize(); + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); + + my_data_read = process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error); + + if (my_error.Fail()) + return false; + + char prefix_token = options.GetPrefixToken(); + char quote = options.GetQuote(); + + if (prefix_token != 0) + options.GetStream()->Printf("%c%c",prefix_token,quote); + else if (quote != 0) + options.GetStream()->Printf("%c",quote); + + uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize(); + + // since we tend to accept partial data (and even partially malformed data) + // we might end up with no NULL terminator before the end_ptr + // hence we need to take a slower route and ensure we stay within boundaries + for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);) + { + if (options.GetEscapeNonPrintables()) + { + uint8_t* next_data = nullptr; + auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data); + auto printable_bytes = printable.GetBytes(); + auto printable_size = printable.GetSize(); + if (!printable_bytes || !next_data) + { + // GetPrintable() failed on us - print one byte in a desperate resync attempt + printable_bytes = data; + printable_size = 1; + next_data = data+1; + } + for (unsigned c = 0; c < printable_size; c++) + options.GetStream()->Printf("%c", *(printable_bytes+c)); + data = (uint8_t*)next_data; + } + else + { + options.GetStream()->Printf("%c",*data); + data++; + } + } + + if (quote != 0) + options.GetStream()->Printf("%c",quote); + + return true; +} + +template<typename SourceDataType> +static bool +ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, + ConversionResult (*ConvertFunction) (const SourceDataType**, + const SourceDataType*, + UTF8**, + UTF8*, + ConversionFlags)) +{ + assert(options.GetStream() && "need a Stream to print the string to"); + + if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS) + return false; + + lldb::ProcessSP process_sp(options.GetProcessSP()); + + if (!process_sp) + return false; + + const int type_width = sizeof(SourceDataType); + const int origin_encoding = 8 * type_width ; + if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) + return false; + // if not UTF8, I need a conversion function to return proper UTF8 + if (origin_encoding != 8 && !ConvertFunction) + return false; + + if (!options.GetStream()) + return false; + + uint32_t sourceSize = options.GetSourceSize(); + bool needs_zero_terminator = options.GetNeedsZeroTermination(); + + if (!sourceSize) + { + sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + needs_zero_terminator = true; + } + else + sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary()); + + const int bufferSPSize = sourceSize * type_width; + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); + + if (!buffer_sp->GetBytes()) + return false; + + Error error; + char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes()); + + size_t data_read = 0; + if (needs_zero_terminator) + data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width); + else + data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error); + + if (error.Fail()) + { + options.GetStream()->Printf("unable to read data"); + return true; + } + + DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); + + return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables()); +} + +template <> +bool +ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options) +{ + return ReadUTFBufferAndDumpToStream<UTF8>(options, + nullptr); +} + +template <> +bool +ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options) +{ + return ReadUTFBufferAndDumpToStream<UTF16>(options, + ConvertUTF16toUTF8); +} + +template <> +bool +ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options) +{ + return ReadUTFBufferAndDumpToStream<UTF32>(options, + ConvertUTF32toUTF8); +} + +template <> +bool +ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options) +{ + assert(options.GetStream() && "need a Stream to print the string to"); + + return DumpUTFBufferToStream<UTF8>(nullptr, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); +} + +template <> +bool +ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options) +{ + // treat ASCII the same as UTF8 + // FIXME: can we optimize ASCII some more? + return ReadBufferAndDumpToStream<StringElementType::UTF8>(options); +} + +template <> +bool +ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options) +{ + assert(options.GetStream() && "need a Stream to print the string to"); + + return DumpUTFBufferToStream(ConvertUTF16toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); +} + +template <> +bool +ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options) +{ + assert(options.GetStream() && "need a Stream to print the string to"); + + return DumpUTFBufferToStream(ConvertUTF32toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); +} + +} // namespace formatters + +} // namespace lldb_private diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp index 322d1cf55437e..3df6884fe679e 100644 --- a/source/DataFormatters/TypeCategory.cpp +++ b/source/DataFormatters/TypeCategory.cpp @@ -27,6 +27,7 @@ m_filter_cont("filter","regex-filter",clist), #ifndef LLDB_DISABLE_PYTHON m_synth_cont("synth","regex-synth",clist), #endif +m_validator_cont("validator","regex-validator",clist), m_enabled(false), m_change_listener(clist), m_mutex(Mutex::eMutexTypeRecursive), @@ -129,6 +130,22 @@ TypeCategoryImpl::Get (ValueObject& valobj, return false; } +bool +TypeCategoryImpl::Get (ValueObject& valobj, + const FormattersMatchVector& candidates, + lldb::TypeValidatorImplSP& entry, + uint32_t* reason) +{ + if (!IsEnabled()) + return false; + if (GetTypeValidatorsContainer()->Get(candidates, entry, reason)) + return true; + bool regex = GetRegexTypeValidatorsContainer()->Get(candidates, entry, reason); + if (regex && reason) + *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; + return regex; +} + void TypeCategoryImpl::Clear (FormatCategoryItems items) { @@ -153,6 +170,11 @@ TypeCategoryImpl::Clear (FormatCategoryItems items) if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) GetRegexTypeSyntheticsContainer()->Clear(); #endif + + if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator ) + GetTypeValidatorsContainer()->Clear(); + if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator ) + GetRegexTypeValidatorsContainer()->Clear(); } bool @@ -182,6 +204,12 @@ TypeCategoryImpl::Delete (ConstString name, if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) success = GetRegexTypeSyntheticsContainer()->Delete(name) || success; #endif + + if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator ) + success = GetTypeValidatorsContainer()->Delete(name) || success; + if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator ) + success = GetRegexTypeValidatorsContainer()->Delete(name) || success; + return success; } @@ -211,6 +239,12 @@ TypeCategoryImpl::GetCount (FormatCategoryItems items) if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) count += GetRegexTypeSyntheticsContainer()->GetCount(); #endif + + if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator ) + count += GetTypeValidatorsContainer()->GetCount(); + if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator ) + count += GetRegexTypeValidatorsContainer()->GetCount(); + return count; } @@ -230,6 +264,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, #ifndef LLDB_DISABLE_PYTHON ScriptedSyntheticChildren::SharedPointer synth_sp; #endif + TypeValidatorImpl::SharedPointer validator_sp; if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue ) { @@ -324,6 +359,30 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, } } #endif + + if ( (items & eFormatCategoryItemValidator) == eFormatCategoryItemValidator ) + { + if (GetTypeValidatorsContainer()->Get(type_name, validator_sp)) + { + if (matching_category) + *matching_category = m_name.GetCString(); + if (matching_type) + *matching_type = eFormatCategoryItemValidator; + return true; + } + } + if ( (items & eFormatCategoryItemRegexValidator) == eFormatCategoryItemRegexValidator ) + { + if (GetRegexTypeValidatorsContainer()->Get(type_name, validator_sp)) + { + if (matching_category) + *matching_category = m_name.GetCString(); + if (matching_type) + *matching_type = eFormatCategoryItemRegexValidator; + return true; + } + } + return false; } @@ -393,6 +452,22 @@ TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp) } #endif +TypeCategoryImpl::ValidatorContainer::MapValueType +TypeCategoryImpl::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp) +{ + ValidatorContainer::MapValueType retval; + + if (type_sp) + { + if (type_sp->IsRegex()) + GetRegexTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval); + else + GetTypeValidatorsContainer()->GetExact(ConstString(type_sp->GetName()),retval); + } + + return retval; +} + lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex (size_t index) { @@ -467,12 +542,30 @@ TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex (size_t index) } #endif +TypeCategoryImpl::ValidatorContainer::MapValueType +TypeCategoryImpl::GetValidatorAtIndex (size_t index) +{ + if (index < GetTypeValidatorsContainer()->GetCount()) + return GetTypeValidatorsContainer()->GetAtIndex(index); + else + return GetRegexTypeValidatorsContainer()->GetAtIndex(index-GetTypeValidatorsContainer()->GetCount()); +} + +lldb::TypeNameSpecifierImplSP +TypeCategoryImpl::GetTypeNameSpecifierForValidatorAtIndex (size_t index) +{ + if (index < GetTypeValidatorsContainer()->GetCount()) + return GetTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index); + else + return GetRegexTypeValidatorsContainer()->GetTypeNameSpecifierAtIndex(index - GetTypeValidatorsContainer()->GetCount()); +} + void TypeCategoryImpl::Enable (bool value, uint32_t position) { Mutex::Locker locker(m_mutex); - m_enabled = value; - m_enabled_position = position; + if ( (m_enabled = value) ) + m_enabled_position = position; if (m_change_listener) m_change_listener->Changed(); } diff --git a/source/DataFormatters/TypeCategoryMap.cpp b/source/DataFormatters/TypeCategoryMap.cpp index c6dba1b9f4bd0..ae34d0339011d 100644 --- a/source/DataFormatters/TypeCategoryMap.cpp +++ b/source/DataFormatters/TypeCategoryMap.cpp @@ -120,6 +120,46 @@ TypeCategoryMap::Disable (ValueSP category) } void +TypeCategoryMap::EnableAllCategories () +{ + Mutex::Locker locker(m_map_mutex); + std::vector<ValueSP> sorted_categories(m_map.size(), ValueSP()); + MapType::iterator iter = m_map.begin(), end = m_map.end(); + for (; iter != end; ++iter) + { + if (iter->second->IsEnabled()) + continue; + auto pos = iter->second->GetLastEnabledPosition(); + if (pos >= sorted_categories.size()) + { + auto iter = std::find_if(sorted_categories.begin(), + sorted_categories.end(), + [] (const ValueSP& sp) -> bool { + return sp.get() == nullptr; + }); + pos = std::distance(sorted_categories.begin(), iter); + } + sorted_categories.at(pos) = iter->second; + } + decltype(sorted_categories)::iterator viter = sorted_categories.begin(), vend = sorted_categories.end(); + for (; viter != vend; viter++) + if (viter->get()) + Enable(*viter, Last); +} + +void +TypeCategoryMap::DisableAllCategories () +{ + Mutex::Locker locker(m_map_mutex); + Position p = First; + for (; false == m_active_categories.empty(); p++) + { + m_active_categories.front()->SetEnabledPosition(p); + Disable(m_active_categories.front()); + } +} + +void TypeCategoryMap::Clear () { Mutex::Locker locker(m_map_mutex); @@ -266,6 +306,34 @@ TypeCategoryMap::GetSyntheticChildren (ValueObject& valobj, } #endif +lldb::TypeValidatorImplSP +TypeCategoryMap::GetValidator (ValueObject& valobj, + lldb::DynamicValueType use_dynamic) +{ + Mutex::Locker locker(m_map_mutex); + + uint32_t reason_why; + ActiveCategoriesIterator begin, end = m_active_categories.end(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + + FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic); + + for (begin = m_active_categories.begin(); begin != end; begin++) + { + lldb::TypeCategoryImplSP category_sp = *begin; + lldb::TypeValidatorImplSP current_format; + if (log) + log->Printf("\n[CategoryMap::GetValidator] Trying to use category %s", category_sp->GetName()); + if (!category_sp->Get(valobj, matches, current_format, &reason_why)) + continue; + return current_format; + } + if (log) + log->Printf("[CategoryMap::GetValidator] nothing found - returning empty SP"); + return lldb::TypeValidatorImplSP(); +} + void TypeCategoryMap::LoopThrough(CallbackType callback, void* param) { diff --git a/source/DataFormatters/TypeFormat.cpp b/source/DataFormatters/TypeFormat.cpp index 0c62daf87bbcd..f07d8127d2b9e 100644 --- a/source/DataFormatters/TypeFormat.cpp +++ b/source/DataFormatters/TypeFormat.cpp @@ -59,9 +59,9 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj, { if (!valobj) return false; - if (valobj->GetClangType().IsAggregateType () == false) + if (valobj->CanProvideValue()) { - const Value& value(valobj->GetValue()); + Value& value(valobj->GetValue()); const Value::ContextType context_type = value.GetContextType(); ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); DataExtractor data; @@ -92,14 +92,14 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj, } else { - ClangASTType clang_type = valobj->GetClangType (); + ClangASTType clang_type = value.GetClangType (); if (clang_type) { // put custom bytes to display in the DataExtractor to override the default value logic if (GetFormat() == eFormatCString) { lldb_private::Flags type_flags(clang_type.GetTypeInfo(NULL)); // disambiguate w.r.t. TypeFormatImpl::Flags - if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC)) + if (type_flags.Test(eTypeIsPointer) && !type_flags.Test(eTypeIsObjC)) { // if we are dumping a pointer as a c-string, get the pointee data as a string TargetSP target_sp(valobj->GetTargetSP()); @@ -180,7 +180,7 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj, dest.clear(); if (!valobj) return false; - if (valobj->GetClangType().IsAggregateType ()) + if (!valobj->CanProvideValue()) return false; ProcessSP process_sp; TargetSP target_sp; @@ -209,7 +209,7 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj, { if (!type_sp) continue; - if ( (type_sp->GetClangForwardType().GetTypeInfo() & ClangASTType::eTypeIsEnumeration) == ClangASTType::eTypeIsEnumeration) + if ( (type_sp->GetClangForwardType().GetTypeInfo() & eTypeIsEnumeration) == eTypeIsEnumeration) { valobj_enum_type = type_sp->GetClangFullType(); m_types.emplace(valobj_key,valobj_enum_type); diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp index e5d80174c3ccc..ff089af58cb70 100644 --- a/source/DataFormatters/TypeSummary.cpp +++ b/source/DataFormatters/TypeSummary.cpp @@ -34,6 +34,50 @@ using namespace lldb; using namespace lldb_private; +TypeSummaryOptions::TypeSummaryOptions () : + m_lang(eLanguageTypeUnknown), + m_capping(eTypeSummaryCapped) +{} + +TypeSummaryOptions::TypeSummaryOptions (const TypeSummaryOptions& rhs) : + m_lang(rhs.m_lang), + m_capping(rhs.m_capping) +{} + +TypeSummaryOptions& +TypeSummaryOptions::operator = (const TypeSummaryOptions& rhs) +{ + m_lang = rhs.m_lang; + m_capping = rhs.m_capping; + return *this; +} + +lldb::LanguageType +TypeSummaryOptions::GetLanguage () const +{ + return m_lang; +} + +lldb::TypeSummaryCapping +TypeSummaryOptions::GetCapping () const +{ + return m_capping; +} + +TypeSummaryOptions& +TypeSummaryOptions::SetLanguage (lldb::LanguageType lang) +{ + m_lang = lang; + return *this; +} + +TypeSummaryOptions& +TypeSummaryOptions::SetCapping (lldb::TypeSummaryCapping cap) +{ + m_capping = cap; + return *this; +} + TypeSummaryImpl::TypeSummaryImpl (const TypeSummaryImpl::Flags& flags) : m_flags(flags) { @@ -51,7 +95,8 @@ m_format() bool StringSummaryFormat::FormatObject (ValueObject *valobj, - std::string& retval) + std::string& retval, + const TypeSummaryOptions& options) { if (!valobj) { @@ -115,11 +160,12 @@ m_description(description ? description : "") bool CXXFunctionSummaryFormat::FormatObject (ValueObject *valobj, - std::string& dest) + std::string& dest, + const TypeSummaryOptions& options) { dest.clear(); StreamString stream; - if (!m_impl || m_impl(*valobj,stream) == false) + if (!m_impl || m_impl(*valobj,stream,options) == false) return false; dest.assign(stream.GetData()); return true; @@ -160,7 +206,8 @@ m_script_function_sp() bool ScriptSummaryFormat::FormatObject (ValueObject *valobj, - std::string& retval) + std::string& retval, + const TypeSummaryOptions& options) { Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); @@ -190,6 +237,7 @@ ScriptSummaryFormat::FormatObject (ValueObject *valobj, return script_interpreter->GetScriptedSummary(m_function_name.c_str(), valobj->GetSP(), m_script_function_sp, + options, retval); } diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp index 3949673a4be89..13c1c7508b683 100644 --- a/source/DataFormatters/TypeSynthetic.cpp +++ b/source/DataFormatters/TypeSynthetic.cpp @@ -23,6 +23,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/DataFormatters/TypeSynthetic.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -30,6 +31,59 @@ using namespace lldb; using namespace lldb_private; +void +TypeFilterImpl::AddExpressionPath (const std::string& path) +{ + bool need_add_dot = true; + if (path[0] == '.' || + (path[0] == '-' && path[1] == '>') || + path[0] == '[') + need_add_dot = false; + // add a '.' symbol to help forgetful users + if(!need_add_dot) + m_expression_paths.push_back(path); + else + m_expression_paths.push_back(std::string(".") + path); +} + +bool +TypeFilterImpl::SetExpressionPathAtIndex (size_t i, const std::string& path) +{ + if (i >= GetCount()) + return false; + bool need_add_dot = true; + if (path[0] == '.' || + (path[0] == '-' && path[1] == '>') || + path[0] == '[') + need_add_dot = false; + // add a '.' symbol to help forgetful users + if(!need_add_dot) + m_expression_paths[i] = path; + else + m_expression_paths[i] = std::string(".") + path; + return true; +} + +size_t +TypeFilterImpl::FrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + const char* name_cstr = name.GetCString(); + for (size_t i = 0; i < filter->GetCount(); i++) + { + const char* expr_cstr = filter->GetExpressionPathAtIndex(i); + if (expr_cstr) + { + if (*expr_cstr == '.') + expr_cstr++; + else if (*expr_cstr == '-' && *(expr_cstr+1) == '>') + expr_cstr += 2; + } + if (!::strcmp(name_cstr, expr_cstr)) + return i; + } + return UINT32_MAX; +} + std::string TypeFilterImpl::GetDescription() { @@ -63,6 +117,41 @@ CXXSyntheticChildren::GetDescription() return sstr.GetString(); } +lldb::ValueObjectSP +SyntheticChildrenFrontEnd::CreateValueObjectFromExpression (const char* name, + const char* expression, + const ExecutionContext& exe_ctx) +{ + ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx)); + if (valobj_sp) + valobj_sp->SetSyntheticChildrenGenerated(true); + return valobj_sp; +} + +lldb::ValueObjectSP +SyntheticChildrenFrontEnd::CreateValueObjectFromAddress (const char* name, + uint64_t address, + const ExecutionContext& exe_ctx, + ClangASTType type) +{ + ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type)); + if (valobj_sp) + valobj_sp->SetSyntheticChildrenGenerated(true); + return valobj_sp; +} + +lldb::ValueObjectSP +SyntheticChildrenFrontEnd::CreateValueObjectFromData (const char* name, + const DataExtractor& data, + const ExecutionContext& exe_ctx, + ClangASTType type) +{ + ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type)); + if (valobj_sp) + valobj_sp->SetSyntheticChildrenGenerated(true); + return valobj_sp; +} + #ifndef LLDB_DISABLE_PYTHON ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, ValueObject &backend) : @@ -98,6 +187,55 @@ ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex (size_t idx) return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx); } +bool +ScriptedSyntheticChildren::FrontEnd::IsValid () +{ + return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr; +} + +size_t +ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren () +{ + if (!m_wrapper_sp || m_interpreter == NULL) + return 0; + return m_interpreter->CalculateNumChildren(m_wrapper_sp); +} + +bool +ScriptedSyntheticChildren::FrontEnd::Update () +{ + if (!m_wrapper_sp || m_interpreter == NULL) + return false; + + return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp); +} + +bool +ScriptedSyntheticChildren::FrontEnd::MightHaveChildren () +{ + if (!m_wrapper_sp || m_interpreter == NULL) + return false; + + return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp); +} + +size_t +ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName (const ConstString &name) +{ + if (!m_wrapper_sp || m_interpreter == NULL) + return UINT32_MAX; + return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString()); +} + +lldb::ValueObjectSP +ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue () +{ + if (!m_wrapper_sp || m_interpreter == NULL) + return nullptr; + + return m_interpreter->GetSyntheticValue(m_wrapper_sp); +} + std::string ScriptedSyntheticChildren::GetDescription() { diff --git a/source/DataFormatters/TypeValidator.cpp b/source/DataFormatters/TypeValidator.cpp new file mode 100644 index 0000000000000..b5efac8f586a0 --- /dev/null +++ b/source/DataFormatters/TypeValidator.cpp @@ -0,0 +1,75 @@ +//===-- TypeValidator.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes + +// C++ Includes + +// Other libraries and framework includes + +// Project includes +#include "lldb/DataFormatters/TypeValidator.h" +#include "lldb/Core/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +TypeValidatorImpl::TypeValidatorImpl(const Flags &flags) : + m_flags(flags), + m_my_revision(0) +{ +} + +TypeValidatorImpl::~TypeValidatorImpl() +{ +} + +TypeValidatorImpl::ValidationResult +TypeValidatorImpl::Success () +{ + return ValidationResult { TypeValidatorResult::Success, "" }; +} + +TypeValidatorImpl::ValidationResult +TypeValidatorImpl::Failure (std::string message) +{ + return ValidationResult { TypeValidatorResult::Failure, message }; +} + +TypeValidatorImpl_CXX::TypeValidatorImpl_CXX (ValidatorFunction f, std::string d, const TypeValidatorImpl::Flags& flags) : + TypeValidatorImpl(flags), + m_description(d), + m_validator_function(f) +{ +} + +TypeValidatorImpl_CXX::~TypeValidatorImpl_CXX() +{ +} + +TypeValidatorImpl::ValidationResult +TypeValidatorImpl_CXX::FormatObject (ValueObject *valobj) const +{ + if (!valobj) + return Success(); // I guess there's nothing wrong with a null valueobject.. + + return m_validator_function(valobj); +} + +std::string +TypeValidatorImpl_CXX::GetDescription() +{ + StreamString sstr; + sstr.Printf ("%s%s%s%s", + m_description.c_str(), + Cascades() ? "" : " (not cascading)", + SkipsPointers() ? " (skip pointers)" : "", + SkipsReferences() ? " (skip references)" : ""); + return sstr.GetString(); +} diff --git a/source/DataFormatters/ValueObjectPrinter.cpp b/source/DataFormatters/ValueObjectPrinter.cpp index 65e5e3f458238..5560ce2971e7f 100644 --- a/source/DataFormatters/ValueObjectPrinter.cpp +++ b/source/DataFormatters/ValueObjectPrinter.cpp @@ -66,11 +66,13 @@ ValueObjectPrinter::Init (ValueObject* valobj, bool ValueObjectPrinter::PrintValueObject () { - if (!GetDynamicValueIfNeeded () || m_valobj == nullptr) + if (!GetMostSpecializedValue () || m_valobj == nullptr) return false; if (ShouldPrintValueObject()) { + PrintValidationMarkerIfNeeded(); + PrintLocationIfNeeded(); m_stream->Indent(); @@ -89,11 +91,13 @@ ValueObjectPrinter::PrintValueObject () else m_stream->EOL(); + PrintValidationErrorIfNeeded(); + return true; } bool -ValueObjectPrinter::GetDynamicValueIfNeeded () +ValueObjectPrinter::GetMostSpecializedValue () { if (m_valobj) return true; @@ -130,6 +134,25 @@ ValueObjectPrinter::GetDynamicValueIfNeeded () else m_valobj = m_orig_valobj; } + + if (m_valobj->IsSynthetic()) + { + if (options.m_use_synthetic == false) + { + ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); + if (non_synthetic) + m_valobj = non_synthetic; + } + } + else + { + if (options.m_use_synthetic == true) + { + ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); + if (synthetic) + m_valobj = synthetic; + } + } } m_clang_type = m_valobj->GetClangType(); m_type_flags = m_clang_type.GetTypeInfo (); @@ -160,7 +183,7 @@ bool ValueObjectPrinter::ShouldPrintValueObject () { if (m_should_print == eLazyBoolCalculate) - m_should_print = (options.m_flat_output == false || m_type_flags.Test (ClangASTType::eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo; + m_should_print = (options.m_flat_output == false || m_type_flags.Test (eTypeHasValue)) ? eLazyBoolYes : eLazyBoolNo; return m_should_print == eLazyBoolYes; } @@ -176,7 +199,7 @@ bool ValueObjectPrinter::IsPtr () { if (m_is_ptr == eLazyBoolCalculate) - m_is_ptr = m_type_flags.Test (ClangASTType::eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; + m_is_ptr = m_type_flags.Test (eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; return m_is_ptr == eLazyBoolYes; } @@ -184,7 +207,7 @@ bool ValueObjectPrinter::IsRef () { if (m_is_ref == eLazyBoolCalculate) - m_is_ref = m_type_flags.Test (ClangASTType::eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; + m_is_ref = m_type_flags.Test (eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; return m_is_ref == eLazyBoolYes; } @@ -192,7 +215,7 @@ bool ValueObjectPrinter::IsAggregate () { if (m_is_aggregate == eLazyBoolCalculate) - m_is_aggregate = m_type_flags.Test (ClangASTType::eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; + m_is_aggregate = m_type_flags.Test (eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; return m_is_aggregate == eLazyBoolYes; } @@ -222,13 +245,13 @@ ValueObjectPrinter::PrintTypeIfNeeded () { // Some ValueObjects don't have types (like registers sets). Only print // the type if there is one to print - ConstString qualified_type_name; - if (options.m_be_raw) - qualified_type_name = m_valobj->GetQualifiedTypeName(); + ConstString type_name; + if (options.m_use_type_display_name) + type_name = m_valobj->GetDisplayTypeName(); else - qualified_type_name = m_valobj->GetDisplayTypeName(); - if (qualified_type_name) - m_stream->Printf("(%s) ", qualified_type_name.GetCString()); + type_name = m_valobj->GetQualifiedTypeName(); + if (type_name) + m_stream->Printf("(%s) ", type_name.GetCString()); else show_type = false; } @@ -438,8 +461,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, ValueObject* ValueObjectPrinter::GetValueObjectForChildrenGeneration () { - ValueObjectSP synth_valobj_sp = m_valobj->GetSyntheticValue (options.m_use_synthetic); - return (synth_valobj_sp ? synth_valobj_sp.get() : m_valobj); + return m_valobj; } void @@ -536,7 +558,13 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth) { // Aggregate, no children... if (ShouldPrintValueObject()) - m_stream->PutCString(" {}\n"); + { + // if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value + if (m_valobj->DoesProvideSyntheticValue()) + m_stream->PutCString( "\n"); + else + m_stream->PutCString(" {}\n"); + } } else { @@ -548,7 +576,7 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth) bool ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names) { - if (!GetDynamicValueIfNeeded () || m_valobj == nullptr) + if (!GetMostSpecializedValue () || m_valobj == nullptr) return false; ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration(); @@ -563,9 +591,8 @@ ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names) for (uint32_t idx=0; idx<num_children; ++idx) { lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); - lldb::ValueObjectSP child_dyn_sp = child_sp.get() ? child_sp->GetDynamicValue(options.m_use_dynamic) : child_sp; - if (child_dyn_sp) - child_sp = child_dyn_sp; + if (child_sp) + child_sp = child_sp->GetQualifiedRepresentationIfAvailable(options.m_use_dynamic, options.m_use_synthetic); if (child_sp) { if (idx) @@ -604,7 +631,7 @@ ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed, uint32_t curr_ptr_depth = m_ptr_depth; bool print_children = ShouldPrintChildren (is_failed_description,curr_ptr_depth); - bool print_oneline = (curr_ptr_depth > 0 || options.m_show_types || options.m_be_raw) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); + bool print_oneline = (curr_ptr_depth > 0 || options.m_show_types || !options.m_allow_oneliner_mode) ? false : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); if (print_children) { @@ -624,3 +651,44 @@ ValueObjectPrinter::PrintChildrenIfNeeded (bool value_printed, else m_stream->EOL(); } + +bool +ValueObjectPrinter::ShouldPrintValidation () +{ + return options.m_run_validator; +} + +bool +ValueObjectPrinter::PrintValidationMarkerIfNeeded () +{ + if (!ShouldPrintValidation()) + return false; + + m_validation = m_valobj->GetValidationStatus(); + + if (TypeValidatorResult::Failure == m_validation.first) + { + m_stream->Printf("! "); + return true; + } + + return false; +} + +bool +ValueObjectPrinter::PrintValidationErrorIfNeeded () +{ + if (!ShouldPrintValidation()) + return false; + + if (TypeValidatorResult::Success == m_validation.first) + return false; + + if (m_validation.second.empty()) + m_validation.second.assign("unknown error"); + + m_stream->Printf(" ! validation error: %s", m_validation.second.c_str()); + m_stream->EOL(); + + return true; +} |