Skip to content

Commit b4c1a18

Browse files
committed
[lldb][CPlusPlus] Add plugin.cplusplus.display.function-name-format setting (llvm#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. llvm#131836 (cherry picked from commit d555b9f)
1 parent 3ddde4c commit b4c1a18

13 files changed

+302
-8
lines changed

lldb/include/lldb/Core/PluginManager.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ class PluginManager {
134134
GetOperatingSystemCreateCallbackForPluginName(llvm::StringRef name);
135135

136136
// Language
137-
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
138-
LanguageCreateInstance create_callback);
137+
static bool
138+
RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
139+
LanguageCreateInstance create_callback,
140+
DebuggerInitializeCallback debugger_init_callback = nullptr);
139141

140142
static bool UnregisterPlugin(LanguageCreateInstance create_callback);
141143

@@ -600,6 +602,14 @@ class PluginManager {
600602
static bool CreateSettingForStructuredDataPlugin(
601603
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
602604
llvm::StringRef description, bool is_global_property);
605+
606+
static lldb::OptionValuePropertiesSP
607+
GetSettingForCPlusPlusLanguagePlugin(Debugger &debugger,
608+
llvm::StringRef setting_name);
609+
610+
static bool CreateSettingForCPlusPlusLanguagePlugin(
611+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
612+
llvm::StringRef description, bool is_global_property);
603613
};
604614

605615
} // namespace lldb_private

lldb/include/lldb/Target/Language.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ class Language : public PluginInterface {
399399
/// Python uses \b except. Defaults to \b catch.
400400
virtual llvm::StringRef GetCatchKeyword() const { return "catch"; }
401401

402+
virtual const FormatEntity::Entry *GetFunctionNameFormat() const {
403+
return nullptr;
404+
}
405+
402406
protected:
403407
// Classes that inherit from Language can see and modify these
404408

lldb/source/Core/FormatEntity.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,35 @@ static bool HandleFunctionNameWithArgs(Stream &s,
12371237
return true;
12381238
}
12391239

1240+
static bool FormatFunctionNameForLanguage(Stream &s,
1241+
const ExecutionContext *exe_ctx,
1242+
const SymbolContext *sc) {
1243+
assert(sc);
1244+
1245+
Language *language_plugin = nullptr;
1246+
if (sc->function)
1247+
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1248+
else if (sc->symbol)
1249+
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1250+
1251+
if (!language_plugin)
1252+
return false;
1253+
1254+
const auto *format = language_plugin->GetFunctionNameFormat();
1255+
if (!format)
1256+
return false;
1257+
1258+
StreamString name_stream;
1259+
const bool success =
1260+
FormatEntity::Format(*format, name_stream, sc, exe_ctx, /*addr=*/nullptr,
1261+
/*valobj=*/nullptr, /*function_changed=*/false,
1262+
/*initial_function=*/false);
1263+
if (success)
1264+
s << name_stream.GetString();
1265+
1266+
return success;
1267+
}
1268+
12401269
bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s,
12411270
const SymbolContext *sc,
12421271
const ExecutionContext *exe_ctx,
@@ -1804,6 +1833,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
18041833
if (!sc)
18051834
return false;
18061835

1836+
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1837+
return true;
1838+
18071839
return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
18081840
}
18091841
case Entry::Type::FunctionMangledName: {

lldb/source/Core/PluginManager.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,12 @@ static LanguageInstances &GetLanguageInstances() {
508508
return g_instances;
509509
}
510510

511-
bool PluginManager::RegisterPlugin(llvm::StringRef name,
512-
llvm::StringRef description,
513-
LanguageCreateInstance create_callback) {
514-
return GetLanguageInstances().RegisterPlugin(name, description,
515-
create_callback);
511+
bool PluginManager::RegisterPlugin(
512+
llvm::StringRef name, llvm::StringRef description,
513+
LanguageCreateInstance create_callback,
514+
DebuggerInitializeCallback debugger_init_callback) {
515+
return GetLanguageInstances().RegisterPlugin(
516+
name, description, create_callback, debugger_init_callback);
516517
}
517518

518519
bool PluginManager::UnregisterPlugin(LanguageCreateInstance create_callback) {
@@ -1635,6 +1636,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
16351636
GetTracePluginInstances().PerformDebuggerCallback(debugger);
16361637
GetTypeSystemInstances().PerformDebuggerCallback(debugger);
16371638
GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
1639+
GetLanguageInstances().PerformDebuggerCallback(debugger);
16381640
}
16391641

16401642
// This is the preferred new way to register plugin specific settings. e.g.
@@ -1763,6 +1765,7 @@ static constexpr llvm::StringLiteral kSymbolLocatorPluginName("symbol-locator");
17631765
static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader");
17641766
static constexpr llvm::StringLiteral
17651767
kStructuredDataPluginName("structured-data");
1768+
static constexpr llvm::StringLiteral kCPlusPlusLanguagePlugin("cplusplus");
17661769

17671770
lldb::OptionValuePropertiesSP
17681771
PluginManager::GetSettingForDynamicLoaderPlugin(Debugger &debugger,
@@ -1920,3 +1923,17 @@ bool PluginManager::CreateSettingForStructuredDataPlugin(
19201923
"Settings for structured data plug-ins",
19211924
properties_sp, description, is_global_property);
19221925
}
1926+
1927+
lldb::OptionValuePropertiesSP
1928+
PluginManager::GetSettingForCPlusPlusLanguagePlugin(
1929+
Debugger &debugger, llvm::StringRef setting_name) {
1930+
return GetSettingForPlugin(debugger, setting_name, kCPlusPlusLanguagePlugin);
1931+
}
1932+
1933+
bool PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
1934+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
1935+
llvm::StringRef description, bool is_global_property) {
1936+
return CreateSettingForPlugin(debugger, kCPlusPlusLanguagePlugin,
1937+
"Settings for CPlusPlus language plug-ins",
1938+
properties_sp, description, is_global_property);
1939+
}

lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
lldb_tablegen(LanguageCPlusPlusProperties.inc -gen-lldb-property-defs
2+
SOURCE LanguageCPlusPlusProperties.td
3+
TARGET LLDBPluginLanguageCPlusPlusPropertiesGen)
4+
5+
lldb_tablegen(LanguageCPlusPlusPropertiesEnum.inc -gen-lldb-property-enum-defs
6+
SOURCE LanguageCPlusPlusProperties.td
7+
TARGET LLDBPluginLanguageCPlusPlusPropertiesEnumGen)
8+
19
add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
210
BlockPointer.cpp
311
Coroutines.cpp
@@ -41,3 +49,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
4149
LINK_COMPONENTS
4250
Support
4351
)
52+
53+
add_dependencies(lldbPluginCPlusPlusLanguage
54+
LLDBPluginLanguageCPlusPlusPropertiesGen
55+
LLDBPluginLanguageCPlusPlusPropertiesEnumGen)

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "lldb/DataFormatters/DataVisualization.h"
2828
#include "lldb/DataFormatters/FormattersHelpers.h"
2929
#include "lldb/DataFormatters/VectorType.h"
30+
#include "lldb/Interpreter/OptionValueProperties.h"
3031
#include "lldb/Symbol/SymbolFile.h"
3132
#include "lldb/Symbol/VariableList.h"
3233
#include "lldb/Utility/ConstString.h"
@@ -55,7 +56,7 @@ LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
5556

