Skip to content

Commit d77cf28

Browse files
committed
[lldb][Format] Only display inlined frame name in backtraces if available
1 parent a45b133 commit d77cf28

File tree

8 files changed

+208
-89
lines changed

8 files changed

+208
-89
lines changed

lldb/include/lldb/Symbol/SymbolContext.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,13 @@ class SymbolContext {
307307
SymbolContext &next_frame_sc,
308308
Address &inlined_frame_addr) const;
309309

310+
/// If available, will return the function name according to the specified
311+
/// mangling preference. If this object represents an inlined function,
312+
/// returns the name of the inlined function. Returns nullptr if no function
313+
/// name could be determined.
314+
const char *GetPossiblyInlinedFunctionName(
315+
Mangled::NamePreference mangling_preference) const;
316+
310317
// Member variables
311318
lldb::TargetSP target_sp; ///< The Target for a given query
312319
lldb::ModuleSP module_sp; ///< The Module for a given query

lldb/source/Core/FormatEntity.cpp

Lines changed: 24 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,19 +1147,6 @@ static void PrettyPrintFunctionNameWithArgs(Stream &out_stream,
11471147
out_stream.PutChar(')');
11481148
}
11491149

1150-
static void FormatInlinedBlock(Stream &out_stream, Block *block) {
1151-
if (!block)
1152-
return;
1153-
Block *inline_block = block->GetContainingInlinedBlock();
1154-
if (inline_block) {
1155-
if (const InlineFunctionInfo *inline_info =
1156-
inline_block->GetInlinedFunctionInfo()) {
1157-
out_stream.PutCString(" [inlined] ");
1158-
inline_info->GetName().Dump(&out_stream);
1159-
}
1160-
}
1161-
}
1162-
11631150
static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
11641151
assert(sc.function);
11651152

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

1173-
static char const *GetInlinedFunctionName(const SymbolContext &sc) {
1174-
if (!sc.block)
1175-
return nullptr;
1176-
1177-
const Block *inline_block = sc.block->GetContainingInlinedBlock();
1178-
if (!inline_block)
1179-
return nullptr;
1180-
1181-
const InlineFunctionInfo *inline_info =
1182-
inline_block->GetInlinedFunctionInfo();
1183-
if (!inline_info)
1184-
return nullptr;
1185-
1186-
return inline_info->GetName().AsCString(nullptr);
1187-
}
1188-
11891160
static bool PrintFunctionNameWithArgs(Stream &s,
11901161
const ExecutionContext *exe_ctx,
11911162
const SymbolContext &sc) {
@@ -1194,16 +1165,11 @@ static bool PrintFunctionNameWithArgs(Stream &s,
11941165
ExecutionContextScope *exe_scope =
11951166
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
11961167

1197-
const char *cstr = sc.function->GetName().AsCString(nullptr);
1168+
const char *cstr =
1169+
sc.GetPossiblyInlinedFunctionName(Mangled::ePreferDemangled);
11981170
if (!cstr)
11991171
return false;
12001172

1201-
if (const char *inlined_name = GetInlinedFunctionName(sc)) {
1202-
s.PutCString(cstr);
1203-
s.PutCString(" [inlined] ");
1204-
cstr = inlined_name;
1205-
}
1206-
12071173
VariableList args;
12081174
if (auto variable_list_sp = GetFunctionVariableList(sc))
12091175
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
@@ -1724,21 +1690,17 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
17241690
if (language_plugin_handled) {
17251691
s << ss.GetString();
17261692
return true;
1727-
} else {
1728-
const char *name = nullptr;
1729-
if (sc->function)
1730-
name = sc->function->GetName().AsCString(nullptr);
1731-
else if (sc->symbol)
1732-
name = sc->symbol->GetName().AsCString(nullptr);
1733-
1734-
if (name) {
1735-
s.PutCString(name);
1736-
FormatInlinedBlock(s, sc->block);
1737-
return true;
1738-
}
17391693
}
1694+
1695+
const char *name = sc->GetPossiblyInlinedFunctionName(
1696+
Mangled::NamePreference::ePreferDemangled);
1697+
if (!name)
1698+
return false;
1699+
1700+
s.PutCString(name);
1701+
1702+
return true;
17401703
}
1741-
return false;
17421704

17431705
case Entry::Type::FunctionNameNoArgs: {
17441706
if (!sc)
@@ -1760,20 +1722,17 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
17601722
if (language_plugin_handled) {
17611723
s << ss.GetString();
17621724
return true;
1763-
} else {
1764-
ConstString name;
1765-
if (sc->function)
1766-
name = sc->function->GetNameNoArguments();
1767-
else if (sc->symbol)
1768-
name = sc->symbol->GetNameNoArguments();
1769-
if (name) {
1770-
s.PutCString(name.GetCString());
1771-
FormatInlinedBlock(s, sc->block);
1772-
return true;
1773-
}
17741725
}
1726+
1727+
const char *name = sc->GetPossiblyInlinedFunctionName(
1728+
Mangled::NamePreference::ePreferDemangledWithoutArguments);
1729+
if (!name)
1730+
return false;
1731+
1732+
s.PutCString(name);
1733+
1734+
return true;
17751735
}
1776-
return false;
17771736

17781737
case Entry::Type::FunctionNameWithArgs: {
17791738
if (!sc)
@@ -1814,19 +1773,13 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
18141773
if (!sc)
18151774
return false;
18161775

1817-
const char *name = nullptr;
1818-
if (sc->symbol)
1819-
name =
1820-
sc->symbol->GetMangled().GetName(Mangled::ePreferMangled).AsCString();
1821-
else if (sc->function)
1822-
name = sc->function->GetMangled()
1823-
.GetName(Mangled::ePreferMangled)
1824-
.AsCString();
1825-
1776+
const char *name = sc->GetPossiblyInlinedFunctionName(
1777+
Mangled::NamePreference::ePreferMangled);
18261778
if (!name)
18271779
return false;
1780+
18281781
s.PutCString(name);
1829-
FormatInlinedBlock(s, sc->block);
1782+
18301783
return true;
18311784
}
18321785
case Entry::Type::FunctionAddrOffset:

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,142 @@ static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
208208
return true;
209209
}
210210

