[Lldb-commits] [lldb] [Demangling] Refactor Demangler range tracking (PR #140762)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Wed May 28 03:27:33 PDT 2025


https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/140762

>From cc3c6d1c86ae0ed579c4f325778ee1b4cd90d6be Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 20 May 2025 17:45:20 +0100
Subject: [PATCH 1/9] refactor demangler range tracking

---
 lldb/include/lldb/Core/DemangledNameInfo.h     | 18 +++++++++++++++++-
 lldb/include/lldb/Core/FormatEntity.h          |  1 +
 lldb/source/Core/FormatEntity.cpp              |  3 +++
 lldb/source/Core/Mangled.cpp                   |  2 ++
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp   |  4 ++--
 lldb/unittests/Core/CMakeLists.txt             |  2 +-
 ...{MangledTest.cpp => ItaniumMangledTest.cpp} | 13 +++++++------
 7 files changed, 33 insertions(+), 10 deletions(-)
 rename lldb/unittests/Core/{MangledTest.cpp => ItaniumMangledTest.cpp} (98%)

diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h b/lldb/include/lldb/Core/DemangledNameInfo.h
index 11d3bb58871b8..76cf8908fcbe6 100644
--- a/lldb/include/lldb/Core/DemangledNameInfo.h
+++ b/lldb/include/lldb/Core/DemangledNameInfo.h
@@ -39,7 +39,7 @@ struct DemangledNameInfo {
   /// \endcode
   std::pair<size_t, size_t> ScopeRange;
 
-  /// Indicates the [start, end) of the function argument lits.
+  /// Indicates the [start, end) of the function argument list.
   /// E.g.,
   /// \code{.cpp}
   ///    int (*getFunc<float>(float, double))(int, int)
@@ -59,11 +59,27 @@ struct DemangledNameInfo {
   /// \endcode
   std::pair<size_t, size_t> QualifiersRange;
 
+  /// Indicates the [start, end) of the function's prefix. This is a
+  /// catch-all range for anything that is not tracked by the rest of
+  /// the pairs.
+  std::pair<size_t, size_t> PrefixRange;
+
+  /// Indicates the [start, end) of the function's suffix. This is a
+  /// catch-all range for anything that is not tracked by the rest of
+  /// the pairs.
+  std::pair<size_t, size_t> SuffixRange;
+
   /// Returns \c true if this object holds a valid basename range.
   bool hasBasename() const {
     return BasenameRange.second > BasenameRange.first &&
            BasenameRange.second > 0;
   }
+
+  /// Returns \c true if this object holds a valid arguments range.
+  bool hasArguments() const {
+    return ArgumentsRange.second > ArgumentsRange.first &&
+           ArgumentsRange.second > 0;
+  }
 };
 
 /// An OutputBuffer which keeps a record of where certain parts of a
diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h
index 6acf6fbe43239..1aed3c6ff9e9d 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -88,6 +88,7 @@ struct Entry {
     FunctionNameWithArgs,
     FunctionNameNoArgs,
     FunctionMangledName,
+    FunctionPrefix,
     FunctionScope,
     FunctionBasename,
     FunctionTemplateArguments,
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 4f2d39873c7fb..4dcfa43a7bb04 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -124,6 +124,7 @@ constexpr Definition g_function_child_entries[] = {
     Definition("initial-function", EntryType::FunctionInitial),
     Definition("changed", EntryType::FunctionChanged),
     Definition("is-optimized", EntryType::FunctionIsOptimized),
+    Definition("prefix", EntryType::FunctionPrefix),
     Definition("scope", EntryType::FunctionScope),
     Definition("basename", EntryType::FunctionBasename),
     Definition("template-arguments", EntryType::FunctionTemplateArguments),
@@ -385,6 +386,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
     ENUM_TO_CSTR(FunctionNameWithArgs);
     ENUM_TO_CSTR(FunctionNameNoArgs);
     ENUM_TO_CSTR(FunctionMangledName);
+    ENUM_TO_CSTR(FunctionPrefix);
     ENUM_TO_CSTR(FunctionScope);
     ENUM_TO_CSTR(FunctionBasename);
     ENUM_TO_CSTR(FunctionTemplateArguments);
@@ -1835,6 +1837,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
     return true;
   }
 
+  case Entry::Type::FunctionPrefix:
   case Entry::Type::FunctionScope:
   case Entry::Type::FunctionBasename:
   case Entry::Type::FunctionTemplateArguments:
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index ce4db4e0daa8b..e6f7d198d7316 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -172,6 +172,8 @@ GetItaniumDemangledStr(const char *M) {
 
     TrackingOutputBuffer OB(demangled_cstr, demangled_size);
     demangled_cstr = ipd.finishDemangle(&OB);
+    OB.NameInfo.SuffixRange.first = OB.NameInfo.QualifiersRange.second;
+    OB.NameInfo.SuffixRange.second = std::string(demangled_cstr).length();
     info = std::move(OB.NameInfo);
 
     assert(demangled_cstr &&
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 542f13bef23e7..f45b4fb816b3b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -401,8 +401,8 @@ GetDemangledFunctionSuffix(const SymbolContext &sc) {
   if (!info->hasBasename())
     return std::nullopt;
 
-  return demangled_name.slice(info->QualifiersRange.second,
-                              llvm::StringRef::npos);
+  return demangled_name.slice(info->SuffixRange.first,
+                              info->SuffixRange.second);
 }
 
 static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt
index 97268b3dbf8f8..234eb43b95257 100644
--- a/lldb/unittests/Core/CMakeLists.txt
+++ b/lldb/unittests/Core/CMakeLists.txt
@@ -6,7 +6,7 @@ add_lldb_unittest(LLDBCoreTests
   DumpDataExtractorTest.cpp
   DumpRegisterInfoTest.cpp
   FormatEntityTest.cpp
-  MangledTest.cpp
+  ItaniumMangledTest.cpp
   ModuleSpecTest.cpp
   PluginManagerTest.cpp
   ProgressReportTest.cpp
diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/ItaniumMangledTest.cpp
similarity index 98%
rename from lldb/unittests/Core/MangledTest.cpp
rename to lldb/unittests/Core/ItaniumMangledTest.cpp
index 44651eb94c23b..fef2b14af0948 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/ItaniumMangledTest.cpp
@@ -1,4 +1,4 @@
-//===-- MangledTest.cpp ---------------------------------------------------===//
+//===-- ItaniumMangledTest.cpp --------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -401,7 +401,7 @@ TEST(MangledTest, DemangledNameInfo_SetValue) {
   EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
 }
 
-struct DemanglingPartsTestCase {
+struct ItaniumDemanglingPartsTestCase {
   const char *mangled;
   DemangledNameInfo expected_info;
   std::string_view basename;
@@ -410,7 +410,7 @@ struct DemanglingPartsTestCase {
   bool valid_basename = true;
 };
 
-DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+ItaniumDemanglingPartsTestCase g_demangling_itanium_parts_test_cases[] = {
     // clang-format off
    { "_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
      { /*.BasenameRange=*/{92, 98}, /*.ScopeRange=*/{36, 92}, /*.ArgumentsRange=*/{ 108, 158 },
@@ -555,7 +555,7 @@ DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
 };
 
 struct DemanglingPartsTestFixture
-    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+    : public ::testing::TestWithParam<ItaniumDemanglingPartsTestCase> {};
 
 namespace {
 class TestAllocator {
@@ -608,5 +608,6 @@ TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
   std::free(OB.getBuffer());
 }
 
-INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
-                         ::testing::ValuesIn(g_demangling_parts_test_cases));
+INSTANTIATE_TEST_SUITE_P(
+    DemanglingPartsTests, DemanglingPartsTestFixture,
+    ::testing::ValuesIn(g_demangling_itanium_parts_test_cases));

>From 296a105fa6eb6dbf19792229c349427330b50f0a Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 20 May 2025 17:50:48 +0100
Subject: [PATCH 2/9] remove redundant check

---
 lldb/include/lldb/Core/DemangledNameInfo.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h b/lldb/include/lldb/Core/DemangledNameInfo.h
index 76cf8908fcbe6..cda0cb6ff3dad 100644
--- a/lldb/include/lldb/Core/DemangledNameInfo.h
+++ b/lldb/include/lldb/Core/DemangledNameInfo.h
@@ -71,14 +71,12 @@ struct DemangledNameInfo {
 
   /// Returns \c true if this object holds a valid basename range.
   bool hasBasename() const {
-    return BasenameRange.second > BasenameRange.first &&
-           BasenameRange.second > 0;
+    return BasenameRange.second > BasenameRange.first;
   }
 
   /// Returns \c true if this object holds a valid arguments range.
   bool hasArguments() const {
-    return ArgumentsRange.second > ArgumentsRange.first &&
-           ArgumentsRange.second > 0;
+    return ArgumentsRange.second > ArgumentsRange.first;
   }
 };
 

>From 32c50951db7d06f2c8f7217843f43037df4ff014 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 27 May 2025 14:40:06 +0100
Subject: [PATCH 3/9] update documentation

---
 lldb/docs/use/formatting.rst | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst
index 61f51812d2ea9..897ce8c47d7f1 100644
--- a/lldb/docs/use/formatting.rst
+++ b/lldb/docs/use/formatting.rst
@@ -91,7 +91,9 @@ A complete list of currently supported format string variables is listed below:
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | ``function.basename``                             | The basename of the current function depending on the frame's language. E.g., for C++ the basename for ``void ns::foo<float>::bar<int>(int) const`` is ``bar``.                                                                                                                             |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-| ``function.scope``                                |  The scope qualifiers of the current function depending on the frame's language. E.g., for C++ the scope for ``void ns::foo<float>::bar<int>(int) const`` is ``ns::foo<float>``.                                                                                                            |
+| ``function.prefix``                               | Any prefix added to the demangled function name of the current function. This depends on the frame's language. E.g., for C++ the suffix will always be empty.                                                                                                                               |
++---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``function.scope``                                | The scope qualifiers of the current function depending on the frame's language. E.g., for C++ the scope for ``void ns::foo<float>::bar<int>(int) const`` is ``ns::foo<float>``.                                                                                                             |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | ``function.template-arguments``                   | The template arguments of the current function depending on the frame's language. E.g., for C++ the template arguments for ``void ns::foo<float>::bar<int>(int) const`` are ``<float>``.                                                                                                    |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -325,6 +327,7 @@ _____________________
 The function names displayed in backtraces/``frame info``/``thread info`` are the demangled names of functions. On some platforms (like ones using Itanium the mangling scheme), LLDB supports decomposing these names into fine-grained components. These are currently:
 
 - ``${function.return-left}``
+- ``${function.prefix}``
 - ``${function.scope}``
 - ``${function.basename}``
 - ``${function.template-arguments}``

>From 69e86fde65ca57ed0f3b2fbce35999f852456fa4 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 27 May 2025 14:44:15 +0100
Subject: [PATCH 4/9] revert unnecessary changes

---
 lldb/include/lldb/Core/DemangledNameInfo.h |   8 +-
 lldb/unittests/Core/CMakeLists.txt         |   2 +-
 lldb/unittests/Core/ItaniumMangledTest.cpp | 613 ---------------------
 lldb/unittests/Core/MangledTest.cpp        | 321 +++++++++++
 4 files changed, 324 insertions(+), 620 deletions(-)
 delete mode 100644 lldb/unittests/Core/ItaniumMangledTest.cpp
 create mode 100644 lldb/unittests/Core/MangledTest.cpp

diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h b/lldb/include/lldb/Core/DemangledNameInfo.h
index cda0cb6ff3dad..ab9bb3e211b66 100644
--- a/lldb/include/lldb/Core/DemangledNameInfo.h
+++ b/lldb/include/lldb/Core/DemangledNameInfo.h
@@ -71,12 +71,8 @@ struct DemangledNameInfo {
 
   /// Returns \c true if this object holds a valid basename range.
   bool hasBasename() const {
-    return BasenameRange.second > BasenameRange.first;
-  }
-
-  /// Returns \c true if this object holds a valid arguments range.
-  bool hasArguments() const {
-    return ArgumentsRange.second > ArgumentsRange.first;
+    return BasenameRange.second > BasenameRange.first &&
+           BasenameRange.second > 0;
   }
 };
 
diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt
index 234eb43b95257..97268b3dbf8f8 100644
--- a/lldb/unittests/Core/CMakeLists.txt
+++ b/lldb/unittests/Core/CMakeLists.txt
@@ -6,7 +6,7 @@ add_lldb_unittest(LLDBCoreTests
   DumpDataExtractorTest.cpp
   DumpRegisterInfoTest.cpp
   FormatEntityTest.cpp
-  ItaniumMangledTest.cpp
+  MangledTest.cpp
   ModuleSpecTest.cpp
   PluginManagerTest.cpp
   ProgressReportTest.cpp
diff --git a/lldb/unittests/Core/ItaniumMangledTest.cpp b/lldb/unittests/Core/ItaniumMangledTest.cpp
deleted file mode 100644
index fef2b14af0948..0000000000000
--- a/lldb/unittests/Core/ItaniumMangledTest.cpp
+++ /dev/null
@@ -1,613 +0,0 @@
-//===-- ItaniumMangledTest.cpp --------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
-#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
-#include "TestingSupport/SubsystemRAII.h"
-#include "TestingSupport/TestUtilities.h"
-
-#include "lldb/Core/DemangledNameInfo.h"
-#include "lldb/Core/Mangled.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/SymbolContext.h"
-
-#include "llvm/Support/FileUtilities.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Testing/Support/Error.h"
-
-#include "gtest/gtest.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-TEST(MangledTest, ResultForValidName) {
-  ConstString MangledName("_ZN1a1b1cIiiiEEvm");
-  Mangled TheMangled(MangledName);
-  ConstString TheDemangled = TheMangled.GetDemangledName();
-
-  ConstString ExpectedResult("void a::b::c<int, int, int>(unsigned long)");
-  EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
-}
-
-TEST(MangledTest, ResultForBlockInvocation) {
-  ConstString MangledName("___Z1fU13block_pointerFviE_block_invoke");
-  Mangled TheMangled(MangledName);
-  ConstString TheDemangled = TheMangled.GetDemangledName();
-
-  ConstString ExpectedResult(
-      "invocation function for block in f(void (int) block_pointer)");
-  EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
-}
-
-TEST(MangledTest, EmptyForInvalidName) {
-  ConstString MangledName("_ZN1a1b1cmxktpEEvm");
-  Mangled TheMangled(MangledName);
-  ConstString TheDemangled = TheMangled.GetDemangledName();
-
-  EXPECT_STREQ("", TheDemangled.GetCString());
-}
-
-TEST(MangledTest, ResultForValidRustV0Name) {
-  ConstString mangled_name("_RNvC1a4main");
-  Mangled the_mangled(mangled_name);
-  ConstString the_demangled = the_mangled.GetDemangledName();
-
-  ConstString expected_result("a::main");
-  EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
-}
-
-TEST(MangledTest, EmptyForInvalidRustV0Name) {
-  ConstString mangled_name("_RRR");
-  Mangled the_mangled(mangled_name);
-  ConstString the_demangled = the_mangled.GetDemangledName();
-
-  EXPECT_STREQ("", the_demangled.GetCString());
-}
-
-TEST(MangledTest, ResultForValidDLangName) {
-  ConstString mangled_name("_Dmain");
-  Mangled the_mangled(mangled_name);
-  ConstString the_demangled = the_mangled.GetDemangledName();
-
-  ConstString expected_result("D main");
-  EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
-}
-
-TEST(MangledTest, SameForInvalidDLangPrefixedName) {
-  ConstString mangled_name("_DDD");
-  Mangled the_mangled(mangled_name);
-  ConstString the_demangled = the_mangled.GetDemangledName();
-
-  EXPECT_STREQ("_DDD", the_demangled.GetCString());
-}
-
-TEST(MangledTest, RecognizeSwiftMangledNames) {
-  llvm::StringRef valid_swift_mangled_names[] = {
-      "_TtC4main7MyClass",   // Mangled objc class name
-      "_TtP4main3Foo_",      // Mangld objc protocol name
-      "$s4main3BarCACycfC",  // Mangled name
-      "_$s4main3BarCACycfC", // Mangled name with leading underscore
-      "$S4main3BarCACycfC",  // Older swift mangled name
-      "_$S4main3BarCACycfC", // Older swift mangled name
-                             // with leading underscore
-      // Mangled swift filename
-      "@__swiftmacro_4main16FunVariableNames9OptionSetfMm_.swift",
-  };
-
-  for (llvm::StringRef mangled : valid_swift_mangled_names)
-    EXPECT_EQ(Mangled::GetManglingScheme(mangled),
-              Mangled::eManglingSchemeSwift);
-}
-
-TEST(MangledTest, BoolConversionOperator) {
-  {
-    ConstString MangledName("_ZN1a1b1cIiiiEEvm");
-    Mangled TheMangled(MangledName);
-    EXPECT_EQ(true, bool(TheMangled));
-    EXPECT_EQ(false, !TheMangled);
-  }
-  {
-    ConstString UnmangledName("puts");
-    Mangled TheMangled(UnmangledName);
-    EXPECT_EQ(true, bool(TheMangled));
-    EXPECT_EQ(false, !TheMangled);
-  }
-  {
-    Mangled TheMangled{};
-    EXPECT_EQ(false, bool(TheMangled));
-    EXPECT_EQ(true, !TheMangled);
-  }
-}
-
-TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
-  SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
-      subsystems;
-
-  auto ExpectedFile = TestFile::fromYaml(R"(
---- !ELF
-FileHeader:      
-  Class:           ELFCLASS64
-  Data:            ELFDATA2LSB
-  Type:            ET_EXEC
-  Machine:         EM_X86_64
-Sections:        
-  - Name:            .text
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    AddressAlign:    0x0000000000000010
-    Size:            0x20
-  - Name:            .anothertext
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    Address:         0x0000000000000010
-    AddressAlign:    0x0000000000000010
-    Size:            0x40
-  - Name:            .data
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_WRITE, SHF_ALLOC ]
-    Address:         0x00000000000000A8
-    AddressAlign:    0x0000000000000004
-    Content:         '01000000'
-Symbols:
-  - Name:            somedata
-    Type:            STT_OBJECT
-    Section:         .anothertext
-    Value:           0x0000000000000045
-    Binding:         STB_GLOBAL
-  - Name:            main
-    Type:            STT_FUNC
-    Section:         .anothertext
-    Value:           0x0000000000000010
-    Size:            0x000000000000003F
-    Binding:         STB_GLOBAL
-  - Name:            _Z3foov
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            puts at GLIBC_2.5
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            puts at GLIBC_2.6
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _Z5annotv at VERSION3
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZN1AC2Ev
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZN1AD2Ev
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZN1A3barEv
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZGVZN4llvm4dbgsEvE7thestrm
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZZN4llvm4dbgsEvE7thestrm
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _ZTVN5clang4DeclE
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            -[ObjCfoo]
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            +[B ObjCbar(WithCategory)]
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-  - Name:            _Z12undemangableEvx42
-    Type:            STT_FUNC
-    Section:         .text
-    Size:            0x000000000000000D
-    Binding:         STB_GLOBAL
-...
-)");
-  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
-
-  auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
-
-  auto Count = [M](const char *Name, FunctionNameType Type) -> int {
-    SymbolContextList SymList;
-    M->FindFunctionSymbols(ConstString(Name), Type, SymList);
-    return SymList.GetSize();
-  };
-
-  // Unmangled
-  EXPECT_EQ(1, Count("main", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("main", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("main", eFunctionNameTypeMethod));
-
-  // Itanium mangled
-  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("foo", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("foo", eFunctionNameTypeMethod));
-
-  // Unmangled with linker annotation
-  EXPECT_EQ(1, Count("puts at GLIBC_2.5", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("puts at GLIBC_2.6", eFunctionNameTypeFull));
-  EXPECT_EQ(2, Count("puts", eFunctionNameTypeFull));
-  EXPECT_EQ(2, Count("puts", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("puts", eFunctionNameTypeMethod));
-
-  // Itanium mangled with linker annotation
-  EXPECT_EQ(1, Count("_Z5annotv at VERSION3", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("annot", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("annot", eFunctionNameTypeMethod));
-
-  // Itanium mangled ctor A::A()
-  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("A", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("A", eFunctionNameTypeBase));
-
-  // Itanium mangled dtor A::~A()
-  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("~A", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("~A", eFunctionNameTypeBase));
-
-  // Itanium mangled method A::bar()
-  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("bar", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("bar", eFunctionNameTypeBase));
-
-  // Itanium mangled names that are explicitly excluded from parsing
-  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
-  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeBase));
-
-  // ObjC mangled static
-  EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("ObjCfoo", eFunctionNameTypeMethod));
-
-  // ObjC mangled method with category
-  EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("ObjCbar", eFunctionNameTypeMethod));
-
-  // Invalid things: unable to decode but still possible to find by full name
-  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeFull));
-  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("_Z12undemangableEvx42", eFunctionNameTypeMethod));
-  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
-  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
-}
-
-static bool NameInfoEquals(const DemangledNameInfo &lhs,
-                           const DemangledNameInfo &rhs) {
-  return std::tie(lhs.BasenameRange, lhs.ArgumentsRange, lhs.ScopeRange,
-                  lhs.QualifiersRange) ==
-         std::tie(rhs.BasenameRange, rhs.ArgumentsRange, rhs.ScopeRange,
-                  rhs.QualifiersRange);
-}
-
-TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
-  Mangled mangled;
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
-
-  mangled.SetMangledName(ConstString("_Z3foov"));
-  ASSERT_TRUE(mangled);
-
-  auto info1 = mangled.GetDemangledInfo();
-  EXPECT_NE(info1, std::nullopt);
-  EXPECT_TRUE(info1->hasBasename());
-
-  mangled.SetMangledName(ConstString("_Z4funcv"));
-
-  // Should have re-calculated demangled-info since mangled name changed.
-  auto info2 = mangled.GetDemangledInfo();
-  ASSERT_NE(info2, std::nullopt);
-  EXPECT_TRUE(info2->hasBasename());
-
-  EXPECT_FALSE(NameInfoEquals(info1.value(), info2.value()));
-  EXPECT_EQ(mangled.GetDemangledName(), "func()");
-}
-
-TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
-  Mangled mangled("_Z3foov");
-  ASSERT_TRUE(mangled);
-
-  mangled.SetDemangledName(ConstString(""));
-
-  // Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
-  // of previously set mangled name.
-  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
-  EXPECT_EQ(mangled.GetDemangledName(), "foo()");
-}
-
-TEST(MangledTest, DemangledNameInfo_Clear) {
-  Mangled mangled("_Z3foov");
-  ASSERT_TRUE(mangled);
-  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
-
-  mangled.Clear();
-
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
-}
-
-TEST(MangledTest, DemangledNameInfo_SetValue) {
-  Mangled mangled("_Z4funcv");
-  ASSERT_TRUE(mangled);
-
-  auto demangled_func = mangled.GetDemangledInfo();
-
-  // SetValue(mangled) resets demangled-info
-  mangled.SetValue(ConstString("_Z3foov"));
-  auto demangled_foo = mangled.GetDemangledInfo();
-  EXPECT_NE(demangled_foo, std::nullopt);
-  EXPECT_FALSE(NameInfoEquals(demangled_foo.value(), demangled_func.value()));
-
-  // SetValue(demangled) resets demangled-info
-  mangled.SetValue(ConstString("_Z4funcv"));
-  EXPECT_TRUE(NameInfoEquals(mangled.GetDemangledInfo().value(),
-                             demangled_func.value()));
-
-  // SetValue(empty) resets demangled-info
-  mangled.SetValue(ConstString());
-  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
-
-  // Demangling invalid mangled name will set demangled-info
-  // (without a valid basename).
-  mangled.SetValue(ConstString("_Zinvalid"));
-  ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
-  EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
-}
-
-struct ItaniumDemanglingPartsTestCase {
-  const char *mangled;
-  DemangledNameInfo expected_info;
-  std::string_view basename;
-  std::string_view scope;
-  std::string_view qualifiers;
-  bool valid_basename = true;
-};
-
-ItaniumDemanglingPartsTestCase g_demangling_itanium_parts_test_cases[] = {
-    // clang-format off
-   { "_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
-     { /*.BasenameRange=*/{92, 98}, /*.ScopeRange=*/{36, 92}, /*.ArgumentsRange=*/{ 108, 158 },
-       /*.QualifiersRange=*/{158, 176} },
-     /*.basename=*/"method",
-     /*.scope=*/"Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::",
-     /*.qualifiers=*/" const volatile &&"
-   },
-   { "_Z7getFuncIfEPFiiiET_",
-     { /*.BasenameRange=*/{6, 13}, /*.ScopeRange=*/{6, 6}, /*.ArgumentsRange=*/{ 20, 27 }, /*.QualifiersRange=*/{38, 38} },
-     /*.basename=*/"getFunc",
-     /*.scope=*/"",
-     /*.qualifiers=*/""
-   },
-   { "_ZN1f1b1c1gEv",
-     { /*.BasenameRange=*/{9, 10}, /*.ScopeRange=*/{0, 9}, /*.ArgumentsRange=*/{ 10, 12 },
-       /*.QualifiersRange=*/{12, 12} },
-     /*.basename=*/"g",
-     /*.scope=*/"f::b::c::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
-     { /*.BasenameRange=*/{45, 48}, /*.ScopeRange=*/{38, 45}, /*.ArgumentsRange=*/{ 53, 58 },
-       /*.QualifiersRange=*/{58, 58} },
-     /*.basename=*/"fD1",
-     /*.scope=*/"test7::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
-     { /*.BasenameRange=*/{61, 64}, /*.ScopeRange=*/{54, 61}, /*.ArgumentsRange=*/{ 69, 79 },
-       /*.QualifiersRange=*/{79, 79} },
-     /*.basename=*/"fD1",
-     /*.scope=*/"test7::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
-     { /*.BasenameRange=*/{120, 123}, /*.ScopeRange=*/{81, 120}, /*.ArgumentsRange=*/{ 155, 168 },
-       /*.QualifiersRange=*/{168, 168} },
-     /*.basename=*/"fD1",
-     /*.scope=*/"test7<decltype(c)::d<decltype(c)::d>>::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
-     { /*.BasenameRange=*/{687, 692}, /*.ScopeRange=*/{343, 687}, /*.ArgumentsRange=*/{ 713, 1174 },
-       /*.QualifiersRange=*/{1174, 1174} },
-     /*.basename=*/"parse",
-     /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
-     { /*.BasenameRange=*/{344, 354}, /*.ScopeRange=*/{0, 344}, /*.ArgumentsRange=*/{ 354, 370 },
-       /*.QualifiersRange=*/{370, 370} },
-     /*.basename=*/"basic_json",
-     /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::",
-     /*.qualifiers=*/""
-   },
-   { "_Z3fppIiEPFPFvvEiEf",
-     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, /*.QualifiersRange=*/{34,34} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"",
-     /*.qualifiers=*/""
-   },
-   { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
-     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 },
-       /*.QualifiersRange=*/{43, 43} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"",
-     /*.qualifiers=*/""
-   },
-   { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
-     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 },
-       /*.QualifiersRange=*/{108, 108} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"",
-     /*.qualifiers=*/""
-   },
-   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
-     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
-       /*.QualifiersRange=*/{88, 88} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
-     /*.qualifiers=*/""
-   },
-   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
-     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
-       /*.QualifiersRange=*/{97, 97} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
-     /*.qualifiers=*/"",
-   },
-   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
-     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
-       /*.QualifiersRange=*/{162, 162} },
-     /*.basename=*/"fpp",
-     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
-     /*.qualifiers=*/"",
-   },
-   { "_ZNKO2ns3ns23Bar3fooIiEEPFPFNS0_3FooIiEEiENS3_IfEEEi",
-     { /*.BasenameRange=*/{37, 40}, /*.ScopeRange=*/{23, 37}, /*.ArgumentsRange=*/{ 45, 50 },
-       /*.QualifiersRange=*/{78, 87} },
-     /*.basename=*/"foo",
-     /*.scope=*/"ns::ns2::Bar::",
-     /*.qualifiers=*/" const &&",
-   },
-   { "_ZTV11ImageLoader",
-     { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{ 0, 0 },
-       /*.QualifiersRange=*/{0, 0} },
-     /*.basename=*/"",
-     /*.scope=*/"",
-     /*.qualifiers=*/"",
-     /*.valid_basename=*/false
-   },
-   { "___ZNK5dyld313MachOAnalyzer18forEachInitializerER11DiagnosticsRKNS0_15VMAddrConverterEU13block_pointerFvjEPKv_block_invoke.204",
-     { /*.BasenameRange=*/{55, 73}, /*.ScopeRange=*/{33, 55}, /*.ArgumentsRange=*/{ 73, 181 },
-       /*.QualifiersRange=*/{181, 187} },
-     /*.basename=*/"forEachInitializer",
-     /*.scope=*/"dyld3::MachOAnalyzer::",
-     /*.qualifiers=*/" const",
-   },
-   { "_ZZN5dyld45startEPNS_10KernelArgsEPvS2_ENK3$_1clEv",
-     { /*.BasenameRange=*/{53, 63}, /*.ScopeRange=*/{0, 53}, /*.ArgumentsRange=*/{ 63, 65 },
-       /*.QualifiersRange=*/{65, 71} },
-     /*.basename=*/"operator()",
-     /*.scope=*/"dyld4::start(dyld4::KernelArgs*, void*, void*)::$_1::",
-     /*.qualifiers=*/" const",
-   },
-   { "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv",
-     { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 },
-       /*.QualifiersRange=*/{100, 106} },
-     /*.basename=*/"operator()",
-     /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::",
-     /*.qualifiers=*/" const",
-   },
-   { "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv.cold",
-     { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 },
-       /*.QualifiersRange=*/{100, 106} },
-     /*.basename=*/"operator()",
-     /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::",
-     /*.qualifiers=*/" const",
-   }
-    // clang-format on
-};
-
-struct DemanglingPartsTestFixture
-    : public ::testing::TestWithParam<ItaniumDemanglingPartsTestCase> {};
-
-namespace {
-class TestAllocator {
-  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 *));
-  }
-};
-} // namespace
-
-TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
-  const auto &[mangled, info, basename, scope, qualifiers, valid_basename] =
-      GetParam();
-
-  llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
-      mangled, mangled + ::strlen(mangled));
-
-  const auto *Root = Parser.parse();
-
-  ASSERT_NE(nullptr, Root);
-
-  TrackingOutputBuffer OB;
-  Root->print(OB);
-  auto demangled = std::string_view(OB);
-
-  ASSERT_EQ(OB.NameInfo.hasBasename(), valid_basename);
-
-  EXPECT_EQ(OB.NameInfo.BasenameRange, info.BasenameRange);
-  EXPECT_EQ(OB.NameInfo.ScopeRange, info.ScopeRange);
-  EXPECT_EQ(OB.NameInfo.ArgumentsRange, info.ArgumentsRange);
-  EXPECT_EQ(OB.NameInfo.QualifiersRange, info.QualifiersRange);
-
-  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
-    return demangled.substr(loc.first, loc.second - loc.first);
-  };
-
-  EXPECT_EQ(get_part(OB.NameInfo.BasenameRange), basename);
-  EXPECT_EQ(get_part(OB.NameInfo.ScopeRange), scope);
-  EXPECT_EQ(get_part(OB.NameInfo.QualifiersRange), qualifiers);
-  std::free(OB.getBuffer());
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    DemanglingPartsTests, DemanglingPartsTestFixture,
-    ::testing::ValuesIn(g_demangling_itanium_parts_test_cases));
diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp
new file mode 100644
index 0000000000000..a3760ba43b3c9
--- /dev/null
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -0,0 +1,321 @@
+//===-- MangledTest.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(MangledTest, ResultForValidName) {
+  ConstString MangledName("_ZN1a1b1cIiiiEEvm");
+  Mangled TheMangled(MangledName);
+  ConstString TheDemangled = TheMangled.GetDemangledName();
+
+  ConstString ExpectedResult("void a::b::c<int, int, int>(unsigned long)");
+  EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
+}
+
+TEST(MangledTest, ResultForBlockInvocation) {
+  ConstString MangledName("___Z1fU13block_pointerFviE_block_invoke");
+  Mangled TheMangled(MangledName);
+  ConstString TheDemangled = TheMangled.GetDemangledName();
+
+  ConstString ExpectedResult(
+      "invocation function for block in f(void (int) block_pointer)");
+  EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString());
+}
+
+TEST(MangledTest, EmptyForInvalidName) {
+  ConstString MangledName("_ZN1a1b1cmxktpEEvm");
+  Mangled TheMangled(MangledName);
+  ConstString TheDemangled = TheMangled.GetDemangledName();
+
+  EXPECT_STREQ("", TheDemangled.GetCString());
+}
+
+TEST(MangledTest, ResultForValidRustV0Name) {
+  ConstString mangled_name("_RNvC1a4main");
+  Mangled the_mangled(mangled_name);
+  ConstString the_demangled = the_mangled.GetDemangledName();
+
+  ConstString expected_result("a::main");
+  EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
+}
+
+TEST(MangledTest, EmptyForInvalidRustV0Name) {
+  ConstString mangled_name("_RRR");
+  Mangled the_mangled(mangled_name);
+  ConstString the_demangled = the_mangled.GetDemangledName();
+
+  EXPECT_STREQ("", the_demangled.GetCString());
+}
+
+TEST(MangledTest, ResultForValidDLangName) {
+  ConstString mangled_name("_Dmain");
+  Mangled the_mangled(mangled_name);
+  ConstString the_demangled = the_mangled.GetDemangledName();
+
+  ConstString expected_result("D main");
+  EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString());
+}
+
+TEST(MangledTest, SameForInvalidDLangPrefixedName) {
+  ConstString mangled_name("_DDD");
+  Mangled the_mangled(mangled_name);
+  ConstString the_demangled = the_mangled.GetDemangledName();
+
+  EXPECT_STREQ("_DDD", the_demangled.GetCString());
+}
+
+TEST(MangledTest, RecognizeSwiftMangledNames) {
+  llvm::StringRef valid_swift_mangled_names[] = {
+      "_TtC4main7MyClass",   // Mangled objc class name
+      "_TtP4main3Foo_",      // Mangld objc protocol name
+      "$s4main3BarCACycfC",  // Mangled name
+      "_$s4main3BarCACycfC", // Mangled name with leading underscore
+      "$S4main3BarCACycfC",  // Older swift mangled name
+      "_$S4main3BarCACycfC", // Older swift mangled name
+                             // with leading underscore
+      // Mangled swift filename
+      "@__swiftmacro_4main16FunVariableNames9OptionSetfMm_.swift",
+  };
+
+  for (llvm::StringRef mangled : valid_swift_mangled_names)
+    EXPECT_EQ(Mangled::GetManglingScheme(mangled),
+              Mangled::eManglingSchemeSwift);
+}
+
+TEST(MangledTest, BoolConversionOperator) {
+  {
+    ConstString MangledName("_ZN1a1b1cIiiiEEvm");
+    Mangled TheMangled(MangledName);
+    EXPECT_EQ(true, bool(TheMangled));
+    EXPECT_EQ(false, !TheMangled);
+  }
+  {
+    ConstString UnmangledName("puts");
+    Mangled TheMangled(UnmangledName);
+    EXPECT_EQ(true, bool(TheMangled));
+    EXPECT_EQ(false, !TheMangled);
+  }
+  {
+    Mangled TheMangled{};
+    EXPECT_EQ(false, bool(TheMangled));
+    EXPECT_EQ(true, !TheMangled);
+  }
+}
+
+TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
+  SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab>
+      subsystems;
+
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:      
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+Sections:        
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Size:            0x20
+  - Name:            .anothertext
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x0000000000000010
+    AddressAlign:    0x0000000000000010
+    Size:            0x40
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x00000000000000A8
+    AddressAlign:    0x0000000000000004
+    Content:         '01000000'
+Symbols:
+  - Name:            somedata
+    Type:            STT_OBJECT
+    Section:         .anothertext
+    Value:           0x0000000000000045
+    Binding:         STB_GLOBAL
+  - Name:            main
+    Type:            STT_FUNC
+    Section:         .anothertext
+    Value:           0x0000000000000010
+    Size:            0x000000000000003F
+    Binding:         STB_GLOBAL
+  - Name:            _Z3foov
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            puts at GLIBC_2.5
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            puts at GLIBC_2.6
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _Z5annotv at VERSION3
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZN1AC2Ev
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZN1AD2Ev
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZN1A3barEv
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZGVZN4llvm4dbgsEvE7thestrm
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZZN4llvm4dbgsEvE7thestrm
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _ZTVN5clang4DeclE
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            -[ObjCfoo]
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            +[B ObjCbar(WithCategory)]
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+  - Name:            _Z12undemangableEvx42
+    Type:            STT_FUNC
+    Section:         .text
+    Size:            0x000000000000000D
+    Binding:         STB_GLOBAL
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto M = std::make_shared<Module>(ExpectedFile->moduleSpec());
+
+  auto Count = [M](const char *Name, FunctionNameType Type) -> int {
+    SymbolContextList SymList;
+    M->FindFunctionSymbols(ConstString(Name), Type, SymList);
+    return SymList.GetSize();
+  };
+
+  // Unmangled
+  EXPECT_EQ(1, Count("main", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("main", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("main", eFunctionNameTypeMethod));
+
+  // Itanium mangled
+  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z3foov", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("foo", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("foo", eFunctionNameTypeMethod));
+
+  // Unmangled with linker annotation
+  EXPECT_EQ(1, Count("puts at GLIBC_2.5", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("puts at GLIBC_2.6", eFunctionNameTypeFull));
+  EXPECT_EQ(2, Count("puts", eFunctionNameTypeFull));
+  EXPECT_EQ(2, Count("puts", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("puts", eFunctionNameTypeMethod));
+
+  // Itanium mangled with linker annotation
+  EXPECT_EQ(1, Count("_Z5annotv at VERSION3", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z5annotv", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("annot", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("annot", eFunctionNameTypeMethod));
+
+  // Itanium mangled ctor A::A()
+  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1AC2Ev", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("A", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("A", eFunctionNameTypeBase));
+
+  // Itanium mangled dtor A::~A()
+  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1AD2Ev", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("~A", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("~A", eFunctionNameTypeBase));
+
+  // Itanium mangled method A::bar()
+  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZN1A3barEv", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("bar", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("bar", eFunctionNameTypeBase));
+
+  // Itanium mangled names that are explicitly excluded from parsing
+  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("dbgs", eFunctionNameTypeBase));
+  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_ZTVN5clang4DeclE", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("Decl", eFunctionNameTypeBase));
+
+  // ObjC mangled static
+  EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("-[ObjCfoo]", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("ObjCfoo", eFunctionNameTypeMethod));
+
+  // ObjC mangled method with category
+  EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("ObjCbar", eFunctionNameTypeMethod));
+
+  // Invalid things: unable to decode but still possible to find by full name
+  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeFull));
+  EXPECT_EQ(1, Count("_Z12undemangableEvx42", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("_Z12undemangableEvx42", eFunctionNameTypeMethod));
+  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
+  EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
+}

>From ce31f3a4f9409edc430b1581e61de7888ec63286 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 27 May 2025 18:25:12 +0100
Subject: [PATCH 5/9] revert changes to MangledTest.cpp

---
 lldb/unittests/Core/MangledTest.cpp | 291 ++++++++++++++++++++++++++++
 1 file changed, 291 insertions(+)

diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp
index a3760ba43b3c9..b96691a4e01c9 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -11,6 +11,7 @@
 #include "TestingSupport/SubsystemRAII.h"
 #include "TestingSupport/TestUtilities.h"
 
+#include "lldb/Core/DemangledNameInfo.h"
 #include "lldb/Core/Mangled.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
@@ -319,3 +320,293 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeBase));
   EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
 }
