From 70621dc307b1ddb4239e49e8d81776c7aa529742 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Wed, 28 May 2025 13:53:02 +0100 Subject: [PATCH 1/2] [Demangling] Refactor Demangler range tracking (#140762) This PR is a subset of the commits made in https://github.com/swiftlang/llvm-project/pull/10710. The most notable change is the addition of `PrefixRange` and `SuffixRange` which are a catch-all to track anything after or before a function's demangled name. In the case of Swift, this allows to add support for name highlighting without having to track the range of the scope and specifiers of a function (this will come in another PR). --- lldb/docs/use/formatting.rst | 5 +++- lldb/include/lldb/Core/DemangledNameInfo.h | 12 +++++++++- lldb/include/lldb/Core/FormatEntity.h | 1 + lldb/source/Core/FormatEntity.cpp | 3 +++ lldb/source/Core/Mangled.cpp | 2 ++ .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 4 ++-- .../TestFrameFormatFunctionPrefix.test | 24 +++++++++++++++++++ 7 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 lldb/test/Shell/Settings/TestFrameFormatFunctionPrefix.test diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst index 61f51812d2ea9..e71b08780eb3d 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 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``. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``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}`` diff --git a/lldb/include/lldb/Core/DemangledNameInfo.h b/lldb/include/lldb/Core/DemangledNameInfo.h index 11d3bb58871b8..ab9bb3e211b66 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,6 +59,16 @@ 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 && 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 5e900d32eee42..4db5fd37a0285 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); @@ -1843,6 +1845,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 093451f070e70..13d51a1b80bc9 100644 --- a/lldb/source/Core/Mangled.cpp +++ b/lldb/source/Core/Mangled.cpp @@ -181,6 +181,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_view(OB).size(); 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 a219cf3b04f07..19eee054433b4 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -374,8 +374,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/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 542d3e8c38c84fb66436ca822001e6277101d2f7 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Wed, 28 May 2025 21:41:45 +0100 Subject: [PATCH 2/2] add explicit default initialization to DemangledNameInfo to remove warning (#141790) https://github.com/llvm/llvm-project/pull/140762 introduces some compilation warnings in `lldb/unittests/Core/MangledTest.cpp`. This patch adds explicit default initialization to `DemangledNameInfo` to suppress those warnings. We only had the default initialization values to `PrefixRange` and `SuffixRange` because they are the only _optional_ fields of the structure. --- lldb/unittests/Core/MangledTest.cpp | 62 +++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp index 8a452a84614ef..60222e60cfcae 100644 --- a/lldb/unittests/Core/MangledTest.cpp +++ b/lldb/unittests/Core/MangledTest.cpp @@ -414,114 +414,144 @@ 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} }, + /*.QualifiersRange=*/{158, 176}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"method", /*.scope=*/"Bar>::C, Bar>)>::", /*.qualifiers=*/" const volatile &&" }, { "_Z7getFuncIfEPFiiiET_", - { /*.BasenameRange=*/{6, 13}, /*.ScopeRange=*/{6, 6}, /*.ArgumentsRange=*/{ 20, 27 }, /*.QualifiersRange=*/{38, 38} }, + { /*.BasenameRange=*/{6, 13}, /*.ScopeRange=*/{6, 6}, /*.ArgumentsRange=*/{ 20, 27 }, + /*.QualifiersRange=*/{38, 38}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"getFunc", /*.scope=*/"", /*.qualifiers=*/"" }, { "_ZN1f1b1c1gEv", { /*.BasenameRange=*/{9, 10}, /*.ScopeRange=*/{0, 9}, /*.ArgumentsRange=*/{ 10, 12 }, - /*.QualifiersRange=*/{12, 12} }, + /*.QualifiersRange=*/{12, 12}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"g", /*.scope=*/"f::b::c::", /*.qualifiers=*/"" }, { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_", { /*.BasenameRange=*/{45, 48}, /*.ScopeRange=*/{38, 45}, /*.ArgumentsRange=*/{ 53, 58 }, - /*.QualifiersRange=*/{58, 58} }, + /*.QualifiersRange=*/{58, 58}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fD1", /*.scope=*/"test7::", /*.qualifiers=*/"" }, { "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_", { /*.BasenameRange=*/{61, 64}, /*.ScopeRange=*/{54, 61}, /*.ArgumentsRange=*/{ 69, 79 }, - /*.QualifiersRange=*/{79, 79} }, + /*.QualifiersRange=*/{79, 79}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fD1", /*.scope=*/"test7::", /*.qualifiers=*/"" }, { "_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_", { /*.BasenameRange=*/{120, 123}, /*.ScopeRange=*/{81, 120}, /*.ArgumentsRange=*/{ 155, 168 }, - /*.QualifiersRange=*/{168, 168} }, + /*.QualifiersRange=*/{168, 168}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.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} }, + /*.QualifiersRange=*/{1174, 1174}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.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} }, + /*.QualifiersRange=*/{370, 370}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.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} }, + { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, + /*.QualifiersRange=*/{34,34}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fpp", /*.scope=*/"", /*.qualifiers=*/"" }, { "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf", { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, - /*.QualifiersRange=*/{43, 43} }, + /*.QualifiersRange=*/{43, 43}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fpp", /*.scope=*/"", /*.qualifiers=*/"" }, { "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf", { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, - /*.QualifiersRange=*/{108, 108} }, + /*.QualifiersRange=*/{108, 108}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fpp", /*.scope=*/"", /*.qualifiers=*/"" }, { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf", { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, - /*.QualifiersRange=*/{88, 88} }, + /*.QualifiersRange=*/{88, 88}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fpp", /*.scope=*/"ns::HasFuncs::Bar::Qux>>::", /*.qualifiers=*/"" }, { "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef", { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, - /*.QualifiersRange=*/{97, 97} }, + /*.QualifiersRange=*/{97, 97}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.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} }, + /*.QualifiersRange=*/{162, 162}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"fpp", /*.scope=*/"ns::HasFuncs::Bar::Qux>>::", /*.qualifiers=*/"", }, { "_ZNKO2ns3ns23Bar3fooIiEEPFPFNS0_3FooIiEEiENS3_IfEEEi", { /*.BasenameRange=*/{37, 40}, /*.ScopeRange=*/{23, 37}, /*.ArgumentsRange=*/{ 45, 50 }, - /*.QualifiersRange=*/{78, 87} }, + /*.QualifiersRange=*/{78, 87}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, /*.basename=*/"foo", /*.scope=*/"ns::ns2::Bar::", /*.qualifiers=*/" const &&", }, { "_ZTV11ImageLoader", { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{ 0, 0 }, - /*.QualifiersRange=*/{0, 0} }, + /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{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}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, + /*.basename=*/"forEachInitializer", + /*.scope=*/"dyld3::MachOAnalyzer::", + /*.qualifiers=*/" const", + }, + { "_ZZN5dyld45startEPNS_10KernelArgsEPvS2_ENK3$_1clEv", + { /*.BasenameRange=*/{53, 63}, /*.ScopeRange=*/{0, 53}, /*.ArgumentsRange=*/{ 63, 65 }, + /*.QualifiersRange=*/{65, 71}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, + /*.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}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, + /*.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}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, + /*.basename=*/"operator()", + /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::", + /*.qualifiers=*/" const", } // clang-format on };