Skip to content

Commit 057d8da

Browse files
Merge pull request #11068 from charles-zablit/charles-zablit/lldb/fix-cropped-swift-closures-in-backtraces
[lldb] fix cropped demangled names in Swift backtraces
2 parents 43985fc + 7a56965 commit 057d8da

File tree

9 files changed

+514
-423
lines changed

9 files changed

+514
-423
lines changed

lldb/source/Core/Mangled.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,21 @@ GetSwiftDemangledStr(ConstString m_mangled, const SymbolContext *sc,
168168
}
169169
auto [demangled, info] = SwiftLanguageRuntime::TrackedDemangleSymbolAsString(
170170
mangled_name, demangle_mode, sc);
171+
// TODO: The logic below should be in the NodePrinter.
171172
info.PrefixRange.second =
172173
std::min(info.BasenameRange.first, info.ArgumentsRange.first);
173174
info.SuffixRange.first =
174175
std::max(info.BasenameRange.second, info.ArgumentsRange.second);
175176
info.SuffixRange.second = demangled.length();
177+
if (info.hasBasename() && info.hasArguments()) {
178+
if (info.hasTemplateArguments() && info.TemplateArgumentsRange.first > 0) {
179+
info.NameQualifiersRange.second = std::min(
180+
info.ArgumentsRange.first, info.TemplateArgumentsRange.first);
181+
} else {
182+
info.NameQualifiersRange.second = info.ArgumentsRange.first;
183+
}
184+
info.NameQualifiersRange.first = info.BasenameRange.second;
185+
}
176186

177187
// Don't cache the demangled name if the function isn't available yet.
178188
// Only cache eFullName demangled functions to keep the cache consistent.

lldb/source/Plugins/Language/Swift/LanguageSwiftProperties.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ include "../../../../include/lldb/Core/PropertiesBase.td"
33
let Definition = "language_swift" in {
44
def FunctionNameFormat: Property<"function-name-format", "FormatEntity">,
55
Global,
6-
DefaultStringValue<"${function.prefix}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.formatted-arguments}${function.suffix}">,
6+
DefaultStringValue<"${function.prefix}${ansi.fg.yellow}${function.basename}${ansi.normal}${function.name-qualifiers}${function.template-arguments}${function.formatted-arguments}${function.suffix}">,
77
Desc<"Swift specific frame format string to use when displaying stack frame information for threads.">;
88
}

lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,13 +1722,7 @@ bool SwiftLanguage::GetFunctionDisplayName(
17221722
// No need to customize this.
17231723
return false;
17241724
case Language::FunctionNameRepresentation::eNameWithNoArgs: {
1725-
if (!sc.function)
1726-
return false;
1727-
if (sc.function->GetLanguage() != eLanguageTypeSwift)
1728-
return false;
1729-
std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString(
1730-
sc.function->GetMangled().GetMangledName().GetStringRef(),
1731-
SwiftLanguageRuntime::eSimplified, &sc, exe_ctx);
1725+
std::string display_name = GetDemangledFunctionName(sc, exe_ctx);
17321726
if (display_name.empty())
17331727
return false;
17341728
s << display_name;
@@ -1763,69 +1757,81 @@ bool SwiftLanguage::GetFunctionDisplayName(
17631757
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
17641758
args);
17651759

1760+
s << GetFunctionTemplateArguments(sc, exe_ctx);
17661761
s << GetFunctionDisplayArgs(sc, args, exe_ctx);
17671762
return true;
17681763
}
17691764
}
17701765
return false;
17711766
}
17721767

