Author: Michael Buch
Date: 2025-04-25T10:04:27+01:00
New Revision: d555b9f9a01705097edf2434cf897e351095e5c9

URL: 
https://github.com/llvm/llvm-project/commit/d555b9f9a01705097edf2434cf897e351095e5c9
DIFF: 
https://github.com/llvm/llvm-project/commit/d555b9f9a01705097edf2434cf897e351095e5c9.diff

LOG: [lldb][CPlusPlus] Add plugin.cplusplus.display.function-name-format 
setting (#131836)

Adds the new `plugin.cplusplus.display.function-name-format` setting and makes 
the `${function.name-with-args}` query it for formatting the function name.

One caveat is that the setting can't itself be set to 
`${function.name-with-args}` because that would cause infinite recursion and 
blow the stack. I added an XFAILed test-case for it and will address it in a 
follow-up patch.

https://github.com/llvm/llvm-project/pull/131836

Added: 
    lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td
    lldb/test/Shell/Settings/TestCxxFrameFormat.test
    lldb/test/Shell/Settings/TestCxxFrameFormatMixedLanguages.test
    lldb/test/Shell/Settings/TestCxxFrameFormatObjC.test
    lldb/test/Shell/Settings/TestCxxFrameFormatPartialFailure.test
    lldb/test/Shell/Settings/TestCxxFrameFormatRecursive.test

Modified: 
    lldb/include/lldb/Core/PluginManager.h
    lldb/include/lldb/Target/Language.h
    lldb/source/Core/FormatEntity.cpp
    lldb/source/Core/PluginManager.cpp
    lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
    lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/PluginManager.h 
b/lldb/include/lldb/Core/PluginManager.h
index a6dab045adf27..d73dd71d833f3 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -141,8 +141,10 @@ class PluginManager {
   GetOperatingSystemCreateCallbackForPluginName(llvm::StringRef name);
 
   // Language
-  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
-                             LanguageCreateInstance create_callback);
+  static bool
+  RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
+                 LanguageCreateInstance create_callback,
+                 DebuggerInitializeCallback debugger_init_callback = nullptr);
 
   static bool UnregisterPlugin(LanguageCreateInstance create_callback);
 
@@ -613,6 +615,14 @@ class PluginManager {
   static bool CreateSettingForStructuredDataPlugin(
       Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
       llvm::StringRef description, bool is_global_property);
+
+  static lldb::OptionValuePropertiesSP
+  GetSettingForCPlusPlusLanguagePlugin(Debugger &debugger,
+                                       llvm::StringRef setting_name);
+
+  static bool CreateSettingForCPlusPlusLanguagePlugin(
+      Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
+      llvm::StringRef description, bool is_global_property);
 };
 
 } // namespace lldb_private

