summaryrefslogtreecommitdiff
path: root/source/Plugins/Language/CPlusPlus
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Language/CPlusPlus')
-rw-r--r--source/Plugins/Language/CPlusPlus/BlockPointer.cpp6
-rw-r--r--source/Plugins/Language/CPlusPlus/CMakeLists.txt5
-rw-r--r--source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp216
-rw-r--r--source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h11
-rw-r--r--source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h4
-rw-r--r--source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp14
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxx.cpp186
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxx.h31
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp19
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp15
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxList.cpp4
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxMap.cpp4
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp85
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp4
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp256
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxVariant.h31
-rw-r--r--source/Plugins/Language/CPlusPlus/LibCxxVector.cpp38
-rw-r--r--source/Plugins/Language/CPlusPlus/LibStdcpp.cpp11
-rw-r--r--source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp99
-rw-r--r--source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h51
20 files changed, 904 insertions, 186 deletions
diff --git a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
index 82b7ac1675fa..40200503a8a7 100644
--- a/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
+++ b/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "BlockPointer.h"
#include "lldb/Core/ValueObject.h"
@@ -89,7 +85,7 @@ public:
size_t CalculateNumChildren() override {
const bool omit_empty_base_classes = false;
- return m_block_struct_type.GetNumChildren(omit_empty_base_classes);
+ return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr);
}
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
diff --git a/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 180440a244a4..bc357aa52b84 100644
--- a/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -9,13 +9,16 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxInitializerList.cpp
LibCxxList.cpp
LibCxxMap.cpp
+ LibCxxOptional.cpp
LibCxxQueue.cpp
LibCxxTuple.cpp
LibCxxUnorderedMap.cpp
+ LibCxxVariant.cpp
LibCxxVector.cpp
LibStdcpp.cpp
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
+ MSVCUndecoratedNameParser.cpp
LINK_LIBS
lldbCore
@@ -24,6 +27,8 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
lldbSymbol
lldbTarget
lldbUtility
+ lldbPluginClangCommon
+
LINK_COMPONENTS
Support
)
diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 2c63e6467d4c..982b286d0f05 100644
--- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -9,20 +9,17 @@
#include "CPlusPlusLanguage.h"
-// C Includes
#include <cctype>
#include <cstring>
-// C++ Includes
#include <functional>
#include <memory>
#include <mutex>
#include <set>
-// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/ItaniumDemangle.h"
-// Project includes
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/DataFormatters/CXXFunctionPointer.h"
@@ -30,7 +27,6 @@
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/VectorType.h"
#include "lldb/Utility/ConstString.h"
-#include "lldb/Utility/FastDemangle.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
@@ -39,7 +35,9 @@
#include "CxxStringTypes.h"
#include "LibCxx.h"
#include "LibCxxAtomic.h"
+#include "LibCxxVariant.h"
#include "LibStdcpp.h"
+#include "MSVCUndecoratedNameParser.h"
using namespace lldb;
using namespace lldb_private;
@@ -143,10 +141,7 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) {
}
// We processed all characters. It is a vaild basename.
- if (idx == basename.size())
- return true;
-
- return false;
+ return idx == basename.size();
}
bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
@@ -251,19 +246,23 @@ std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
// FIXME!! we should really run through all the known C++ Language plugins
// and ask each one if this is a C++ mangled name
-
+
if (name == nullptr)
return false;
-
- // MSVC style mangling
+
+ // MSVC style mangling
if (name[0] == '?')
return true;
-
+
return (name[0] != '\0' && name[0] == '_' && name[1] == 'Z');
}
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
+ if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
+ return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
+ identifier);
+
CPlusPlusNameParser parser(name);
if (auto full_name = parser.ParseAsFullName()) {
identifier = full_name.getValue().basename;
@@ -273,53 +272,89 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier(
return false;
}
-/// Given a mangled function `mangled`, replace all the primitive function type
-/// arguments of `search` with type `replace`.
-static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled,
- llvm::StringRef search,
- llvm::StringRef replace) {
- Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
-
- const size_t max_len =
- mangled.size() + mangled.count(search) * replace.size() + 1;
-
- // Make a temporary buffer to fix up the mangled parameter types and copy the
- // original there
- std::string output_buf;
- output_buf.reserve(max_len);
- output_buf.insert(0, mangled.str());
- ptrdiff_t replaced_offset = 0;
-
- auto swap_parms_hook = [&](const char *parsee) {
- if (!parsee || !*parsee)
- return;
-
- // Check whether we've found a substitutee
- llvm::StringRef s(parsee);
- if (s.startswith(search)) {
- // account for the case where a replacement is of a different length to
- // the original
- replaced_offset += replace.size() - search.size();
-
- ptrdiff_t replace_idx = (mangled.size() - s.size()) + replaced_offset;
- output_buf.erase(replace_idx, search.size());
- output_buf.insert(replace_idx, replace.str());
+namespace {
+class NodeAllocator {
+ llvm::BumpPtrAllocator Alloc;
+
+public:
+ void reset() { Alloc.Reset(); }
+
+ template <typename T, typename... Args> T *makeNode(Args &&... args) {
+ return new (Alloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+ alignof(llvm::itanium_demangle::Node *));
+ }
+};
+
+/// Given a mangled function `Mangled`, replace all the primitive function type
+/// arguments of `Search` with type `Replace`.
+class TypeSubstitutor
+ : public llvm::itanium_demangle::AbstractManglingParser<TypeSubstitutor,
+ NodeAllocator> {
+ /// Input character until which we have constructed the respective output
+ /// already
+ const char *Written;
+
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+ llvm::SmallString<128> Result;
+
+ /// Whether we have performed any substitutions.
+ bool Substituted;
+
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ AbstractManglingParser::reset(Mangled.begin(), Mangled.end());
+ Written = Mangled.begin();
+ this->Search = Search;
+ this->Replace = Replace;
+ Result.clear();
+ Substituted = false;
+ }
+
+ void appendUnchangedInput() {
+ Result += llvm::StringRef(Written, First - Written);
+ Written = First;
+ }
+
+public:
+ TypeSubstitutor() : AbstractManglingParser(nullptr, nullptr) {}
+
+ ConstString substitute(llvm::StringRef Mangled, llvm::StringRef From,
+ llvm::StringRef To) {
+ Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
+
+ reset(Mangled, From, To);
+ if (parse() == nullptr) {
+ LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
+ return ConstString();
}
- };
+ if (!Substituted)
+ return ConstString();
- // FastDemangle will call our hook for each instance of a primitive type,
- // allowing us to perform substitution
- char *const demangled =
- FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook);
+ // Append any trailing unmodified input.
+ appendUnchangedInput();
+ LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
+ return ConstString(Result);
+ }
- if (log)
- log->Printf("substituted mangling for %s:{%s} %s:{%s}\n",
- mangled.str().c_str(), demangled, output_buf.c_str(),
- FastDemangle(output_buf.c_str()));
- // FastDemangle malloc'd this string.
- free(demangled);
+ llvm::itanium_demangle::Node *parseType() {
+ if (llvm::StringRef(First, numLeft()).startswith(Search)) {
+ // We found a match. Append unmodified input up to this point.
+ appendUnchangedInput();
- return output_buf == mangled ? ConstString() : ConstString(output_buf);
+ // And then perform the replacement.
+ Result += Replace;
+ Written += Search.size();
+ Substituted = true;
+ }
+ return AbstractManglingParser::parseType();
+ }
+};
}
uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
@@ -348,23 +383,24 @@ uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
alternates.insert(ConstString(fixed_scratch));
}
+ TypeSubstitutor TS;
// `char` is implementation defined as either `signed` or `unsigned`. As a
// result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
// char, 'h'-unsigned char. If we're looking for symbols with a signed char
// parameter, try finding matches which have the general case 'c'.
if (ConstString char_fixup =
- SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c"))
+ TS.substitute(mangled_name.GetStringRef(), "a", "c"))
alternates.insert(char_fixup);
// long long parameter mangling 'x', may actually just be a long 'l' argument
if (ConstString long_fixup =
- SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l"))
+ TS.substitute(mangled_name.GetStringRef(), "x", "l"))
alternates.insert(long_fixup);
// unsigned long long parameter mangling 'y', may actually just be unsigned
// long 'm' argument
if (ConstString ulong_fixup =
- SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m"))
+ TS.substitute(mangled_name.GetStringRef(), "y", "m"))
alternates.insert(ulong_fixup);
return alternates.size() - start_size;
@@ -385,8 +421,17 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
#ifndef LLDB_DISABLE_PYTHON
lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(
- stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider,
+ stl_summary_flags,
+ lldb_private::formatters::LibcxxStringSummaryProviderASCII,
"std::string summary provider"));
+ lldb::TypeSummaryImplSP std_stringu16_summary_sp(new CXXFunctionSummaryFormat(
+ stl_summary_flags,
+ lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
+ "std::u16string summary provider"));
+ lldb::TypeSummaryImplSP std_stringu32_summary_sp(new CXXFunctionSummaryFormat(
+ stl_summary_flags,
+ lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
+ "std::u32string summary provider"));
lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(
stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider,
"std::wstring summary provider"));
@@ -400,6 +445,16 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::__1::allocator<char> >"),
std_string_summary_sp);
cpp_category_sp->GetTypeSummariesContainer()->Add(
+ ConstString(
+ "std::__1::basic_string<char16_t, std::__1::char_traits<char16_t>, "
+ "std::__1::allocator<char16_t> >"),
+ std_stringu16_summary_sp);
+ cpp_category_sp->GetTypeSummariesContainer()->Add(
+ ConstString(
+ "std::__1::basic_string<char32_t, std::__1::char_traits<char32_t>, "
+ "std::__1::allocator<char32_t> >"),
+ std_stringu32_summary_sp);
+ cpp_category_sp->GetTypeSummariesContainer()->Add(
ConstString("std::__ndk1::basic_string<char, "
"std::__ndk1::char_traits<char>, "
"std::__ndk1::allocator<char> >"),
@@ -493,6 +548,14 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::tuple synthetic children",
ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_synth_flags,
true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator,
+ "libc++ std::optional synthetic children",
+ ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"),
+ stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
+ "libc++ std::variant synthetic children",
+ ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"),
+ stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
@@ -519,6 +582,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags,
true);
+ AddCXXSummary(
+ cpp_category_sp, lldb_private::formatters::LibcxxFunctionSummaryProvider,
+ "libc++ std::function summary provider",
+ ConstString("^std::__(ndk)?1::function<.+>$"), stl_summary_flags, true);
+
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
AddCXXSummary(cpp_category_sp,
@@ -584,6 +652,16 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider,
"libc++ std::atomic summary provider",
ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxOptionalSummaryProvider,
+ "libc++ std::optional summary provider",
+ ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"),
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxVariantSummaryProvider,
+ "libc++ std::variant summary provider",
+ ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"),
+ stl_summary_flags, true);
stl_summary_flags.SetSkipPointers(true);
@@ -610,11 +688,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::map iterator synthetic children",
ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags,
true);
-
- AddCXXSynthetic(
- cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator,
- "std::function synthetic value provider",
- ConstString("^std::__(ndk)?1::function<.+>$"), stl_synth_flags, true);
#endif
}
@@ -1002,3 +1075,16 @@ CPlusPlusLanguage::GetHardcodedSynthetics() {
return g_formatters;
}
+
+bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
+ ".h", ".hh", ".hpp", ".hxx", ".h++"};
+ for (auto suffix : suffixes) {
+ if (file_path.endswith_lower(suffix))
+ return true;
+ }
+
+ // Check if we're in a STL path (where the files usually have no extension
+ // that we could check for.
+ return file_path.contains("/usr/include/c++/");
+}
diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 7380ef321305..3c8ca96e81f6 100644
--- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -10,15 +10,12 @@
#ifndef liblldb_CPlusPlusLanguage_h_
#define liblldb_CPlusPlusLanguage_h_
-// C Includes
-// C++ Includes
#include <set>
#include <vector>
-// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
-// Project includes
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
#include "lldb/Target/Language.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
@@ -26,6 +23,8 @@
namespace lldb_private {
class CPlusPlusLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
public:
class MethodName {
public:
@@ -90,6 +89,10 @@ public:
HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics() override;
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
index fe1d46f32c17..d46a53a7a704 100644
--- a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
+++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -10,16 +10,12 @@
#ifndef liblldb_CPlusPlusNameParser_h_
#define liblldb_CPlusPlusNameParser_h_
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-// Project includes
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
diff --git a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
index 0f6fb54e8384..24185b314466 100644
--- a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
+++ b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
@@ -100,8 +100,11 @@ bool lldb_private::formatters::WCharStringSummaryProvider(
if (!wchar_compiler_type)
return false;
- const uint32_t wchar_size = wchar_compiler_type.GetBitSize(
- nullptr); // Safe to pass NULL for exe_scope here
+ // Safe to pass nullptr for exe_scope here.
+ llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
options.SetLocation(valobj_addr);
@@ -194,8 +197,11 @@ bool lldb_private::formatters::WCharSummaryProvider(
if (!wchar_compiler_type)
return false;
- const uint32_t wchar_size = wchar_compiler_type.GetBitSize(
- nullptr); // Safe to pass NULL for exe_scope here
+ // Safe to pass nullptr for exe_scope here.
+ llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
options.SetData(data);
diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 95e02a473cd7..7e8c06bd4c75 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -9,10 +9,7 @@
#include "LibCxx.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
+#include "llvm/ADT/ScopeExit.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/ValueObject.h"
@@ -22,7 +19,9 @@
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/VectorIterator.h"
#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/ProcessStructReader.h"
+#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Endian.h"
@@ -33,6 +32,76 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+bool lldb_private::formatters::LibcxxOptionalSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ // An optional either contains a value or not, the member __engaged_ is
+ // a bool flag, it is true if the optional has a value and false otherwise.
+ ValueObjectSP engaged_sp(
+ valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true));
+
+ if (!engaged_sp)
+ return false;
+
+ llvm::StringRef engaged_as_cstring(
+ engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false");
+
+ stream.Printf(" Has Value=%s ", engaged_as_cstring.data());
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+
+ if (!valobj_sp)
+ return false;
+
+ ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == nullptr)
+ return false;
+
+ CPPLanguageRuntime *cpp_runtime = process->GetCPPLanguageRuntime();
+
+ if (!cpp_runtime)
+ return false;
+
+ CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
+ cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
+
+ switch (callable_info.callable_case) {
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
+ stream.Printf(" __f_ = %" PRIu64, callable_info.member__f_pointer_value);
+ return false;
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
+ stream.Printf(
+ " Lambda in File %s at Line %u",
+ callable_info.callable_line_entry.file.GetFilename().GetCString(),
+ callable_info.callable_line_entry.line);
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
+ stream.Printf(
+ " Function in File %s at Line %u",
+ callable_info.callable_line_entry.file.GetFilename().GetCString(),
+ callable_info.callable_line_entry.line);
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
+ stream.Printf(" Function = %s ",
+ callable_info.callable_symbol.GetName().GetCString());
+ break;
+ }
+
+ return true;
+}
+
bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
@@ -120,9 +189,9 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
if (!valobj_sp)
return false;
-
+
static ConstString g___i_("__i_");
-
+
// this must be a ValueObject* because it is a child of the ValueObject we
// are producing children for it if were a ValueObjectSP, we would end up
// with a loop (iterator -> synthetic -> child -> parent == iterator) and
@@ -156,37 +225,53 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
m_pair_ptr = nullptr;
return false;
}
- CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0));
- std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr;
- pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
+ CompilerType pair_type(
+ __i_->GetCompilerType().GetTypeTemplateArgument(0));
+ std::string name;
+ uint64_t bit_offset_ptr;
+ uint32_t bitfield_bit_size_ptr;
+ bool is_bitfield_ptr;
+ pair_type = pair_type.GetFieldAtIndex(
+ 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
if (!pair_type) {
m_pair_ptr = nullptr;
return false;
}
-
+
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());
+ if (addr && addr != LLDB_INVALID_ADDRESS) {
+ ClangASTContext *ast_ctx =
+ llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem());
if (!ast_ctx)
return false;
- CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), {
- {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
- {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
- {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
- {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
- {"payload",pair_type}
- });
- DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0));
+ CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
+ ConstString(),
+ {{"ptr0",
+ ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
+ {"ptr1",
+ ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
+ {"ptr2",
+ ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
+ {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
+ {"payload", pair_type}});
+ llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
+ if (!size)
+ return false;
+ DataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
ProcessSP process_sp(target_sp->GetProcessSP());
Status error;
- process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error);
+ process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
+ buffer_sp->GetByteSize(), error);
if (error.Fail())
return false;
- DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
- auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
+ DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+ auto pair_sp = CreateValueObjectFromData(
+ "pair", extractor, valobj_sp->GetExecutionContextRef(),
+ tree_node_type);
if (pair_sp)
- m_pair_sp = pair_sp->GetChildAtIndex(4,true);
+ m_pair_sp = pair_sp->GetChildAtIndex(4, true);
}
}
}
@@ -491,6 +576,8 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider(
->GetScratchClangASTContext()
->GetBasicType(lldb::eBasicTypeWChar)
.GetByteSize(nullptr);
+ if (!wchar_t_size)
+ return false;
options.SetData(extractor);
options.SetStream(&stream);
@@ -499,7 +586,7 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider(
options.SetSourceSize(size);
options.SetBinaryZeroIsTerminator(false);
- switch (wchar_t_size) {
+ switch (*wchar_t_size) {
case 1:
StringPrinter::ReadBufferAndDumpToStream<
lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
@@ -526,9 +613,10 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider(
return true;
}
-bool lldb_private::formatters::LibcxxStringSummaryProvider(
- ValueObject &valobj, Stream &stream,
- const TypeSummaryOptions &summary_options) {
+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;
@@ -557,31 +645,37 @@ bool lldb_private::formatters::LibcxxStringSummaryProvider(
options.SetData(extractor);
options.SetStream(&stream);
- options.SetPrefixToken(nullptr);
+
+ if (prefix_token.empty())
+ options.SetPrefixToken(nullptr);
+ else
+ options.SetPrefixToken(prefix_token);
+
options.SetQuote('"');
options.SetSourceSize(size);
options.SetBinaryZeroIsTerminator(false);
- StringPrinter::ReadBufferAndDumpToStream<
- StringPrinter::StringElementType::ASCII>(options);
+ StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
return true;
}
-class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd {
-public:
- LibcxxFunctionFrontEnd(ValueObject &backend)
- : SyntheticValueProviderFrontEnd(backend) {}
+bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return LibcxxStringSummaryProvider<StringPrinter::StringElementType::ASCII>(
+ valobj, stream, summary_options);
+}
- lldb::ValueObjectSP GetSyntheticValue() override {
- static ConstString g___f_("__f_");
- return m_backend.GetChildMemberWithName(g___f_, true);
- }
-};
+bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF16>(
+ valobj, stream, summary_options, "u");
+}
-SyntheticChildrenFrontEnd *
-lldb_private::formatters::LibcxxFunctionFrontEndCreator(
- CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
- if (valobj_sp)
- return new LibcxxFunctionFrontEnd(*valobj_sp);
- return nullptr;
+bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return LibcxxStringSummaryProvider<StringPrinter::StringElementType::UTF32>(
+ valobj, stream, summary_options, "U");
}
diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.h b/source/Plugins/Language/CPlusPlus/LibCxx.h
index 3f6e0d6e14d7..224a540eda04 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -19,19 +19,35 @@
namespace lldb_private {
namespace formatters {
-bool LibcxxStringSummaryProvider(
+bool LibcxxStringSummaryProviderASCII(
ValueObject &valobj, Stream &stream,
- const TypeSummaryOptions &options); // libc++ std::string
+ const TypeSummaryOptions &summary_options); // libc++ std::string
+
+bool LibcxxStringSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u16string
+
+bool LibcxxStringSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u32string
bool LibcxxWStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options); // libc++ std::wstring
+bool LibcxxOptionalSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::optional<>
+
bool LibcxxSmartPointerSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions
&options); // libc++ std::shared_ptr<> and std::weak_ptr<>
+bool LibcxxFunctionSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::function<>
+
SyntheticChildrenFrontEnd *
LibcxxVectorBoolSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
@@ -124,15 +140,20 @@ SyntheticChildrenFrontEnd *
LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
-SyntheticChildrenFrontEnd *LibcxxFunctionFrontEndCreator(CXXSyntheticChildren *,
- lldb::ValueObjectSP);
-
SyntheticChildrenFrontEnd *LibcxxQueueFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *LibcxxTupleFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
+SyntheticChildrenFrontEnd *
+LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
+SyntheticChildrenFrontEnd *
+LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
} // namespace formatters
} // namespace lldb_private
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
index 0cdb0b26cf3b..489ac4d96072 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp
@@ -79,17 +79,24 @@ ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
CompilerType type;
ValueObjectSP chunk;
// For small bitsets __first_ is not an array, but a plain size_t.
- if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr))
- chunk = m_first->GetChildAtIndex(
- idx / type.GetBitSize(ctx.GetBestExecutionContextScope()), true);
- else {
+ if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) {
+ llvm::Optional<uint64_t> bit_size =
+ type.GetBitSize(ctx.GetBestExecutionContextScope());
+ if (!bit_size || *bit_size == 0)
+ return {};
+ chunk = m_first->GetChildAtIndex(idx / *bit_size, true);
+ } else {
type = m_first->GetCompilerType();
chunk = m_first;
}
if (!type || !chunk)
- return ValueObjectSP();
+ return {};
- size_t chunk_idx = idx % type.GetBitSize(ctx.GetBestExecutionContextScope());
+ llvm::Optional<uint64_t> bit_size =
+ type.GetBitSize(ctx.GetBestExecutionContextScope());
+ if (!bit_size || *bit_size == 0)
+ return {};
+ size_t chunk_idx = idx % *bit_size;
uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
index 5823f6f3e038..390483d02668 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "LibCxx.h"
#include "lldb/Core/ValueObject.h"
@@ -98,12 +94,11 @@ bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
if (!m_element_type.IsValid())
return false;
- m_element_size = m_element_type.GetByteSize(nullptr);
-
- if (m_element_size > 0)
- m_start =
- m_backend.GetChildMemberWithName(g___begin_, true)
- .get(); // store raw pointers or end up with a circular dependency
+ if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
+ m_element_size = *size;
+ // Store raw pointers or end up with a circular dependency.
+ m_start = m_backend.GetChildMemberWithName(g___begin_, true).get();
+ }
return false;
}
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index 6066f14b18cc..81606b573cea 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "LibCxx.h"
#include "lldb/Core/ValueObject.h"
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 8f82bdcbfd59..429569d57928 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "LibCxx.h"
#include "lldb/Core/ValueObject.h"
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp b/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp
new file mode 100644
index 000000000000..762b824f262a
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/LibCxxOptional.cpp
@@ -0,0 +1,85 @@
+//===-- LibCxxOptional.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class OptionalFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ OptionalFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ bool Update() override;
+ size_t CalculateNumChildren() override { return m_size; }
+ ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+private:
+ size_t m_size = 0;
+ ValueObjectSP m_base_sp;
+};
+} // namespace
+
+bool OptionalFrontEnd::Update() {
+ ValueObjectSP engaged_sp(
+ m_backend.GetChildMemberWithName(ConstString("__engaged_"), true));
+
+ if (!engaged_sp)
+ return false;
+
+ // __engaged_ is a bool flag and is true if the optional contains a value.
+ // Converting it to unsigned gives us a size of 1 if it contains a value
+ // and 0 if not.
+ m_size = engaged_sp->GetValueAsUnsigned(0);
+
+ return false;
+}
+
+ValueObjectSP OptionalFrontEnd::GetChildAtIndex(size_t idx) {
+ if (idx >= m_size)
+ return ValueObjectSP();
+
+ // __val_ contains the underlying value of an optional if it has one.
+ // Currently because it is part of an anonymous union GetChildMemberWithName()
+ // does not peer through and find it unless we are at the parent itself.
+ // We can obtain the parent through __engaged_.
+ ValueObjectSP val_sp(
+ m_backend.GetChildMemberWithName(ConstString("__engaged_"), true)
+ ->GetParent()
+ ->GetChildAtIndex(0, true)
+ ->GetChildMemberWithName(ConstString("__val_"), true));
+
+ if (!val_sp)
+ return ValueObjectSP();
+
+ CompilerType holder_type = val_sp->GetCompilerType();
+
+ if (!holder_type)
+ return ValueObjectSP();
+
+ return val_sp->Clone(ConstString(llvm::formatv("Value").str()));
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxOptionalFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new OptionalFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 0f1c2537d651..51ae8cb3184c 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "LibCxx.h"
#include "lldb/Core/ValueObject.h"
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
new file mode 100644
index 000000000000..e874616c3251
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
@@ -0,0 +1,256 @@
+//===-- LibCxxVariant.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxxVariant.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/ScopeExit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// libc++ variant implementation contains two members that we care about both
+// are contained in the __impl member.
+// - __index which tells us which of the variadic template types is the active
+// type for the variant
+// - __data is a variadic union which recursively contains itself as member
+// which refers to the tailing variadic types.
+// - __head which refers to the leading non pack type
+// - __value refers to the actual value contained
+// - __tail which refers to the remaining pack types
+//
+// e.g. given std::variant<int,double,char> v1
+//
+// (lldb) frame var -R v1.__impl.__data
+//(... __union<... 0, int, double, char>) v1.__impl.__data = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// ...
+//
+// So given
+// - __index equal to 0 the active value is contained in
+//
+// __data.__head.__value
+//
+// - __index equal to 1 the active value is contained in
+//
+// __data.__tail.__head.__value
+//
+// - __index equal to 2 the active value is contained in
+//
+// __data.__tail.__tail.__head.__value
+//
+
+namespace {
+// libc++ std::variant index could have one of three states
+// 1) VALID, we can obtain it and its not variant_npos
+// 2) INVALID, we can't obtain it or it is not a type we expect
+// 3) NPOS, its value is variant_npos which means the variant has no value
+enum class LibcxxVariantIndexValidity { VALID, INVALID, NPOS };
+
+LibcxxVariantIndexValidity
+LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__index"), true));
+
+ if (!index_sp)
+ return LibcxxVariantIndexValidity::INVALID;
+
+ int64_t index_value = index_sp->GetValueAsSigned(0);
+
+ if (index_value == -1)
+ return LibcxxVariantIndexValidity::NPOS;
+
+ return LibcxxVariantIndexValidity::VALID;
+}
+
+llvm::Optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__index"), true));
+
+ if (!index_sp)
+ return {};
+
+ return {index_sp->GetValueAsUnsigned(0)};
+}
+
+ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
+ ValueObjectSP data_sp(
+ impl_sp->GetChildMemberWithName(ConstString("__data"), true));
+
+ if (!data_sp)
+ return ValueObjectSP{};
+
+ ValueObjectSP current_level = data_sp;
+ for (uint64_t n = index; n != 0; --n) {
+ ValueObjectSP tail_sp(
+ current_level->GetChildMemberWithName(ConstString("__tail"), true));
+
+ if (!tail_sp)
+ return ValueObjectSP{};
+
+ current_level = tail_sp;
+ }
+
+ return current_level->GetChildMemberWithName(ConstString("__head"), true);
+}
+} // namespace
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP impl_sp(
+ valobj_sp->GetChildMemberWithName(ConstString("__impl"), true));
+
+ if (!impl_sp)
+ return false;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::INVALID)
+ return false;
+
+ if (validity == LibcxxVariantIndexValidity::NPOS) {
+ stream.Printf(" No Value");
+ return true;
+ }
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return false;
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return false;
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return false;
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return false;
+
+ stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString());
+
+ return true;
+}
+} // namespace formatters
+} // namespace lldb_private
+
+namespace {
+class VariantFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(const ConstString &name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ bool Update() override;
+ size_t CalculateNumChildren() override { return m_size; }
+ ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+private:
+ size_t m_size = 0;
+ ValueObjectSP m_base_sp;
+};
+} // namespace
+
+bool VariantFrontEnd::Update() {
+ m_size = 0;
+ ValueObjectSP impl_sp(
+ m_backend.GetChildMemberWithName(ConstString("__impl"), true));
+ if (!impl_sp)
+ return false;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::INVALID)
+ return false;
+
+ if (validity == LibcxxVariantIndexValidity::NPOS)
+ return true;
+
+ m_size = 1;
+
+ return false;
+}
+
+ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) {
+ if (idx >= m_size)
+ return ValueObjectSP();
+
+ ValueObjectSP impl_sp(
+ m_backend.GetChildMemberWithName(ConstString("__impl"), true));
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return ValueObjectSP();
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return ValueObjectSP();
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return ValueObjectSP();
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return ValueObjectSP();
+
+ ValueObjectSP head_value(
+ nth_head->GetChildMemberWithName(ConstString("__value"), true));
+
+ if (!head_value)
+ return ValueObjectSP();
+
+ return head_value->Clone(ConstString(ConstString("Value").AsCString()));
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new VariantFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVariant.h b/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
new file mode 100644
index 000000000000..04834581963f
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
@@ -0,0 +1,31 @@
+//===-- LibCxxVariant.h -------------------------------------------*- C++
+//-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_LibCxxVariant_h_
+#define liblldb_LibCxxVariant_h_
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::variant<>
+
+SyntheticChildrenFrontEnd *LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // liblldb_LibCxxVariant_h_
diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 711130639cd2..ed405c875174 100644
--- a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -7,10 +7,6 @@
//
//===----------------------------------------------------------------------===//
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "LibCxx.h"
#include "lldb/Core/ValueObject.h"
@@ -149,14 +145,16 @@ bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
if (!data_type_finder_sp)
return false;
m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
- m_element_size = m_element_type.GetByteSize(nullptr);
-
- 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();
+ if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
+ m_element_size = *size;
+
+ 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;
}
@@ -196,27 +194,29 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
if (iter != end)
return iter->second;
if (idx >= m_count)
- return ValueObjectSP();
+ return {};
if (m_base_data_address == 0 || m_count == 0)
- return ValueObjectSP();
+ return {};
if (!m_bool_type)
- return ValueObjectSP();
+ return {};
size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
lldb::addr_t byte_location = m_base_data_address + byte_idx;
ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
if (!process_sp)
- return ValueObjectSP();
+ return {};
uint8_t byte = 0;
uint8_t mask = 0;
Status err;
size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
if (err.Fail() || bytes_read == 0)
- return ValueObjectSP();
+ return {};
mask = 1 << bit_index;
bool bit_set = ((byte & mask) != 0);
- DataBufferSP buffer_sp(
- new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0));
+ llvm::Optional<uint64_t> size = m_bool_type.GetByteSize(nullptr);
+ if (!size)
+ return {};
+ DataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
// regardless of endianness, anything non-zero is true
*(buffer_sp->GetBytes()) = 1;
diff --git a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index 3e2b7159f894..695371fc3992 100644
--- a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -9,10 +9,6 @@
#include "LibStdcpp.h"
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
@@ -301,8 +297,11 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
if (!wchar_compiler_type)
return false;
- const uint32_t wchar_size = wchar_compiler_type.GetBitSize(
- nullptr); // Safe to pass NULL for exe_scope here
+ // Safe to pass nullptr for exe_scope here.
+ llvm::Optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
Status error;
diff --git a/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
new file mode 100644
index 000000000000..84f03e0e3016
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
@@ -0,0 +1,99 @@
+//===-- MSVCUndecoratedNameParser.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSVCUndecoratedNameParser.h"
+
+#include <stack>
+
+MSVCUndecoratedNameParser::MSVCUndecoratedNameParser(llvm::StringRef name) {
+ std::size_t last_base_start = 0;
+
+ std::stack<std::size_t> stack;
+ unsigned int open_angle_brackets = 0;
+ for (size_t i = 0; i < name.size(); i++) {
+ switch (name[i]) {
+ case '<':
+ // Do not treat `operator<' and `operator<<' as templates
+ // (sometimes they represented as `<' and `<<' in the name).
+ if (i == last_base_start ||
+ (i == last_base_start + 1 && name[last_base_start] == '<'))
+ break;
+
+ stack.push(i);
+ open_angle_brackets++;
+
+ break;
+ case '>':
+ if (!stack.empty() && name[stack.top()] == '<') {
+ open_angle_brackets--;
+ stack.pop();
+ }
+
+ break;
+ case '`':
+ stack.push(i);
+
+ break;
+ case '\'':
+ while (!stack.empty()) {
+ std::size_t top = stack.top();
+ if (name[top] == '<')
+ open_angle_brackets--;
+
+ stack.pop();
+
+ if (name[top] == '`')
+ break;
+ }
+
+ break;
+ case ':':
+ if (open_angle_brackets)
+ break;
+ if (i == 0 || name[i - 1] != ':')
+ break;
+
+ m_specifiers.emplace_back(name.take_front(i - 1),
+ name.slice(last_base_start, i - 1));
+
+ last_base_start = i + 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ m_specifiers.emplace_back(name, name.drop_front(last_base_start));
+}
+
+bool MSVCUndecoratedNameParser::IsMSVCUndecoratedName(llvm::StringRef name) {
+ return name.find('`') != llvm::StringRef::npos;
+}
+
+bool MSVCUndecoratedNameParser::ExtractContextAndIdentifier(
+ llvm::StringRef name, llvm::StringRef &context,
+ llvm::StringRef &identifier) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ std::size_t count = specs.size();
+ identifier = count > 0 ? specs[count - 1].GetBaseName() : "";
+ context = count > 1 ? specs[count - 2].GetFullName() : "";
+
+ return count;
+}
+
+llvm::StringRef MSVCUndecoratedNameParser::DropScope(llvm::StringRef name) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+ if (specs.empty())
+ return "";
+
+ return specs[specs.size() - 1].GetBaseName();
+}
diff --git a/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
new file mode 100644
index 000000000000..0c49100d8d49
--- /dev/null
+++ b/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
@@ -0,0 +1,51 @@
+//===-- MSVCUndecoratedNameParser.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MSVCUndecoratedNameParser_h_
+#define liblldb_MSVCUndecoratedNameParser_h_
+
+#include <vector>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+class MSVCUndecoratedNameSpecifier {
+public:
+ MSVCUndecoratedNameSpecifier(llvm::StringRef full_name,
+ llvm::StringRef base_name)
+ : m_full_name(full_name), m_base_name(base_name) {}
+
+ llvm::StringRef GetFullName() const { return m_full_name; }
+ llvm::StringRef GetBaseName() const { return m_base_name; }
+
+private:
+ llvm::StringRef m_full_name;
+ llvm::StringRef m_base_name;
+};
+
+class MSVCUndecoratedNameParser {
+public:
+ explicit MSVCUndecoratedNameParser(llvm::StringRef name);
+
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> GetSpecifiers() const {
+ return m_specifiers;
+ }
+
+ static bool IsMSVCUndecoratedName(llvm::StringRef name);
+ static bool ExtractContextAndIdentifier(llvm::StringRef name,
+ llvm::StringRef &context,
+ llvm::StringRef &identifier);
+
+ static llvm::StringRef DropScope(llvm::StringRef name);
+
+private:
+ std::vector<MSVCUndecoratedNameSpecifier> m_specifiers;
+};
+
+#endif