5657
void CPlusPlusLanguage::Initialize() {
5758
PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
58-
CreateInstance);
59+
CreateInstance, &DebuggerInitialize);
5960
}
6061

6162
void CPlusPlusLanguage::Terminate() {
@@ -1991,3 +1992,47 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
19911992
return false;
19921993
}
19931994
}
1995+
1996+
#define LLDB_PROPERTIES_language_cplusplus
1997+
#include "LanguageCPlusPlusProperties.inc"
1998+
1999+
enum {
2000+
#define LLDB_PROPERTIES_language_cplusplus
2001+
#include "LanguageCPlusPlusPropertiesEnum.inc"
2002+
};
2003+
2004+
namespace {
2005+
class PluginProperties : public Properties {
2006+
public:
2007+
static llvm::StringRef GetSettingName() { return "display"; }
2008+
2009+
PluginProperties() {
2010+
m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
2011+
m_collection_sp->Initialize(g_language_cplusplus_properties);
2012+
}
2013+
2014+
const FormatEntity::Entry *GetFunctionNameFormat() const {
2015+
return GetPropertyAtIndexAs<const FormatEntity::Entry *>(
2016+
ePropertyFunctionNameFormat);
2017+
}
2018+
};
2019+
} // namespace
2020+
2021+
static PluginProperties &GetGlobalPluginProperties() {
2022+
static PluginProperties g_settings;
2023+
return g_settings;
2024+
}
2025+
2026+
const FormatEntity::Entry *CPlusPlusLanguage::GetFunctionNameFormat() const {
2027+
return GetGlobalPluginProperties().GetFunctionNameFormat();
2028+
}
2029+
2030+
void CPlusPlusLanguage::DebuggerInitialize(Debugger &debugger) {
2031+
if (!PluginManager::GetSettingForCPlusPlusLanguagePlugin(
2032+
debugger, PluginProperties::GetSettingName())) {
2033+
PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
2034+
debugger, GetGlobalPluginProperties().GetValueProperties(),
2035+
"Properties for the CPlusPlus language plug-in.",
2036+
/*is_global_property=*/true);
2037+
}
2038+
}

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,13 @@ class CPlusPlusLanguage : public Language {
174174

175175
llvm::StringRef GetInstanceVariableName() override { return "this"; }
176176

177+
const FormatEntity::Entry *GetFunctionNameFormat() const override;
178+
177179
// PluginInterface protocol
178180
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
181+
182+
private:
183+
static void DebuggerInitialize(Debugger &);
179184
};
180185