diff  --git a/lldb/include/lldb/Target/Language.h 
b/lldb/include/lldb/Target/Language.h
index 94ace6433df2f..d62871bd7ed70 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -495,6 +495,10 @@ class Language : public PluginInterface {
   /// Python uses \b except. Defaults to \b catch.
   virtual llvm::StringRef GetCatchKeyword() const { return "catch"; }
 
+  virtual const FormatEntity::Entry *GetFunctionNameFormat() const {
+    return nullptr;
+  }
+
 protected:
   // Classes that inherit from Language can see and modify these
 

diff  --git a/lldb/source/Core/FormatEntity.cpp 
b/lldb/source/Core/FormatEntity.cpp
index eafc8c932208c..e352d07fe487d 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -1237,6 +1237,35 @@ static bool HandleFunctionNameWithArgs(Stream &s,
   return true;
 }
 
+static bool FormatFunctionNameForLanguage(Stream &s,
+                                          const ExecutionContext *exe_ctx,
+                                          const SymbolContext *sc) {
+  assert(sc);
+
+  Language *language_plugin = nullptr;
+  if (sc->function)
+    language_plugin = Language::FindPlugin(sc->function->GetLanguage());
+  else if (sc->symbol)
+    language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
+
+  if (!language_plugin)
+    return false;
+
+  const auto *format = language_plugin->GetFunctionNameFormat();
+  if (!format)
+    return false;
+
+  StreamString name_stream;
+  const bool success =
+      FormatEntity::Format(*format, name_stream, sc, exe_ctx, /*addr=*/nullptr,
+                           /*valobj=*/nullptr, /*function_changed=*/false,
+                           /*initial_function=*/false);
+  if (success)
+    s << name_stream.GetString();
+
+  return success;
+}
+
 bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream 
&s,
                                    const SymbolContext *sc,
                                    const ExecutionContext *exe_ctx,
@@ -1796,6 +1825,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
     if (!sc)
       return false;
 
+    if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
+      return true;
+
     return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
   }
   case Entry::Type::FunctionMangledName: {

diff  --git a/lldb/source/Core/PluginManager.cpp 
b/lldb/source/Core/PluginManager.cpp
index e6cb248ef31ce..73c018330a24e 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -564,11 +564,12 @@ static LanguageInstances &GetLanguageInstances() {
   return g_instances;
 }
 
-bool PluginManager::RegisterPlugin(llvm::StringRef name,
-                                   llvm::StringRef description,
-                                   LanguageCreateInstance create_callback) {
-  return GetLanguageInstances().RegisterPlugin(name, description,
-                                               create_callback);
+bool PluginManager::RegisterPlugin(
+    llvm::StringRef name, llvm::StringRef description,
+    LanguageCreateInstance create_callback,
+    DebuggerInitializeCallback debugger_init_callback) {
+  return GetLanguageInstances().RegisterPlugin(
+      name, description, create_callback, debugger_init_callback);
 }
 
 bool PluginManager::UnregisterPlugin(LanguageCreateInstance create_callback) {
@@ -1682,6 +1683,7 @@ void PluginManager::DebuggerInitialize(Debugger 
&debugger) {
   GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
   GetTracePluginInstances().PerformDebuggerCallback(debugger);
   GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
+  GetLanguageInstances().PerformDebuggerCallback(debugger);
 }
 
 // This is the preferred new way to register plugin specific settings.  e.g.
@@ -1810,6 +1812,7 @@ static constexpr llvm::StringLiteral 
kSymbolLocatorPluginName("symbol-locator");
 static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader");
 static constexpr llvm::StringLiteral
     kStructuredDataPluginName("structured-data");
+static constexpr llvm::StringLiteral kCPlusPlusLanguagePlugin("cplusplus");
 
 lldb::OptionValuePropertiesSP
 PluginManager::GetSettingForDynamicLoaderPlugin(Debugger &debugger,
@@ -1967,3 +1970,17 @@ bool PluginManager::CreateSettingForStructuredDataPlugin(
                                 "Settings for structured data plug-ins",
                                 properties_sp, description, 
is_global_property);
 }
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForCPlusPlusLanguagePlugin(
+    Debugger &debugger, llvm::StringRef setting_name) {
+  return GetSettingForPlugin(debugger, setting_name, kCPlusPlusLanguagePlugin);
+}
+
+bool PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
+    Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
+    llvm::StringRef description, bool is_global_property) {
+  return CreateSettingForPlugin(debugger, kCPlusPlusLanguagePlugin,
+                                "Settings for CPlusPlus language plug-ins",
+                                properties_sp, description, 
is_global_property);
+}

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt 
b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index ccdc4d0ae99b3..9bb10c2a792a9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -1,3 +1,11 @@
+lldb_tablegen(LanguageCPlusPlusProperties.inc -gen-lldb-property-defs
+  SOURCE LanguageCPlusPlusProperties.td
+  TARGET LLDBPluginLanguageCPlusPlusPropertiesGen)
+
+lldb_tablegen(LanguageCPlusPlusPropertiesEnum.inc -gen-lldb-property-enum-defs
+  SOURCE LanguageCPlusPlusProperties.td
+  TARGET LLDBPluginLanguageCPlusPlusPropertiesEnumGen)
+
 add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   BlockPointer.cpp
   Coroutines.cpp
@@ -41,3 +49,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   LINK_COMPONENTS
     Support
 )
+
+add_dependencies(lldbPluginCPlusPlusLanguage
+  LLDBPluginLanguageCPlusPlusPropertiesGen
+  LLDBPluginLanguageCPlusPlusPropertiesEnumGen)

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index cf425fcc81c2f..943bc93348942 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -27,6 +27,7 @@
 #include "lldb/DataFormatters/DataVisualization.h"
 #include "lldb/DataFormatters/FormattersHelpers.h"
 #include "lldb/DataFormatters/VectorType.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
 #include "lldb/Symbol/SymbolFile.h"
 #include "lldb/Symbol/VariableList.h"
 #include "lldb/Utility/ConstString.h"
@@ -55,7 +56,7 @@ LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
 
 void CPlusPlusLanguage::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
-                                CreateInstance);
+                                CreateInstance, &DebuggerInitialize);
 }
 
 void CPlusPlusLanguage::Terminate() {
@@ -1968,3 +1969,47 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
     return false;
   }
 }
