diff options
Diffstat (limited to 'source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp')
-rw-r--r-- | source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp | 216 |
1 files changed, 151 insertions, 65 deletions
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++/"); +} |