1773-
std::string SwiftLanguage::GetFunctionName(const SymbolContext &sc,
1774-
const ExecutionContext *exe_ctx) {
1768+
std::string
1769+
SwiftLanguage::GetDemangledFunctionName(const SymbolContext &sc,
1770+
const ExecutionContext *exe_ctx) {
17751771
if (!sc.function)
17761772
return {};
17771773
if (sc.function->GetLanguage() != eLanguageTypeSwift)
17781774
return {};
1779-
std::string name = SwiftLanguageRuntime::DemangleSymbolAsString(
1775+
return SwiftLanguageRuntime::DemangleSymbolAsString(
17801776
sc.GetPossiblyInlinedFunctionName().GetMangledName(),
17811777
SwiftLanguageRuntime::eSimplified, &sc, exe_ctx);
1782-
if (name.empty())
1778+
}
1779+
1780+
std::string SwiftLanguage::GetFunctionName(const SymbolContext &sc,
1781+
const ExecutionContext *exe_ctx) {
1782+
std::string demangled_name = GetDemangledFunctionName(sc, exe_ctx);
1783+
if (demangled_name.empty())
17831784
return {};
1784-
size_t open_paren = name.find('(');
1785-
size_t generic = name.find('<');
1785+
size_t open_paren = demangled_name.find('(');
1786+
size_t generic = demangled_name.find('<');
17861787
size_t name_end = std::min(open_paren, generic);
17871788
if (name_end == std::string::npos)
1788-
return name;
1789-
return name.substr(0, name_end);
1789+
return demangled_name;
1790+
return demangled_name.substr(0, name_end);
1791+
}
1792+
1793+
std::string
1794+
SwiftLanguage::GetFunctionTemplateArguments(const SymbolContext &sc,
1795+
const ExecutionContext *exe_ctx) {
1796+
std::string demangled_name = GetDemangledFunctionName(sc, exe_ctx);
1797+
if (demangled_name.empty())
1798+
return {};
1799+
size_t open_paren = demangled_name.find('(');
1800+
size_t generic_start = demangled_name.find('<');
1801+
if (generic_start == std::string::npos || generic_start > open_paren)
1802+
return {};
1803+
1804+
int generic_depth = 1;
1805+
size_t generic_end = generic_start + 1;
1806+
1807+
while (generic_end < demangled_name.size() && generic_depth > 0) {
1808+
if (demangled_name[generic_end] == '<')
1809+
generic_depth++;
1810+
else if (demangled_name[generic_end] == '>')
1811+
generic_depth--;
1812+
generic_end++;
1813+
}
1814+
1815+
if (generic_depth != 0)
1816+
return {};
1817+
1818+
return demangled_name.substr(generic_start, generic_end - generic_start);
17901819
}
17911820

17921821
std::string SwiftLanguage::GetFunctionDisplayArgs(
17931822
const SymbolContext &sc, VariableList &args,
17941823
const lldb_private::ExecutionContext *exe_ctx) {
17951824
ExecutionContextScope *exe_scope =
17961825
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL;
1797-
std::string name = SwiftLanguageRuntime::DemangleSymbolAsString(
1798-
sc.function->GetMangled().GetMangledName().GetStringRef(),
1799-
SwiftLanguageRuntime::eSimplified, &sc, exe_ctx);
1826+
std::string name = GetDemangledFunctionName(sc, exe_ctx);
18001827
lldb_private::StreamString s;
18011828
const char *cstr = name.data();
18021829
const char *open_paren = strchr(cstr, '(');
18031830
const char *close_paren = nullptr;
1804-
const char *generic = strchr(cstr, '<');
1805-
// If before the arguments list begins there is a template sign
1806-
// then scan to the end of the generic args before you try to find
1807-
// the arguments list.
1808-
const char *generic_start = generic;
1809-
if (generic && open_paren && generic < open_paren) {
1810-
int generic_depth = 1;
1811-
++generic;
1812-
for (; *generic && generic_depth > 0; generic++) {
1813-
if (*generic == '<')
1814-
generic_depth++;
1815-
if (*generic == '>')
1816-
generic_depth--;
1817-
}
1818-
if (*generic)
1819-
open_paren = strchr(generic, '(');
1820-
else
1821-
open_paren = nullptr;
1822-
}
18231831
if (open_paren) {
18241832
close_paren = strchr(open_paren, ')');
18251833
}
18261834

1827-
if (generic_start && generic_start < open_paren)
1828-
s.Write(generic_start, open_paren - generic_start);
18291835
s.PutChar('(');
18301836

18311837
const size_t num_args = args.GetSize();
@@ -1931,7 +1937,7 @@ GetAndValidateInfo(const SymbolContext &sc) {
19311937
// Function without a basename is nonsense.
19321938
if (!info->hasBasename())
19331939
return llvm::createStringError(
1934-
"DemangledInfo for '%s does not have basename range.",
1940+
"The demangled name for '%s does not have basename range.",
19351941
demangled_name.data());
19361942

19371943
return std::make_pair(demangled_name, *info);
@@ -1949,6 +1955,23 @@ GetDemangledBasename(const SymbolContext &sc) {
19491955
info.BasenameRange.second);
19501956
}
19511957

1958+
static llvm::Expected<llvm::StringRef>
1959+
GetDemangledNameQualifiers(const SymbolContext &sc) {
1960+
auto info_or_err = GetAndValidateInfo(sc);
1961+
if (!info_or_err)
1962+
return info_or_err.takeError();
1963+
1964+
auto [demangled_name, info] = *info_or_err;
1965+
1966+
if (!info.hasPrefix())
1967+
return llvm::createStringError(
1968+
"The demangled name for '%s does not have a name qualifiers range.",
1969+
demangled_name.data());
1970+
1971+
return demangled_name.slice(info.NameQualifiersRange.first,
1972+
info.NameQualifiersRange.second);
1973+
}
1974+
19521975
static llvm::Expected<llvm::StringRef>
19531976
GetDemangledFunctionPrefix(const SymbolContext &sc) {
19541977
auto info_or_err = GetAndValidateInfo(sc);
@@ -1959,7 +1982,7 @@ GetDemangledFunctionPrefix(const SymbolContext &sc) {
19591982

19601983
if (!info.hasPrefix())
19611984
return llvm::createStringError(
1962-
"DemangledInfo for '%s does not have suffix range.",
1985+
"The demangled name for '%s does not have a prefix range.",
19631986
demangled_name.data());
19641987

19651988
return demangled_name.slice(info.PrefixRange.first, info.PrefixRange.second);
@@ -1975,7 +1998,7 @@ GetDemangledFunctionSuffix(const SymbolContext &sc) {
19751998

19761999
if (!info.hasSuffix())
19772000
return llvm::createStringError(
1978-
"DemangledInfo for '%s does not have suffix range.",
2001+
"The demangled name for '%s does not have a suffix range.",
19792002
demangled_name.data());
19802003

19812004
return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second);
@@ -2030,6 +2053,24 @@ bool SwiftLanguage::HandleFrameFormatVariable(const SymbolContext &sc,
20302053

20312054
return true;
20322055
}
2056+
case FormatEntity::Entry::Type::FunctionNameQualifiers: {
2057+
auto qualifiers_or_err = GetDemangledNameQualifiers(sc);
2058+
if (!qualifiers_or_err) {
2059+
LLDB_LOG_ERROR(GetLog(LLDBLog::Language), qualifiers_or_err.takeError(),
2060+
"Failed to handle ${{function.name-qualifiers}} "
2061+
"frame-format variable: {0}");
2062+
return false;
2063+
}
2064+
2065+
s << *qualifiers_or_err;
2066+
2067+
return true;
2068+
}
2069+
case FormatEntity::Entry::Type::FunctionTemplateArguments: {
2070+
s << GetFunctionTemplateArguments(sc, exe_ctx);
2071+
2072+
return true;
2073+
}
20332074
case FormatEntity::Entry::Type::FunctionFormattedArguments: {
20342075
// This ensures we print the arguments even when no debug-info is available.
20352076
//
@@ -2038,9 +2079,7 @@ bool SwiftLanguage::HandleFrameFormatVariable(const SymbolContext &sc,
20382079
// once we have a "fallback operator" in the frame-format language.
20392080
if (!sc.function && sc.symbol)
20402081
return PrintDemangledArgumentList(s, sc);
2041-
std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString(
2042-
sc.function->GetMangled().GetMangledName().GetStringRef(),
2043-
SwiftLanguageRuntime::eSimplified, &sc, exe_ctx);
2082+
std::string display_name = GetDemangledFunctionName(sc, exe_ctx);
20442083
if (display_name.empty())
20452084
return false;
20462085

@@ -2080,7 +2119,6 @@ bool SwiftLanguage::HandleFrameFormatVariable(const SymbolContext &sc,
20802119
}
20812120

20822121
case FormatEntity::Entry::Type::FunctionScope:
2083-
case FormatEntity::Entry::Type::FunctionTemplateArguments:
20842122
case FormatEntity::Entry::Type::FunctionReturnRight:
20852123
case FormatEntity::Entry::Type::FunctionReturnLeft:
20862124
case FormatEntity::Entry::Type::FunctionQualifiers:

lldb/source/Plugins/Language/Swift/SwiftLanguage.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class SwiftLanguage : public Language {
6969
FunctionNameRepresentation representation,
7070
Stream &s) override;
7171

72+
std::string GetDemangledFunctionName(const SymbolContext &sc,
73+
const ExecutionContext *exe_ctx);
74+
7275
/// Returns the name of function up to the first generic or opening
7376
/// parenthesis.
7477
///
@@ -83,6 +86,9 @@ class SwiftLanguage : public Language {
8386
std::string GetFunctionName(const SymbolContext &sc,
8487
const ExecutionContext *exe_ctx);
8588

89+
std::string GetFunctionTemplateArguments(const SymbolContext &sc,
90+
const ExecutionContext *exe_ctx);
91+
8692
/// Returns the arguments of a function call with its generics if any.
8793
///
8894
/// Calling GetFunctionDisplayArgs on the following function call will return

lldb/source/Plugins/Language/Swift/SwiftMangled.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class TrackingNodePrinter : public NodePrinter {
3232
private:
3333
lldb_private::DemangledNameInfo info;
3434
std::optional<unsigned> parametersDepth;
35+
std::optional<unsigned> genericsSignatureDepth;
3536

3637
void startName() {
3738
if (!info.hasBasename())
@@ -43,6 +44,25 @@ class TrackingNodePrinter : public NodePrinter {
4344
info.BasenameRange.second = getStreamLength();
4445
}
4546

47+
void startGenericSignature(unsigned depth) {
48+
if (genericsSignatureDepth || !info.hasBasename() ||
49+
info.TemplateArgumentsRange.first <
50+
info.TemplateArgumentsRange.second) {
51+
return;
52+
}
53+
info.TemplateArgumentsRange.first = getStreamLength();
54+
genericsSignatureDepth = depth;
55+
}
56+
57+
void endGenericSignature(unsigned depth) {
58+
if (!genericsSignatureDepth || *genericsSignatureDepth != depth ||
59+
info.TemplateArgumentsRange.first <
60+
info.TemplateArgumentsRange.second) {
61+
return;
62+
}
63+
info.TemplateArgumentsRange.second = getStreamLength();
64+
}
65+
4666
void startParameters(unsigned depth) {
4767
if (parametersDepth || !info.hasBasename() ||
4868
info.ArgumentsRange.first < info.ArgumentsRange.second) {
@@ -85,6 +105,12 @@ class TrackingNodePrinter : public NodePrinter {
85105
endName();
86106
}
87107

108+
void printGenericSignature(NodePointer Node, unsigned depth) override {
109+
startGenericSignature(depth);
110+
NodePrinter::printGenericSignature(Node, depth);
111+
endGenericSignature(depth);
112+
}
113+
88114
void printFunctionParameters(NodePointer LabelList, NodePointer ParameterType,
89115
unsigned depth, bool showTypes) override {
90116
startParameters(depth);

lldb/test/API/lang/swift/async/tasks/TestSwiftTaskBacktrace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ def do_backtrace(self, arg):
3131
".sleep(",
3232
"`second() at main.swift:6",
3333
"`first() at main.swift:2",
34-
"`closure #1() at main.swift:12:19",
34+
"`closure #1 in static Main.main() at main.swift:12:19",
3535
],
3636
)

lldb/test/API/lang/swift/async/tasks/TestSwiftTaskSelect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def do_backtrace_selected_task(self, arg):
3333
".sleep(",
3434
"`second() at main.swift:6:",
3535
"`first() at main.swift:2:",
36-
"`closure #1() at main.swift:12:",
36+
"`closure #1 in static Main.main() at main.swift:12:",
3737
],
3838
)
3939

lldb/test/API/lang/swift/async/unwind/hidden_frames/TestSwiftAsyncHiddenFrames.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import lldbsuite.test.lldbutil as lldbutil
55

66

7-
@skipIf(bugnumber="rdar://156178892")
87
class TestSwiftAsyncHiddenFrames(lldbtest.TestBase):
98

109
NO_DEBUG_INFO_TESTCASE = True

0 commit comments

Comments
 (0)