Skip to content

[lldb][Format] Display only the inlined frame name in backtraces if available #135343

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

Merged
merged 9 commits into from
Apr 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lldb/include/lldb/Symbol/SymbolContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ class SymbolContext {
SymbolContext &next_frame_sc,
Address &inlined_frame_addr) const;

/// If available, will return the function name according to the specified
/// 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;

// Member variables
lldb::TargetSP target_sp; ///< The Target for a given query
lldb::ModuleSP module_sp; ///< The Module for a given query
Expand Down
95 changes: 24 additions & 71 deletions lldb/source/Core/FormatEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1147,19 +1147,6 @@ 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);
}
}
}

static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
assert(sc.function);

Expand All @@ -1170,22 +1157,6 @@ static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
return sc.function->GetBlock(true).GetBlockVariableList(true);
}

static char const *GetInlinedFunctionName(const SymbolContext &sc) {
if (!sc.block)
return nullptr;

const Block *inline_block = sc.block->GetContainingInlinedBlock();
if (!inline_block)
return nullptr;

const InlineFunctionInfo *inline_info =
inline_block->GetInlinedFunctionInfo();
if (!inline_info)
return nullptr;

return inline_info->GetName().AsCString(nullptr);
}

static bool PrintFunctionNameWithArgs(Stream &s,
const ExecutionContext *exe_ctx,
const SymbolContext &sc) {
Expand All @@ -1194,16 +1165,11 @@ static bool PrintFunctionNameWithArgs(Stream &s,
ExecutionContextScope *exe_scope =
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;

const char *cstr = sc.function->GetName().AsCString(nullptr);
const char *cstr =
sc.GetPossiblyInlinedFunctionName(Mangled::ePreferDemangled);
if (!cstr)
return false;

if (const char *inlined_name = GetInlinedFunctionName(sc)) {
s.PutCString(cstr);
s.PutCString(" [inlined] ");
cstr = inlined_name;
}

VariableList args;
if (auto variable_list_sp = GetFunctionVariableList(sc))
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
Expand Down Expand Up @@ -1724,21 +1690,17 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
if (language_plugin_handled) {
s << ss.GetString();
return true;
} else {
const char *name = nullptr;
if (sc->function)
name = sc->function->GetName().AsCString(nullptr);
else if (sc->symbol)
name = sc->symbol->GetName().AsCString(nullptr);

if (name) {
s.PutCString(name);
FormatInlinedBlock(s, sc->block);
return true;
}
}

const char *name = sc->GetPossiblyInlinedFunctionName(
Mangled::NamePreference::ePreferDemangled);
if (!name)
return false;

s.PutCString(name);

return true;
}
return false;

case Entry::Type::FunctionNameNoArgs: {
if (!sc)
Expand All @@ -1760,20 +1722,17 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
if (language_plugin_handled) {
s << ss.GetString();
return true;
} else {
ConstString name;
if (sc->function)
name = sc->function->GetNameNoArguments();
else if (sc->symbol)
name = sc->symbol->GetNameNoArguments();
if (name) {
s.PutCString(name.GetCString());
FormatInlinedBlock(s, sc->block);
return true;
}
}

const char *name = sc->GetPossiblyInlinedFunctionName(
Mangled::NamePreference::ePreferDemangledWithoutArguments);
if (!name)
return false;

s.PutCString(name);

return true;
}
return false;

case Entry::Type::FunctionNameWithArgs: {
if (!sc)
Expand Down Expand Up @@ -1814,19 +1773,13 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
if (!sc)
return false;

const char *name = nullptr;
if (sc->symbol)
name =
sc->symbol->GetMangled().GetName(Mangled::ePreferMangled).AsCString();
else if (sc->function)
name = sc->function->GetMangled()
.GetName(Mangled::ePreferMangled)
.AsCString();

const char *name = sc->GetPossiblyInlinedFunctionName(
Mangled::NamePreference::ePreferMangled);
if (!name)
return false;

s.PutCString(name);
FormatInlinedBlock(s, sc->block);

return true;
}
case Entry::Type::FunctionAddrOffset:
Expand Down
25 changes: 2 additions & 23 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1707,22 +1707,6 @@ static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
return sc.function->GetBlock(true).GetBlockVariableList(true);
}

static char const *GetInlinedFunctionName(const SymbolContext &sc) {
if (!sc.block)
return nullptr;

const Block *inline_block = sc.block->GetContainingInlinedBlock();
if (!inline_block)
return nullptr;

const InlineFunctionInfo *inline_info =
inline_block->GetInlinedFunctionInfo();
if (!inline_info)
return nullptr;

return inline_info->GetName().AsCString(nullptr);
}

