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

Reply via email to