+
+#define LLDB_PROPERTIES_language_cplusplus
+#include "LanguageCPlusPlusProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_language_cplusplus
+#include "LanguageCPlusPlusPropertiesEnum.inc"
+};
+
+namespace {
+class PluginProperties : public Properties {
+public:
+  static llvm::StringRef GetSettingName() { return "display"; }
+
+  PluginProperties() {
+    m_collection_sp = 
std::make_shared<OptionValueProperties>(GetSettingName());
+    m_collection_sp->Initialize(g_language_cplusplus_properties);
+  }
+
+  const FormatEntity::Entry *GetFunctionNameFormat() const {
+    return GetPropertyAtIndexAs<const FormatEntity::Entry *>(
+        ePropertyFunctionNameFormat);
+  }
+};
+} // namespace
+
+static PluginProperties &GetGlobalPluginProperties() {
+  static PluginProperties g_settings;
+  return g_settings;
+}
+
+const FormatEntity::Entry *CPlusPlusLanguage::GetFunctionNameFormat() const {
+  return GetGlobalPluginProperties().GetFunctionNameFormat();
+}
+
+void CPlusPlusLanguage::DebuggerInitialize(Debugger &debugger) {
+  if (!PluginManager::GetSettingForCPlusPlusLanguagePlugin(
+          debugger, PluginProperties::GetSettingName())) {
+    PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
+        debugger, GetGlobalPluginProperties().GetValueProperties(),
+        "Properties for the CPlusPlus language plug-in.",
+        /*is_global_property=*/true);
+  }
+}

diff  --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 6192ff702773a..575f76c3101ed 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -136,8 +136,13 @@ class CPlusPlusLanguage : public Language {
 
   llvm::StringRef GetInstanceVariableName() override { return "this"; }
 
+  const FormatEntity::Entry *GetFunctionNameFormat() const override;
+
   // PluginInterface protocol
   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+private:
+  static void DebuggerInitialize(Debugger &);
 };
 
 } // namespace lldb_private

diff  --git 
a/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td 
b/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td
new file mode 100644
index 0000000000000..6ec87afe25758
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LanguageCPlusPlusProperties.td
@@ -0,0 +1,8 @@
+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}${function.basename}${function.template-arguments}${function.formatted-arguments}${function.return-right}${function.qualifiers}">,
+    Desc<"C++ specific frame format string to use when displaying stack frame 
information for threads.">;
+}

diff  --git a/lldb/test/Shell/Settings/TestCxxFrameFormat.test 
b/lldb/test/Shell/Settings/TestCxxFrameFormat.test
new file mode 100644
index 0000000000000..c26d339f57130
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestCxxFrameFormat.test
@@ -0,0 +1,32 @@
+# Test the plugin.cplusplus.display.function-name-format setting.
+
+# RUN: split-file %s %t
+# RUN: %build %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
+namespace ns::ns2 {
+void custom(int x) asm("_Zinvalid_mangling");
+void custom(int x) {}
+
+void bar() { custom(5); }
+void foo() { bar(); }
+}
+
+int main(int argc, char const *argv[]) {
+    ns::ns2::foo();
+    return 0;
+}
+
+#--- commands.input
+settings set plugin.cplusplus.display.function-name-format 
"${function.scope}${function.basename}"
+settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
+break set -l 3
+
+run
+bt
+
+# CHECK: custom-frame '_Zinvalid_mangling(x=5)'
+# CHECK: custom-frame 'ns::ns2::bar'
+# CHECK: custom-frame 'ns::ns2::foo'

