Skip to content

Commit d3a09f4

Browse files
Michael137IanWood1
authored andcommitted
[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
1 parent acfc1f3 commit d3a09f4

13 files changed

+302
-8
lines changed

lldb/include/lldb/Core/PluginManager.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ class PluginManager {
141141
GetOperatingSystemCreateCallbackForPluginName(llvm::StringRef name);
142142

143143
// Language
144-
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
145-
LanguageCreateInstance create_callback);
144+
static bool
145+
RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
146+
LanguageCreateInstance create_callback,
147+
DebuggerInitializeCallback debugger_init_callback = nullptr);
146148

147149
static bool UnregisterPlugin(LanguageCreateInstance create_callback);
148150

@@ -613,6 +615,14 @@ class PluginManager {
613615
static bool CreateSettingForStructuredDataPlugin(
614616
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
615617
llvm::StringRef description, bool is_global_property);
618+
619+
static lldb::OptionValuePropertiesSP
620+
GetSettingForCPlusPlusLanguagePlugin(Debugger &debugger,
621+
llvm::StringRef setting_name);
622+
623+
static bool CreateSettingForCPlusPlusLanguagePlugin(
624+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
625+
llvm::StringRef description, bool is_global_property);
616626
};
617627

618628
} // namespace lldb_private

lldb/include/lldb/Target/Language.h

+4
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ class Language : public PluginInterface {
495495
/// Python uses \b except. Defaults to \b catch.
496496
virtual llvm::StringRef GetCatchKeyword() const { return "catch"; }
497497

498+
virtual const FormatEntity::Entry *GetFunctionNameFormat() const {
499+
return nullptr;
500+
}
501+
498502
protected:
499503
// Classes that inherit from Language can see and modify these
500504

lldb/source/Core/FormatEntity.cpp

+32
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,
@@ -1796,6 +1825,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
17961825
if (!sc)
17971826
return false;
17981827

1828+
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1829+
return true;
1830+
17991831
return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
18001832
}
18011833
case Entry::Type::FunctionMangledName: {

lldb/source/Core/PluginManager.cpp

+22-5
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,12 @@ static LanguageInstances &GetLanguageInstances() {
564564
return g_instances;
565565
}
566566

567-
bool PluginManager::RegisterPlugin(llvm::StringRef name,
568-
llvm::StringRef description,
569-
LanguageCreateInstance create_callback) {
570-
return GetLanguageInstances().RegisterPlugin(name, description,
571-
create_callback);
567+
bool PluginManager::RegisterPlugin(
568+
llvm::StringRef name, llvm::StringRef description,
569+
LanguageCreateInstance create_callback,
570+
DebuggerInitializeCallback debugger_init_callback) {
571+
return GetLanguageInstances().RegisterPlugin(
572+
name, description, create_callback, debugger_init_callback);
572573
}
573574

574575
bool PluginManager::UnregisterPlugin(LanguageCreateInstance create_callback) {
@@ -1682,6 +1683,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) {
16821683
GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger);
16831684
GetTracePluginInstances().PerformDebuggerCallback(debugger);
16841685
GetScriptedInterfaceInstances().PerformDebuggerCallback(debugger);
1686+
GetLanguageInstances().PerformDebuggerCallback(debugger);
16851687
}
16861688

16871689
// This is the preferred new way to register plugin specific settings. e.g.
@@ -1810,6 +1812,7 @@ static constexpr llvm::StringLiteral kSymbolLocatorPluginName("symbol-locator");
18101812
static constexpr llvm::StringLiteral kJITLoaderPluginName("jit-loader");
18111813
static constexpr llvm::StringLiteral
18121814
kStructuredDataPluginName("structured-data");
1815+
static constexpr llvm::StringLiteral kCPlusPlusLanguagePlugin("cplusplus");
18131816

18141817
lldb::OptionValuePropertiesSP
18151818
PluginManager::GetSettingForDynamicLoaderPlugin(Debugger &debugger,
@@ -1967,3 +1970,17 @@ bool PluginManager::CreateSettingForStructuredDataPlugin(
19671970
"Settings for structured data plug-ins",
19681971
properties_sp, description, is_global_property);
19691972
}
1973+
1974+
lldb::OptionValuePropertiesSP
1975+
PluginManager::GetSettingForCPlusPlusLanguagePlugin(
1976+
Debugger &debugger, llvm::StringRef setting_name) {
1977+
return GetSettingForPlugin(debugger, setting_name, kCPlusPlusLanguagePlugin);
1978+
}
1979+
1980+
bool PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
1981+
Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
1982+
llvm::StringRef description, bool is_global_property) {
1983+
return CreateSettingForPlugin(debugger, kCPlusPlusLanguagePlugin,
1984+
"Settings for CPlusPlus language plug-ins",
1985+
properties_sp, description, is_global_property);
1986+
}

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

+12
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

+46-1
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() {
@@ -1968,3 +1969,47 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
19681969
return false;
19691970
}
19701971
}
1972+
1973+
#define LLDB_PROPERTIES_language_cplusplus
1974+
#include "LanguageCPlusPlusProperties.inc"
1975+
1976+
enum {
1977+
#define LLDB_PROPERTIES_language_cplusplus
1978+
#include "LanguageCPlusPlusPropertiesEnum.inc"
1979+
};
1980+
1981+
namespace {
1982+
class PluginProperties : public Properties {
1983+
public:
1984+
static llvm::StringRef GetSettingName() { return "display"; }
1985+
1986+
PluginProperties() {
1987+
m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
1988+
m_collection_sp->Initialize(g_language_cplusplus_properties);
1989+
}
1990+
1991+
const FormatEntity::Entry *GetFunctionNameFormat() const {
1992+
return GetPropertyAtIndexAs<const FormatEntity::Entry *>(
1993+
ePropertyFunctionNameFormat);
1994+
}
1995+
};
1996+
} // namespace
1997+
1998+
static PluginProperties &GetGlobalPluginProperties() {
1999+
static PluginProperties g_settings;
2000+
return g_settings;
2001+
}
2002+
2003+
const FormatEntity::Entry *CPlusPlusLanguage::GetFunctionNameFormat() const {
2004+
return GetGlobalPluginProperties().GetFunctionNameFormat();
2005+
}
2006+
2007+
void CPlusPlusLanguage::DebuggerInitialize(Debugger &debugger) {
2008+
if (!PluginManager::GetSettingForCPlusPlusLanguagePlugin(
2009+
debugger, PluginProperties::GetSettingName())) {
2010+
PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
2011+
debugger, GetGlobalPluginProperties().GetValueProperties(),
2012+
"Properties for the CPlusPlus language plug-in.",
2013+
/*is_global_property=*/true);
2014+
}
2015+
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,13 @@ class CPlusPlusLanguage : public Language {
136136

137137
llvm::StringRef GetInstanceVariableName() override { return "this"; }
138138

139+
const FormatEntity::Entry *GetFunctionNameFormat() const override;
140+
139141
// PluginInterface protocol
140142
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
143+
144+
private:
145+
static void DebuggerInitialize(Debugger &);
141146
};
142147

143148
} // namespace lldb_private
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+
}
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'
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'
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
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)