-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[lldb][Format] Make function name frame-format variables work without debug-info #137408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lldb Author: Michael Buch (Michael137) ChangesThis patch makes the frame-format variables introduced in #131836 also work when no debug-info is available. Previously, we assumed For the function arguments case I added a fallback that will just print the arguments we get from the demangler (which is what LLDB does for stacktraces with no debug-info anyway). Ideally we'd have a separate
I.e., when we can't format the arguments, print the ones from the demangler. But we currently don't have the Full diff: https://github.com/llvm/llvm-project/pull/137408.diff 8 Files Affected:
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index e352d07fe487d..4ac50e2d30f3c 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -1809,11 +1809,12 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
case Entry::Type::FunctionReturnRight:
case Entry::Type::FunctionReturnLeft:
case Entry::Type::FunctionQualifiers: {
- if (!sc->function)
- return false;
+ Language *language_plugin = nullptr;
+ if (sc->function)
+ language_plugin = Language::FindPlugin(sc->function->GetLanguage());
+ else if (sc->symbol)
+ language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
- Language *language_plugin =
- Language::FindPlugin(sc->function->GetLanguage());
if (!language_plugin)
return false;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 283e867d53bb7..ab8e9883868ce 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -381,6 +381,34 @@ GetDemangledScope(const SymbolContext &sc) {
return demangled_name.slice(info->ScopeRange.first, info->ScopeRange.second);
}
+static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
+ assert(sc.symbol);
+
+ Mangled mangled = sc.GetPossiblyInlinedFunctionName();
+ if (!mangled)
+ return false;
+
+ auto demangled_name = mangled.GetDemangledName().GetStringRef();
+ if (demangled_name.empty())
+ return false;
+
+ const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
+ if (!info)
+ return false;
+
+ // Function without a basename is nonsense.
+ if (!info->hasBasename())
+ return false;
+
+ if (info->ArgumentsRange.second < info->ArgumentsRange.first)
+ return false;
+
+ s << demangled_name.slice(info->ArgumentsRange.first,
+ info->ArgumentsRange.second);
+
+ return true;
+}
+
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
@@ -1890,8 +1918,6 @@ bool CPlusPlusLanguage::GetFunctionDisplayName(
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);
@@ -1925,6 +1951,14 @@ bool CPlusPlusLanguage::HandleFrameFormatVariable(
}
case FormatEntity::Entry::Type::FunctionFormattedArguments: {
+ // This ensures we print the arguments even when no debug-info is available.
+ //
+ // FIXME: we should have a Entry::Type::FunctionArguments and
+ // use it in the plugin.cplusplus.display.function-name-format
+ // once we have a "fallback operator" in the frame-format language.
+ if (!sc.function && sc.symbol)
+ return PrintDemangledArgumentList(s, sc);
+
VariableList args;
if (auto variable_list_sp = GetFunctionVariableList(sc))
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
index 249a5fac5b55e..35d443d872c7d 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionBasename.test
@@ -1,10 +1,14 @@
# Test the ${function.basename} frame-format variable.
# RUN: split-file %s %t
-# RUN: %build %t/main.cpp -o %t.out
+# RUN: %clang_host -g %t/main.cpp -o %t.out
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
# RUN: | FileCheck %s
#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
+# RUN: | FileCheck %s
+
#--- main.cpp
namespace ns {
template<typename T>
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
index 5554830d3a247..46fb518158ce2 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionFormattedArguments.test
@@ -1,9 +1,13 @@
# Test the ${function.formatted-arguments} frame-format variable.
# RUN: split-file %s %t
-# RUN: %build %t/main.cpp -o %t.out
+# RUN: %clang_host -g %t/main.cpp -o %t.out
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
# RUN: | FileCheck %s
+#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-NODEBUG
#--- main.cpp
struct Foo {
@@ -40,3 +44,8 @@ bt
# 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={{.*}})'
+
+# CHECK-NODEBUG: custom-frame '()'
+# CHECK-NODEBUG: custom-frame '()'
+# CHECK-NODEBUG: custom-frame '(int, int)'
+# CHECK-NODEBUG: custom-frame '(char const*, void (*)(int, int))'
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
index 95a3be3811d85..ad7ea65d0a261 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionQualifiers.test
@@ -1,9 +1,13 @@
# Test the ${function.qualifiers} frame-format variable.
# RUN: split-file %s %t
-# RUN: %build %t/main.cpp -o %t.out
+# RUN: %clang_host -g %t/main.cpp -o %t.out
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
# RUN: | FileCheck %s
+#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
+# RUN: | FileCheck %s
#--- main.cpp
struct Foo {
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
index a5e49a1054c86..dd4cc68817712 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionReturn.test
@@ -2,9 +2,13 @@
# frame-format variables.
# RUN: split-file %s %t
-# RUN: %build %t/main.cpp -o %t.out
+# RUN: %clang_host -g %t/main.cpp -o %t.out
# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
# RUN: | FileCheck %s
+#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
+# RUN: | FileCheck %s
#--- main.cpp
namespace ns::ns2 {
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
index 28f0ab7ca39e3..a1d4cc01054db 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionScope.test
@@ -1,9 +1,12 @@
# 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: %clang_host -g %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN: | FileCheck %s
+#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
# RUN: | FileCheck %s
#--- main.cpp
diff --git a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
index 396dd29dfd02c..384ba0adc4ce9 100644
--- a/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
+++ b/lldb/test/Shell/Settings/TestFrameFormatFunctionTemplateArguments.test
@@ -1,8 +1,12 @@
# 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: %clang_host -g %t/main.cpp -o %t.out
+# RUN: %lldb -x -b -s %t/commands.input %t.out -o exit 2>&1 \
+# RUN: | FileCheck %s
+#
+# RUN: %clang_host -O0 %t/main.cpp -o %t-nodebug.out
+# RUN: %lldb -x -b -s %t/commands.input %t-nodebug.out -o exit 2>&1 \
# RUN: | FileCheck %s
#--- main.cpp
|
That sounds useful! |
@JDevlieghere was working on this separately. Not sure what syntax was settled on |
63a74fe
to
db417e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having separate variables for these makes sense since they are kind of showing completely different information (demangler will show you the types, while the formatter will show you names and values), but I think that a single variable makes sense as well ("just show me something about the arguments").
As for the syntax for alternatives, I was suggesting (privately, I think) to use :-
, as that what bash uses for conditional expansion (and the formatter language feels more like bash than C). However, I am having some doubts about that now since the way you're thinking of using it is not exactly bash-like (the :-
thingy only works for a single variable, but I think you want to mostly use it on the block level (and bash doesn't have blocks))
Would the syntax be |
So, the bash syntax requires another level of
If it were to be used only on a single variable, then I think this syntax is great (including the nested expansion, since you also might want to replace the expansion with a constant string). For blocks (which I think makes sense), I'm less sure. There's also a question of how to parse that (i.e., how to print a literal |
I think this change broke lldb/test/Shell/Unwind/split-machine-functions.test. I can reproduce locally at HEAD with The test binary has a symbol named
but now it gets
|
FWIW, I have a little prototype that uses |
Ah thanks for the ping. I can see it's failing on the x86 Linux LLDB ubuntu Yea this case is kind of weird because it's a non-standard mangling extension where the |
… without debug-info" (#137757) Reverts #137408 This change broke `lldb/test/Shell/Unwind/split-machine-functions.test`. The test binary has a symbol named `_Z3foov.cold` and the test expects the backtrace to print the name of the cold part of the function like this: ``` # SPLIT: frame #1: {{.*}}`foo() (.cold) + ``` but now it gets ``` frame #1: 0x000055555555514f split-machine-functions.test.tmp`foo() + 12 ```
Proposed fix: #137763 |
… without debug-info" (llvm#137757) Reverts llvm#137408 This change broke `lldb/test/Shell/Unwind/split-machine-functions.test`. The test binary has a symbol named `_Z3foov.cold` and the test expects the backtrace to print the name of the cold part of the function like this: ``` # SPLIT: frame llvm#1: {{.*}}`foo() (.cold) + ``` but now it gets ``` frame llvm#1: 0x000055555555514f split-machine-functions.test.tmp`foo() + 12 ```
This patch makes the frame-format variables introduced in #131836 also work when no debug-info is available. Previously, we assumed
sc.function
was available, but without debug-info we might only havesc.symbol
. We don't really need thesc.function
apart from when formatting arguments.For the function arguments case I added a fallback that will just print the arguments we get from the demangler (which is what LLDB does for stacktraces with no debug-info anyway). Ideally we'd have a separate
FormatEntity::Entry::Type::FunctionArguments
that will just print the arguments from the demangler and have something like the following in theplugin.cplusplus.display.function-name-format
:I.e., when we can't format the arguments, print the ones from the demangler. But we currently don't have the
||
operator in the frame-format language yet.