From f4ede08c61cba631de204398a91aa59bac9d5db9 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 18 Jan 2024 11:06:57 -0500 Subject: [PATCH] [lldb][Format] Fix missing inlined function names in frame formatting. (#78494) This fixes missing inlined function names when formatting frame and the `Block` in `SymbolContext` is a lexical block (e.g. `DW_TAG_lexical_block` in Dwarf). --- lldb/source/Core/FormatEntity.cpp | 38 ++++++------- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 2 +- lldb/test/Shell/Settings/Inputs/names.cpp | 8 ++- .../Shell/Settings/TestFrameFormatName.test | 55 +++++++++++++++++++ .../Settings/TestFrameFormatNameWithArgs.test | 26 --------- 5 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 lldb/test/Shell/Settings/TestFrameFormatName.test delete mode 100644 lldb/test/Shell/Settings/TestFrameFormatNameWithArgs.test diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index 94986457552d94..3c665c2eb2133b 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -1093,6 +1093,19 @@ static void PrettyPrintFunctionNameWithArgs(Stream &out_stream, out_stream.PutChar(')'); } +static void FormatInlinedBlock(Stream &out_stream, Block *block) { + if (!block) + return; + Block *inline_block = block->GetContainingInlinedBlock(); + if (inline_block) { + if (const InlineFunctionInfo *inline_info = + inline_block->GetInlinedFunctionInfo()) { + out_stream.PutCString(" [inlined] "); + inline_info->GetName().Dump(&out_stream); + } + } +} + bool FormatEntity::FormatStringRef(const llvm::StringRef &format_str, Stream &s, const SymbolContext *sc, const ExecutionContext *exe_ctx, @@ -1592,18 +1605,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, if (name) { s.PutCString(name); - - if (sc->block) { - Block *inline_block = sc->block->GetContainingInlinedBlock(); - if (inline_block) { - const InlineFunctionInfo *inline_info = - sc->block->GetInlinedFunctionInfo(); - if (inline_info) { - s.PutCString(" [inlined] "); - inline_info->GetName().Dump(&s); - } - } - } + FormatInlinedBlock(s, sc->block); return true; } } @@ -1638,6 +1640,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, name = sc->symbol->GetNameNoArguments(); if (name) { s.PutCString(name.GetCString()); + FormatInlinedBlock(s, sc->block); return true; } } @@ -1678,7 +1681,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, if (inline_block) { get_function_vars = false; - inline_info = sc->block->GetInlinedFunctionInfo(); + inline_info = inline_block->GetInlinedFunctionInfo(); if (inline_info) variable_list_sp = inline_block->GetBlockVariableList(true); } @@ -1733,14 +1736,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, if (!name) return false; s.PutCString(name); - - if (sc->block && sc->block->GetContainingInlinedBlock()) { - if (const InlineFunctionInfo *inline_info = - sc->block->GetInlinedFunctionInfo()) { - s.PutCString(" [inlined] "); - inline_info->GetName().Dump(&s); - } - } + FormatInlinedBlock(s, sc->block); return true; } case Entry::Type::FunctionAddrOffset: diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 7131ccb9d05eca..21c73e6361904e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1646,7 +1646,7 @@ bool CPlusPlusLanguage::GetFunctionDisplayName( if (inline_block) { get_function_vars = false; - inline_info = sc->block->GetInlinedFunctionInfo(); + inline_info = inline_block->GetInlinedFunctionInfo(); if (inline_info) variable_list_sp = inline_block->GetBlockVariableList(true); } diff --git a/lldb/test/Shell/Settings/Inputs/names.cpp b/lldb/test/Shell/Settings/Inputs/names.cpp index cf6982abb8f354..79ff93be6b76ed 100644 --- a/lldb/test/Shell/Settings/Inputs/names.cpp +++ b/lldb/test/Shell/Settings/Inputs/names.cpp @@ -26,6 +26,12 @@ int anon_bar() { return 1; } auto anon_lambda = [] {}; } // namespace +__attribute__((always_inline)) int inlined_foo(const char *str) { + if (bool b = bar()) + return 1; + return 2; +} + int main() { ns::foo(bar); ns::foo("bar"); @@ -37,6 +43,6 @@ int main() { f.foo(anon_bar); f.operator<< <(2 > 1)>(0); f.returns_func_ptr(detail::Quux{}); - + inlined_foo("bar"); return 0; } diff --git a/lldb/test/Shell/Settings/TestFrameFormatName.test b/lldb/test/Shell/Settings/TestFrameFormatName.test new file mode 100644 index 00000000000000..caa3242527c6ef --- /dev/null +++ b/lldb/test/Shell/Settings/TestFrameFormatName.test @@ -0,0 +1,55 @@ +# UNSUPPORTED: system-windows +# Test different name formats. + +# RUN: %build %S/Inputs/names.cpp --std c++17 -o %t.out +# RUN: split-file %s %t + +#--- name_with_args.input +# RUN: %lldb -b -s %t/name_with_args.input %t.out | FileCheck %s --check-prefix=NAME_WITH_ARGS +settings set -f frame-format "frame ${function.name-with-args}\n" +break set -n foo +break set -n operator<< +break set -n returns_func_ptr +break set -n inlined_foo +run +# NAME_WITH_ARGS: frame int ns::foo(t={{.*}}) +c +# NAME_WITH_ARGS: frame int ns::foo(str="bar") +c +# NAME_WITH_ARGS: frame int ns::foo<(anonymous namespace)::$_0>(t=(anonymous namespace)::(unnamed class) @ {{.*}}) +c +# NAME_WITH_ARGS: frame int ns::foo(t=({{.*}}`(anonymous namespace)::anon_bar() at {{.*}})) +c +# NAME_WITH_ARGS: frame int ns::foo(str="method") +c +# NAME_WITH_ARGS: frame ns::returns_func_ptr((null)={{.*}}) +c +# NAME_WITH_ARGS: frame void Foo::foo(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(this={{.*}}, (null)={{.*}}) +c +# NAME_WITH_ARGS: frame main [inlined] inlined_foo(str="bar") +q + +#--- name.input +# RUN: %lldb -b -s %t/name.input %t.out | FileCheck %s --check-prefix=NAME +settings set -f frame-format "frame ${function.name}\n" +break set -n inlined_foo +run +# NAME: frame main [inlined] inlined_foo(char const*) + +#--- name_without_args.input +# RUN: %lldb -b -s %t/name_without_args.input %t.out | FileCheck %s --check-prefix=NAME_WITHOUT_ARGS +settings set -f frame-format "frame ${function.name-without-args}\n" +break set -n inlined_foo +run +# NAME_WITHOUT_ARGS: frame main [inlined] inlined_foo(char const*) + +#--- mangled_name.input +# RUN: %lldb -b -s %t/mangled_name.input %t.out | FileCheck %s --check-prefix=MANGLED_NAME +settings set -f frame-format "frame ${function.mangled-name}\n" +break set -n inlined_foo +run +# MANGLED_NAME: frame main [inlined] inlined_foo(char const*) diff --git a/lldb/test/Shell/Settings/TestFrameFormatNameWithArgs.test b/lldb/test/Shell/Settings/TestFrameFormatNameWithArgs.test deleted file mode 100644 index eeb46cfd6bf9d6..00000000000000 --- a/lldb/test/Shell/Settings/TestFrameFormatNameWithArgs.test +++ /dev/null @@ -1,26 +0,0 @@ -# UNSUPPORTED: system-windows -# RUN: %build %S/Inputs/names.cpp --std c++17 -o %t.out -# RUN: %lldb -b -s %s %t.out | FileCheck %s -settings set -f frame-format "frame ${function.name-with-args}\n" -break set -n foo -break set -n operator<< -break set -n returns_func_ptr -run -# CHECK: frame int ns::foo(t={{.*}}) -c -# CHECK: frame int ns::foo(str="bar") -c -# CHECK: frame int ns::foo<(anonymous namespace)::$_0>(t=(anonymous namespace)::(unnamed class) @ {{.*}}) -c -# CHECK: frame int ns::foo(t=({{.*}}`(anonymous namespace)::anon_bar() at {{.*}})) -c -# CHECK: frame int ns::foo(str="method") -c -# CHECK: frame ns::returns_func_ptr((null)={{.*}}) -c -# CHECK: frame void Foo::foo(this={{.*}}, arg=({{.*}}`(anonymous namespace)::anon_bar() at {{.*}})) -c -# CHECK: frame void Foo::operator<<<1>(this={{.*}}, (null)=0) -c -# CHECK: frame Foo::returns_func_ptr(this={{.*}}, (null)={{.*}}) -q