211+
static std::optional<llvm::StringRef> GetDemangledBasename(Function &function) {
212+
auto demangled_name = function.GetName().GetStringRef();
213+
if (demangled_name.empty())
214+
return std::nullopt;
215+
216+
const std::optional<DemangledNameInfo> &info =
217+
function.GetMangled().GetDemangledInfo();
218+
if (!info)
219+
return std::nullopt;
220+
221+
// Function without a basename is nonsense.
222+
if (!info->hasBasename())
223+
return std::nullopt;
224+
225+
assert(info->BasenameRange.first < demangled_name.size());
226+
assert(info->BasenameRange.second < demangled_name.size());
227+
228+
return demangled_name.substr(info->BasenameRange.first,
229+
info->BasenameRange.second -
230+
info->BasenameRange.first);
231+
}
232+
233+
static std::optional<llvm::StringRef>
234+
GetDemangledTemplateArguments(Function &function) {
235+
auto demangled_name = function.GetName().GetStringRef();
236+
if (demangled_name.empty())
237+
return std::nullopt;
238+
239+
const std::optional<DemangledNameInfo> &info =
240+
function.GetMangled().GetDemangledInfo();
241+
if (!info)
242+
return std::nullopt;
243+
244+
// Function without a basename is nonsense.
245+
if (!info->hasBasename())
246+
return std::nullopt;
247+
248+
assert(info->BasenameRange.second < demangled_name.size());
249+
assert(info->ArgumentsRange.first < demangled_name.size());
250+
assert(info->ArgumentsRange.first >= info->BasenameRange.second);
251+
252+
return demangled_name.substr(info->BasenameRange.second,
253+
info->ArgumentsRange.first -
254+
info->BasenameRange.second);
255+
}
256+
257+
static std::optional<llvm::StringRef>
258+
GetDemangledReturnTypeLHS(Function &function) {
259+
auto demangled_name = function.GetName().GetStringRef();
260+
if (demangled_name.empty())
261+
return std::nullopt;
262+
263+
const std::optional<DemangledNameInfo> &info =
264+
function.GetMangled().GetDemangledInfo();
265+
if (!info)
266+
return std::nullopt;
267+
268+
// Function without a basename is nonsense.
269+
if (!info->hasBasename())
270+
return std::nullopt;
271+
272+
assert(info->ScopeRange.first < demangled_name.size());
273+
274+
return demangled_name.substr(0, info->ScopeRange.first);
275+
}
276+
277+
static std::optional<llvm::StringRef>
278+
GetDemangledFunctionQualifiers(Function &function) {
279+
auto demangled_name = function.GetName().GetStringRef();
280+
if (demangled_name.empty())
281+
return std::nullopt;
282+
283+
const std::optional<DemangledNameInfo> &info =
284+
function.GetMangled().GetDemangledInfo();
285+
if (!info)
286+
return std::nullopt;
287+
288+
// Function without a basename is nonsense.
289+
if (!info->hasBasename())
290+
return std::nullopt;
291+
292+
assert(info->QualifiersRange.first <= demangled_name.size());
293+
assert(info->QualifiersRange.second <= demangled_name.size());
294+
assert(info->QualifiersRange.second >= info->QualifiersRange.first);
295+
296+
return demangled_name.substr(info->QualifiersRange.first,
297+
info->QualifiersRange.second -
298+
info->QualifiersRange.first);
299+
}
300+
301+
static std::optional<llvm::StringRef>
302+
GetDemangledReturnTypeRHS(Function &function) {
303+
auto demangled_name = function.GetName().GetStringRef();
304+
if (demangled_name.empty())
305+
return std::nullopt;
306+
307+
const std::optional<DemangledNameInfo> &info =
308+
function.GetMangled().GetDemangledInfo();
309+
if (!info)
310+
return std::nullopt;
311+
312+
// Function without a basename is nonsense.
313+
if (!info->hasBasename())
314+
return std::nullopt;
315+
316+
assert(info->QualifiersRange.first <= demangled_name.size());
317+
assert(info->ArgumentsRange.second <= demangled_name.size());
318+
assert(info->QualifiersRange.first >= info->ArgumentsRange.second);
319+
320+
return demangled_name.substr(info->ArgumentsRange.second,
321+
info->QualifiersRange.first -
322+
info->ArgumentsRange.second);
323+
}
324+
325+
static std::optional<llvm::StringRef> GetDemangledScope(Function &function) {
326+
auto demangled_name = function.GetName().GetStringRef();
327+
if (demangled_name.empty())
328+
return std::nullopt;
329+
330+
const std::optional<DemangledNameInfo> &info =
331+
function.GetMangled().GetDemangledInfo();
332+
if (!info)
333+
return std::nullopt;
334+
335+
// Function without a basename is nonsense.
336+
if (!info->hasBasename())
337+
return std::nullopt;
338+
339+
assert(info->ScopeRange.first < demangled_name.size());
340+
assert(info->ScopeRange.second < demangled_name.size());
341+
assert(info->ScopeRange.second >= info->ScopeRange.first);
342+
343+
return demangled_name.substr(
344+
info->ScopeRange.first, info->ScopeRange.second - info->ScopeRange.first);
345+
}
346+
211347
bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
212348
// This method tries to parse simple method definitions which are presumably
213349
// most comman in user programs. Definitions that can be parsed by this
@@ -1731,16 +1867,11 @@ static bool PrintFunctionNameWithArgs(Stream &s,
17311867
ExecutionContextScope *exe_scope =
17321868
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
17331869

1734-
const char *cstr = sc.function->GetName().AsCString(nullptr);
1870+
const char *cstr = sc.GetPossiblyInlinedFunctionName(
1871+
Mangled::NamePreference::ePreferDemangled);
17351872
if (!cstr)
17361873
return false;
17371874

1738-
if (const char *inlined_name = GetInlinedFunctionName(sc)) {
1739-
s.PutCString(cstr);
1740-
s.PutCString(" [inlined] ");
1741-
cstr = inlined_name;
1742-
}
1743-
17441875
VariableList args;
17451876
if (auto variable_list_sp = GetFunctionVariableList(sc))
17461877
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,

lldb/source/Symbol/SymbolContext.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,36 @@ const Symbol *SymbolContext::FindBestGlobalDataSymbol(ConstString name,
872872
return nullptr; // no error; we just didn't find anything
873873
}
874874

875+
char const *SymbolContext::GetPossiblyInlinedFunctionName(
876+
Mangled::NamePreference mangling_preference) const {
877+
const char *name = nullptr;
878+
if (function)
879+
name = function->GetMangled().GetName(mangling_preference).AsCString();
880+
else if (symbol)
881+
name = symbol->GetMangled().GetName(mangling_preference).AsCString();
882+
883+
if (!block)
884+
return name;
885+
886+
const Block *inline_block = block->GetContainingInlinedBlock();
887+
if (!inline_block)
888+
return name;
889+
890+
const InlineFunctionInfo *inline_info =
891+
inline_block->GetInlinedFunctionInfo();
892+
if (!inline_info)
893+
return name;
894+
895+
// If we do have an inlined frame name, return that.
896+
if (char const *inline_name =
897+
inline_info->GetMangled().GetName(mangling_preference).AsCString())
898+
return inline_name;
899+
900+
// Sometimes an inline frame may not have mangling information,
901+
// but does have a valid name.
902+
return inline_info->GetName().AsCString();
903+
}
904+
875905
//
876906
// SymbolContextSpecifier
877907
//

lldb/test/API/functionalities/param_entry_vals/basic_entry_values/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ __attribute__((noinline)) void func6(int &sink, int x) {
7070
__attribute__((noinline)) void func7(int &sink, int x) {
7171
//% self.filecheck("bt", "main.cpp", "-check-prefix=FUNC7-BT")
7272
// FUNC7-BT: func7
73-
// FUNC7-BT-NEXT: [inlined] func8_inlined
74-
// FUNC7-BT-NEXT: [inlined] func9_inlined
73+
// FUNC7-BT-NEXT: func8_inlined
74+
// FUNC7-BT-NEXT: func9_inlined
7575
// FUNC7-BT-NEXT: func10
7676
use<int &, int>(sink, x);
7777
use<int &, int>(dummy, 0);

lldb/test/API/functionalities/tail_call_frames/inlining_and_tail_calls/main.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ volatile int x;
33
void __attribute__((noinline)) tail_call_sink() {
44
x++; //% self.filecheck("bt", "main.cpp", "-check-prefix=TAIL-CALL-SINK")
55
// TAIL-CALL-SINK: frame #0: 0x{{[0-9a-f]+}} a.out`tail_call_sink() at main.cpp:[[@LINE-1]]:4
6-
// TAIL-CALL-SINK-NEXT: func3{{.*}} [artificial]
6+
// TAIL-CALL-SINK-NEXT: inlinable_function_which_tail_calls() at main.cpp{{.*}} [artificial]
77
// TAIL-CALL-SINK-NEXT: main{{.*}}
8-
9-
// TODO: The backtrace should include inlinable_function_which_tail_calls.
108
}
119

1210
void __attribute__((always_inline)) inlinable_function_which_tail_calls() {
@@ -19,7 +17,7 @@ void __attribute__((noinline)) func3() {
1917

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

lldb/test/Shell/Recognizer/verbose_trap-in-stl-max-depth.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ run
1212
frame recognizer info 0
1313
# CHECK: frame 0 is recognized by Verbose Trap StackFrame Recognizer
1414
frame info
15-
# CHECK: frame #0: {{.*}}`std::recursively_aborts(int) {{.*}} at verbose_trap-in-stl-max-depth.cpp
15+
# CHECK: frame #0: {{.*}}`__clang_trap_msg$Error$max depth at verbose_trap-in-stl-max-depth.cpp
1616
q

0 commit comments

Comments
 (0)