diff  --git a/lldb/test/Shell/Settings/TestCxxFrameFormatMixedLanguages.test 
b/lldb/test/Shell/Settings/TestCxxFrameFormatMixedLanguages.test
new file mode 100644
index 0000000000000..854cf6384d8ee
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestCxxFrameFormatMixedLanguages.test
@@ -0,0 +1,51 @@
+# Test the plugin.cplusplus.display.function-name-format setting
+# when interoperating multiple languages.
+
+# RUN: split-file %s %t
+# RUN: %clangxx_host -x c -c -g %t/lib.c -o %t.clib.o
+# RUN: %clangxx_host -c -g %t/lib.cpp -o %t.cxxlib.o
+# RUN: %clangxx_host %t/main.m %t.cxxlib.o %t.clib.o -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 | FileCheck %s
+
+#--- lib.c
+
+void foo();
+
+void func() {
+  foo();
+}
+
+#--- lib.cpp
+
+namespace ns {
+struct Foo {
+    void method() {}
+};
+}
+
+extern "C" {
+void foo() {
+  ns::Foo{}.method();
+}
+}
+
+#--- main.m
+
+void func();
+
+int main() {
+  func();
+}
+
+#--- commands.input
+settings set plugin.cplusplus.display.function-name-format "this affects C++ 
only"
+settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
+break set -n method
+
+run
+bt
+
+# CHECK: custom-frame 'this affects C++ only' 
+# CHECK: custom-frame 'this affects C++ only' 
+# CHECK: custom-frame 'func' 
+# CHECK: custom-frame 'main' 

diff  --git a/lldb/test/Shell/Settings/TestCxxFrameFormatObjC.test 
b/lldb/test/Shell/Settings/TestCxxFrameFormatObjC.test
new file mode 100644
index 0000000000000..525ada2afe99c
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestCxxFrameFormatObjC.test
@@ -0,0 +1,24 @@
+# Test the plugin.cplusplus.display.function-name-format setting.
+
+# RUN: split-file %s %t
+# RUN: %build %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 x) {}
+int bar(int y) { func(y); }
+
+int main() { return bar(10); }
+
+#--- commands.input
+settings set plugin.cplusplus.display.function-name-format "this affects C++ 
only"
+settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
+break set -l 3
+run
+
+bt
+
+# CHECK: bt
+# CHECK-NOT: this affects C++ only

diff  --git a/lldb/test/Shell/Settings/TestCxxFrameFormatPartialFailure.test 
b/lldb/test/Shell/Settings/TestCxxFrameFormatPartialFailure.test
new file mode 100644
index 0000000000000..73564ae41837b
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestCxxFrameFormatPartialFailure.test
@@ -0,0 +1,29 @@
+# Test that the plugin.cplusplus.display.function-name-format setting
+# doesn't print into the frame-format setting unless all its format variables
+# were successful.
+
+# RUN: split-file %s %t
+# RUN: %build %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
+template<typename T> T gunc(int x = 10) {
+  return T{};
+}
+
+int main(int argc, const char *argv[]) {
+  gunc<int>();
+  return 0;
+}
+
+#--- commands.input
+settings set plugin.cplusplus.display.function-name-format 
"${function.basename}${script.target:invalid_func}"
+settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
+break set -n gunc
+
+run
+bt
+
+# CHECK: custom-frame 'int gunc<int>(x=10)'
+# CHECK: custom-frame 'main(argc=1, argv={{.*}})'

diff  --git a/lldb/test/Shell/Settings/TestCxxFrameFormatRecursive.test 
b/lldb/test/Shell/Settings/TestCxxFrameFormatRecursive.test
new file mode 100644
index 0000000000000..90cd2d3e327c9
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestCxxFrameFormatRecursive.test
@@ -0,0 +1,25 @@
+# XFAIL: *
+
+# Test disallowed variables inside the
+# plugin.cplusplus.display.function-name-format setting.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.out
+# RUN: %lldb -o "settings set interpreter.stop-command-source-on-error false" \
+# RUN:       -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN:       | FileCheck %s
+
+#--- main.cpp
+int main(int argc, char const *argv[]) { return 0; }
+
+#--- commands.input
+settings set plugin.cplusplus.display.function-name-format 
"${function.name-with-args}"
+settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
+b main
+run
+
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
+# CHECK: main


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to