Skip to content

Commit 6f22fc8

Browse files
[lldb] add function name syntax highlighting in Swift backtraces
1 parent 0ac3111 commit 6f22fc8

File tree

8 files changed

+1574
-32
lines changed

8 files changed

+1574
-32
lines changed

lldb/include/lldb/Core/DemangledNameInfo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ struct DemangledNameInfo {
7373
bool hasBasename() const {
7474
return BasenameRange.second > BasenameRange.first;
7575
}
76+
77+
/// Returns \c true if this object holds a valid arguments range.
78+
bool hasArguments() const {
79+
return ArgumentsRange.second > ArgumentsRange.first;
80+
}
7681
};
7782

7883
/// An OutputBuffer which keeps a record of where certain parts of a

lldb/source/Core/Mangled.cpp

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,41 @@ void Mangled::SetValue(ConstString name) {
148148
}
149149
}
150150

151+
// BEGIN SWIFT
152+
#ifdef LLDB_ENABLE_SWIFT
153+
static ConstString GetSwiftDemangledStr(ConstString m_mangled,
154+
const SymbolContext *sc,
155+
ConstString &m_demangled) {
156+
const char *mangled_name = m_mangled.GetCString();
157+
Log *log = GetLog(LLDBLog::Demangle);
158+
LLDB_LOGF(log, "demangle swift: %s", mangled_name);
159+
auto [demangled, info] = SwiftLanguageRuntime::TrackedDemangleSymbolAsString(
160+
mangled_name, SwiftLanguageRuntime::eSimplified, sc);
161+
info.PrefixRange.second =
162+
std::min(info.BasenameRange.first, info.ArgumentsRange.first);
163+
info.SuffixRange.first =
164+
std::max(info.BasenameRange.second, info.ArgumentsRange.second);
165+
info.SuffixRange.second = demangled.length();
166+
167+
// Don't cache the demangled name the function isn't available yet.
168+
if (!sc || !sc->function) {
169+
LLDB_LOGF(log, "demangle swift: %s -> \"%s\" (not cached)", mangled_name,
170+
demangled.c_str());
171+
return ConstString(demangled);
172+
}
173+
if (demangled.empty()) {
174+
LLDB_LOGF(log, "demangle swift: %s -> error: failed to demangle",
175+
mangled_name);
176+
} else {
177+
LLDB_LOGF(log, "demangle swift: %s -> \"%s\"", mangled_name,
178+
demangled.c_str());
179+
m_demangled.SetStringWithMangledCounterpart(demangled, m_mangled);
180+
}
181+
return m_demangled;
182+
}
183+
#endif // LLDB_ENABLE_SWIFT
184+
// END SWIFT
185+
151186
// Local helpers for different demangling implementations.
152187
static char *GetMSVCDemangledStr(llvm::StringRef M) {
153188
char *demangled_cstr = llvm::microsoftDemangle(
@@ -349,28 +384,7 @@ ConstString Mangled::GetDemangledNameImpl(bool force, // BEGIN SWIFT
349384
// Demangling a swift name requires the swift compiler. This is
350385
// explicitly unsupported on llvm.org.
351386
#ifdef LLDB_ENABLE_SWIFT
352-
{
353-
const char *mangled_name = m_mangled.GetCString();
354-
Log *log = GetLog(LLDBLog::Demangle);
355-
LLDB_LOGF(log, "demangle swift: %s", mangled_name);
356-
std::string demangled(SwiftLanguageRuntime::DemangleSymbolAsString(
357-
mangled_name, SwiftLanguageRuntime::eTypeName, sc));
358-
// Don't cache the demangled name the function isn't available yet.
359-
if (!sc || !sc->function) {
360-
LLDB_LOGF(log, "demangle swift: %s -> \"%s\" (not cached)", mangled_name,
361-
demangled.c_str());
362-
return ConstString(demangled);
363-
}
364-
if (demangled.empty()) {
365-
LLDB_LOGF(log, "demangle swift: %s -> error: failed to demangle",
366-
mangled_name);
367-
} else {
368-
LLDB_LOGF(log, "demangle swift: %s -> \"%s\"", mangled_name,
369-
demangled.c_str());
370-
m_demangled.SetStringWithMangledCounterpart(demangled, m_mangled);
371-
}
372-
return m_demangled;
373-
}
387+
return GetSwiftDemangledStr(m_mangled, sc, m_demangled);
374388
#endif // LLDB_ENABLE_SWIFT
375389
break;
376390
case eManglingSchemeNone:

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

Lines changed: 138 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,21 +1896,96 @@ SwiftLanguage::GetDemangledFunctionNameWithoutArguments(Mangled mangled) const {
18961896

18971897
static std::optional<llvm::StringRef>
18981898
GetDemangledBasename(const SymbolContext &sc) {
1899-
return std::nullopt;
1899+
Mangled mangled = sc.GetPossiblyInlinedFunctionName();
1900+
if (!mangled)
1901+
return std::nullopt;
1902+
1903+
auto demangled_name = mangled.GetDemangledName().GetStringRef();
1904+
if (demangled_name.empty())
1905+
return std::nullopt;
1906+
1907+
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
1908+
if (!info)
1909+
return std::nullopt;
1910+
1911+
// Function without a basename is nonsense.
1912+
if (!info->hasBasename())
1913+
return std::nullopt;
1914+
1915+
return demangled_name.slice(info->BasenameRange.first,
1916+
info->BasenameRange.second);
19001917
}
19011918

19021919
static std::optional<llvm::StringRef>
19031920
GetDemangledFunctionPrefix(const SymbolContext &sc) {
1904-
return std::nullopt;
1921+
Mangled mangled = sc.GetPossiblyInlinedFunctionName();
1922+
if (!mangled)
1923+
return std::nullopt;
1924+
1925+
auto demangled_name = mangled.GetDemangledName().GetStringRef();
1926+
if (demangled_name.empty())
1927+
return std::nullopt;
1928+
1929+
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
1930+
if (!info)
1931+
return std::nullopt;
1932+
1933+
// Function without a basename is nonsense.
1934+
if (!info->hasBasename())
1935+
return std::nullopt;
1936+
1937+
return demangled_name.slice(info->PrefixRange.first,
1938+
info->PrefixRange.second);
19051939
}
19061940

19071941
static std::optional<llvm::StringRef>
19081942
GetDemangledFunctionSuffix(const SymbolContext &sc) {
1909-
return std::nullopt;
1943+
Mangled mangled = sc.GetPossiblyInlinedFunctionName();
1944+
if (!mangled)
1945+
return std::nullopt;
1946+
1947+
auto demangled_name = mangled.GetDemangledName().GetStringRef();
1948+
if (demangled_name.empty())
1949+
return std::nullopt;
1950+
1951+
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
1952+
if (!info)
1953+
return std::nullopt;
1954+
1955+
// Function without a basename is nonsense.
1956+
if (!info->hasBasename())
1957+
return std::nullopt;
1958+
1959+
return demangled_name.slice(info->SuffixRange.first,
1960+
info->SuffixRange.second);
19101961
}
19111962

19121963
static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
1913-
return false;
1964+
assert(sc.symbol);
1965+
1966+
Mangled mangled = sc.GetPossiblyInlinedFunctionName();
1967+
if (!mangled)
1968+
return false;
1969+
1970+
auto demangled_name = mangled.GetDemangledName().GetStringRef();
1971+
if (demangled_name.empty())
1972+
return false;
1973+
1974+
const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
1975+
if (!info)
1976+
return false;
1977+
1978+
// Function without a basename is nonsense.
1979+
if (!info->hasBasename())
1980+
return false;
1981+
1982+
if (info->ArgumentsRange.second < info->ArgumentsRange.first)
1983+
return false;
1984+
1985+
s << demangled_name.slice(info->ArgumentsRange.first,
1986+
info->ArgumentsRange.second);
1987+
1988+
return true;
19141989
}
19151990

19161991
static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
@@ -1927,7 +2002,65 @@ bool SwiftLanguage::HandleFrameFormatVariable(const SymbolContext &sc,
19272002
const ExecutionContext *exe_ctx,
19282003
FormatEntity::Entry::Type type,
19292004
Stream &s) {
1930-
return false;
2005+
switch (type) {
2006+
case FormatEntity::Entry::Type::FunctionBasename: {
2007+
std::optional<llvm::StringRef> name = GetDemangledBasename(sc);
2008+
if (!name)
2009+
return false;
2010+
2011+
s << *name;
2012+
2013+
return true;
2014+
}
2015+
case FormatEntity::Entry::Type::FunctionFormattedArguments: {
2016+
// This ensures we print the arguments even when no debug-info is available.
2017+
//
2018+
// FIXME: we should have a Entry::Type::FunctionArguments and
2019+
// use it in the plugin.cplusplus.display.function-name-format
2020+
// once we have a "fallback operator" in the frame-format language.
2021+
if (!sc.function && sc.symbol)
2022+
return PrintDemangledArgumentList(s, sc);
2023+
std::string display_name = SwiftLanguageRuntime::DemangleSymbolAsString(
2024+
sc.function->GetMangled().GetMangledName().GetStringRef(),
2025+
SwiftLanguageRuntime::eSimplified, &sc, exe_ctx);
2026+
if (display_name.empty())
2027+
return false;
2028+
2029+
VariableList args;
2030+
if (auto variable_list_sp = GetFunctionVariableList(sc))
2031+
variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
2032+
args);
2033+
2034+
s << GetFunctionDisplayArgs(sc, args, exe_ctx);
2035+
return true;
2036+
}
2037+
case FormatEntity::Entry::Type::FunctionPrefix: {
2038+
std::optional<llvm::StringRef> prefix = GetDemangledFunctionPrefix(sc);
2039+
if (!prefix)
2040+
return false;
2041+
2042+
s << *prefix;
2043+
2044+
return true;
2045+
}
2046+
case FormatEntity::Entry::Type::FunctionSuffix: {
2047+
std::optional<llvm::StringRef> suffix = GetDemangledFunctionSuffix(sc);
2048+
if (!suffix)
2049+
return false;
2050+
2051+
s << *suffix;
2052+
2053+
return true;
2054+
}
2055+
2056+
case FormatEntity::Entry::Type::FunctionScope:
2057+
case FormatEntity::Entry::Type::FunctionTemplateArguments:
2058+
case FormatEntity::Entry::Type::FunctionReturnRight:
2059+
case FormatEntity::Entry::Type::FunctionReturnLeft:
2060+
case FormatEntity::Entry::Type::FunctionQualifiers:
2061+
default:
2062+
return true;
2063+
}
19312064
}
19322065

19332066
#define LLDB_PROPERTIES_language_swift
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//===-- SwiftMangled.h ------------------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef liblldb_SwiftMangled_h_
14+
#define liblldb_SwiftMangled_h_
15+
16+
#include "lldb/Core/DemangledNameInfo.h"
17+
#include "swift/Demangling/Demangle.h"
18+
19+
using namespace swift::Demangle;
20+
21+
class TrackingNodePrinter : public NodePrinter {
22+
public:
23+
TrackingNodePrinter(DemangleOptions options) : NodePrinter(options) {}
24+
25+
lldb_private::DemangledNameInfo takeInfo() { return std::move(info); }
26+
27+
private:
28+
lldb_private::DemangledNameInfo info;
29+
std::optional<unsigned> parametersDepth;
30+
31+
void startName() {
32+
if (!info.hasBasename())
33+
info.BasenameRange.first = getStreamLength();
34+
}
35+
36+
void endName() {
37+
if (!info.hasBasename())
38+
info.BasenameRange.second = getStreamLength();
39+
}
40+
41+
void startParameters(unsigned depth) {
42+
if (parametersDepth || !info.hasBasename() || info.hasArguments()) {
43+
return;
44+
}
45+
info.ArgumentsRange.first = getStreamLength();
46+
parametersDepth = depth;
47+
}
48+
49+
void endParameters(unsigned depth) {
50+
if (!parametersDepth || *parametersDepth != depth || info.hasArguments()) {
51+
return;
52+
}
53+
info.ArgumentsRange.second = getStreamLength();
54+
}
55+
56+
bool shouldTrackNameRange(NodePointer Node) const {
57+
switch (Node->getKind()) {
58+
case Node::Kind::Function:
59+
case Node::Kind::Constructor:
60+
case Node::Kind::Allocator:
61+
case Node::Kind::ExplicitClosure:
62+
return true;
63+
default:
64+
return false;
65+
}
66+
}
67+
68+
void printFunctionName(bool hasName, llvm::StringRef &OverwriteName,
69+
llvm::StringRef &ExtraName, bool MultiWordName,
70+
int &ExtraIndex, NodePointer Entity,
71+
unsigned int depth) override {
72+
if (shouldTrackNameRange(Entity))
73+
startName();
74+
NodePrinter::printFunctionName(hasName, OverwriteName, ExtraName,
75+
MultiWordName, ExtraIndex, Entity, depth);
76+
if (shouldTrackNameRange(Entity))
77+
endName();
78+
}
79+
80+
void printFunctionParameters(NodePointer LabelList, NodePointer ParameterType,
81+
unsigned depth, bool showTypes) override {
82+
startParameters(depth);
83+
NodePrinter::printFunctionParameters(LabelList, ParameterType, depth,
84+
showTypes);
85+
endParameters(depth);
86+
}
87+
};
88+
89+
#endif // liblldb_SwiftMangled_h_

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,17 @@ class SwiftLanguageRuntime : public LanguageRuntime {
200200
IsSwiftAsyncAwaitResumePartialFunctionSymbol(llvm::StringRef name);
201201

202202
enum DemangleMode { eSimplified, eTypeName, eDisplayTypeName };
203+
203204
static std::string
204205
DemangleSymbolAsString(llvm::StringRef symbol, DemangleMode mode,
205206
const SymbolContext *sc = nullptr,
206207
const ExecutionContext *exe_ctx = nullptr);
207208

209+
static std::pair<std::string, DemangledNameInfo>
210+
TrackedDemangleSymbolAsString(llvm::StringRef symbol, DemangleMode mode,
211+
const SymbolContext *sc = nullptr,
212+
const ExecutionContext *exe_ctx = nullptr);
213+
208214
static std::string GetParentNameIfClosure(llvm::StringRef mangled_name);
209215

210216
/// Demangle a symbol to a swift::Demangle node tree.
@@ -885,6 +891,11 @@ class SwiftLanguageRuntime : public LanguageRuntime {
885891

886892
/// Swift native NSError isa.
887893
std::optional<lldb::addr_t> m_SwiftNativeNSErrorISA;
894+
895+
static std::pair<std::string, std::optional<DemangledNameInfo>>
896+
DemangleSymbolAsString(llvm::StringRef symbol, DemangleMode mode,
897+
bool tracking, const SymbolContext *sc,
898+
const ExecutionContext *exe_ctx);
888899
};
889900

890901
/// The target specific register numbers used for async unwinding.

0 commit comments

Comments
 (0)