https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/137763
This patch adds another frame-format variable (currently only implemented in the CPlusPlus language plugin) that represents the "suffix" of a function. The name is derived from the `DotSuffix` node of LLVM's Itanium demangler. For a function name such as `int foo() (.cold)`, the suffix would be `(.cold)`. >From 4d102853c77456873b8360de32789f1c15416bc6 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Tue, 29 Apr 2025 08:04:34 +0100 Subject: [PATCH] [lldb][Format] Add function.suffix frame-format variable This patch adds another frame-format variable (currently only implemented in the CPlusPlus language plugin) that represents the "suffix" of a function. The name is derived from the `DotSuffix` node of LLVM's Itanium demangler. For a function name such as `int foo() (.cold)`, the suffix would be `(.cold)`. --- .../utils/yaml-bench/cmake_install.cmake | 39 +++++++++++++++++++ lldb/docs/use/formatting.rst | 11 ++++-- lldb/include/lldb/Core/FormatEntity.h | 1 + lldb/source/Core/FormatEntity.cpp | 3 ++ .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 32 +++++++++++++++ .../CPlusPlus/LanguageCPlusPlusProperties.td | 2 +- .../TestFrameFormatFunctionSuffix.test | 23 +++++++++++ 7 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 lldb-builds/release/utils/yaml-bench/cmake_install.cmake create mode 100644 lldb/test/Shell/Settings/TestFrameFormatFunctionSuffix.test diff --git a/lldb-builds/release/utils/yaml-bench/cmake_install.cmake b/lldb-builds/release/utils/yaml-bench/cmake_install.cmake new file mode 100644 index 0000000000000..fa0d8ddfac037 --- /dev/null +++ b/lldb-builds/release/utils/yaml-bench/cmake_install.cmake @@ -0,0 +1,39 @@ +# Install script for directory: /Users/jonas/Git/llvm-worktrees/frame-format/llvm/utils/yaml-bench + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Release") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set path to fallback-tool for dependency-resolution. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/objdump") +endif() + diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst index a21165a3ecae3..61f51812d2ea9 100644 --- a/lldb/docs/use/formatting.rst +++ b/lldb/docs/use/formatting.rst @@ -106,6 +106,8 @@ A complete list of currently supported format string variables is listed below: | ``function.return-right`` | The return type to the right of the demangled function name of the current function. This depends on the frame's language. In ``void ns::foo(int)`` there is no ``function.return-right`` so this would correspond to an empty string. However, in some cases, particularly for functions | | | returning function pointers, part of the return type is to the right of the function name. E.g., for ``void (*ns::func(float))(int)`` the ``function.return-left`` would be ``void (*`` and the ``function.return-right`` would be ``)(int)``. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``function.suffix`` | Any suffix added to the demangled function name of the current function. This depends on the frame's language. E.g., for C++ the suffix for ``void ns::foo(int) (.cold)`` is '(.cold). | ++---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``function.mangled-name`` | The mangled name of the current function or symbol. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``function.pc-offset`` | The program counter offset within the current function or symbol | @@ -329,6 +331,7 @@ The function names displayed in backtraces/``frame info``/``thread info`` are th - ``${function.formatted-arguments}`` - ``${function.qualifiers}`` - ``${function.return-right}`` +- ``${function.suffix}`` Each language plugin decides how to handle these variables. For C++, LLDB uses these variables to dictate how function names are formatted. This can be customized using the ``plugin.cplusplus.display.function-name-format`` LLDB setting. @@ -336,19 +339,19 @@ E.g., the following setting would reconstruct the entire function name (and is L :: - (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.return-left}${function.scope}${function.basename}${function.template-arguments}${function.formatted-arguments}${function.qualifiers}${function.return-right}" + (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.return-left}${function.scope}${function.basename}${function.template-arguments}${function.formatted-arguments}${function.qualifiers}${function.return-right}${function.suffix}" -If a user wanted to omit the return type and template arguments of C++ function names one could do: +If a user wanted to only print the name and arguments of a C++ function one could do: :: - (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.scope}${function.basename}${function.formatted-arguments}${function.qualifiers}" + (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.scope}${function.basename}${function.formatted-arguments}" Then the following would highlight just the basename in green: :: - (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.scope}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.formatted-arguments}${function.qualifiers}" + (lldb) settings set plugin.cplusplus.dislpay.function-name-format "${function.scope}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.formatted-arguments}" The ``${function.name-with-args}`` by default asks the language plugin whether it supports a language-specific ``function-name-format`` (e.g., the ``plugin.cplusplus.display.function-name-format`` for C++), and if it does, uses it. Otherwise it will display the demangled function name. diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h index e62c82d080d5f..97065afe19bfe 100644 --- a/lldb/include/lldb/Core/FormatEntity.h +++ b/lldb/include/lldb/Core/FormatEntity.h @@ -95,6 +95,7 @@ struct Entry { FunctionReturnLeft, FunctionReturnRight, FunctionQualifiers, + FunctionSuffix, FunctionAddrOffset, FunctionAddrOffsetConcrete, FunctionLineOffset, diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index 6cdfcfedf8be5..468203ac73a42 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -130,6 +130,7 @@ constexpr Definition g_function_child_entries[] = { Definition("return-left", EntryType::FunctionReturnLeft), Definition("return-right", EntryType::FunctionReturnRight), Definition("qualifiers", EntryType::FunctionQualifiers), + Definition("suffix", EntryType::FunctionSuffix), }; constexpr Definition g_line_child_entries[] = { @@ -368,6 +369,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) { ENUM_TO_CSTR(FunctionReturnLeft); ENUM_TO_CSTR(FunctionReturnRight); ENUM_TO_CSTR(FunctionQualifiers); + ENUM_TO_CSTR(FunctionSuffix); ENUM_TO_CSTR(FunctionAddrOffset); ENUM_TO_CSTR(FunctionAddrOffsetConcrete); ENUM_TO_CSTR(FunctionLineOffset); @@ -1808,6 +1810,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, case Entry::Type::FunctionFormattedArguments: case Entry::Type::FunctionReturnRight: case Entry::Type::FunctionReturnLeft: + case Entry::Type::FunctionSuffix: case Entry::Type::FunctionQualifiers: { if (!sc->function) return false; diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 283e867d53bb7..90db03c45700e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -381,6 +381,29 @@ GetDemangledScope(const SymbolContext &sc) { return demangled_name.slice(info->ScopeRange.first, info->ScopeRange.second); } +/// Handles anything printed after the FunctionEncoding ItaniumDemangle +/// node. Most notably the DotSUffix node. +static std::optional<llvm::StringRef> +GetDemangledFunctionSuffix(const SymbolContext &sc) { + Mangled mangled = sc.GetPossiblyInlinedFunctionName(); + if (!mangled) + return std::nullopt; + + auto demangled_name = mangled.GetDemangledName().GetStringRef(); + if (demangled_name.empty()) + return std::nullopt; + + const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo(); + if (!info) + return std::nullopt; + + // Function without a basename is nonsense. + if (!info->hasBasename()) + return std::nullopt; + + return demangled_name.slice(info->QualifiersRange.second, llvm::StringRef::npos); +} + bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() { // This method tries to parse simple method definitions which are presumably // most comman in user programs. Definitions that can be parsed by this @@ -1966,6 +1989,15 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable( return true; } + case FormatEntity::Entry::Type::FunctionSuffix: { + std::optional<llvm::StringRef> suffix = GetDemangledFunctionSuffix(sc); + if (!suffix) + return false; + + s << *suffix; + + return true; + } default: return false; } diff --git a/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td b/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td index 348de256b154a..4d74a040f4de4 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td +++ b/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td @@ -3,6 +3,6 @@ include "../../../../include/lldb/Core/PropertiesBase.td" let Definition = "language_cplusplus" in { def FunctionNameFormat: Property<"function-name-format", "FormatEntity">, Global, - DefaultStringValue<"${function.return-left}${function.scope}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.template-arguments}${function.formatted-arguments}${function.return-right}${function.qualifiers}">, + DefaultStringValue<"${function.return-left}${function.scope}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.template-arguments}${function.formatted-arguments}${function.return-right}${function.qualifiers}${function.suffix}">, Desc<"C++ specific frame format string to use when displaying stack frame information for threads.">; } diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionSuffix.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionSuffix.test new file mode 100644 index 0000000000000..ce7fa22b00b5a --- /dev/null +++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionSuffix.test @@ -0,0 +1,23 @@ +# XFAIL: target-windows + +# Test the ${function.suffix} frame-format variable. + +# RUN: split-file %s %t +# RUN: %clang_host -g -gdwarf %t/main.cpp -o %t.out +# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \ +# RUN: | FileCheck %s + +#--- main.cpp +void bar() asm("_Z3barv.cold"); +void bar() {} + +int main() { bar(); } + +#--- commands.input +settings set -f frame-format "custom-frame '${function.suffix}'\n" +break set -n "_Z3barv.cold" + +run +bt + +# CHECK: custom-frame ' (.cold)' _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits