Introduce the notion of an escape helper. Different languages have different notion of what to print in a string and how to escape non-printable things. The escape helper is where this notion is provided to LLDB
This is NFC, other than a code re-org
llvm-svn: 247200
diff --git a/lldb/source/DataFormatters/Cocoa.cpp b/lldb/source/DataFormatters/Cocoa.cpp
index 0942c8d..64d4edb 100644
--- a/lldb/source/DataFormatters/Cocoa.cpp
+++ b/lldb/source/DataFormatters/Cocoa.cpp
@@ -866,7 +866,7 @@
return false;
if (has_explicit_length && is_unicode)
{
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -876,11 +876,11 @@
options.SetNeedsZeroTermination(false);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(false);
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options);
}
else
{
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location+1);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -889,14 +889,14 @@
options.SetNeedsZeroTermination(false);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(false);
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII>(options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII>(options);
}
}
else if (is_inline && has_explicit_length && !is_unicode && !is_path_store && !is_mutable)
{
uint64_t location = 3 * ptr_size + valobj_addr;
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -904,7 +904,7 @@
options.SetQuote('"');
options.SetSourceSize(explicit_length);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII> (options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (options);
}
else if (is_unicode)
{
@@ -925,7 +925,7 @@
if (error.Fail())
return false;
}
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -935,7 +935,7 @@
options.SetNeedsZeroTermination(has_explicit_length == false);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(has_explicit_length == false);
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16> (options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (options);
}
else if (is_path_store)
{
@@ -943,7 +943,7 @@
explicit_length = reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20;
lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -953,7 +953,7 @@
options.SetNeedsZeroTermination(has_explicit_length == false);
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(has_explicit_length == false);
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16> (options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (options);
}
else if (is_inline)
{
@@ -970,7 +970,7 @@
has_explicit_length = true;
location++;
}
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(location);
options.SetProcessSP(process_sp);
options.SetStream(&stream);
@@ -980,9 +980,9 @@
options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
options.SetBinaryZeroIsTerminator(!has_explicit_length);
if (has_explicit_length)
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options);
else
- return StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII>(options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII>(options);
}
else
{
@@ -992,14 +992,14 @@
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
- ReadStringAndDumpToStreamOptions options(valobj);
+ StringPrinter::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 StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII>(options);
+ return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII>(options);
}
}
diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp
index bc8e8e7..3fdb9b8 100644
--- a/lldb/source/DataFormatters/FormatManager.cpp
+++ b/lldb/source/DataFormatters/FormatManager.cpp
@@ -651,6 +651,12 @@
FormatManager::GetCandidateLanguages (ValueObject& valobj)
{
lldb::LanguageType lang_type = valobj.GetObjectRuntimeLanguage();
+ return GetCandidateLanguages(lang_type);
+}
+
+std::vector<lldb::LanguageType>
+FormatManager::GetCandidateLanguages (lldb::LanguageType lang_type)
+{
switch (lang_type)
{
case lldb::eLanguageTypeC:
diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp
index a5ed7e4..3225168 100644
--- a/lldb/source/DataFormatters/StringPrinter.cpp
+++ b/lldb/source/DataFormatters/StringPrinter.cpp
@@ -13,6 +13,7 @@
#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"
@@ -27,7 +28,7 @@
// 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>
+template <lldb_private::formatters::StringPrinter::StringElementType type>
static StringPrinter::StringPrinterBufferPointer<>
GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
@@ -60,7 +61,7 @@
template <>
StringPrinter::StringPrinterBufferPointer<>
-GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+GetPrintableImpl<StringPrinter::StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
{
StringPrinter::StringPrinterBufferPointer<> retval = {nullptr};
@@ -130,7 +131,7 @@
template <>
StringPrinter::StringPrinterBufferPointer<>
-GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+GetPrintableImpl<StringPrinter::StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
{
StringPrinter::StringPrinterBufferPointer<> retval {nullptr};
@@ -149,7 +150,7 @@
{
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;
@@ -227,22 +228,38 @@
// a sequence of bytes to actually print out + a length
// the following unscanned position of the buffer is in next
static StringPrinter::StringPrinterBufferPointer<>
-GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
+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);
+ };
+ }
+}
+
// use this call if you already have an LLDB-side buffer for the data
template<typename SourceDataType>
static bool
@@ -251,7 +268,7 @@
UTF8**,
UTF8*,
ConversionFlags),
- const ReadBufferAndDumpToStreamOptions& dump_options)
+ const StringPrinter::ReadBufferAndDumpToStreamOptions& dump_options)
{
Stream &stream(*dump_options.GetStream());
if (dump_options.GetPrefixToken() != 0)
@@ -312,6 +329,14 @@
}
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)
// we might end up with no NULL terminator before the end_ptr
@@ -324,7 +349,7 @@
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)
@@ -350,19 +375,19 @@
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::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const lldb_private::formatters::ReadStringAndDumpToStreamOptions& options) :
+lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options) :
ReadBufferAndDumpToStreamOptions()
{
SetStream(options.GetStream());
@@ -370,6 +395,7 @@
SetQuote(options.GetQuote());
SetEscapeNonPrintables(options.GetEscapeNonPrintables());
SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
+ SetLanguage(options.GetLanguage());
}
@@ -381,7 +407,7 @@
template <>
bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
{
assert(options.GetStream() && "need a Stream to print the string to");
Error my_error;
@@ -417,15 +443,25 @@
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)
@@ -454,7 +490,7 @@
template<typename SourceDataType>
static bool
-ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options,
+ReadUTFBufferAndDumpToStream (const StringPrinter::ReadStringAndDumpToStreamOptions& options,
ConversionResult (*ConvertFunction) (const SourceDataType**,
const SourceDataType*,
UTF8**,
@@ -516,7 +552,7 @@
DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
- ReadBufferAndDumpToStreamOptions dump_options(options);
+ StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options);
dump_options.SetData(data);
dump_options.SetSourceSize(sourceSize);
@@ -525,7 +561,7 @@
template <>
bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
{
return ReadUTFBufferAndDumpToStream<UTF8>(options,
nullptr);
@@ -533,7 +569,7 @@
template <>
bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
{
return ReadUTFBufferAndDumpToStream<UTF16>(options,
ConvertUTF16toUTF8);
@@ -541,7 +577,7 @@
template <>
bool
-StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
+StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
{
return ReadUTFBufferAndDumpToStream<UTF32>(options,
ConvertUTF32toUTF8);
@@ -549,7 +585,7 @@
template <>
bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
{
assert(options.GetStream() && "need a Stream to print the string to");
@@ -558,7 +594,7 @@
template <>
bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
{
// treat ASCII the same as UTF8
// FIXME: can we optimize ASCII some more?
@@ -567,7 +603,7 @@
template <>
bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
{
assert(options.GetStream() && "need a Stream to print the string to");
@@ -576,7 +612,7 @@
template <>
bool
-StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
+StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
{
assert(options.GetStream() && "need a Stream to print the string to");