diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp | 307 |
1 files changed, 156 insertions, 151 deletions
diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp index a011cd5..b114add 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/StringPrinter.cpp @@ -9,109 +9,26 @@ #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/Language.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<> +template <lldb_private::formatters::StringPrinter::StringElementType type> +static StringPrinter::StringPrinterBufferPointer<> GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next); // mimic isprint() for Unicode codepoints @@ -142,10 +59,10 @@ isprint(char32_t codepoint) } template <> -StringPrinterBufferPointer<> -GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) +StringPrinter::StringPrinterBufferPointer<> +GetPrintableImpl<StringPrinter::StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) { - StringPrinterBufferPointer<> retval = {nullptr}; + StringPrinter::StringPrinterBufferPointer<> retval = {nullptr}; switch (*buffer) { @@ -212,10 +129,10 @@ ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, un } template <> -StringPrinterBufferPointer<> -GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) +StringPrinter::StringPrinterBufferPointer<> +GetPrintableImpl<StringPrinter::StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) { - StringPrinterBufferPointer<> retval {nullptr}; + StringPrinter::StringPrinterBufferPointer<> retval {nullptr}; unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer); @@ -232,7 +149,7 @@ GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, { case 1: // this is just an ASCII byte - ask ASCII - return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); + return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next); case 2: codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1)); break; @@ -309,23 +226,40 @@ GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, // 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) +static StringPrinter::StringPrinterBufferPointer<> +GetPrintable(StringPrinter::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); + case StringPrinter::StringElementType::ASCII: + return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next); + case StringPrinter::StringElementType::UTF8: + return GetPrintableImpl<StringPrinter::StringElementType::UTF8>(buffer, buffer_end, next); default: return {nullptr}; } } +StringPrinter::EscapingHelper +StringPrinter::GetDefaultEscapingHelper (GetPrintableElementType elem_type) +{ + switch (elem_type) + { + case GetPrintableElementType::UTF8: + return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> { + return GetPrintable(StringPrinter::StringElementType::UTF8, buffer, buffer_end, next); + }; + case GetPrintableElementType::ASCII: + return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> { + return GetPrintable(StringPrinter::StringElementType::ASCII, buffer, buffer_end, next); + }; + } + llvm_unreachable("bad element type"); +} + // use this call if you already have an LLDB-side buffer for the data template<typename SourceDataType> static bool @@ -334,41 +268,44 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType UTF8**, UTF8*, ConversionFlags), - const DataExtractor& data, - Stream& stream, - char prefix_token, - char quote, - uint32_t sourceSize, - bool escapeNonPrintables) + const StringPrinter::ReadBufferAndDumpToStreamOptions& dump_options) { - if (prefix_token != 0) - stream.Printf("%c",prefix_token); - if (quote != 0) - stream.Printf("%c",quote); + Stream &stream(*dump_options.GetStream()); + if (dump_options.GetPrefixToken() != 0) + stream.Printf("%s",dump_options.GetPrefixToken()); + if (dump_options.GetQuote() != 0) + stream.Printf("%c",dump_options.GetQuote()); + auto data(dump_options.GetData()); + auto source_size(dump_options.GetSourceSize()); if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) { const int bufferSPSize = data.GetByteSize(); - if (sourceSize == 0) + if (dump_options.GetSourceSize() == 0) { const int origin_encoding = 8*sizeof(SourceDataType); - sourceSize = bufferSPSize/(origin_encoding / 4); + source_size = bufferSPSize/(origin_encoding / 4); } const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart(); - const SourceDataType *data_end_ptr = data_ptr + sourceSize; + const SourceDataType *data_end_ptr = data_ptr + source_size; - while (data_ptr < data_end_ptr) + const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator(); + + if (zero_is_terminator) { - if (!*data_ptr) + while (data_ptr < data_end_ptr) { - data_end_ptr = data_ptr; - break; + if (!*data_ptr) + { + data_end_ptr = data_ptr; + break; + } + data_ptr++; } - data_ptr++; + + data_ptr = (const SourceDataType*)data.GetDataStart(); } - data_ptr = (const SourceDataType*)data.GetDataStart(); - lldb::DataBufferSP utf8_data_buffer_sp; UTF8* utf8_data_ptr = nullptr; UTF8* utf8_data_end_ptr = nullptr; @@ -379,14 +316,26 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize(); ConvertFunction ( &data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); + if (false == zero_is_terminator) + utf8_data_end_ptr = utf8_data_ptr; 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; + utf8_data_ptr = const_cast<UTF8 *>(reinterpret_cast<const UTF8*>(data_ptr)); + utf8_data_end_ptr = const_cast<UTF8 *>(reinterpret_cast<const UTF8*>(data_end_ptr)); + } + + const bool escape_non_printables = dump_options.GetEscapeNonPrintables(); + lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback; + if (escape_non_printables) + { + if (Language *language = Language::FindPlugin(dump_options.GetLanguage())) + escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8); + else + escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8); } // since we tend to accept partial data (and even partially malformed data) @@ -394,13 +343,13 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType // 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) + if (zero_is_terminator && !*utf8_data_ptr) break; - if (escapeNonPrintables) + if (escape_non_printables) { uint8_t* next_data = nullptr; - auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data); + auto printable = escaping_callback(utf8_data_ptr, utf8_data_end_ptr, next_data); auto printable_bytes = printable.GetBytes(); auto printable_size = printable.GetSize(); if (!printable_bytes || !next_data) @@ -421,23 +370,39 @@ DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType } } } - if (quote != 0) - stream.Printf("%c",quote); + if (dump_options.GetQuote() != 0) + stream.Printf("%c",dump_options.GetQuote()); + if (dump_options.GetSuffixToken() != 0) + stream.Printf("%s",dump_options.GetSuffixToken()); + if (dump_options.GetIsTruncated()) + stream.Printf("..."); return true; } -lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) : +lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) : ReadStringAndDumpToStreamOptions() { SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); } -lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) : +lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) : ReadBufferAndDumpToStreamOptions() { SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); } +lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options) : + ReadBufferAndDumpToStreamOptions() +{ + SetStream(options.GetStream()); + SetPrefixToken(options.GetPrefixToken()); + SetSuffixToken(options.GetSuffixToken()); + SetQuote(options.GetQuote()); + SetEscapeNonPrintables(options.GetEscapeNonPrintables()); + SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator()); + SetLanguage(options.GetLanguage()); +} + namespace lldb_private { @@ -447,7 +412,7 @@ namespace formatters template <> bool -ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options) +StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options) { assert(options.GetStream() && "need a Stream to print the string to"); Error my_error; @@ -458,11 +423,20 @@ ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOp return false; size_t size; + const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + bool is_truncated = false; if (options.GetSourceSize() == 0) - size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + size = max_size; else if (!options.GetIgnoreMaxLength()) - size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary()); + { + size = options.GetSourceSize(); + if (size > max_size) + { + size = max_size; + is_truncated = true; + } + } else size = options.GetSourceSize(); @@ -473,25 +447,35 @@ ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOp if (my_error.Fail()) return false; - char prefix_token = options.GetPrefixToken(); + const char* prefix_token = options.GetPrefixToken(); char quote = options.GetQuote(); if (prefix_token != 0) - options.GetStream()->Printf("%c%c",prefix_token,quote); + options.GetStream()->Printf("%s%c",prefix_token,quote); else if (quote != 0) options.GetStream()->Printf("%c",quote); uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize(); + const bool escape_non_printables = options.GetEscapeNonPrintables(); + lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback; + if (escape_non_printables) + { + if (Language *language = Language::FindPlugin(options.GetLanguage())) + escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII); + else + escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII); + } + // 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()) + if (escape_non_printables) { uint8_t* next_data = nullptr; - auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data); + auto printable = escaping_callback(data, data_end, next_data); auto printable_bytes = printable.GetBytes(); auto printable_size = printable.GetSize(); if (!printable_bytes || !next_data) @@ -511,16 +495,23 @@ ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOp data++; } } - - if (quote != 0) + + const char* suffix_token = options.GetSuffixToken(); + + if (suffix_token != 0) + options.GetStream()->Printf("%c%s",quote, suffix_token); + else if (quote != 0) options.GetStream()->Printf("%c",quote); + if (is_truncated) + options.GetStream()->Printf("..."); + return true; } template<typename SourceDataType> static bool -ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, +ReadUTFBufferAndDumpToStream (const StringPrinter::ReadStringAndDumpToStreamOptions& options, ConversionResult (*ConvertFunction) (const SourceDataType**, const SourceDataType*, UTF8**, @@ -550,14 +541,23 @@ ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, uint32_t sourceSize = options.GetSourceSize(); bool needs_zero_terminator = options.GetNeedsZeroTermination(); + + bool is_truncated = false; + const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); if (!sourceSize) { - sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); + sourceSize = max_size; needs_zero_terminator = true; } else if (!options.GetIgnoreMaxLength()) - sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary()); + { + if (sourceSize > max_size) + { + sourceSize = max_size; + is_truncated = true; + } + } const int bufferSPSize = sourceSize * type_width; @@ -581,13 +581,18 @@ ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, } DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); + + StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options); + dump_options.SetData(data); + dump_options.SetSourceSize(sourceSize); + dump_options.SetIsTruncated(is_truncated); - return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables()); + return DumpUTFBufferToStream(ConvertFunction, dump_options); } template <> bool -ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options) +StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options) { return ReadUTFBufferAndDumpToStream<UTF8>(options, nullptr); @@ -595,7 +600,7 @@ ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOpt template <> bool -ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options) +StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options) { return ReadUTFBufferAndDumpToStream<UTF16>(options, ConvertUTF16toUTF8); @@ -603,7 +608,7 @@ ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOp template <> bool -ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options) +StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options) { return ReadUTFBufferAndDumpToStream<UTF32>(options, ConvertUTF32toUTF8); @@ -611,16 +616,16 @@ ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOp template <> bool -ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options) +StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF8> (const 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()); + return DumpUTFBufferToStream<UTF8>(nullptr, options); } template <> bool -ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options) +StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options) { // treat ASCII the same as UTF8 // FIXME: can we optimize ASCII some more? @@ -629,20 +634,20 @@ ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOp template <> bool -ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options) +StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF16> (const 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()); + return DumpUTFBufferToStream(ConvertUTF16toUTF8, options); } template <> bool -ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options) +StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF32> (const 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()); + return DumpUTFBufferToStream(ConvertUTF32toUTF8, options); } } // namespace formatters |