CXXFormatterFunctions.{h|cpp} is not a good thing to have around, so start splitting stuff in different files in preparation for removing it and factoring formatters to the plugins where they belong
llvm-svn: 246743
diff --git a/lldb/source/DataFormatters/LibCxx.cpp b/lldb/source/DataFormatters/LibCxx.cpp
index 8a490e0..7395d93 100644
--- a/lldb/source/DataFormatters/LibCxx.cpp
+++ b/lldb/source/DataFormatters/LibCxx.cpp
@@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===//
#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Debugger.h"
@@ -461,3 +463,173 @@
}
return FormatEntity::FormatStringRef("size=${svar%#}", stream, NULL, NULL, NULL, &valobj, false, false);
}
+
+// the field layout in a libc++ string (cap, side, data or data, size, cap)
+enum LibcxxStringLayoutMode
+{
+ eLibcxxStringLayoutModeCSD = 0,
+ eLibcxxStringLayoutModeDSC = 1,
+ eLibcxxStringLayoutModeInvalid = 0xffff
+};
+
+// this function abstracts away the layout and mode details of a libc++ string
+// and returns the address of the data and the size ready for callers to consume
+static bool
+ExtractLibcxxStringInfo (ValueObject& valobj,
+ ValueObjectSP &location_sp,
+ uint64_t& size)
+{
+ ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
+ if (!D)
+ return false;
+
+ ValueObjectSP layout_decider(D->GetChildAtIndexPath({0,0}));
+
+ // this child should exist
+ if (!layout_decider)
+ return false;
+
+ ConstString g_data_name("__data_");
+ ConstString g_size_name("__size_");
+ bool short_mode = false; // this means the string is in short-mode and the data is stored inline
+ LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) ? eLibcxxStringLayoutModeDSC : eLibcxxStringLayoutModeCSD;
+ uint64_t size_mode_value = 0;
+
+ if (layout == eLibcxxStringLayoutModeDSC)
+ {
+ ValueObjectSP size_mode(D->GetChildAtIndexPath({1,1,0}));
+ if (!size_mode)
+ return false;
+
+ if (size_mode->GetName() != g_size_name)
+ {
+ // we are hitting the padding structure, move along
+ size_mode = D->GetChildAtIndexPath({1,1,1});
+ if (!size_mode)
+ return false;
+ }
+
+ size_mode_value = (size_mode->GetValueAsUnsigned(0));
+ short_mode = ((size_mode_value & 0x80) == 0);
+ }
+ else
+ {
+ ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
+ if (!size_mode)
+ return false;
+
+ size_mode_value = (size_mode->GetValueAsUnsigned(0));
+ short_mode = ((size_mode_value & 1) == 0);
+ }
+
+ if (short_mode)
+ {
+ ValueObjectSP s(D->GetChildAtIndex(1, true));
+ if (!s)
+ return false;
+ location_sp = s->GetChildAtIndex((layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
+ size = (layout == eLibcxxStringLayoutModeDSC) ? size_mode_value : ((size_mode_value >> 1) % 256);
+ return (location_sp.get() != nullptr);
+ }
+ else
+ {
+ ValueObjectSP l(D->GetChildAtIndex(0, true));
+ if (!l)
+ return false;
+ // we can use the layout_decider object as the data pointer
+ location_sp = (layout == eLibcxxStringLayoutModeDSC) ? layout_decider : l->GetChildAtIndex(2, true);
+ ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
+ if (!size_vo || !location_sp)
+ return false;
+ size = size_vo->GetValueAsUnsigned(0);
+ return true;
+ }
+}
+
+bool
+lldb_private::formatters::LibcxxWStringSummaryProvider (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("L\"\"");
+ return true;
+ }
+ if (!location_sp)
+ return false;
+
+ DataExtractor extractor;
+ if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped)
+ size = std::min<decltype(size)>(size, valobj.GetTargetSP()->GetMaximumSizeOfStringSummary());
+ location_sp->GetPointeeData(extractor, 0, size);
+
+ // std::wstring::size() is measured in 'characters', not bytes
+ auto wchar_t_size = valobj.GetTargetSP()->GetScratchClangASTContext()->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
+
+ ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(extractor);
+ options.SetStream(&stream);
+ options.SetPrefixToken('L');
+ options.SetQuote('"');
+ options.SetSourceSize(size);
+ options.SetBinaryZeroIsTerminator(false);
+
+ switch (wchar_t_size)
+ {
+ case 1:
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::UTF8>(options);
+ break;
+
+ case 2:
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::UTF16>(options);
+ break;
+
+ case 4:
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::UTF32>(options);
+ break;
+
+ default:
+ stream.Printf("size for wchar_t is not valid");
+ return true;
+ }
+
+ return true;
+}
+
+bool
+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;
+
+ 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);
+ options.SetStream(&stream);
+ options.SetPrefixToken(0);
+ options.SetQuote('"');
+ options.SetSourceSize(size);
+ options.SetBinaryZeroIsTerminator(false);
+ lldb_private::formatters::ReadBufferAndDumpToStream<lldb_private::formatters::StringElementType::ASCII>(options);
+
+ return true;
+}