+
+static bool NameInfoEquals(const DemangledNameInfo &lhs,
+                           const DemangledNameInfo &rhs) {
+  return std::tie(lhs.BasenameRange, lhs.ArgumentsRange, lhs.ScopeRange,
+                  lhs.QualifiersRange) ==
+         std::tie(rhs.BasenameRange, rhs.ArgumentsRange, rhs.ScopeRange,
+                  rhs.QualifiersRange);
+}
+
+TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
+  Mangled mangled;
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+
+  mangled.SetMangledName(ConstString("_Z3foov"));
+  ASSERT_TRUE(mangled);
+
+  auto info1 = mangled.GetDemangledInfo();
+  EXPECT_NE(info1, std::nullopt);
+  EXPECT_TRUE(info1->hasBasename());
+
+  mangled.SetMangledName(ConstString("_Z4funcv"));
+
+  // Should have re-calculated demangled-info since mangled name changed.
+  auto info2 = mangled.GetDemangledInfo();
+  ASSERT_NE(info2, std::nullopt);
+  EXPECT_TRUE(info2->hasBasename());
+
+  EXPECT_FALSE(NameInfoEquals(info1.value(), info2.value()));
+  EXPECT_EQ(mangled.GetDemangledName(), "func()");
+}
+
+TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
+  Mangled mangled("_Z3foov");
+  ASSERT_TRUE(mangled);
+
+  mangled.SetDemangledName(ConstString(""));
+
+  // Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
+  // of previously set mangled name.
+  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_EQ(mangled.GetDemangledName(), "foo()");
+}
+
+TEST(MangledTest, DemangledNameInfo_Clear) {
+  Mangled mangled("_Z3foov");
+  ASSERT_TRUE(mangled);
+  EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
+
+  mangled.Clear();
+
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+}
+
+TEST(MangledTest, DemangledNameInfo_SetValue) {
+  Mangled mangled("_Z4funcv");
+  ASSERT_TRUE(mangled);
+
+  auto demangled_func = mangled.GetDemangledInfo();
+
+  // SetValue(mangled) resets demangled-info
+  mangled.SetValue(ConstString("_Z3foov"));
+  auto demangled_foo = mangled.GetDemangledInfo();
+  EXPECT_NE(demangled_foo, std::nullopt);
+  EXPECT_FALSE(NameInfoEquals(demangled_foo.value(), demangled_func.value()));
+
+  // SetValue(demangled) resets demangled-info
+  mangled.SetValue(ConstString("_Z4funcv"));
+  EXPECT_TRUE(NameInfoEquals(mangled.GetDemangledInfo().value(),
+                             demangled_func.value()));
+
+  // SetValue(empty) resets demangled-info
+  mangled.SetValue(ConstString());
+  EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
+
+  // Demangling invalid mangled name will set demangled-info
+  // (without a valid basename).
+  mangled.SetValue(ConstString("_Zinvalid"));
+  ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
+  EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
+}
+
+struct DemanglingPartsTestCase {
+  const char *mangled;
+  DemangledNameInfo expected_info;
+  std::string_view basename;
+  std::string_view scope;
+  std::string_view qualifiers;
+  bool valid_basename = true;
+};
+
+DemanglingPartsTestCase g_demangling_parts_test_cases[] = {
+    // clang-format off
+   { "_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_",
+     { /*.BasenameRange=*/{92, 98}, /*.ScopeRange=*/{36, 92}, /*.ArgumentsRange=*/{ 108, 158 },
+       /*.QualifiersRange=*/{158, 176} },
+     /*.basename=*/"method",
+     /*.scope=*/"Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::",
+     /*.qualifiers=*/" const volatile &&"
+   },
+   { "_Z7getFuncIfEPFiiiET_",
+     { /*.BasenameRange=*/{6, 13}, /*.ScopeRange=*/{6, 6}, /*.ArgumentsRange=*/{ 20, 27 }, /*.QualifiersRange=*/{38, 38} },
+     /*.basename=*/"getFunc",
+     /*.scope=*/"",
+     /*.qualifiers=*/""
+   },
+   { "_ZN1f1b1c1gEv",
+     { /*.BasenameRange=*/{9, 10}, /*.ScopeRange=*/{0, 9}, /*.ArgumentsRange=*/{ 10, 12 },
+       /*.QualifiersRange=*/{12, 12} },
+     /*.basename=*/"g",
+     /*.scope=*/"f::b::c::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_",
+     { /*.BasenameRange=*/{45, 48}, /*.ScopeRange=*/{38, 45}, /*.ArgumentsRange=*/{ 53, 58 },
+       /*.QualifiersRange=*/{58, 58} },
+     /*.basename=*/"fD1",
+     /*.scope=*/"test7::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { /*.BasenameRange=*/{61, 64}, /*.ScopeRange=*/{54, 61}, /*.ArgumentsRange=*/{ 69, 79 },
+       /*.QualifiersRange=*/{79, 79} },
+     /*.basename=*/"fD1",
+     /*.scope=*/"test7::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_",
+     { /*.BasenameRange=*/{120, 123}, /*.ScopeRange=*/{81, 120}, /*.ArgumentsRange=*/{ 155, 168 },
+       /*.QualifiersRange=*/{168, 168} },
+     /*.basename=*/"fD1",
+     /*.scope=*/"test7<decltype(c)::d<decltype(c)::d>>::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb",
+     { /*.BasenameRange=*/{687, 692}, /*.ScopeRange=*/{343, 687}, /*.ArgumentsRange=*/{ 713, 1174 },
+       /*.QualifiersRange=*/{1174, 1174} },
+     /*.basename=*/"parse",
+     /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn",
+     { /*.BasenameRange=*/{344, 354}, /*.ScopeRange=*/{0, 344}, /*.ArgumentsRange=*/{ 354, 370 },
+       /*.QualifiersRange=*/{370, 370} },
+     /*.basename=*/"basic_json",
+     /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::",
+     /*.qualifiers=*/""
+   },
+   { "_Z3fppIiEPFPFvvEiEf",
+     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, /*.QualifiersRange=*/{34,34} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"",
+     /*.qualifiers=*/""
+   },
+   { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf",
+     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 },
+       /*.QualifiersRange=*/{43, 43} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"",
+     /*.qualifiers=*/""
+   },
+   { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf",
+     { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 },
+       /*.QualifiersRange=*/{108, 108} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"",
+     /*.qualifiers=*/""
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf",
+     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
+       /*.QualifiersRange=*/{88, 88} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     /*.qualifiers=*/""
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef",
+     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
+       /*.QualifiersRange=*/{97, 97} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     /*.qualifiers=*/"",
+   },
+   { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf",
+     { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 },
+       /*.QualifiersRange=*/{162, 162} },
+     /*.basename=*/"fpp",
+     /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::",
+     /*.qualifiers=*/"",
+   },
+   { "_ZNKO2ns3ns23Bar3fooIiEEPFPFNS0_3FooIiEEiENS3_IfEEEi",
+     { /*.BasenameRange=*/{37, 40}, /*.ScopeRange=*/{23, 37}, /*.ArgumentsRange=*/{ 45, 50 },
+       /*.QualifiersRange=*/{78, 87} },
+     /*.basename=*/"foo",
+     /*.scope=*/"ns::ns2::Bar::",
+     /*.qualifiers=*/" const &&",
+   },
+   { "_ZTV11ImageLoader",
+     { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{ 0, 0 },
+       /*.QualifiersRange=*/{0, 0} },
+     /*.basename=*/"",
+     /*.scope=*/"",
+     /*.qualifiers=*/"",
+     /*.valid_basename=*/false
+   },
+   { "___ZNK5dyld313MachOAnalyzer18forEachInitializerER11DiagnosticsRKNS0_15VMAddrConverterEU13block_pointerFvjEPKv_block_invoke.204",
+     { /*.BasenameRange=*/{55, 73}, /*.ScopeRange=*/{33, 55}, /*.ArgumentsRange=*/{ 73, 181 },
+       /*.QualifiersRange=*/{181, 187} },
+     /*.basename=*/"forEachInitializer",
+     /*.scope=*/"dyld3::MachOAnalyzer::",
+     /*.qualifiers=*/" const",
+   },
+   { "_ZZN5dyld45startEPNS_10KernelArgsEPvS2_ENK3$_1clEv",
+     { /*.BasenameRange=*/{53, 63}, /*.ScopeRange=*/{0, 53}, /*.ArgumentsRange=*/{ 63, 65 },
+       /*.QualifiersRange=*/{65, 71} },
+     /*.basename=*/"operator()",
+     /*.scope=*/"dyld4::start(dyld4::KernelArgs*, void*, void*)::$_1::",
+     /*.qualifiers=*/" const",
+   },
+   { "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv",
+     { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 },
+       /*.QualifiersRange=*/{100, 106} },
+     /*.basename=*/"operator()",
+     /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::",
+     /*.qualifiers=*/" const",
+   },
+   { "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv.cold",
+     { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 },
+       /*.QualifiersRange=*/{100, 106} },
+     /*.basename=*/"operator()",
+     /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::",
+     /*.qualifiers=*/" const",
+   }
+    // clang-format on
+};
+
+struct DemanglingPartsTestFixture
+    : public ::testing::TestWithParam<DemanglingPartsTestCase> {};
+
+namespace {
+class TestAllocator {
+  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 *));
+  }
+};
+} // namespace
+
+TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
+  const auto &[mangled, info, basename, scope, qualifiers, valid_basename] =
+      GetParam();
+
+  llvm::itanium_demangle::ManglingParser<TestAllocator> Parser(
+      mangled, mangled + ::strlen(mangled));
+
+  const auto *Root = Parser.parse();
+
+  ASSERT_NE(nullptr, Root);
+
+  TrackingOutputBuffer OB;
+  Root->print(OB);
+  auto demangled = std::string_view(OB);
+
+  ASSERT_EQ(OB.NameInfo.hasBasename(), valid_basename);
+
+  EXPECT_EQ(OB.NameInfo.BasenameRange, info.BasenameRange);
+  EXPECT_EQ(OB.NameInfo.ScopeRange, info.ScopeRange);
+  EXPECT_EQ(OB.NameInfo.ArgumentsRange, info.ArgumentsRange);
+  EXPECT_EQ(OB.NameInfo.QualifiersRange, info.QualifiersRange);
+
+  auto get_part = [&](const std::pair<size_t, size_t> &loc) {
+    return demangled.substr(loc.first, loc.second - loc.first);
+  };
+
+  EXPECT_EQ(get_part(OB.NameInfo.BasenameRange), basename);
+  EXPECT_EQ(get_part(OB.NameInfo.ScopeRange), scope);
+  EXPECT_EQ(get_part(OB.NameInfo.QualifiersRange), qualifiers);
+  std::free(OB.getBuffer());
+}
+
+INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
+                         ::testing::ValuesIn(g_demangling_parts_test_cases));
\ No newline at end of file

>From 68e3fd729f1cf839d690375d2c70bdbc9a347929 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 27 May 2025 18:26:23 +0100
Subject: [PATCH 6/9] fixup! revert changes to MangledTest.cpp

---
 lldb/unittests/Core/MangledTest.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp
index b96691a4e01c9..44651eb94c23b 100644
--- a/lldb/unittests/Core/MangledTest.cpp
+++ b/lldb/unittests/Core/MangledTest.cpp
@@ -609,4 +609,4 @@ TEST_P(DemanglingPartsTestFixture, DemanglingParts) {
 }
 
 INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture,
-                         ::testing::ValuesIn(g_demangling_parts_test_cases));
\ No newline at end of file
+                         ::testing::ValuesIn(g_demangling_parts_test_cases));

>From 0acb2a4e5bd8f96ede2e13c9715df4c5271af8d2 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 27 May 2025 18:45:12 +0100
Subject: [PATCH 7/9] add test to show that function.prefix is a no-op

---
 .../TestFrameFormatFunctionPrefix.test        | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 lldb/test/Shell/Settings/TestFrameFormatFunctionPrefix.test

diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionPrefix.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionPrefix.test
new file mode 100644
index 0000000000000..5bf1990d24c32
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionPrefix.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.prefix} in languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# RUN: split-file %s %t
+# RUN: %clang_host -g -gdwarf %t/main.m -o %t.objc.out
+# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.m
+
+int func() {}
+int bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.prefix}'\n"
+break set -n bar
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame

>From c74d879048fa2e33bb61345684d54250df5eec47 Mon Sep 17 00:00:00 2001
From: Charles Zablit <zablitcharles at gmail.com>
Date: Wed, 28 May 2025 11:27:10 +0100
Subject: [PATCH 8/9] Update lldb/source/Core/Mangled.cpp

Co-authored-by: Michael Buch <michaelbuch12 at gmail.com>
---
 lldb/source/Core/Mangled.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
index e6f7d198d7316..0027bfaeda4f7 100644
--- a/lldb/source/Core/Mangled.cpp
+++ b/lldb/source/Core/Mangled.cpp
@@ -173,7 +173,7 @@ GetItaniumDemangledStr(const char *M) {
     TrackingOutputBuffer OB(demangled_cstr, demangled_size);
     demangled_cstr = ipd.finishDemangle(&OB);
     OB.NameInfo.SuffixRange.first = OB.NameInfo.QualifiersRange.second;
-    OB.NameInfo.SuffixRange.second = std::string(demangled_cstr).length();
+    OB.NameInfo.SuffixRange.second = std::string_view(OB).size();
     info = std::move(OB.NameInfo);
 
     assert(demangled_cstr &&

>From 85416f9a68d506a7aa4ad534a43406180a3d6f01 Mon Sep 17 00:00:00 2001
From: Charles Zablit <zablitcharles at gmail.com>
Date: Wed, 28 May 2025 11:27:22 +0100
Subject: [PATCH 9/9] Update lldb/docs/use/formatting.rst

Co-authored-by: Michael Buch <michaelbuch12 at gmail.com>
---
 lldb/docs/use/formatting.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst
index 897ce8c47d7f1..e71b08780eb3d 100644
--- a/lldb/docs/use/formatting.rst
+++ b/lldb/docs/use/formatting.rst
@@ -91,7 +91,7 @@ A complete list of currently supported format string variables is listed below:
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | ``function.basename``                             | The basename of the current function depending on the frame's language. E.g., for C++ the basename for ``void ns::foo<float>::bar<int>(int) const`` is ``bar``.                                                                                                                             |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-| ``function.prefix``                               | Any prefix added to the demangled function name of the current function. This depends on the frame's language. E.g., for C++ the suffix will always be empty.                                                                                                                               |
+| ``function.prefix``                               | Any prefix added to the demangled function name of the current function. This depends on the frame's language. E.g., for C++ the prefix will always be empty.                                                                                                                               |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | ``function.scope``                                | The scope qualifiers of the current function depending on the frame's language. E.g., for C++ the scope for ``void ns::foo<float>::bar<int>(int) const`` is ``ns::foo<float>``.                                                                                                             |
 +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+



More information about the lldb-commits mailing list