static bool PrintFunctionNameWithArgs(Stream &s,
const ExecutionContext *exe_ctx,
const SymbolContext &sc) {
Expand All @@ -1731,16 +1715,11 @@ static bool PrintFunctionNameWithArgs(Stream &s,
ExecutionContextScope *exe_scope =
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;

const char *cstr = sc.function->GetName().AsCString(nullptr);
const char *cstr = sc.GetPossiblyInlinedFunctionName(
Mangled::NamePreference::ePreferDemangled);
if (!cstr)
return false;

if (const char *inlined_name = GetInlinedFunctionName(sc)) {
s.PutCString(cstr);
s.PutCString(" [inlined] ");
cstr = inlined_name;
}

VariableList args;
if (auto variable_list_sp = GetFunctionVariableList(sc))
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
Expand Down
30 changes: 30 additions & 0 deletions lldb/source/Symbol/SymbolContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,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();

if (!block)
return name;

const Block *inline_block = block->GetContainingInlinedBlock();
if (!inline_block)
return name;

const InlineFunctionInfo *inline_info =
inline_block->GetInlinedFunctionInfo();
if (!inline_info)
return name;

// If we do have an inlined frame name, return that.
if (char const *inline_name =
inline_info->GetMangled().GetName(mangling_preference).AsCString())
return inline_name;

// Sometimes an inline frame may not have mangling information,
// but does have a valid name.
return inline_info->GetName().AsCString();
}

//
// SymbolContextSpecifier
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ __attribute__((noinline)) void func6(int &sink, int x) {
__attribute__((noinline)) void func7(int &sink, int x) {
//% self.filecheck("bt", "main.cpp", "-check-prefix=FUNC7-BT")
// FUNC7-BT: func7
// FUNC7-BT-NEXT: [inlined] func8_inlined
// FUNC7-BT-NEXT: [inlined] func9_inlined
// FUNC7-BT-NEXT: func8_inlined
// FUNC7-BT-NEXT: func9_inlined
// FUNC7-BT-NEXT: func10
use<int &, int>(sink, x);
use<int &, int>(dummy, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
volatile int x;

// clang-format off
void __attribute__((noinline)) tail_call_sink() {
x++; //% self.filecheck("bt", "main.cpp", "-check-prefix=TAIL-CALL-SINK")
// TAIL-CALL-SINK: frame #0: 0x{{[0-9a-f]+}} a.out`tail_call_sink() at main.cpp:[[@LINE-1]]:4
// TAIL-CALL-SINK-NEXT: func3{{.*}} [artificial]
// TAIL-CALL-SINK-NEXT: inlinable_function_which_tail_calls() at main.cpp{{.*}} [artificial]
// TAIL-CALL-SINK-NEXT: main{{.*}}

// TODO: The backtrace should include inlinable_function_which_tail_calls.
}
// clang-format on

void __attribute__((always_inline)) inlinable_function_which_tail_calls() {
tail_call_sink();
Expand All @@ -17,13 +17,15 @@ void __attribute__((noinline)) func3() {
inlinable_function_which_tail_calls();
}

// clang-format off
void __attribute__((always_inline)) inline_sink() {
x++; //% self.filecheck("bt", "main.cpp", "-check-prefix=INLINE-SINK")
// INLINE-SINK: frame #0: 0x{{[0-9a-f]+}} a.out`func2() [inlined] inline_sink() at main.cpp:[[@LINE-1]]:4
// INLINE-SINK: frame #0: 0x{{[0-9a-f]+}} a.out`inline_sink() at main.cpp:[[@LINE-1]]:4
// INLINE-SINK-NEXT: func2{{.*}}
// INLINE-SINK-NEXT: func1{{.*}} [artificial]
// INLINE-SINK-NEXT: main{{.*}}
}
// clang-format on

void __attribute__((noinline)) func2() { inline_sink(); /* inlined */ }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ run
frame recognizer info 0
# CHECK: frame 0 is recognized by Verbose Trap StackFrame Recognizer
frame info
# CHECK: frame #0: {{.*}}`std::recursively_aborts(int) {{.*}} at verbose_trap-in-stl-max-depth.cpp
# CHECK: frame #0: {{.*}}`__clang_trap_msg$Error$max depth at verbose_trap-in-stl-max-depth.cpp
q
8 changes: 4 additions & 4 deletions lldb/test/Shell/Settings/TestFrameFormatName.test
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,26 @@ c
c
# NAME_WITH_ARGS: frame Foo::returns_func_ptr<int>(this={{.*}}, (null)={{.*}})
c
# NAME_WITH_ARGS: frame main [inlined] inlined_foo(str="bar")
# NAME_WITH_ARGS: frame 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: frame 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*)
# NAME_WITHOUT_ARGS: frame inlined_foo

#--- 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*)
# MANGLED_NAME: frame _Z11inlined_fooPKc