diff options
Diffstat (limited to 'source/Plugins/Language/CPlusPlus')
19 files changed, 1097 insertions, 393 deletions
diff --git a/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 5e105aa19b6b..8f769c499987 100644 --- a/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -1,6 +1,7 @@ -add_lldb_library(lldbPluginCPlusPlusLanguage +add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN BlockPointer.cpp CPlusPlusLanguage.cpp + CPlusPlusNameParser.cpp CxxStringTypes.cpp LibCxx.cpp LibCxxAtomic.cpp @@ -12,4 +13,14 @@ add_lldb_library(lldbPluginCPlusPlusLanguage LibStdcpp.cpp LibStdcppTuple.cpp LibStdcppUniquePointer.cpp + + LINK_LIBS + lldbCore + lldbDataFormatters + lldbHost + lldbSymbol + lldbTarget + lldbUtility + LINK_COMPONENTS + Support ) diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index b5527edacd13..fe42a5ed9214 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -23,18 +23,19 @@ #include "llvm/ADT/StringRef.h" // Project includes -#include "lldb/Core/ConstString.h" -#include "lldb/Core/FastDemangle.h" -#include "lldb/Core/Log.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/RegularExpression.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/DataFormatters/CXXFunctionPointer.h" #include "lldb/DataFormatters/DataVisualization.h" #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" #include "BlockPointer.h" +#include "CPlusPlusNameParser.h" #include "CxxStringTypes.h" #include "LibCxx.h" #include "LibCxxAtomic.h" @@ -84,15 +85,14 @@ void CPlusPlusLanguage::MethodName::Clear() { m_context = llvm::StringRef(); m_arguments = llvm::StringRef(); m_qualifiers = llvm::StringRef(); - m_type = eTypeInvalid; m_parsed = false; m_parse_error = false; } -bool ReverseFindMatchingChars(const llvm::StringRef &s, - const llvm::StringRef &left_right_chars, - size_t &left_pos, size_t &right_pos, - size_t pos = llvm::StringRef::npos) { +static bool ReverseFindMatchingChars(const llvm::StringRef &s, + const llvm::StringRef &left_right_chars, + size_t &left_pos, size_t &right_pos, + size_t pos = llvm::StringRef::npos) { assert(left_right_chars.size() == 2); left_pos = llvm::StringRef::npos; const char left_char = left_right_chars[0]; @@ -118,10 +118,9 @@ bool ReverseFindMatchingChars(const llvm::StringRef &s, return false; } -static bool IsValidBasename(const llvm::StringRef &basename) { - // Check that the basename matches with the following regular expression or is - // an operator name: - // "^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$" +static bool IsTrivialBasename(const llvm::StringRef &basename) { + // Check that the basename matches with the following regular expression + // "^~?([A-Za-z_][A-Za-z_0-9]*)$" // We are using a hand written implementation because it is significantly more // efficient then // using the general purpose regular expression library. @@ -148,100 +147,69 @@ static bool IsValidBasename(const llvm::StringRef &basename) { if (idx == basename.size()) return true; - // Check for basename with template arguments - // TODO: Improve the quality of the validation with validating the template - // arguments - if (basename[idx] == '<' && basename.back() == '>') - return true; + return false; +} - // Check if the basename is a vaild C++ operator name - if (!basename.startswith("operator")) - return false; +bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() { + // This method tries to parse simple method definitions + // which are presumably most comman in user programs. + // Definitions that can be parsed by this function don't have return types + // and templates in the name. + // A::B::C::fun(std::vector<T> &) const + size_t arg_start, arg_end; + llvm::StringRef full(m_full.GetCString()); + llvm::StringRef parens("()", 2); + if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { + m_arguments = full.substr(arg_start, arg_end - arg_start + 1); + if (arg_end + 1 < full.size()) + m_qualifiers = full.substr(arg_end + 1).ltrim(); + + if (arg_start == 0) + return false; + size_t basename_end = arg_start; + size_t context_start = 0; + size_t context_end = full.rfind(':', basename_end); + if (context_end == llvm::StringRef::npos) + m_basename = full.substr(0, basename_end); + else { + if (context_start < context_end) + m_context = full.substr(context_start, context_end - 1 - context_start); + const size_t basename_begin = context_end + 1; + m_basename = full.substr(basename_begin, basename_end - basename_begin); + } - static RegularExpression g_operator_regex( - llvm::StringRef("^(operator)( " - "?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|" - "\\[\\]|[\\^<>=!\\/" - "*+-]+)(<.*>)?(\\[\\])?$")); - std::string basename_str(basename.str()); - return g_operator_regex.Execute(basename_str, nullptr); + if (IsTrivialBasename(m_basename)) { + return true; + } else { + // The C++ basename doesn't match our regular expressions so this can't + // be a valid C++ method, clear everything out and indicate an error + m_context = llvm::StringRef(); + m_basename = llvm::StringRef(); + m_arguments = llvm::StringRef(); + m_qualifiers = llvm::StringRef(); + return false; + } + } + return false; } void CPlusPlusLanguage::MethodName::Parse() { if (!m_parsed && m_full) { - // ConstString mangled; - // m_full.GetMangledCounterpart(mangled); - // printf ("\n parsing = '%s'\n", m_full.GetCString()); - // if (mangled) - // printf (" mangled = '%s'\n", mangled.GetCString()); - m_parse_error = false; - m_parsed = true; - llvm::StringRef full(m_full.GetCString()); - - size_t arg_start, arg_end; - llvm::StringRef parens("()", 2); - if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { - m_arguments = full.substr(arg_start, arg_end - arg_start + 1); - if (arg_end + 1 < full.size()) - m_qualifiers = full.substr(arg_end + 1); - if (arg_start > 0) { - size_t basename_end = arg_start; - size_t context_start = 0; - size_t context_end = llvm::StringRef::npos; - if (basename_end > 0 && full[basename_end - 1] == '>') { - // TODO: handle template junk... - // Templated function - size_t template_start, template_end; - llvm::StringRef lt_gt("<>", 2); - if (ReverseFindMatchingChars(full, lt_gt, template_start, - template_end, basename_end)) { - // Check for templated functions that include return type like: - // 'void foo<Int>()' - context_start = full.rfind(' ', template_start); - if (context_start == llvm::StringRef::npos) - context_start = 0; - else - ++context_start; - - context_end = full.rfind(':', template_start); - if (context_end == llvm::StringRef::npos || - context_end < context_start) - context_end = context_start; - } else { - context_end = full.rfind(':', basename_end); - } - } else if (context_end == llvm::StringRef::npos) { - context_end = full.rfind(':', basename_end); - } - - if (context_end == llvm::StringRef::npos) - m_basename = full.substr(0, basename_end); - else { - if (context_start < context_end) - m_context = - full.substr(context_start, context_end - 1 - context_start); - const size_t basename_begin = context_end + 1; - m_basename = - full.substr(basename_begin, basename_end - basename_begin); - } - m_type = eTypeUnknownMethod; + if (TrySimplifiedParse()) { + m_parse_error = false; + } else { + CPlusPlusNameParser parser(m_full.GetStringRef()); + if (auto function = parser.ParseAsFunctionDefinition()) { + m_basename = function.getValue().name.basename; + m_context = function.getValue().name.context; + m_arguments = function.getValue().arguments; + m_qualifiers = function.getValue().qualifiers; + m_parse_error = false; } else { m_parse_error = true; - return; - } - - if (!IsValidBasename(m_basename)) { - // The C++ basename doesn't match our regular expressions so this can't - // be a valid C++ method, clear everything out and indicate an error - m_context = llvm::StringRef(); - m_basename = llvm::StringRef(); - m_arguments = llvm::StringRef(); - m_qualifiers = llvm::StringRef(); - m_parse_error = true; } - } else { - m_parse_error = true; } + m_parsed = true; } } @@ -272,14 +240,13 @@ llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() { std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { if (!m_parsed) Parse(); - if (m_basename.empty() || m_context.empty()) - return std::string(); + if (m_context.empty()) + return m_basename; std::string res; res += m_context; res += "::"; res += m_basename; - return res; } @@ -295,13 +262,10 @@ bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { bool CPlusPlusLanguage::ExtractContextAndIdentifier( const char *name, llvm::StringRef &context, llvm::StringRef &identifier) { - static RegularExpression g_basename_regex(llvm::StringRef( - "^(([A-Za-z_][A-Za-z_0-9]*::)*)(~?[A-Za-z_~][A-Za-z_0-9]*)$")); - RegularExpression::Match match(4); - if (g_basename_regex.Execute(llvm::StringRef::withNullAsEmpty(name), - &match)) { - match.GetMatchAtIndex(name, 1, context); - match.GetMatchAtIndex(name, 3, identifier); + CPlusPlusNameParser parser(name); + if (auto full_name = parser.ParseAsFullName()) { + identifier = full_name.getValue().basename; + context = full_name.getValue().context; return true; } return false; @@ -596,13 +560,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, - lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, - "libc++ std::vector<bool> synthetic children", - ConstString( - "^std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >$"), - stl_synth_flags, true); - AddCXXSynthetic( - cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags, @@ -620,19 +577,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { true); AddCXXSynthetic( cpp_category_sp, - lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, - "libc++ std::vector<bool> synthetic children", - ConstString("std::__(ndk)?1::vector<std::__(ndk)?1::allocator<bool> >"), - stl_synth_flags); - AddCXXSynthetic( - cpp_category_sp, - lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, - "libc++ std::vector<bool> synthetic children", - ConstString( - "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"), - stl_synth_flags); - AddCXXSynthetic( - cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags, @@ -689,12 +633,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::vector<bool> summary provider", - ConstString( - "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"), - stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", @@ -759,12 +697,6 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::vector iterator synthetic children", ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::vector<bool> summary provider", - ConstString( - "std::__(ndk)?1::vector<bool, std::__(ndk)?1::allocator<bool> >"), - stl_summary_flags); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, @@ -775,7 +707,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator, "std::function synthetic value provider", - ConstString("^std::__1::function<.+>$"), stl_synth_flags, true); + ConstString("^std::__(ndk)?1::function<.+>$"), stl_synth_flags, true); #endif } @@ -1036,10 +968,10 @@ std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() { } lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { - static std::once_flag g_initialize; + static llvm::once_flag g_initialize; static TypeCategoryImplSP g_category; - std::call_once(g_initialize, [this]() -> void { + llvm::call_once(g_initialize, [this]() -> void { DataVisualization::Categories::GetCategory(GetPluginName(), g_category); if (g_category) { LoadLibCxxFormatters(g_category); @@ -1052,11 +984,11 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { HardcodedFormatters::HardcodedSummaryFinder CPlusPlusLanguage::GetHardcodedSummaries() { - static std::once_flag g_initialize; + static llvm::once_flag g_initialize; static ConstString g_vectortypes("VectorTypes"); static HardcodedFormatters::HardcodedSummaryFinder g_formatters; - std::call_once(g_initialize, []() -> void { + llvm::call_once(g_initialize, []() -> void { g_formatters.push_back( [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, FormatManager &) -> TypeSummaryImpl::SharedPointer { @@ -1116,11 +1048,11 @@ CPlusPlusLanguage::GetHardcodedSummaries() { HardcodedFormatters::HardcodedSyntheticFinder CPlusPlusLanguage::GetHardcodedSynthetics() { - static std::once_flag g_initialize; + static llvm::once_flag g_initialize; static ConstString g_vectortypes("VectorTypes"); static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; - std::call_once(g_initialize, []() -> void { + llvm::call_once(g_initialize, []() -> void { g_formatters.push_back([](lldb_private::ValueObject &valobj, lldb::DynamicValueType, FormatManager & diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index be5cbae57de2..056cced2808a 100644 --- a/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -19,8 +19,8 @@ #include "llvm/ADT/StringRef.h" // Project includes -#include "lldb/Core/ConstString.h" #include "lldb/Target/Language.h" +#include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -29,20 +29,13 @@ class CPlusPlusLanguage : public Language { public: class MethodName { public: - enum Type { - eTypeInvalid, - eTypeUnknownMethod, - eTypeClassMethod, - eTypeInstanceMethod - }; - MethodName() : m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers(), - m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {} + m_parsed(false), m_parse_error(false) {} MethodName(const ConstString &s) : m_full(s), m_basename(), m_context(), m_arguments(), m_qualifiers(), - m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {} + m_parsed(false), m_parse_error(false) {} void Clear(); @@ -51,13 +44,9 @@ public: Parse(); if (m_parse_error) return false; - if (m_type == eTypeInvalid) - return false; return (bool)m_full; } - Type GetType() const { return m_type; } - const ConstString &GetFullName() const { return m_full; } std::string GetScopeQualifiedName(); @@ -72,6 +61,7 @@ public: protected: void Parse(); + bool TrySimplifiedParse(); ConstString m_full; // Full name: // "lldb::SBTarget::GetBreakpointAtIndex(unsigned int) @@ -80,7 +70,6 @@ public: llvm::StringRef m_context; // Decl context: "lldb::SBTarget" llvm::StringRef m_arguments; // Arguments: "(unsigned int)" llvm::StringRef m_qualifiers; // Qualifiers: "const" - Type m_type; bool m_parsed; bool m_parse_error; }; @@ -121,7 +110,7 @@ public: // If the name is a lone C identifier (e.g. C) or a qualified C identifier // (e.g. A::B::C) it will return true, // and identifier will be the identifier (C and C respectively) and the - // context will be "" and "A::B::" respectively. + // context will be "" and "A::B" respectively. // If the name fails the heuristic matching for a qualified or unqualified // C/C++ identifier, then it will return false // and identifier and context will be unchanged. diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp new file mode 100644 index 000000000000..5f0596cc9ad2 --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -0,0 +1,630 @@ +//===-- CPlusPlusNameParser.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CPlusPlusNameParser.h" + +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Threading.h" + +using namespace lldb; +using namespace lldb_private; +using llvm::Optional; +using llvm::None; +using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction; +using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName; +namespace tok = clang::tok; + +Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() { + m_next_token_index = 0; + Optional<ParsedFunction> result(None); + + // Try to parse the name as function without a return type specified + // e.g. main(int, char*[]) + { + Bookmark start_position = SetBookmark(); + result = ParseFunctionImpl(false); + if (result && !HasMoreTokens()) + return result; + } + + // Try to parse the name as function with function pointer return type + // e.g. void (*get_func(const char*))() + result = ParseFuncPtr(true); + if (result) + return result; + + // Finally try to parse the name as a function with non-function return type + // e.g. int main(int, char*[]) + result = ParseFunctionImpl(true); + if (HasMoreTokens()) + return None; + return result; +} + +Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() { + m_next_token_index = 0; + Optional<ParsedNameRanges> name_ranges = ParseFullNameImpl(); + if (!name_ranges) + return None; + if (HasMoreTokens()) + return None; + ParsedName result; + result.basename = GetTextForRange(name_ranges.getValue().basename_range); + result.context = GetTextForRange(name_ranges.getValue().context_range); + return result; +} + +bool CPlusPlusNameParser::HasMoreTokens() { + return m_next_token_index < m_tokens.size(); +} + +void CPlusPlusNameParser::Advance() { ++m_next_token_index; } + +void CPlusPlusNameParser::TakeBack() { --m_next_token_index; } + +bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) { + if (!HasMoreTokens()) + return false; + + if (!Peek().is(kind)) + return false; + + Advance(); + return true; +} + +template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) { + if (!HasMoreTokens()) + return false; + + if (!Peek().isOneOf(kinds...)) + return false; + + Advance(); + return true; +} + +CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() { + return Bookmark(m_next_token_index); +} + +size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; } + +clang::Token &CPlusPlusNameParser::Peek() { + assert(HasMoreTokens()); + return m_tokens[m_next_token_index]; +} + +Optional<ParsedFunction> +CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) { + Bookmark start_position = SetBookmark(); + if (expect_return_type) { + // Consume return type if it's expected. + if (!ConsumeTypename()) + return None; + } + + auto maybe_name = ParseFullNameImpl(); + if (!maybe_name) { + return None; + } + + size_t argument_start = GetCurrentPosition(); + if (!ConsumeArguments()) { + return None; + } + + size_t qualifiers_start = GetCurrentPosition(); + SkipFunctionQualifiers(); + size_t end_position = GetCurrentPosition(); + + ParsedFunction result; + result.name.basename = GetTextForRange(maybe_name.getValue().basename_range); + result.name.context = GetTextForRange(maybe_name.getValue().context_range); + result.arguments = GetTextForRange(Range(argument_start, qualifiers_start)); + result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position)); + start_position.Remove(); + return result; +} + +Optional<ParsedFunction> +CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) { + Bookmark start_position = SetBookmark(); + if (expect_return_type) { + // Consume return type. + if (!ConsumeTypename()) + return None; + } + + if (!ConsumeToken(tok::l_paren)) + return None; + if (!ConsumePtrsAndRefs()) + return None; + + { + Bookmark before_inner_function_pos = SetBookmark(); + auto maybe_inner_function_name = ParseFunctionImpl(false); + if (maybe_inner_function_name) + if (ConsumeToken(tok::r_paren)) + if (ConsumeArguments()) { + SkipFunctionQualifiers(); + start_position.Remove(); + before_inner_function_pos.Remove(); + return maybe_inner_function_name; + } + } + + auto maybe_inner_function_ptr_name = ParseFuncPtr(false); + if (maybe_inner_function_ptr_name) + if (ConsumeToken(tok::r_paren)) + if (ConsumeArguments()) { + SkipFunctionQualifiers(); + start_position.Remove(); + return maybe_inner_function_ptr_name; + } + return None; +} + +bool CPlusPlusNameParser::ConsumeArguments() { + return ConsumeBrackets(tok::l_paren, tok::r_paren); +} + +bool CPlusPlusNameParser::ConsumeTemplateArgs() { + Bookmark start_position = SetBookmark(); + if (!HasMoreTokens() || Peek().getKind() != tok::less) + return false; + Advance(); + + // Consuming template arguments is a bit trickier than consuming function + // arguments, because '<' '>' brackets are not always trivially balanced. + // In some rare cases tokens '<' and '>' can appear inside template arguments + // as arithmetic or shift operators not as template brackets. + // Examples: std::enable_if<(10u)<(64), bool> + // f<A<operator<(X,Y)::Subclass>> + // Good thing that compiler makes sure that really ambiguous cases of + // '>' usage should be enclosed within '()' brackets. + int template_counter = 1; + bool can_open_template = false; + while (HasMoreTokens() && template_counter > 0) { + tok::TokenKind kind = Peek().getKind(); + switch (kind) { + case tok::greatergreater: + template_counter -= 2; + can_open_template = false; + Advance(); + break; + case tok::greater: + --template_counter; + can_open_template = false; + Advance(); + break; + case tok::less: + // '<' is an attempt to open a subteamplte + // check if parser is at the point where it's actually possible, + // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. + // No need to do the same for '>' because compiler actually makes sure + // that '>' always surrounded by brackets to avoid ambiguity. + if (can_open_template) + ++template_counter; + can_open_template = false; + Advance(); + break; + case tok::kw_operator: // C++ operator overloading. + if (!ConsumeOperator()) + return false; + can_open_template = true; + break; + case tok::raw_identifier: + can_open_template = true; + Advance(); + break; + case tok::l_square: + if (!ConsumeBrackets(tok::l_square, tok::r_square)) + return false; + can_open_template = false; + break; + case tok::l_paren: + if (!ConsumeArguments()) + return false; + can_open_template = false; + break; + default: + can_open_template = false; + Advance(); + break; + } + } + + assert(template_counter >= 0); + if (template_counter > 0) { + return false; + } + start_position.Remove(); + return true; +} + +bool CPlusPlusNameParser::ConsumeAnonymousNamespace() { + Bookmark start_position = SetBookmark(); + if (!ConsumeToken(tok::l_paren)) { + return false; + } + constexpr llvm::StringLiteral g_anonymous("anonymous"); + if (HasMoreTokens() && Peek().is(tok::raw_identifier) && + Peek().getRawIdentifier() == g_anonymous) { + Advance(); + } else { + return false; + } + + if (!ConsumeToken(tok::kw_namespace)) { + return false; + } + + if (!ConsumeToken(tok::r_paren)) { + return false; + } + start_position.Remove(); + return true; +} + +bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left, + tok::TokenKind right) { + Bookmark start_position = SetBookmark(); + if (!HasMoreTokens() || Peek().getKind() != left) + return false; + Advance(); + + int counter = 1; + while (HasMoreTokens() && counter > 0) { + tok::TokenKind kind = Peek().getKind(); + if (kind == right) + --counter; + else if (kind == left) + ++counter; + Advance(); + } + + assert(counter >= 0); + if (counter > 0) { + return false; + } + start_position.Remove(); + return true; +} + +bool CPlusPlusNameParser::ConsumeOperator() { + Bookmark start_position = SetBookmark(); + if (!ConsumeToken(tok::kw_operator)) + return false; + + if (!HasMoreTokens()) { + return false; + } + + const auto &token = Peek(); + switch (token.getKind()) { + case tok::kw_new: + case tok::kw_delete: + // This is 'new' or 'delete' operators. + Advance(); + // Check for array new/delete. + if (HasMoreTokens() && Peek().is(tok::l_square)) { + // Consume the '[' and ']'. + if (!ConsumeBrackets(tok::l_square, tok::r_square)) + return false; + } + break; + +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ + case tok::Token: \ + Advance(); \ + break; +#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly) +#include "clang/Basic/OperatorKinds.def" +#undef OVERLOADED_OPERATOR +#undef OVERLOADED_OPERATOR_MULTI + + case tok::l_paren: + // Call operator consume '(' ... ')'. + if (ConsumeBrackets(tok::l_paren, tok::r_paren)) + break; + return false; + + case tok::l_square: + // This is a [] operator. + // Consume the '[' and ']'. + if (ConsumeBrackets(tok::l_square, tok::r_square)) + break; + return false; + + default: + // This might be a cast operator. + if (ConsumeTypename()) + break; + return false; + } + start_position.Remove(); + return true; +} + +void CPlusPlusNameParser::SkipTypeQualifiers() { + while (ConsumeToken(tok::kw_const, tok::kw_volatile)) + ; +} + +void CPlusPlusNameParser::SkipFunctionQualifiers() { + while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp)) + ; +} + +bool CPlusPlusNameParser::ConsumeBuiltinType() { + bool result = false; + bool continue_parsing = true; + // Built-in types can be made of a few keywords + // like 'unsigned long long int'. This function + // consumes all built-in type keywords without + // checking if they make sense like 'unsigned char void'. + while (continue_parsing && HasMoreTokens()) { + switch (Peek().getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw___float128: + case tok::kw_wchar_t: + case tok::kw_bool: + case tok::kw_char16_t: + case tok::kw_char32_t: + result = true; + Advance(); + break; + default: + continue_parsing = false; + break; + } + } + return result; +} + +void CPlusPlusNameParser::SkipPtrsAndRefs() { + // Ignoring result. + ConsumePtrsAndRefs(); +} + +bool CPlusPlusNameParser::ConsumePtrsAndRefs() { + bool found = false; + SkipTypeQualifiers(); + while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const, + tok::kw_volatile)) { + found = true; + SkipTypeQualifiers(); + } + return found; +} + +bool CPlusPlusNameParser::ConsumeDecltype() { + Bookmark start_position = SetBookmark(); + if (!ConsumeToken(tok::kw_decltype)) + return false; + + if (!ConsumeArguments()) + return false; + + start_position.Remove(); + return true; +} + +bool CPlusPlusNameParser::ConsumeTypename() { + Bookmark start_position = SetBookmark(); + SkipTypeQualifiers(); + if (!ConsumeBuiltinType() && !ConsumeDecltype()) { + if (!ParseFullNameImpl()) + return false; + } + SkipPtrsAndRefs(); + start_position.Remove(); + return true; +} + +Optional<CPlusPlusNameParser::ParsedNameRanges> +CPlusPlusNameParser::ParseFullNameImpl() { + // Name parsing state machine. + enum class State { + Beginning, // start of the name + AfterTwoColons, // right after :: + AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+) + AfterTemplate, // right after template brackets (<something>) + AfterOperator, // right after name of C++ operator + }; + + Bookmark start_position = SetBookmark(); + State state = State::Beginning; + bool continue_parsing = true; + Optional<size_t> last_coloncolon_position = None; + + while (continue_parsing && HasMoreTokens()) { + const auto &token = Peek(); + switch (token.getKind()) { + case tok::raw_identifier: // Just a name. + if (state != State::Beginning && state != State::AfterTwoColons) { + continue_parsing = false; + break; + } + Advance(); + state = State::AfterIdentifier; + break; + case tok::l_paren: { + if (state == State::Beginning || state == State::AfterTwoColons) { + // (anonymous namespace) + if (ConsumeAnonymousNamespace()) { + state = State::AfterIdentifier; + break; + } + } + + // Type declared inside a function 'func()::Type' + if (state != State::AfterIdentifier && state != State::AfterTemplate && + state != State::AfterOperator) { + continue_parsing = false; + break; + } + Bookmark l_paren_position = SetBookmark(); + // Consume the '(' ... ') [const]'. + if (!ConsumeArguments()) { + continue_parsing = false; + break; + } + SkipFunctionQualifiers(); + + // Consume '::' + size_t coloncolon_position = GetCurrentPosition(); + if (!ConsumeToken(tok::coloncolon)) { + continue_parsing = false; + break; + } + l_paren_position.Remove(); + last_coloncolon_position = coloncolon_position; + state = State::AfterTwoColons; + break; + } + case tok::coloncolon: // Type nesting delimiter. + if (state != State::Beginning && state != State::AfterIdentifier && + state != State::AfterTemplate) { + continue_parsing = false; + break; + } + last_coloncolon_position = GetCurrentPosition(); + Advance(); + state = State::AfterTwoColons; + break; + case tok::less: // Template brackets. + if (state != State::AfterIdentifier && state != State::AfterOperator) { + continue_parsing = false; + break; + } + if (!ConsumeTemplateArgs()) { + continue_parsing = false; + break; + } + state = State::AfterTemplate; + break; + case tok::kw_operator: // C++ operator overloading. + if (state != State::Beginning && state != State::AfterTwoColons) { + continue_parsing = false; + break; + } + if (!ConsumeOperator()) { + continue_parsing = false; + break; + } + state = State::AfterOperator; + break; + case tok::tilde: // Destructor. + if (state != State::Beginning && state != State::AfterTwoColons) { + continue_parsing = false; + break; + } + Advance(); + if (ConsumeToken(tok::raw_identifier)) { + state = State::AfterIdentifier; + } else { + TakeBack(); + continue_parsing = false; + } + break; + default: + continue_parsing = false; + break; + } + } + + if (state == State::AfterIdentifier || state == State::AfterOperator || + state == State::AfterTemplate) { + ParsedNameRanges result; + if (last_coloncolon_position) { + result.context_range = Range(start_position.GetSavedPosition(), + last_coloncolon_position.getValue()); + result.basename_range = + Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition()); + } else { + result.basename_range = + Range(start_position.GetSavedPosition(), GetCurrentPosition()); + } + start_position.Remove(); + return result; + } else { + return None; + } +} + +llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) { + if (range.empty()) + return llvm::StringRef(); + assert(range.begin_index < range.end_index); + assert(range.begin_index < m_tokens.size()); + assert(range.end_index <= m_tokens.size()); + clang::Token &first_token = m_tokens[range.begin_index]; + clang::Token &last_token = m_tokens[range.end_index - 1]; + clang::SourceLocation start_loc = first_token.getLocation(); + clang::SourceLocation end_loc = last_token.getLocation(); + unsigned start_pos = start_loc.getRawEncoding(); + unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength(); + return m_text.take_front(end_pos).drop_front(start_pos); +} + +static const clang::LangOptions &GetLangOptions() { + static clang::LangOptions g_options; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + g_options.LineComment = true; + g_options.C99 = true; + g_options.C11 = true; + g_options.CPlusPlus = true; + g_options.CPlusPlus11 = true; + g_options.CPlusPlus14 = true; + g_options.CPlusPlus1z = true; + }); + return g_options; +} + +static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() { + static llvm::StringMap<tok::TokenKind> g_map{ +#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name}, +#include "clang/Basic/TokenKinds.def" +#undef KEYWORD + }; + return g_map; +} + +void CPlusPlusNameParser::ExtractTokens() { + clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(), + m_text.data(), m_text.data() + m_text.size()); + const auto &kw_map = GetKeywordsMap(); + clang::Token token; + for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof); + lexer.LexFromRawLexer(token)) { + if (token.is(clang::tok::raw_identifier)) { + auto it = kw_map.find(token.getRawIdentifier()); + if (it != kw_map.end()) { + token.setKind(it->getValue()); + } + } + + m_tokens.push_back(token); + } +} diff --git a/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h new file mode 100644 index 000000000000..f936fb787c94 --- /dev/null +++ b/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h @@ -0,0 +1,179 @@ +//===-- CPlusPlusNameParser.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_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" + +namespace lldb_private { + +// Helps to validate and obtain various parts of C++ definitions. +class CPlusPlusNameParser { +public: + CPlusPlusNameParser(llvm::StringRef text) : m_text(text) { ExtractTokens(); } + + struct ParsedName { + llvm::StringRef basename; + llvm::StringRef context; + }; + + struct ParsedFunction { + ParsedName name; + llvm::StringRef arguments; + llvm::StringRef qualifiers; + }; + + // Treats given text as a function definition and parses it. + // Function definition might or might not have a return type and this should + // change parsing result. + // Examples: + // main(int, chat const*) + // T fun(int, bool) + // std::vector<int>::push_back(int) + // int& map<int, pair<short, int>>::operator[](short) const + // int (*get_function(const chat *))() + llvm::Optional<ParsedFunction> ParseAsFunctionDefinition(); + + // Treats given text as a potentially nested name of C++ entity (function, + // class, field) and parses it. + // Examples: + // main + // fun + // std::vector<int>::push_back + // map<int, pair<short, int>>::operator[] + // func<C>(int, C&)::nested_class::method + llvm::Optional<ParsedName> ParseAsFullName(); + +private: + // A C++ definition to parse. + llvm::StringRef m_text; + // Tokens extracted from m_text. + llvm::SmallVector<clang::Token, 30> m_tokens; + // Index of the next token to look at from m_tokens. + size_t m_next_token_index = 0; + + // Range of tokens saved in m_next_token_index. + struct Range { + size_t begin_index = 0; + size_t end_index = 0; + + Range() {} + Range(size_t begin, size_t end) : begin_index(begin), end_index(end) { + assert(end >= begin); + } + + size_t size() const { return end_index - begin_index; } + + bool empty() const { return size() == 0; } + }; + + struct ParsedNameRanges { + Range basename_range; + Range context_range; + }; + + // Bookmark automatically restores parsing position (m_next_token_index) + // when destructed unless it's manually removed with Remove(). + class Bookmark { + public: + Bookmark(size_t &position) + : m_position(position), m_position_value(position) {} + Bookmark(const Bookmark &) = delete; + Bookmark(Bookmark &&b) + : m_position(b.m_position), m_position_value(b.m_position_value), + m_restore(b.m_restore) { + b.Remove(); + } + Bookmark &operator=(Bookmark &&) = delete; + Bookmark &operator=(const Bookmark &) = delete; + + void Remove() { m_restore = false; } + size_t GetSavedPosition() { return m_position_value; } + ~Bookmark() { + if (m_restore) { + m_position = m_position_value; + } + } + + private: + size_t &m_position; + size_t m_position_value; + bool m_restore = true; + }; + + bool HasMoreTokens(); + void Advance(); + void TakeBack(); + bool ConsumeToken(clang::tok::TokenKind kind); + template <typename... Ts> bool ConsumeToken(Ts... kinds); + Bookmark SetBookmark(); + size_t GetCurrentPosition(); + clang::Token &Peek(); + bool ConsumeBrackets(clang::tok::TokenKind left, clang::tok::TokenKind right); + + llvm::Optional<ParsedFunction> ParseFunctionImpl(bool expect_return_type); + + // Parses functions returning function pointers 'string (*f(int x))(float y)' + llvm::Optional<ParsedFunction> ParseFuncPtr(bool expect_return_type); + + // Consumes function arguments enclosed within '(' ... ')' + bool ConsumeArguments(); + + // Consumes template arguments enclosed within '<' ... '>' + bool ConsumeTemplateArgs(); + + // Consumes '(anonymous namespace)' + bool ConsumeAnonymousNamespace(); + + // Consumes operator declaration like 'operator *' or 'operator delete []' + bool ConsumeOperator(); + + // Skips 'const' and 'volatile' + void SkipTypeQualifiers(); + + // Skips 'const', 'volatile', '&', '&&' in the end of the function. + void SkipFunctionQualifiers(); + + // Consumes built-in types like 'int' or 'unsigned long long int' + bool ConsumeBuiltinType(); + + // Consumes types defined via decltype keyword. + bool ConsumeDecltype(); + + // Skips 'const' and 'volatile' + void SkipPtrsAndRefs(); + + // Consumes things like 'const * const &' + bool ConsumePtrsAndRefs(); + + // Consumes full type name like 'Namespace::Class<int>::Method()::InnerClass' + bool ConsumeTypename(); + + llvm::Optional<ParsedNameRanges> ParseFullNameImpl(); + llvm::StringRef GetTextForRange(const Range &range); + + // Populate m_tokens by calling clang lexer on m_text. + void ExtractTokens(); +}; + +} // namespace lldb_private + +#endif // liblldb_CPlusPlusNameParser_h_ diff --git a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index 346ea0bbd519..b69b69530428 100644 --- a/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -11,21 +11,21 @@ #include "llvm/Support/ConvertUTF.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" -#include "lldb/Host/Endian.h" #include "lldb/Host/Time.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "lldb/Utility/ProcessStructReader.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" #include <algorithm> diff --git a/source/Plugins/Language/CPlusPlus/CxxStringTypes.h b/source/Plugins/Language/CPlusPlus/CxxStringTypes.h index 0bee3bd3b0f2..8e2ec44dc71c 100644 --- a/source/Plugins/Language/CPlusPlus/CxxStringTypes.h +++ b/source/Plugins/Language/CPlusPlus/CxxStringTypes.h @@ -11,9 +11,9 @@ #ifndef liblldb_CxxStringTypes_h_ #define liblldb_CxxStringTypes_h_ -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Utility/Stream.h" namespace lldb_private { namespace formatters { diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 82441a69b1d4..72d99671612c 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -13,21 +13,21 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/Error.h" #include "lldb/Core/FormatEntity.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/ProcessStructReader.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; @@ -76,155 +76,6 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } -lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(), - m_count(0), m_base_data_address(0), m_children() { - if (valobj_sp) { - Update(); - m_bool_type = - valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool); - } -} - -size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - CalculateNumChildren() { - return m_count; -} - -lldb::ValueObjectSP -lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { - auto iter = m_children.find(idx), end = m_children.end(); - if (iter != end) - return iter->second; - if (idx >= m_count) - return ValueObjectSP(); - if (m_base_data_address == 0 || m_count == 0) - return ValueObjectSP(); - if (!m_bool_type) - return ValueObjectSP(); - 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(); - uint8_t byte = 0; - uint8_t mask = 0; - Error err; - size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); - if (err.Fail() || bytes_read == 0) - return ValueObjectSP(); - switch (bit_index) { - case 0: - mask = 1; - break; - case 1: - mask = 2; - break; - case 2: - mask = 4; - break; - case 3: - mask = 8; - break; - case 4: - mask = 16; - break; - case 5: - mask = 32; - break; - case 6: - mask = 64; - break; - case 7: - mask = 128; - break; - default: - return ValueObjectSP(); - } - bool bit_set = ((byte & mask) != 0); - DataBufferSP buffer_sp( - new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0)); - if (bit_set && buffer_sp && buffer_sp->GetBytes()) - *(buffer_sp->GetBytes()) = - 1; // regardless of endianness, anything non-zero is true - StreamString name; - name.Printf("[%" PRIu64 "]", (uint64_t)idx); - ValueObjectSP retval_sp(CreateValueObjectFromData( - name.GetString(), DataExtractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()), - m_exe_ctx_ref, m_bool_type)); - if (retval_sp) - m_children[idx] = retval_sp; - return retval_sp; -} - -/*(std::__1::vector<std::__1::allocator<bool> >) vBool = { - __begin_ = 0x00000001001000e0 - __size_ = 56 - __cap_alloc_ = { - std::__1::__libcpp_compressed_pair_imp<unsigned long, - std::__1::allocator<unsigned long> > = { - __first_ = 1 - } - } - }*/ - -bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { - m_children.clear(); - ValueObjectSP valobj_sp = m_backend.GetSP(); - if (!valobj_sp) - return false; - m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); - ValueObjectSP size_sp( - valobj_sp->GetChildMemberWithName(ConstString("__size_"), true)); - if (!size_sp) - return false; - m_count = size_sp->GetValueAsUnsigned(0); - if (!m_count) - return true; - ValueObjectSP begin_sp( - valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true)); - if (!begin_sp) { - m_count = 0; - return false; - } - m_base_data_address = begin_sp->GetValueAsUnsigned(0); - if (!m_base_data_address) { - m_count = 0; - return false; - } - return false; -} - -bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - MightHaveChildren() { - return true; -} - -size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - GetIndexOfChildWithName(const ConstString &name) { - if (!m_count || !m_base_data_address) - return UINT32_MAX; - const char *item_name = name.GetCString(); - uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) - return UINT32_MAX; - return idx; -} - -lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - ~LibcxxVectorBoolSyntheticFrontEnd() = default; - -SyntheticChildrenFrontEnd * -lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return (valobj_sp ? new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp) - : nullptr); -} - /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, diff --git a/source/Plugins/Language/CPlusPlus/LibCxx.h b/source/Plugins/Language/CPlusPlus/LibCxx.h index a8638513376c..7610212b4245 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -11,10 +11,10 @@ #ifndef liblldb_LibCxx_h_ #define liblldb_LibCxx_h_ -#include "lldb/Core/Stream.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 { @@ -32,30 +32,6 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> -class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - - size_t CalculateNumChildren() override; - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; - - bool Update() override; - - bool MightHaveChildren() override; - - size_t GetIndexOfChildWithName(const ConstString &name) override; - - ~LibcxxVectorBoolSyntheticFrontEnd() override; - -private: - CompilerType m_bool_type; - ExecutionContextRef m_exe_ctx_ref; - uint64_t m_count; - lldb::addr_t m_base_data_address; - std::map<size_t, lldb::ValueObjectSP> m_children; -}; - SyntheticChildrenFrontEnd * LibcxxVectorBoolSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h b/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h index e2cc01150a2e..a9d948bf189c 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h +++ b/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h @@ -11,10 +11,10 @@ #ifndef liblldb_LibCxxAtomic_h_ #define liblldb_LibCxxAtomic_h_ -#include "lldb/Core/Stream.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 { diff --git a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp index b7aa70c0d2e7..4e839532afb7 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp @@ -13,9 +13,9 @@ // Project includes #include "LibCxx.h" -#include "lldb/Core/ConstString.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/ConstString.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 16bd631a6c2f..4ad3df3d6038 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -13,15 +13,15 @@ // Project includes #include "LibCxx.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 759a7008d3f3..50d4510ec5f9 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -13,15 +13,15 @@ // Project includes #include "LibCxx.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; @@ -406,7 +406,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( case 1: { auto child0_sp = potential_child_sp->GetChildAtIndex(0, true); if (child0_sp && child0_sp->GetName() == g___cc) - potential_child_sp = child0_sp; + potential_child_sp = child0_sp->Clone(ConstString(name.GetString())); break; } case 2: { @@ -414,11 +414,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( auto child1_sp = potential_child_sp->GetChildAtIndex(1, true); if (child0_sp && child0_sp->GetName() == g___cc && child1_sp && child1_sp->GetName() == g___nc) - potential_child_sp = child0_sp; + potential_child_sp = child0_sp->Clone(ConstString(name.GetString())); break; } } - potential_child_sp->SetName(ConstString(name.GetString())); } m_iterators[idx] = iterator; return potential_child_sp; diff --git a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 5fe4b3a9fc9e..c3566b7c6bfb 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -13,15 +13,15 @@ // Project includes #include "LibCxx.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index b5c9b6d0f11e..2843201e2ed9 100644 --- a/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -13,9 +13,9 @@ // Project includes #include "LibCxx.h" -#include "lldb/Core/ConstString.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/ConstString.h" using namespace lldb; using namespace lldb_private; @@ -45,6 +45,29 @@ private: CompilerType m_element_type; uint32_t m_element_size; }; + +class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override { return true; } + + size_t GetIndexOfChildWithName(const ConstString &name) override; + +private: + CompilerType m_bool_type; + ExecutionContextRef m_exe_ctx_ref; + uint64_t m_count; + lldb::addr_t m_base_data_address; + std::map<size_t, lldb::ValueObjectSP> m_children; +}; + } // namespace formatters } // namespace lldb_private @@ -133,9 +156,126 @@ size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: return ExtractIndexFromString(name.GetCString()); } +lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: + LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(), + m_count(0), m_base_data_address(0), m_children() { + if (valobj_sp) { + Update(); + m_bool_type = + valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool); + } +} + +size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: + CalculateNumChildren() { + return m_count; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + auto iter = m_children.find(idx), end = m_children.end(); + if (iter != end) + return iter->second; + if (idx >= m_count) + return ValueObjectSP(); + if (m_base_data_address == 0 || m_count == 0) + return ValueObjectSP(); + if (!m_bool_type) + return ValueObjectSP(); + 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(); + uint8_t byte = 0; + uint8_t mask = 0; + Error err; + size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); + if (err.Fail() || bytes_read == 0) + return ValueObjectSP(); + mask = 1 << bit_index; + bool bit_set = ((byte & mask) != 0); + DataBufferSP buffer_sp( + new DataBufferHeap(m_bool_type.GetByteSize(nullptr), 0)); + if (bit_set && buffer_sp && buffer_sp->GetBytes()) { + // regardless of endianness, anything non-zero is true + *(buffer_sp->GetBytes()) = 1; + } + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + ValueObjectSP retval_sp(CreateValueObjectFromData( + name.GetString(), + DataExtractor(buffer_sp, process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()), + m_exe_ctx_ref, m_bool_type)); + if (retval_sp) + m_children[idx] = retval_sp; + return retval_sp; +} + +/*(std::__1::vector<std::__1::allocator<bool> >) vBool = { + __begin_ = 0x00000001001000e0 + __size_ = 56 + __cap_alloc_ = { + std::__1::__libcpp_compressed_pair_imp<unsigned long, + std::__1::allocator<unsigned long> > = { + __first_ = 1 + } + } + }*/ + +bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { + m_children.clear(); + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + ValueObjectSP size_sp( + valobj_sp->GetChildMemberWithName(ConstString("__size_"), true)); + if (!size_sp) + return false; + m_count = size_sp->GetValueAsUnsigned(0); + if (!m_count) + return true; + ValueObjectSP begin_sp( + valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true)); + if (!begin_sp) { + m_count = 0; + return false; + } + m_base_data_address = begin_sp->GetValueAsUnsigned(0); + if (!m_base_data_address) { + m_count = 0; + return false; + } + return false; +} + +size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: + GetIndexOfChildWithName(const ConstString &name) { + if (!m_count || !m_base_data_address) + return UINT32_MAX; + const char *item_name = name.GetCString(); + uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; +} + lldb_private::SyntheticChildrenFrontEnd * lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator( CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return (valobj_sp ? new LibcxxStdVectorSyntheticFrontEnd(valobj_sp) - : nullptr); + if (!valobj_sp) + return nullptr; + CompilerType type = valobj_sp->GetCompilerType(); + if (!type.IsValid() || type.GetNumTemplateArguments() == 0) + return nullptr; + TemplateArgumentKind kind; + CompilerType arg_type = type.GetTemplateArgument(0, kind); + if (arg_type.GetTypeName() == ConstString("bool")) + return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp); + return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp); } diff --git a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index f931a8d6a046..a4633db8157e 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -13,16 +13,16 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Host/Endian.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Stream.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/source/Plugins/Language/CPlusPlus/LibStdcpp.h index 72e169f50395..1400477dcd0d 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ b/source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -10,10 +10,10 @@ #ifndef liblldb_LibStdCpp_h_ #define liblldb_LibStdCpp_h_ -#include "lldb/Core/Stream.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 { diff --git a/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp index c4a6e3d227b0..943af6ee81e4 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp +++ b/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp @@ -9,10 +9,10 @@ #include "LibStdcpp.h" -#include "lldb/Core/ConstString.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Utility/ConstString.h" #include <memory> #include <vector> @@ -73,9 +73,7 @@ bool LibStdcppTupleSyntheticFrontEnd::Update() { if (value_sp) { StreamString name; name.Printf("[%zd]", m_members.size()); - value_sp->SetName(ConstString(name.GetString())); - - m_members.push_back(value_sp); + m_members.push_back(value_sp->Clone(ConstString(name.GetString()))); } } } diff --git a/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index 4eb3b95afb4e..7693961cae17 100644 --- a/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -9,10 +9,10 @@ #include "LibStdcpp.h" -#include "lldb/Core/ConstString.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Utility/ConstString.h" #include <memory> #include <vector> @@ -70,19 +70,19 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend( LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp)); - m_ptr_obj = tuple_frontend->GetChildAtIndex(0); - if (m_ptr_obj) - m_ptr_obj->SetName(ConstString("pointer")); + ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0); + if (ptr_obj) + m_ptr_obj = ptr_obj->Clone(ConstString("pointer")); - m_del_obj = tuple_frontend->GetChildAtIndex(1); - if (m_del_obj) - m_del_obj->SetName(ConstString("deleter")); + ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); + if (del_obj) + m_del_obj = del_obj->Clone(ConstString("deleter")); if (m_ptr_obj) { Error error; - m_obj_obj = m_ptr_obj->Dereference(error); + ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); if (error.Success()) { - m_obj_obj->SetName(ConstString("object")); + m_obj_obj = obj_obj->Clone(ConstString("object")); } } @@ -94,29 +94,28 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; } lldb::ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { if (idx == 0) - return m_obj_obj; + return m_ptr_obj; if (idx == 1) return m_del_obj; if (idx == 2) - return m_ptr_obj; + return m_obj_obj; return lldb::ValueObjectSP(); } size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { if (m_del_obj) return 2; - if (m_ptr_obj && m_ptr_obj->GetValueAsUnsigned(0) != 0) - return 1; - return 0; + return 1; } size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName( const ConstString &name) { - if (name == ConstString("obj") || name == ConstString("object")) + if (name == ConstString("ptr") || name == ConstString("pointer")) return 0; if (name == ConstString("del") || name == ConstString("deleter")) return 1; - if (name == ConstString("ptr") || name == ConstString("pointer")) + if (name == ConstString("obj") || name == ConstString("object") || + name == ConstString("$$dereference$$")) return 2; return UINT32_MAX; } |