summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Language
diff options
context:
space:
mode:
authorMingming Liu <mingmingl@google.com>2025-09-10 15:25:31 -0700
committerGitHub <noreply@github.com>2025-09-10 15:25:31 -0700
commit1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch)
tree57f4b1f313c8cf74eed8819870f39c36ea263c68 /lldb/source/Plugins/Language
parent898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff)
parentb8cefcb601ddaa18482555c4ff363c01a270c2fe (diff)
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'lldb/source/Plugins/Language')
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp372
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h70
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp24
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp67
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h17
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp29
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp59
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp22
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp10
9 files changed, 403 insertions, 267 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index b4207439f528..277de8f44482 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -604,126 +604,6 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier(
return false;
}
-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 *));
- }
-};
-
-template <typename Derived>
-class ManglingSubstitutor
- : public llvm::itanium_demangle::AbstractManglingParser<Derived,
- NodeAllocator> {
- using Base =
- llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
-
-public:
- ManglingSubstitutor() : Base(nullptr, nullptr) {}
-
- template <typename... Ts>
- ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) {
- this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
- return substituteImpl(Mangled);
- }
-
-protected:
- void reset(llvm::StringRef Mangled) {
- Base::reset(Mangled.begin(), Mangled.end());
- Written = Mangled.begin();
- Result.clear();
- Substituted = false;
- }
-
- ConstString substituteImpl(llvm::StringRef Mangled) {
- Log *log = GetLog(LLDBLog::Language);
- if (this->parse() == nullptr) {
- LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
- return ConstString();
- }
- if (!Substituted)
- return ConstString();
-
- // Append any trailing unmodified input.
- appendUnchangedInput();
- LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
- return ConstString(Result);
- }
-
- void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
- if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
- return;
-
- // We found a match. Append unmodified input up to this point.
- appendUnchangedInput();
-
- // And then perform the replacement.
- Result += To;
- Written += From.size();
- Substituted = true;
- }
-
-private:
- /// Input character until which we have constructed the respective output
- /// already.
- const char *Written = "";
-
- llvm::SmallString<128> Result;
-
- /// Whether we have performed any substitutions.
- bool Substituted = false;
-
- const char *currentParserPos() const { return this->First; }
-
- void appendUnchangedInput() {
- Result +=
- llvm::StringRef(Written, std::distance(Written, currentParserPos()));
- Written = currentParserPos();
- }
-};
-
-/// Given a mangled function `Mangled`, replace all the primitive function type
-/// arguments of `Search` with type `Replace`.
-class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
- llvm::StringRef Search;
- llvm::StringRef Replace;
-
-public:
- void reset(llvm::StringRef Mangled, llvm::StringRef Search,
- llvm::StringRef Replace) {
- ManglingSubstitutor::reset(Mangled);
- this->Search = Search;
- this->Replace = Replace;
- }
-
- llvm::itanium_demangle::Node *parseType() {
- trySubstitute(Search, Replace);
- return ManglingSubstitutor::parseType();
- }
-};
-
-class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
-public:
- llvm::itanium_demangle::Node *
- parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
- trySubstitute("C1", "C2");
- trySubstitute("D1", "D2");
- return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
- }
-};
-} // namespace
-
std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
const ConstString mangled_name) const {
std::vector<ConstString> alternates;
@@ -751,29 +631,49 @@ std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
alternates.push_back(ConstString(fixed_scratch));
}
- TypeSubstitutor TS;
+ auto *log = GetLog(LLDBLog::Language);
+
// `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 =
- TS.substitute(mangled_name.GetStringRef(), "a", "c"))
- alternates.push_back(char_fixup);
+ if (auto char_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "a", "c")) {
+ // LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
+ if (*char_fixup_or_err)
+ alternates.push_back(*char_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, char_fixup_or_err.takeError(),
+ "Failed to substitute 'char' type mangling: {0}");
// long long parameter mangling 'x', may actually just be a long 'l' argument
- if (ConstString long_fixup =
- TS.substitute(mangled_name.GetStringRef(), "x", "l"))
- alternates.push_back(long_fixup);
+ if (auto long_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "x", "l")) {
+ if (*long_fixup_or_err)
+ alternates.push_back(*long_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(log, long_fixup_or_err.takeError(),
+ "Failed to substitute 'long long' type mangling: {0}");
// unsigned long long parameter mangling 'y', may actually just be unsigned
// long 'm' argument
- if (ConstString ulong_fixup =
- TS.substitute(mangled_name.GetStringRef(), "y", "m"))
- alternates.push_back(ulong_fixup);
-
- if (ConstString ctor_fixup =
- CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
- alternates.push_back(ctor_fixup);
+ if (auto ulong_fixup_or_err =
+ SubstituteType_ItaniumMangle(mangled_name.GetStringRef(), "y", "m")) {
+ if (*ulong_fixup_or_err)
+ alternates.push_back(*ulong_fixup_or_err);
+ } else
+ LLDB_LOG_ERROR(
+ log, ulong_fixup_or_err.takeError(),
+ "Failed to substitute 'unsigned long long' type mangling: {0}");
+
+ if (auto ctor_fixup_or_err = SubstituteStructorAliases_ItaniumMangle(
+ mangled_name.GetStringRef())) {
+ if (*ctor_fixup_or_err) {
+ alternates.push_back(*ctor_fixup_or_err);
+ }
+ } else
+ LLDB_LOG_ERROR(log, ctor_fixup_or_err.takeError(),
+ "Failed to substitute structor alias manglings: {0}");
return alternates;
}
@@ -849,31 +749,27 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxStringSummaryProviderASCII,
"std::string summary provider",
"^std::__[[:alnum:]]+::basic_string<char, "
- "std::__[[:alnum:]]+::char_traits<char>, "
- "std::__[[:alnum:]]+::allocator<char> >$",
+ "std::__[[:alnum:]]+::char_traits<char>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderASCII,
"std::string summary provider",
"^std::__[[:alnum:]]+::basic_string<unsigned char, "
- "std::__[[:alnum:]]+::char_traits<unsigned char>, "
- "std::__[[:alnum:]]+::allocator<unsigned char> >$",
+ "std::__[[:alnum:]]+::char_traits<unsigned char>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
"std::u16string summary provider",
"^std::__[[:alnum:]]+::basic_string<char16_t, "
- "std::__[[:alnum:]]+::char_traits<char16_t>, "
- "std::__[[:alnum:]]+::allocator<char16_t> >$",
+ "std::__[[:alnum:]]+::char_traits<char16_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
"std::u32string summary provider",
"^std::__[[:alnum:]]+::basic_string<char32_t, "
- "std::__[[:alnum:]]+::char_traits<char32_t>, "
- "std::__[[:alnum:]]+::allocator<char32_t> >$",
+ "std::__[[:alnum:]]+::char_traits<char32_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
@@ -884,8 +780,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibcxxWStringSummaryProvider,
"std::wstring summary provider",
"^std::__[[:alnum:]]+::basic_string<wchar_t, "
- "std::__[[:alnum:]]+::char_traits<wchar_t>, "
- "std::__[[:alnum:]]+::allocator<wchar_t> >$",
+ "std::__[[:alnum:]]+::char_traits<wchar_t>,.*>$",
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
@@ -1401,24 +1296,16 @@ static void RegisterStdStringSummaryProvider(
category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
- // std::basic_string<char>
category_sp->AddTypeSummary(
makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
summary_sp);
- // std::basic_string<char,std::char_traits<char>,std::allocator<char> >
- category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>,"
- "std::allocator<{0}> >",
- char_ty)
- .str()),
- summary_sp);
- // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+
category_sp->AddTypeSummary(
- makeSpecifier(
- llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, "
- "std::allocator<{0}> >",
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("^std::basic_string<{0}, ?std::char_traits<{0}>,.*>$",
char_ty)
- .str()),
+ .str(),
+ eFormatterMatchRegex),
summary_sp);
}
@@ -1463,20 +1350,17 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
- "std::__cxx11::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >",
- eFormatterMatchExact, string_summary_sp);
- cpp_category_sp->AddTypeSummary("std::__cxx11::basic_string<unsigned char, "
- "std::char_traits<unsigned char>, "
- "std::allocator<unsigned char> >",
- eFormatterMatchExact, string_summary_sp);
+ "^std::__cxx11::basic_string<char, std::char_traits<char>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
+ cpp_category_sp->AddTypeSummary("^std::__cxx11::basic_string<unsigned char, "
+ "std::char_traits<unsigned char>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
string_summary_sp);
cpp_category_sp->AddTypeSummary(
- "std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, "
- "std::allocator<wchar_t> >",
- eFormatterMatchExact, string_summary_sp);
+ "^std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>,.*>$",
+ eFormatterMatchRegex, string_summary_sp);
SyntheticChildren::Flags stl_synth_flags;
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
@@ -2442,6 +2326,160 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
}
+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 *));
+ }
+};
+
+template <typename Derived>
+class ManglingSubstitutor
+ : public llvm::itanium_demangle::AbstractManglingParser<Derived,
+ NodeAllocator> {
+ using Base =
+ llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
+
+public:
+ ManglingSubstitutor() : Base(nullptr, nullptr) {}
+
+ template <typename... Ts>
+ llvm::Expected<ConstString> substitute(llvm::StringRef Mangled,
+ Ts &&...Vals) {
+ this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
+ return substituteImpl(Mangled);
+ }
+
+protected:
+ void reset(llvm::StringRef Mangled) {
+ Base::reset(Mangled.begin(), Mangled.end());
+ Written = Mangled.begin();
+ Result.clear();
+ Substituted = false;
+ }
+
+ llvm::Expected<ConstString> substituteImpl(llvm::StringRef Mangled) {
+ if (this->parse() == nullptr)
+ return llvm::createStringError(
+ llvm::formatv("Failed to substitute mangling in '{0}'", Mangled));
+
+ if (!Substituted)
+ return ConstString();
+
+ // Append any trailing unmodified input.
+ appendUnchangedInput();
+ return ConstString(Result);
+ }
+
+ void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
+ if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
+ return;
+
+ // We found a match. Append unmodified input up to this point.
+ appendUnchangedInput();
+
+ // And then perform the replacement.
+ Result += To;
+ Written += From.size();
+ Substituted = true;
+ }
+
+private:
+ /// Input character until which we have constructed the respective output
+ /// already.
+ const char *Written = "";
+
+ llvm::SmallString<128> Result;
+
+ /// Whether we have performed any substitutions.
+ bool Substituted = false;
+
+ const char *currentParserPos() const { return this->First; }
+
+ void appendUnchangedInput() {
+ Result +=
+ llvm::StringRef(Written, std::distance(Written, currentParserPos()));
+ Written = currentParserPos();
+ }
+};
+
+/// Given a mangled function `Mangled`, replace all the primitive function type
+/// arguments of `Search` with type `Replace`.
+class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ llvm::itanium_demangle::Node *parseType() {
+ trySubstitute(Search, Replace);
+ return ManglingSubstitutor::parseType();
+ }
+};
+
+class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ void reset(llvm::StringRef Mangled) { ManglingSubstitutor::reset(Mangled); }
+
+ llvm::itanium_demangle::Node *
+ parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
+ if (!Search.empty() && !Replace.empty()) {
+ trySubstitute(Search, Replace);
+ } else {
+ trySubstitute("D1", "D2");
+ trySubstitute("C1", "C2");
+ }
+ return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
+ }
+};
+} // namespace
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return TypeSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString> CPlusPlusLanguage::SubstituteStructor_ItaniumMangle(
+ llvm::StringRef mangled_name, llvm::StringRef subst_from,
+ llvm::StringRef subst_to) {
+ return CtorDtorSubstitutor().substitute(mangled_name, subst_from, subst_to);
+}
+
+llvm::Expected<ConstString>
+CPlusPlusLanguage::SubstituteStructorAliases_ItaniumMangle(
+ llvm::StringRef mangled_name) {
+ return CtorDtorSubstitutor().substitute(mangled_name);
+}
+
#define LLDB_PROPERTIES_language_cplusplus
#include "LanguageCPlusPlusProperties.inc"
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 4a30299dd265..9a528ca7b03f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -164,6 +164,76 @@ public:
ConstString FindBestAlternateFunctionMangledName(
const Mangled mangled, const SymbolContext &sym_ctx) const override;
+ /// Substitutes Itanium type encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium type encodings (i.e., <type>
+ /// productions in the Itanium ABI mangling grammar). However, no verifiction
+ /// is done on whether \c subst_from or \c subst_to is a valid type encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteType_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Substitutes Itanium structor encoding substrings given by \c subst_from
+ /// in \c mangled_name with \c subst_to.
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ /// However, no verifiction is done on whether \c subst_from or \c subst_to is
+ /// a valid structor encoding.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \param[in] subst_from The substring to substitute.
+ ///
+ /// \param[in] subst_to The substring to insert.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructor_ItaniumMangle(llvm::StringRef mangled_name,
+ llvm::StringRef subst_from,
+ llvm::StringRef subst_to);
+
+ /// Tries replacing Itanium structor encoding substrings in \c mangled_name
+ /// with potential aliases.j
+ ///
+ /// This function will only replace Itanium structor encodings (i.e.,
+ /// <ctor-dtor-name> productions in the Itanium ABI mangling grammar).
+ ///
+ /// E.g., on some platforms, the C1/D1 variants are aliased to the C2/D2
+ /// variants. This function will try to replace occurrences of C1/D1 with
+ /// C2/D2.
+ ///
+ /// \param[in] mangled_name Mangled name to perform the substitutions in.
+ /// This function only supports Itanium ABI mangling.
+ ///
+ /// \returns The mangled string with substitutions. If no substitutions
+ /// have been made, returns an empty \c ConstString (even if the string
+ /// already contained the substitutions). If an error occurred, this function
+ /// returns the error.
+ ///
+ static llvm::Expected<ConstString>
+ SubstituteStructorAliases_ItaniumMangle(llvm::StringRef mangled_name);
+
llvm::StringRef GetInstanceVariableName() override { return "this"; }
FormatEntity::Entry GetFunctionNameFormat() const override;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index ea1edbfd3ac9..5289027fbd8a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -339,11 +339,18 @@ lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
if (err.Fail() || !backend_addr)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
+ auto list_base_sp = m_backend.GetChildAtIndex(0);
+ if (!list_base_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Anonymous strucutre index is in base class at index 0.
+ auto [impl_sp, is_compressed_pair] =
+ GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
+ "__before_begin_", "__before_begin_");
if (!impl_sp)
return ChildCacheState::eRefetch;
- if (isOldCompressedPairLayout(*impl_sp))
+ if (is_compressed_pair)
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
if (!impl_sp)
@@ -366,17 +373,10 @@ llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
if (!m_head || !m_tail || m_node_address == 0)
return 0;
- ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
- if (!size_node_sp) {
- size_node_sp = m_backend.GetChildMemberWithName(
- "__size_alloc_"); // pre-compressed_pair rework
-
- if (!isOldCompressedPairLayout(*size_node_sp))
- return llvm::createStringError("Unexpected std::list layout: expected "
- "old __compressed_pair layout.");
-
+ auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
+ if (is_compressed_pair)
size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
- }
if (size_node_sp)
m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index a7874047942c..6053d042b29b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -49,11 +49,6 @@ static void consumeInlineNamespace(llvm::StringRef &name) {
}
}
-bool lldb_private::formatters::isOldCompressedPairLayout(
- ValueObject &pair_obj) {
- return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
-}
-
bool lldb_private::formatters::isStdTemplate(ConstString type_name,
llvm::StringRef type) {
llvm::StringRef name = type_name.GetStringRef();
@@ -105,6 +100,44 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
return value;
}
+std::pair<lldb::ValueObjectSP, bool>
+lldb_private::formatters::GetValueOrOldCompressedPair(
+ ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name) {
+ auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool {
+ return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
+ };
+
+ // Try searching the child member in an anonymous structure first.
+ if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) {
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+ }
+
+ // Older versions of libc++ don't wrap the children in anonymous structures.
+ // Try that instead.
+ ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
+ if (node_sp)
+ return {node_sp, is_old_compressed_pair(*node_sp)};
+
+ // Try the even older __compressed_pair layout.
+
+ assert(!compressed_pair_name.empty());
+
+ node_sp = obj.GetChildMemberWithName(compressed_pair_name);
+
+ // Unrecognized layout (possibly older than LLDB supports).
+ if (!node_sp)
+ return {nullptr, false};
+
+ // Expected old compressed_pair layout, but got something else.
+ if (!is_old_compressed_pair(*node_sp))
+ return {nullptr, false};
+
+ return {node_sp, true};
+}
+
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
@@ -205,11 +238,12 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
if (!valobj_sp)
return false;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return false;
- if (isOldCompressedPairLayout(*ptr_sp))
+ if (is_compressed_pair)
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
if (!ptr_sp)
@@ -379,13 +413,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
if (!valobj_sp)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
if (!ptr_sp)
return lldb::ChildCacheState::eRefetch;
// Retrieve the actual pointer and the deleter, and clone them to give them
// user-friendly names.
- if (isOldCompressedPairLayout(*ptr_sp)) {
+ if (is_compressed_pair) {
if (ValueObjectSP value_pointer_sp =
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
@@ -424,17 +459,15 @@ enum class StringLayout { CSD, DSC };
}
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
- if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
- return rep_sp;
-
- ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
- if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
+ auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");
+ if (!valobj_r_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*valobj_r_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
- return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
+ return valobj_r_sp;
}
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index d88a6ecb1fa8..819f8a985f9b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -25,7 +25,22 @@ GetChildMemberWithName(ValueObject &obj,
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
-bool isOldCompressedPairLayout(ValueObject &pair_obj);
+
+/// Returns the ValueObjectSP of the child of \c obj. If \c obj has no
+/// child named \c child_name, returns the __compressed_pair child instead
+/// with \c compressed_pair_name, if one exists.
+///
+/// Latest libc++ wrap the compressed children in an anonymous structure.
+/// The \c anon_struct_idx indicates the location of this struct.
+///
+/// The returned boolean is \c true if the returned child was has an old-style
+/// libc++ __compressed_pair layout.
+///
+/// If no child was found returns a nullptr.
+std::pair<lldb::ValueObjectSP, bool>
+GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx,
+ llvm::StringRef child_name,
+ llvm::StringRef compressed_pair_name);
bool isStdTemplate(ConstString type_name, llvm::StringRef type);
bool LibcxxStringSummaryProviderASCII(
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 41441dfbc718..85766966f155 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -200,7 +200,8 @@ public:
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
private:
- llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
+ llvm::Expected<uint32_t>
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
/// Returns the ValueObject for the __tree_node type that
/// holds the key/value pair of the node at index \ref idx.
@@ -254,16 +255,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
llvm::Expected<uint32_t>
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
- CalculateNumChildrenForOldCompressedPairLayout() {
- ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
- if (!node_sp)
- return 0;
-
- if (!isOldCompressedPairLayout(*node_sp))
- return llvm::createStringError("Unexpected std::map layout: expected "
- "old __compressed_pair layout.");
-
- node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
+ CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) {
+ auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair);
if (!node_sp)
return 0;
@@ -281,12 +274,16 @@ llvm::Expected<uint32_t> lldb_private::formatters::
if (m_tree == nullptr)
return 0;
- if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
- m_count = node_sp->GetValueAsUnsigned(0);
- return m_count;
- }
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_");
+ if (!size_sp)
+ return llvm::createStringError("Unexpected std::map layout");
- return CalculateNumChildrenForOldCompressedPairLayout();
+ if (is_compressed_pair)
+ return CalculateNumChildrenForOldCompressedPairLayout(*size_sp);
+
+ m_count = size_sp->GetValueAsUnsigned(0);
+ return m_count;
}
ValueObjectSP
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 501fd0945b82..f88a5319068a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -130,22 +130,17 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
GetNodeType() {
- auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
-
- if (!node_sp) {
- auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
- if (!p1_sp)
- return {};
+ auto table_sp = m_backend.GetChildMemberWithName("__table_");
+ if (!table_sp)
+ return {};
- if (!isOldCompressedPairLayout(*p1_sp))
- return {};
+ auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ *table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
- node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!node_sp)
- return {};
- }
-
- assert(node_sp);
+ if (!node_sp)
+ return {};
return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
}
@@ -223,19 +218,15 @@ lldb::ValueObjectSP lldb_private::formatters::
llvm::Expected<size_t>
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CalculateNumChildrenImpl(ValueObject &table) {
- if (auto size_sp = table.GetChildMemberWithName("__size_"))
+ auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/2, "__size_", "__p2_");
+ if (!is_compressed_pair && size_sp)
return size_sp->GetValueAsUnsigned(0);
- ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
- if (!p2_sp)
- return llvm::createStringError(
- "Unexpected std::unordered_map layout: __p2_ member not found.");
+ if (!is_compressed_pair)
+ return llvm::createStringError("Unsupported std::unordered_map layout.");
- if (!isOldCompressedPairLayout(*p2_sp))
- return llvm::createStringError("Unexpected std::unordered_map layout: old "
- "__compressed_pair layout not found.");
-
- ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+ ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp);
if (!num_elements_sp)
return llvm::createStringError(
@@ -246,19 +237,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
}
static ValueObjectSP GetTreePointer(ValueObject &table) {
- ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
- if (!tree_sp) {
- ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
- if (!p1_sp)
- return nullptr;
-
- if (!isOldCompressedPairLayout(*p1_sp))
- return nullptr;
-
- tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!tree_sp)
- return nullptr;
- }
+ auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ table, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
+ if (is_compressed_pair)
+ tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp);
+
+ if (!tree_sp)
+ return nullptr;
return tree_sp->GetChildMemberWithName("__next_");
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 4bcdf01c221a..202cebf9bf85 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -84,7 +84,7 @@ llvm::Expected<uint32_t> lldb_private::formatters::
LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
if (!m_start || !m_finish)
return llvm::createStringError(
- "Failed to determine start/end of vector data.");
+ "failed to determine start/end of vector data");
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
@@ -94,18 +94,18 @@ llvm::Expected<uint32_t> lldb_private::formatters::
return 0;
if (start_val == 0)
- return llvm::createStringError("Invalid value for start of vector.");
+ return llvm::createStringError("invalid value for start of vector");
if (finish_val == 0)
- return llvm::createStringError("Invalid value for end of vector.");
+ return llvm::createStringError("invalid value for end of vector");
if (start_val > finish_val)
return llvm::createStringError(
- "Start of vector data begins after end pointer.");
+ "start of vector data begins after end pointer");
size_t num_children = (finish_val - start_val);
if (num_children % m_element_size)
- return llvm::createStringError("Size not multiple of element size.");
+ return llvm::createStringError("size not multiple of element size");
return num_children / m_element_size;
}
@@ -126,17 +126,15 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
}
static ValueObjectSP GetDataPointer(ValueObject &root) {
- if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
- return cap_sp;
-
- ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
+ auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
+ root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
if (!cap_sp)
return nullptr;
- if (!isOldCompressedPairLayout(*cap_sp))
- return nullptr;
+ if (is_compressed_pair)
+ return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
- return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
+ return cap_sp;
}
lldb::ChildCacheState
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
index cfc98d27f56d..99e73ca46fa2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVector.cpp
@@ -70,7 +70,7 @@ llvm::Expected<uint32_t> lldb_private::formatters::
MsvcStlVectorSyntheticFrontEnd::CalculateNumChildren() {
if (!m_start || !m_finish)
return llvm::createStringError(
- "Failed to determine start/end of vector data.");
+ "failed to determine start/end of vector data");
uint64_t start_val = m_start->GetValueAsUnsigned(0);
uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
@@ -80,18 +80,18 @@ llvm::Expected<uint32_t> lldb_private::formatters::
return 0;
if (start_val == 0)
- return llvm::createStringError("Invalid value for start of vector.");
+ return llvm::createStringError("invalid value for start of vector");
if (finish_val == 0)
- return llvm::createStringError("Invalid value for end of vector.");
+ return llvm::createStringError("invalid value for end of vector");
if (start_val > finish_val)
return llvm::createStringError(
- "Start of vector data begins after end pointer.");
+ "start of vector data begins after end pointer");
size_t num_children = (finish_val - start_val);
if (num_children % m_element_size)
- return llvm::createStringError("Size not multiple of element size.");
+ return llvm::createStringError("size not multiple of element size");
return num_children / m_element_size;
}