From cc3c6d1c86ae0ed579c4f325778ee1b4cd90d6be Mon Sep 17 00:00:00 2001 From: Charles Zablit 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 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, double))(int, int) @@ -59,11 +59,27 @@ struct DemangledNameInfo { /// \endcode std::pair 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 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 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 {}; + : public ::testing::TestWithParam {}; 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 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 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::bar(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::bar(int) const`` is ``ns::foo``. | +| ``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::bar(int) const`` is ``ns::foo``. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``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::bar(int) const`` are ````. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -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 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(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 - 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@GLIBC_2.5 - Type: STT_FUNC - Section: .text - Size: 0x000000000000000D - Binding: STB_GLOBAL - - Name: puts@GLIBC_2.6 - Type: STT_FUNC - Section: .text - Size: 0x000000000000000D - Binding: STB_GLOBAL - - Name: _Z5annotv@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(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@GLIBC_2.5", eFunctionNameTypeFull)); - EXPECT_EQ(1, Count("puts@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@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>::C, Bar>)>::", - /*.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>::", - /*.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::allocator>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector>, 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::allocator>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector>, 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::Bar::Qux>>::", - /*.qualifiers=*/"" - }, - { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef", - { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, - /*.QualifiersRange=*/{97, 97} }, - /*.basename=*/"fpp", - /*.scope=*/"ns::HasFuncs::Bar::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::Bar::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 {}; - -namespace { -class TestAllocator { - llvm::BumpPtrAllocator Alloc; - -public: - void reset() { Alloc.Reset(); } - - template T *makeNode(Args &&...args) { - return new (Alloc.Allocate(sizeof(T), alignof(T))) - T(std::forward(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 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 &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(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 + 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@GLIBC_2.5 + Type: STT_FUNC + Section: .text + Size: 0x000000000000000D + Binding: STB_GLOBAL + - Name: puts@GLIBC_2.6 + Type: STT_FUNC + Section: .text + Size: 0x000000000000000D + Binding: STB_GLOBAL + - Name: _Z5annotv@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(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@GLIBC_2.5", eFunctionNameTypeFull)); + EXPECT_EQ(1, Count("puts@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@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 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>::C, Bar>)>::", + /*.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>::", + /*.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::allocator>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector>, 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::allocator>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector>, 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::Bar::Qux>>::", + /*.qualifiers=*/"" + }, + { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef", + { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, + /*.QualifiersRange=*/{97, 97} }, + /*.basename=*/"fpp", + /*.scope=*/"ns::HasFuncs::Bar::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::Bar::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 {}; + +namespace { +class TestAllocator { + llvm::BumpPtrAllocator Alloc; + +public: + void reset() { Alloc.Reset(); } + + template T *makeNode(Args &&...args) { + return new (Alloc.Allocate(sizeof(T), alignof(T))) + T(std::forward(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 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 &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 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 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 Date: Wed, 28 May 2025 11:27:10 +0100 Subject: [PATCH 8/9] Update lldb/source/Core/Mangled.cpp Co-authored-by: Michael Buch --- 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 Date: Wed, 28 May 2025 11:27:22 +0100 Subject: [PATCH 9/9] Update lldb/docs/use/formatting.rst Co-authored-by: Michael Buch --- 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::bar(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::bar(int) const`` is ``ns::foo``. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+