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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits