[Lldb-commits] [lldb] [Demangling] Refactor Demangler range tracking (PR #140762)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Tue May 27 06:44:29 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/4] 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/4] 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/4] 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/4] 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));
+}
More information about the lldb-commits
mailing list