diff options
Diffstat (limited to 'lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp')
-rw-r--r-- | lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp | 261 |
1 files changed, 194 insertions, 67 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index ecadaef7a87e..84dd09a47d8a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -1,4 +1,4 @@ -//===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===// +//===-- LibCxx.cpp --------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,7 +8,6 @@ #include "LibCxx.h" -#include "llvm/ADT/ScopeExit.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FormatEntity.h" #include "lldb/Core/ValueObject.h" @@ -17,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -27,6 +25,7 @@ #include "lldb/Utility/Stream.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; @@ -145,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, @@ -241,8 +277,8 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); m_pair_ptr = nullptr; if (addr && addr != LLDB_INVALID_ADDRESS) { - ClangASTContext *ast_ctx = - llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem()); + TypeSystemClang *ast_ctx = + llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem()); if (!ast_ctx) return false; CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( @@ -450,6 +486,67 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( : nullptr); } +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_compressed_pair_sp() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + ~LibcxxUniquePtrSyntheticFrontEnd() = default; + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp) + : nullptr); +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + CalculateNumChildren() { + return (m_compressed_pair_sp ? 1 : 0); +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + if (!m_compressed_pair_sp) + return lldb::ValueObjectSP(); + + if (idx != 0) + return lldb::ValueObjectSP(); + + return m_compressed_pair_sp; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { @@ -469,22 +566,20 @@ enum LibcxxStringLayoutMode { 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) { +/// Determine the size in bytes of \p valobj (a libc++ std::string object) and +/// extract its data payload. Return the size + payload pair. +static llvm::Optional<std::pair<uint64_t, ValueObjectSP>> +ExtractLibcxxStringInfo(ValueObject &valobj) { ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0})); if (!D) - return false; + return {}; ValueObjectSP layout_decider( D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0}))); // this child should exist if (!layout_decider) - return false; + return {}; ConstString g_data_name("__data_"); ConstString g_size_name("__size_"); @@ -498,13 +593,13 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, if (layout == eLibcxxStringLayoutModeDSC) { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0})); if (!size_mode) - return false; + return {}; 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; + return {}; } size_mode_value = (size_mode->GetValueAsUnsigned(0)); @@ -512,7 +607,7 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, } else { ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0})); if (!size_mode) - return false; + return {}; size_mode_value = (size_mode->GetValueAsUnsigned(0)); short_mode = ((size_mode_value & 1) == 0); @@ -521,36 +616,58 @@ static bool ExtractLibcxxStringInfo(ValueObject &valobj, if (short_mode) { ValueObjectSP s(D->GetChildAtIndex(1, true)); if (!s) - return false; - location_sp = s->GetChildAtIndex( + return {}; + ValueObjectSP 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; + const uint64_t size = (layout == eLibcxxStringLayoutModeDSC) + ? size_mode_value + : ((size_mode_value >> 1) % 256); + + // When the small-string optimization takes place, the data must fit in the + // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's + // likely that the string isn't initialized and we're reading garbage. + ExecutionContext exe_ctx(location_sp->GetExecutionContextRef()); + const llvm::Optional<uint64_t> max_bytes = + location_sp->GetCompilerType().GetByteSize( + exe_ctx.GetBestExecutionContextScope()); + if (!max_bytes || size > *max_bytes || !location_sp) + return {}; + + return std::make_pair(size, location_sp); } + + ValueObjectSP l(D->GetChildAtIndex(0, true)); + if (!l) + return {}; + // we can use the layout_decider object as the data pointer + ValueObjectSP location_sp = (layout == eLibcxxStringLayoutModeDSC) + ? layout_decider + : l->GetChildAtIndex(2, true); + ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); + const unsigned capacity_index = + (layout == eLibcxxStringLayoutModeDSC) ? 2 : 0; + ValueObjectSP capacity_vo(l->GetChildAtIndex(capacity_index, true)); + if (!size_vo || !location_sp || !capacity_vo) + return {}; + const uint64_t size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + const uint64_t capacity = + capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET); + if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET || + capacity < size) + return {}; + return std::make_pair(size, location_sp); } bool lldb_private::formatters::LibcxxWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - uint64_t size = 0; - ValueObjectSP location_sp; - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; + if (size == 0) { stream.Printf("L\"\""); return true; @@ -558,10 +675,8 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( if (!location_sp) return false; - DataExtractor extractor; StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -569,11 +684,15 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( options.SetIsTruncated(true); } } - location_sp->GetPointeeData(extractor, 0, size); + + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; // std::wstring::size() is measured in 'characters', not bytes - ClangASTContext *ast_context = - ClangASTContext::GetScratch(*valobj.GetTargetSP()); + TypeSystemClang *ast_context = + TypeSystemClang::GetScratch(*valobj.GetTargetSP()); if (!ast_context) return false; @@ -591,40 +710,35 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( switch (*wchar_t_size) { case 1: - StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF8>( options); break; case 2: - lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF16>( options); break; case 4: - lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream< + return StringPrinter::ReadBufferAndDumpToStream< lldb_private::formatters::StringPrinter::StringElementType::UTF32>( options); - break; - - default: - stream.Printf("size for wchar_t is not valid"); - return true; } - - return true; + return false; } template <StringPrinter::StringElementType element_type> bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, - std::string prefix_token = "") { - uint64_t size = 0; - ValueObjectSP location_sp; - - if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) + std::string prefix_token) { + auto string_info = ExtractLibcxxStringInfo(valobj); + if (!string_info) return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; if (size == 0) { stream.Printf("\"\""); @@ -636,7 +750,6 @@ bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - DataExtractor extractor; if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); if (size > max_size) { @@ -644,41 +757,55 @@ bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, options.SetIsTruncated(true); } } - location_sp->GetPointeeData(extractor, 0, size); + + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; options.SetData(extractor); options.SetStream(&stream); - if (prefix_token.empty()) options.SetPrefixToken(nullptr); else options.SetPrefixToken(prefix_token); - options.SetQuote('"'); options.SetSourceSize(size); options.SetBinaryZeroIsTerminator(false); - StringPrinter::ReadBufferAndDumpToStream<element_type>(options); + return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); +} +template <StringPrinter::StringElementType element_type> +static bool formatStringImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + StreamString scratch_stream; + const bool success = LibcxxStringSummaryProvider<element_type>( + valobj, scratch_stream, summary_options, prefix_token); + if (success) + stream << scratch_stream.GetData(); + else + stream << "Summary Unavailable"; return true; } bool lldb_private::formatters::LibcxxStringSummaryProviderASCII( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>( - valobj, stream, summary_options); + return formatStringImpl<StringPrinter::StringElementType::ASCII>( + valobj, stream, summary_options, ""); } bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>( + return formatStringImpl<StringPrinter::StringElementType::UTF16>( valobj, stream, summary_options, "u"); } bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { - return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>( + return formatStringImpl<StringPrinter::StringElementType::UTF32>( valobj, stream, summary_options, "U"); } |