[Lldb-commits] [lldb] 8b91b44 - [lldb][Format] Introduce new frame-format variables for function parts (#131836)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Fri Apr 25 02:05:07 PDT 2025
Author: Michael Buch
Date: 2025-04-25T10:04:27+01:00
New Revision: 8b91b44a3be680788f914af72f38f90d35925c23
URL: https://github.com/llvm/llvm-project/commit/8b91b44a3be680788f914af72f38f90d35925c23
DIFF: https://github.com/llvm/llvm-project/commit/8b91b44a3be680788f914af72f38f90d35925c23.diff
LOG: [lldb][Format] Introduce new frame-format variables for function parts (#131836)
Adds new frame-format variables and implements them in the CPlusPlusLanguage plugin.
We use the `DemangledNameInfo` type to retrieve the necessary part of the demangled name.
https://github.com/llvm/llvm-project/pull/131836
Added:
lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test
Modified:
lldb/include/lldb/Core/FormatEntity.h
lldb/include/lldb/Symbol/SymbolContext.h
lldb/include/lldb/Target/Language.h
lldb/source/Core/FormatEntity.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
lldb/source/Symbol/SymbolContext.cpp
lldb/test/Shell/Settings/TestFrameFormatName.test
Removed:
################################################################################
diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h
index f6c3bd981e03a..31a08b3e4add0 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -88,6 +88,13 @@ struct Entry {
FunctionNameWithArgs,
FunctionNameNoArgs,
FunctionMangledName,
+ FunctionScope,
+ FunctionBasename,
+ FunctionTemplateArguments,
+ FunctionFormattedArguments,
+ FunctionReturnLeft,
+ FunctionReturnRight,
+ FunctionQualifiers,
FunctionAddrOffset,
FunctionAddrOffsetConcrete,
FunctionLineOffset,
diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h
index 4f8405f1f0db5..af2f694e554de 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -311,8 +311,7 @@ class SymbolContext {
/// mangling preference. If this object represents an inlined function,
/// returns the name of the inlined function. Returns nullptr if no function
/// name could be determined.
- const char *GetPossiblyInlinedFunctionName(
- Mangled::NamePreference mangling_preference) const;
+ Mangled GetPossiblyInlinedFunctionName() const;
// Member variables
lldb::TargetSP target_sp; ///< The Target for a given query
diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h
index fa856843871e3..94ace6433df2f 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -15,6 +15,7 @@
#include <set>
#include <vector>
+#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/Highlighter.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
@@ -371,6 +372,13 @@ class Language : public PluginInterface {
FunctionNameRepresentation representation,
Stream &s);
+ virtual bool HandleFrameFormatVariable(const SymbolContext &sc,
+ const ExecutionContext *exe_ctx,
+ FormatEntity::Entry::Type type,
+ Stream &s) {
+ return false;
+ }
+
virtual ConstString
GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
if (ConstString demangled = mangled.GetDemangledName())
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 874478340003c..eafc8c932208c 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -122,7 +122,15 @@ constexpr Definition g_function_child_entries[] = {
Definition("pc-offset", EntryType::FunctionPCOffset),
Definition("initial-function", EntryType::FunctionInitial),
Definition("changed", EntryType::FunctionChanged),
- Definition("is-optimized", EntryType::FunctionIsOptimized)};
+ Definition("is-optimized", EntryType::FunctionIsOptimized),
+ Definition("scope", EntryType::FunctionScope),
+ Definition("basename", EntryType::FunctionBasename),
+ Definition("template-arguments", EntryType::FunctionTemplateArguments),
+ Definition("formatted-arguments", EntryType::FunctionFormattedArguments),
+ Definition("return-left", EntryType::FunctionReturnLeft),
+ Definition("return-right", EntryType::FunctionReturnRight),
+ Definition("qualifiers", EntryType::FunctionQualifiers),
+};
constexpr Definition g_line_child_entries[] = {
Entry::DefinitionWithChildren("file", EntryType::LineEntryFile,
@@ -353,6 +361,13 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
ENUM_TO_CSTR(FunctionNameWithArgs);
ENUM_TO_CSTR(FunctionNameNoArgs);
ENUM_TO_CSTR(FunctionMangledName);
+ ENUM_TO_CSTR(FunctionScope);
+ ENUM_TO_CSTR(FunctionBasename);
+ ENUM_TO_CSTR(FunctionTemplateArguments);
+ ENUM_TO_CSTR(FunctionFormattedArguments);
+ ENUM_TO_CSTR(FunctionReturnLeft);
+ ENUM_TO_CSTR(FunctionReturnRight);
+ ENUM_TO_CSTR(FunctionQualifiers);
ENUM_TO_CSTR(FunctionAddrOffset);
ENUM_TO_CSTR(FunctionAddrOffsetConcrete);
ENUM_TO_CSTR(FunctionLineOffset);
@@ -1167,8 +1182,9 @@ static bool PrintFunctionNameWithArgs(Stream &s,
ExecutionContextScope *exe_scope =
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
- const char *cstr =
- sc.GetPossiblyInlinedFunctionName(Mangled::ePreferDemangled);
+ const char *cstr = sc.GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::ePreferDemangled)
+ .AsCString();
if (!cstr)
return false;
@@ -1186,7 +1202,8 @@ static bool PrintFunctionNameWithArgs(Stream &s,
return true;
}
-static bool HandleFunctionNameWithArgs(Stream &s,const ExecutionContext *exe_ctx,
+static bool HandleFunctionNameWithArgs(Stream &s,
+ const ExecutionContext *exe_ctx,
const SymbolContext &sc) {
Language *language_plugin = nullptr;
bool language_plugin_handled = false;
@@ -1711,8 +1728,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return true;
}
- const char *name = sc->GetPossiblyInlinedFunctionName(
- Mangled::NamePreference::ePreferDemangled);
+ const char *name = sc->GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::NamePreference::ePreferDemangled)
+ .AsCString();
if (!name)
return false;
@@ -1743,8 +1761,10 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return true;
}
- const char *name = sc->GetPossiblyInlinedFunctionName(
- Mangled::NamePreference::ePreferDemangledWithoutArguments);
+ const char *name =
+ sc->GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::NamePreference::ePreferDemangledWithoutArguments)
+ .AsCString();
if (!name)
return false;
@@ -1753,19 +1773,38 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
return true;
}
+ case Entry::Type::FunctionScope:
+ case Entry::Type::FunctionBasename:
+ case Entry::Type::FunctionTemplateArguments:
+ case Entry::Type::FunctionFormattedArguments:
+ case Entry::Type::FunctionReturnRight:
+ case Entry::Type::FunctionReturnLeft:
+ case Entry::Type::FunctionQualifiers: {
+ if (!sc->function)
+ return false;
+
+ Language *language_plugin =
+ Language::FindPlugin(sc->function->GetLanguage());
+ if (!language_plugin)
+ return false;
+
+ return language_plugin->HandleFrameFormatVariable(*sc, exe_ctx, entry.type,
+ s);
+ }
+
case Entry::Type::FunctionNameWithArgs: {
if (!sc)
return false;
return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
}
-
case Entry::Type::FunctionMangledName: {
if (!sc)
return false;
- const char *name = sc->GetPossiblyInlinedFunctionName(
- Mangled::NamePreference::ePreferMangled);
+ const char *name = sc->GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::NamePreference::ePreferMangled)
+ .AsCString();
if (!name)
return false;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 40b6563aeb410..cf425fcc81c2f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -235,6 +235,151 @@ static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
return true;
}
+static std::optional<llvm::StringRef>
+GetDemangledBasename(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->BasenameRange.first,
+ info->BasenameRange.second);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledTemplateArguments(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;
+
+ if (info->ArgumentsRange.first < info->BasenameRange.second)
+ return std::nullopt;
+
+ return demangled_name.slice(info->BasenameRange.second,
+ info->ArgumentsRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledReturnTypeLHS(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;
+
+ if (info->ScopeRange.first >= demangled_name.size())
+ return std::nullopt;
+
+ return demangled_name.substr(0, info->ScopeRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledFunctionQualifiers(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;
+
+ if (info->QualifiersRange.second < info->QualifiersRange.first)
+ return std::nullopt;
+
+ return demangled_name.slice(info->QualifiersRange.first,
+ info->QualifiersRange.second);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledReturnTypeRHS(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;
+
+ if (info->QualifiersRange.first < info->ArgumentsRange.second)
+ return std::nullopt;
+
+ return demangled_name.slice(info->ArgumentsRange.second,
+ info->QualifiersRange.first);
+}
+
+static std::optional<llvm::StringRef>
+GetDemangledScope(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;
+
+ if (info->ScopeRange.second < info->ScopeRange.first)
+ return std::nullopt;
+
+ return demangled_name.slice(info->ScopeRange.first, info->ScopeRange.second);
+}
+
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
@@ -1694,8 +1839,9 @@ static bool PrintFunctionNameWithArgs(Stream &s,
ExecutionContextScope *exe_scope =
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
- const char *cstr = sc.GetPossiblyInlinedFunctionName(
- Mangled::NamePreference::ePreferDemangled);
+ const char *cstr = sc.GetPossiblyInlinedFunctionName()
+ .GetName(Mangled::NamePreference::ePreferDemangled)
+ .AsCString();
if (!cstr)
return false;
@@ -1739,3 +1885,86 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
return false;
}
}
+bool CPlusPlusLanguage::HandleFrameFormatVariable(
+ const SymbolContext &sc, const ExecutionContext *exe_ctx,
+ FormatEntity::Entry::Type type, Stream &s) {
+ assert(sc.function);
+
+ switch (type) {
+ case FormatEntity::Entry::Type::FunctionScope: {
+ std::optional<llvm::StringRef> scope = GetDemangledScope(sc);
+ if (!scope)
+ return false;
+
+ s << *scope;
+
+ return true;
+ }
+
+ case FormatEntity::Entry::Type::FunctionBasename: {
+ std::optional<llvm::StringRef> name = GetDemangledBasename(sc);
+ if (!name)
+ return false;
+
+ s << *name;
+
+ return true;
+ }
+
+ case FormatEntity::Entry::Type::FunctionTemplateArguments: {
+ std::optional<llvm::StringRef> template_args =
+ GetDemangledTemplateArguments(sc);
+ if (!template_args)
+ return false;
+
+ s << *template_args;
+
+ return true;
+ }
+
+ case FormatEntity::Entry::Type::FunctionFormattedArguments: {
+ VariableList args;
+ if (auto variable_list_sp = GetFunctionVariableList(sc))
+ variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
+ args);
+
+ ExecutionContextScope *exe_scope =
+ exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
+
+ s << '(';
+ FormatEntity::PrettyPrintFunctionArguments(s, args, exe_scope);
+ s << ')';
+
+ return true;
+ }
+ case FormatEntity::Entry::Type::FunctionReturnRight: {
+ std::optional<llvm::StringRef> return_rhs = GetDemangledReturnTypeRHS(sc);
+ if (!return_rhs)
+ return false;
+
+ s << *return_rhs;
+
+ return true;
+ }
+ case FormatEntity::Entry::Type::FunctionReturnLeft: {
+ std::optional<llvm::StringRef> return_lhs = GetDemangledReturnTypeLHS(sc);
+ if (!return_lhs)
+ return false;
+
+ s << *return_lhs;
+
+ return true;
+ }
+ case FormatEntity::Entry::Type::FunctionQualifiers: {
+ std::optional<llvm::StringRef> quals = GetDemangledFunctionQualifiers(sc);
+ if (!quals)
+ return false;
+
+ s << *quals;
+
+ return true;
+ }
+ default:
+ return false;
+ }
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index b2b308f8e0c4d..6192ff702773a 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -105,6 +105,13 @@ class CPlusPlusLanguage : public Language {
FunctionNameRepresentation representation,
Stream &s) override;
+ bool HandleFrameFormatVariable(const SymbolContext &sc,
+ const ExecutionContext *exe_ctx,
+ FormatEntity::Entry::Type type,
+ Stream &s) override;
+
+ static bool IsCPPMangledName(llvm::StringRef name);
+
// Extract C++ context and identifier from a string using heuristic matching
// (as opposed to
// CPlusPlusLanguage::CxxMethodName which has to have a fully qualified C++
diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
index a9626bbc37777..3bbd1eff824e6 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -10,6 +10,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/DemangledNameInfo.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
@@ -872,34 +873,36 @@ const Symbol *SymbolContext::FindBestGlobalDataSymbol(ConstString name,
return nullptr; // no error; we just didn't find anything
}
-char const *SymbolContext::GetPossiblyInlinedFunctionName(
- Mangled::NamePreference mangling_preference) const {
- const char *name = nullptr;
- if (function)
- name = function->GetMangled().GetName(mangling_preference).AsCString();
- else if (symbol)
- name = symbol->GetMangled().GetName(mangling_preference).AsCString();
+Mangled SymbolContext::GetPossiblyInlinedFunctionName() const {
+ auto get_mangled = [this]() {
+ if (function)
+ return function->GetMangled();
+
+ if (symbol)
+ return symbol->GetMangled();
+
+ return Mangled{};
+ };
if (!block)
- return name;
+ return get_mangled();
const Block *inline_block = block->GetContainingInlinedBlock();
if (!inline_block)
- return name;
+ return get_mangled();
const InlineFunctionInfo *inline_info =
inline_block->GetInlinedFunctionInfo();
if (!inline_info)
- return name;
+ return get_mangled();
// If we do have an inlined frame name, return that.
- if (char const *inline_name =
- inline_info->GetMangled().GetName(mangling_preference).AsCString())
+ if (const Mangled &inline_name = inline_info->GetMangled())
return inline_name;
// Sometimes an inline frame may not have mangling information,
// but does have a valid name.
- return inline_info->GetName().AsCString();
+ return Mangled{inline_info->GetName().AsCString()};
}
//
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
new file mode 100644
index 0000000000000..249a5fac5b55e
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
@@ -0,0 +1,46 @@
+# Test the ${function.basename} frame-format variable.
+
+# 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 {
+template<typename T>
+struct Bar {
+ template<typename K>
+ T bar(K k) const & { return 1.0f; }
+};
+
+template<typename T>
+struct Foo {
+ template<typename K>
+ [[gnu::abi_tag("Test")]] void foo() const volatile && {
+ Bar<float> b;
+ b.bar(b);
+ }
+};
+
+template<typename T>
+T func() {
+ ns::Foo<int>{}.foo<int>();
+ return T{};
+}
+} // namespace ns
+
+int main() {
+ ns::func<ns::Foo<int>>();
+ return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.basename}'\n"
+break set -n bar
+
+run
+bt
+
+# CHECK: custom-frame 'bar'
+# CHECK: custom-frame 'foo[abi:Test]'
+# CHECK: custom-frame 'func'
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
new file mode 100644
index 0000000000000..1a36d049db06c
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasenameObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.basename} in languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# 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 bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.basename}'\n"
+break set -n bar
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
new file mode 100644
index 0000000000000..5554830d3a247
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
@@ -0,0 +1,42 @@
+# Test the ${function.formatted-arguments} frame-format variable.
+
+# 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
+struct Foo {
+ void func() {}
+};
+
+void bar() {
+ Foo{}.func();
+}
+
+void foo(int, int x) {
+ bar();
+}
+
+void myFunc(char const * str,
+ void (*fptr)(int, int)) {
+ fptr(5, 10);
+}
+
+int main(int argc, char const *argv[]) {
+ myFunc("hello", &foo);
+ return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.formatted-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: custom-frame '(this={{.*}})'
+# CHECK: custom-frame '()'
+# CHECK: custom-frame '((null)=5, x=10)'
+# CHECK: custom-frame '(str="hello", fptr=({{.*}}.out`foo(int, int) at main.cpp:{{[0-9]+}}))'
+# CHECK: custom-frame '(argc=1, argv={{.*}})'
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
new file mode 100644
index 0000000000000..fdafa65c6d05d
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArgumentsObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.formatted-arguments} in languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# 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 bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.formatted-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
new file mode 100644
index 0000000000000..95a3be3811d85
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
@@ -0,0 +1,24 @@
+# Test the ${function.qualifiers} frame-format variable.
+
+# 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
+struct Foo {
+ void foo() const volatile && {}
+ void bar() { Foo{}.foo(); }
+};
+
+int main() { Foo{}.bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.qualifiers}'\n"
+break set -n foo
+
+run
+bt
+
+# CHECK: custom-frame ' const volatile &&'
+# CHECK: custom-frame ''
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
new file mode 100644
index 0000000000000..eff1b581c15dc
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiersObjC.test
@@ -0,0 +1,25 @@
+# Check that we have an appropriate fallback for ${function.qualifiers} in
+# languages that don't implement this frame format variable (in this case Objective-C).
+
+# 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 foo() {}
+int bar() { foo(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.qualifiers}'\n"
+break set -n foo
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
new file mode 100644
index 0000000000000..a5e49a1054c86
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
@@ -0,0 +1,55 @@
+# Test the ${function.return-left} and ${function.return-right}
+# frame-format variables.
+
+# 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 {
+template<typename T>
+struct Foo {};
+
+template<typename T>
+Foo<int> qux(int) {
+ return {};
+}
+
+template<typename T>
+Foo<int> (*bar(Foo<float>))(int) {
+ qux<T>(5);
+ return qux<T>;
+}
+
+struct Bar {
+ template<typename T>
+ Foo<int> (* (*foo(int) const &&)(Foo<float>))(int) {
+ bar<T>(Foo<float>{});
+ return bar<T>;
+ }
+};
+}
+
+int main(int argc, char const *argv[]) {
+ ns::ns2::Bar{}.foo<int>(5);
+ return 0;
+}
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.return-left}'\n"
+break set -n qux
+
+run
+bt
+
+# CHECK: custom-frame 'ns::ns2::Foo<int> '
+# CHECK: custom-frame 'ns::ns2::Foo<int> (*'
+# CHECK: custom-frame 'ns::ns2::Foo<int> (* (*'
+
+settings set -f frame-format "other-frame '${function.return-right}'\n"
+bt
+
+# CHECK: other-frame ''
+# CHECK: other-frame ')(int)'
+# CHECK: other-frame ')(ns::ns2::Foo<float>))(int)'
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
new file mode 100644
index 0000000000000..69dd0fdbb0c19
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturnObjC.test
@@ -0,0 +1,31 @@
+# Check that we have an appropriate fallback for ${function.return-left} and
+# ${function.return-right} in languages that don't implement this frame
+# format variable (in this case Objective-C).
+#
+# 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 qux() {}
+int bar() { qux(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.return-left}'\n"
+break set -n qux
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
+
+settings set -f frame-format "other-frame '${function.return-right}'\n"
+bt
+
+# CHECK: bt
+# CHECK-NOT: other-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
new file mode 100644
index 0000000000000..28f0ab7ca39e3
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
@@ -0,0 +1,41 @@
+# Test the ${function.scope} frame-format variable.
+
+# 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
+namespace ns::ns2 {
+inline namespace ins {
+template <typename T>
+struct Foo {
+ void func() {}
+};
+
+int foo() {
+ Foo<int>{}.func();
+ return 5;
+}
+} // namespace ins
+} // namespace ns::ns2
+
+using namespace ns::ns2;
+
+int bar() {
+ return ns::ns2::foo();
+}
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.scope}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: frame 'ns::ns2::ins::Foo<int>::'
+# CHECK: frame 'ns::ns2::ins::'
+# CHECK: frame ''
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
new file mode 100644
index 0000000000000..310b5e1992ab8
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionScopeObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.scope} in languages that
+# don't implement this frame format variable (in this case Objective-C).
+#
+# 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 bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.scope}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
new file mode 100644
index 0000000000000..396dd29dfd02c
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
@@ -0,0 +1,37 @@
+# Test the ${function.template-arguments} frame-format variable.
+
+# RUN: split-file %s %t
+# RUN: %build %t/main.cpp -o %t.cxx.out
+# RUN: %lldb -x -b -s %t/commands.input %t.cxx.out -o exit 2>&1 \
+# RUN: | FileCheck %s
+
+#--- main.cpp
+template<typename K>
+struct Foo {
+ template<typename T>
+ void func() {}
+};
+
+template<typename T, template <typename> class K,
+ typename M>
+int foo() {
+ Foo<int>{}.func<T>();
+ return 5;
+}
+
+int bar() {
+ return foo<int, Foo, Foo<float>>();
+}
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.template-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: custom-frame '<int>'
+# CHECK: custom-frame '<int, Foo, Foo<float>>'
+# CHECK: custom-frame ''
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test
new file mode 100644
index 0000000000000..1726aebacb9eb
--- /dev/null
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArgumentsObjC.test
@@ -0,0 +1,24 @@
+# Check that we have an appropriate fallback for ${function.template-arguments} in
+# languages that don't implement this frame format variable (in this case Objective-C).
+#
+# 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 bar() { func(); }
+
+int main() { return bar(); }
+
+#--- commands.input
+settings set -f frame-format "custom-frame '${function.template-arguments}'\n"
+break set -n func
+
+run
+bt
+
+# CHECK: bt
+# CHECK-NOT: custom-frame
diff --git a/lldb/test/Shell/Settings/TestFrameFormatName.test b/lldb/test/Shell/Settings/TestFrameFormatName.test
index 110daceb47b40..34eb2f4975315 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatName.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatName.test
@@ -22,13 +22,13 @@ c
c
# NAME_WITH_ARGS: frame int ns::foo<void (Foo::*)(int (*)(int)) const noexcept>(str="method")
c
-# NAME_WITH_ARGS: frame ns::returns_func_ptr<int>((null)={{.*}})
+# NAME_WITH_ARGS: frame detail::Quux<double> (* (*ns::returns_func_ptr<int>((null)={{.*}}))(int))(float)
c
# NAME_WITH_ARGS: frame void Foo::foo<int (*)()>(this={{.*}}, arg=({{.*}}`(anonymous namespace)::anon_bar() at {{.*}}))
c
# NAME_WITH_ARGS: frame void Foo::operator<<<1>(this={{.*}}, (null)=0)
c
-# NAME_WITH_ARGS: frame Foo::returns_func_ptr<int>(this={{.*}}, (null)={{.*}})
+# NAME_WITH_ARGS: frame detail::Quux<double> (* (*Foo::returns_func_ptr<int>(this={{.*}}, (null)={{.*}}))(int))(float) const
c
# NAME_WITH_ARGS: frame inlined_foo(str="bar")
q
More information about the lldb-commits
mailing list