Skip to content

Commit 2c8bd79

Browse files
authored
Merge pull request #69697 from al45tair/eng/PR-118055527
[Backtracing] Add an indication that we're working on a backtrace.
2 parents 88b3c57 + e2732f3 commit 2c8bd79

File tree

11 files changed

+518
-252
lines changed

11 files changed

+518
-252
lines changed

include/swift/Runtime/Backtrace.h

Lines changed: 5 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -31,114 +31,17 @@
3131

3232
#include <inttypes.h>
3333

34-
#ifdef _WIN32
35-
// For DWORD
36-
#define WIN32_LEAN_AND_MEAN
37-
#define NOMINMAX
38-
#include <windows.h>
39-
40-
// For wchar_t
41-
#include <cwchar>
42-
#endif
43-
4434
#ifdef __cplusplus
4535
namespace swift {
4636
namespace runtime {
4737
namespace backtrace {
4838
#endif
4939

50-
#ifdef _WIN32
51-
typedef wchar_t ArgChar;
52-
typedef DWORD ErrorCode;
53-
#else
54-
typedef char ArgChar;
55-
typedef int ErrorCode;
56-
#endif
57-
58-
SWIFT_RUNTIME_STDLIB_INTERNAL ErrorCode _swift_installCrashHandler();
59-
60-
#ifdef __linux__
61-
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd);
62-
#else
63-
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv);
64-
#endif
65-
66-
enum class UnwindAlgorithm {
67-
Auto = 0,
68-
Fast = 1,
69-
Precise = 2
70-
};
71-
72-
enum class OnOffTty {
73-
Off = 0,
74-
On = 1,
75-
TTY = 2
76-
};
77-
78-
enum class Preset {
79-
Auto = -1,
80-
Friendly = 0,
81-
Medium = 1,
82-
Full = 2
83-
};
84-
85-
enum class ThreadsToShow {
86-
Preset = -1,
87-
All = 0,
88-
Crashed = 1
89-
};
90-
91-
enum class RegistersToShow {
92-
Preset = -1,
93-
None = 0,
94-
All = 1,
95-
Crashed = 2
96-
};
97-
98-
enum class ImagesToShow {
99-
Preset = -1,
100-
None = 0,
101-
All = 1,
102-
Mentioned = 2
103-
};
104-
105-
enum class SanitizePaths {
106-
Preset = -1,
107-
Off = 0,
108-
On = 1
109-
};
110-
111-
enum class OutputTo {
112-
Auto = -1,
113-
Stdout = 0,
114-
Stderr = 2,
115-
};
116-
117-
struct BacktraceSettings {
118-
UnwindAlgorithm algorithm;
119-
OnOffTty enabled;
120-
bool demangle;
121-
OnOffTty interactive;
122-
OnOffTty color;
123-
unsigned timeout;
124-
ThreadsToShow threads;
125-
RegistersToShow registers;
126-
ImagesToShow images;
127-
unsigned limit;
128-
unsigned top;
129-
SanitizePaths sanitize;
130-
Preset preset;
131-
bool cache;
132-
OutputTo outputTo;
133-
const char *swiftBacktracePath;
134-
};
135-
136-
SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings;
137-
138-
inline bool _swift_backtrace_isEnabled() {
139-
return _swift_backtraceSettings.enabled == OnOffTty::On;
140-
}
141-
40+
// Test if a given function is a Swift thunk of some sort.
41+
//
42+
// @param mangledName is the name of the symbol to test.
43+
//
44+
// @returns true if the function is a thunk.
14245
SWIFT_RUNTIME_STDLIB_SPI
14346
bool _swift_backtrace_isThunkFunction(const char *mangledName);
14447

stdlib/public/libexec/swift-backtrace/main.swift

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,38 @@ internal struct SwiftBacktrace {
113113
}
114114
}
115115