181186
} // namespace lldb_private
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
include "../../../../include/lldb/Core/PropertiesBase.td"
2+
3+
let Definition = "language_cplusplus" in {
4+
def FunctionNameFormat: Property<"function-name-format", "FormatEntity">,
5+
Global,
6+
DefaultStringValue<"${function.return-left}${function.scope}${function.basename}${function.template-arguments}${function.formatted-arguments}${function.return-right}${function.qualifiers}">,
7+
Desc<"C++ specific frame format string to use when displaying stack frame information for threads.">;
8+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Test the plugin.cplusplus.display.function-name-format setting.
2+
3+
# RUN: split-file %s %t
4+
# RUN: %build %t/main.cpp -o %t.out
5+
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
6+
# RUN: | FileCheck %s
7+
8+
#--- main.cpp
9+
namespace ns::ns2 {
10+
void custom(int x) asm("_Zinvalid_mangling");
11+
void custom(int x) {}
12+
13+
void bar() { custom(5); }
14+
void foo() { bar(); }
15+
}
16+
17+
int main(int argc, char const *argv[]) {
18+
ns::ns2::foo();
19+
return 0;
20+
}
21+
22+
#--- commands.input
23+
settings set plugin.cplusplus.display.function-name-format "${function.scope}${function.basename}"
24+
settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
25+
break set -l 3
26+
27+
run
28+
bt
29+
30+
# CHECK: custom-frame '_Zinvalid_mangling(x=5)'
31+
# CHECK: custom-frame 'ns::ns2::bar'
32+
# CHECK: custom-frame 'ns::ns2::foo'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Test the plugin.cplusplus.display.function-name-format setting
2+
# when interoperating multiple languages.
3+
4+
# RUN: split-file %s %t
5+
# RUN: %clangxx_host -x c -c -g %t/lib.c -o %t.clib.o
6+
# RUN: %clangxx_host -c -g %t/lib.cpp -o %t.cxxlib.o
7+
# RUN: %clangxx_host %t/main.m %t.cxxlib.o %t.clib.o -o %t.out
8+
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 | FileCheck %s
9+
10+
#--- lib.c
11+
12+
void foo();
13+
14+
void func() {
15+
foo();
16+
}
17+
18+
#--- lib.cpp
19+
20+
namespace ns {
21+
struct Foo {
22+
void method() {}
23+
};
24+
}
25+
26+
extern "C" {
27+
void foo() {
28+
ns::Foo{}.method();
29+
}
30+
}
31+
32+
#--- main.m
33+
34+
void func();
35+
36+
int main() {
37+
func();
38+
}
39+
40+
#--- commands.input
41+
settings set plugin.cplusplus.display.function-name-format "this affects C++ only"
42+
settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
43+
break set -n method
44+
45+
run
46+
bt
47+
48+
# CHECK: custom-frame 'this affects C++ only'
49+
# CHECK: custom-frame 'this affects C++ only'
50+
# CHECK: custom-frame 'func'
51+
# CHECK: custom-frame 'main'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Test the plugin.cplusplus.display.function-name-format setting.
2+
3+
# RUN: split-file %s %t
4+
# RUN: %build %t/main.m -o %t.objc.out
5+
# RUN: %lldb -x -b -s %t/commands.input %t.objc.out -o exit 2>&1 \
6+
# RUN: | FileCheck %s
7+
8+
#--- main.m
9+
10+
int func(int x) {}
11+
int bar(int y) { func(y); }
12+
13+
int main() { return bar(10); }
14+
15+
#--- commands.input
16+
settings set plugin.cplusplus.display.function-name-format "this affects C++ only"
17+
settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
18+
break set -l 3
19+
run
20+
21+
bt
22+
23+
# CHECK: bt
24+
# CHECK-NOT: this affects C++ only
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Test that the plugin.cplusplus.display.function-name-format setting
2+
# doesn't print into the frame-format setting unless all its format variables
3+
# were successful.
4+
5+
# RUN: split-file %s %t
6+
# RUN: %build %t/main.cpp -o %t.out
7+
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
8+
# RUN: | FileCheck %s
9+
10+
#--- main.cpp
11+
template<typename T> T gunc(int x = 10) {
12+
return T{};
13+
}
14+
15+
int main(int argc, const char *argv[]) {
16+
gunc<int>();
17+
return 0;
18+
}
19+
20+
#--- commands.input
21+
settings set plugin.cplusplus.display.function-name-format "${function.basename}${script.target:invalid_func}"
22+
settings set -f frame-format "custom-frame '${function.name-with-args}'\n"
23+
break set -n gunc
24+
25+
run
26+
bt
27+
28+
# CHECK: custom-frame 'int gunc<int>(x=10)'
29+
# CHECK: custom-frame 'main(argc=1, argv={{.*}})'

0 commit comments

Comments
 (0)