116+
static func subtract(timespec ts: timespec, from: timespec) -> timespec {
117+
var sec = from.tv_sec - ts.tv_sec
118+
var nsec = from.tv_nsec - ts.tv_nsec
119+
if nsec < 0 {
120+
sec -= 1
121+
nsec += 1000000000
122+
}
123+
return timespec(tv_sec: sec, tv_nsec: nsec)
124+
}
125+
126+
// We can't use Foundation here, so there's no String(format:, ...)
127+
static func format(duration: timespec) -> String {
128+
let centisRounded = (duration.tv_nsec + 5000000) / 10000000
129+
let centis = centisRounded % 100
130+
let secs = duration.tv_sec + (centisRounded / 100)
131+
let d1 = centis / 10
132+
let d2 = centis % 10
133+
134+
return "\(secs).\(d1)\(d2)"
135+
}
136+
137+
static func measureDuration(_ body: () -> ()) -> timespec {
138+
var startTime = timespec()
139+
var endTime = timespec()
140+
141+
clock_gettime(CLOCK_MONOTONIC, &startTime)
142+
body()
143+
clock_gettime(CLOCK_MONOTONIC, &endTime)
144+
145+
return subtract(timespec: startTime, from: endTime)
146+
}
147+
116148
static func usage() {
117149
print("""
118150
usage: swift-backtrace [--unwind <algorithm>] [--demangle [<bool>]] [--interactive [<bool>]] [--color [<bool>]] [--timeout <seconds>] [--preset <preset>] [--threads [<bool>]] [--registers <registers>] [--images <images>] [--cache [<bool>]] [--output-to <stream>] --crashinfo <addr>
@@ -460,16 +492,25 @@ Generate a backtrace for the parent process.
460492
// want to do it *once* for all the backtraces we showed.
461493
formattingOptions = formattingOptions.showImages(.none)
462494

463-
target = Target(crashInfoAddr: crashInfoAddr,
464-
limit: args.limit, top: args.top,
465-
cache: args.cache)
495+
// Target's initializer fetches and symbolicates backtraces, so
496+
// we want to time that part here.
497+
let duration = measureDuration {
498+
target = Target(crashInfoAddr: crashInfoAddr,
499+
limit: args.limit, top: args.top,
500+
cache: args.cache)
466501

467-
currentThread = target!.crashingThreadNdx
502+
currentThread = target!.crashingThreadNdx
503+
}
468504

469505
printCrashLog()
470506

471507
writeln("")
472508

509+
let formattedDuration = format(duration: duration)
510+
511+
writeln("Backtrace took \(formattedDuration)s")
512+
writeln("")
513+
473514
if args.interactive {
474515
// Make sure we're line buffered
475516
setvbuf(stdout, nil, _IOLBF, 0)
@@ -611,7 +652,13 @@ Generate a backtrace for the parent process.
611652
description = "Program crashed: \(target.signalDescription) at \(hex(target.faultAddress))"
612653
}
613654

614-
writeln("")
655+
// Clear (or complete) the message written by the crash handler
656+
if args.color {
657+
write("\r\u{1b}[0K")
658+
} else {
659+
write(" done ***\n\n")
660+
}
661+
615662
writeln(theme.crashReason(description))
616663

617664
var mentionedImages = Set<Int>()

stdlib/public/runtime/Backtrace.cpp

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
#include <cxxabi.h>
5959
#endif
6060

61+
#include "BacktracePrivate.h"
62+
6163
#define DEBUG_BACKTRACING_SETTINGS 0
6264

6365
#ifndef lengthof
@@ -74,13 +76,7 @@ SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings = {
7476
UnwindAlgorithm::Auto,
7577

7678
// enabled
77-
#if TARGET_OS_OSX
78-
OnOffTty::TTY,
79-
#elif defined(__linux__) // || defined(_WIN32)
80-
OnOffTty::On,
81-
#else
82-
OnOffTty::Off,
83-
#endif
79+
OnOffTty::Default,
8480

8581
// demangle
8682
true,
@@ -230,6 +226,7 @@ const char *algorithmToString(UnwindAlgorithm algorithm) {
230226

231227
const char *onOffTtyToString(OnOffTty oot) {
232228
switch (oot) {
229+
case OnOffTty::Default: return "Default";
233230
case OnOffTty::On: return "On";
234231
case OnOffTty::Off: return "Off";
235232
case OnOffTty::TTY: return "TTY";
@@ -277,6 +274,32 @@ BacktraceInitializer::BacktraceInitializer() {
277274
if (backtracing)
278275
_swift_parseBacktracingSettings(backtracing);
279276

277+
#if !defined(SWIFT_RUNTIME_FIXED_BACKTRACER_PATH)
278+
if (!_swift_backtraceSettings.swiftBacktracePath) {
279+
_swift_backtraceSettings.swiftBacktracePath
280+
= swift_copyAuxiliaryExecutablePath("swift-backtrace");
281+
282+
if (!_swift_backtraceSettings.swiftBacktracePath) {
283+
if (_swift_backtraceSettings.enabled == OnOffTty::On) {
284+
swift::warning(0,
285+
"swift runtime: unable to locate swift-backtrace; "
286+
"disabling backtracing.\n");
287+
}
288+
_swift_backtraceSettings.enabled = OnOffTty::Off;
289+
}
290+
}
291+
#endif
292+
293+
if (_swift_backtraceSettings.enabled == OnOffTty::Default) {
294+
#if TARGET_OS_OSX
295+
_swift_backtraceSettings.enabled = OnOffTty::TTY;
296+
#elif defined(__linux__) // || defined(_WIN32)
297+
_swift_backtraceSettings.enabled = OnOffTty::On;
298+
#else
299+
_swift_backtraceSettings.enabled = OnOffTty::Off;
300+
#endif
301+
}
302+
280303
#if !SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
281304
if (_swift_backtraceSettings.enabled != OnOffTty::Off) {
282305
swift::warning(0,
@@ -329,22 +352,6 @@ BacktraceInitializer::BacktraceInitializer() {
329352
_swift_backtraceSettings.outputTo = OutputTo::Stderr;
330353
}
331354

332-
#if !defined(SWIFT_RUNTIME_FIXED_BACKTRACER_PATH)
333-
if (_swift_backtraceSettings.enabled == OnOffTty::On
334-
&& !_swift_backtraceSettings.swiftBacktracePath) {
335-
_swift_backtraceSettings.swiftBacktracePath
336-
= swift_copyAuxiliaryExecutablePath("swift-backtrace");
337-
338-
if (!_swift_backtraceSettings.swiftBacktracePath) {
339-
// Disabled warning for now - rdar://106813646
340-
/* swift::warning(0,
341-
"swift runtime: unable to locate swift-backtrace; "
342-
"disabling backtracing.\n"); */
343-
_swift_backtraceSettings.enabled = OnOffTty::Off;
344-
}
345-
}
346-
#endif
347-
348355
if (_swift_backtraceSettings.enabled == OnOffTty::On) {
349356
// Copy the path to swift-backtrace into swiftBacktracePath, then write
350357
// protect it so that it can't be overwritten easily at runtime. We do
@@ -987,6 +994,57 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
987994
#endif
988995
}
989996

997+
// N.B. THIS FUNCTION MUST BE SAFE TO USE FROM A CRASH HANDLER. On Linux
998+
// and macOS, that means it must be async-signal-safe. On Windows, there
999+
// isn't an equivalent notion but a similar restriction applies.
1000+
SWIFT_RUNTIME_STDLIB_INTERNAL void
1001+
_swift_displayCrashMessage(int signum, const void *pc)
1002+
{
1003+
#if !SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
1004+
return;
1005+
#else
1006+
int fd = STDOUT_FILENO;
1007+
1008+
if (_swift_backtraceSettings.outputTo == OutputTo::Stderr)
1009+
fd = STDERR_FILENO;
1010+
1011+
const char *intro;
1012+
if (_swift_backtraceSettings.color == OnOffTty::On) {
1013+
intro = "\n💣 \033[91mProgram crashed: ";
1014+
} else {
1015+
intro = "\n*** ";
1016+
}
1017+
write(fd, intro, strlen(intro));
1018+
1019+
char sigbuf[30];
1020+
strcpy(sigbuf, "Signal ");
1021+
_swift_formatUnsigned((unsigned)signum, sigbuf + 7);
1022+
write(fd, sigbuf, strlen(sigbuf));
1023+
1024+
const char *message;
1025+
if (!pc) {
1026+
message = ": Backtracing";
1027+
} else {
1028+
message = ": Backtracing from 0x";
1029+
}
1030+
write(fd, message, strlen(message));
1031+
1032+
if (pc) {
1033+
char pcbuf[18];
1034+
_swift_formatAddress(pc, pcbuf);
1035+
write(fd, pcbuf, strlen(pcbuf));
1036+
}
1037+
1038+
const char *outro;
1039+
if (_swift_backtraceSettings.color == OnOffTty::On) {
1040+
outro = "...\033[0m";
1041+
} else {
1042+
outro = "...";
1043+
}
1044+
write(fd, outro, strlen(outro));
1045+
#endif
1046+
}
1047+
9901048
} // namespace backtrace
9911049
} // namespace runtime
9921050
} // namespace swift

0 commit comments

Comments
 (0)