Skip to content

Commit bc47698

Browse files
authored
Merge pull request #64100 from al45tair/backtracing/full
[Backtracing] Add improved backtracing support for Swift crashes
2 parents 2979ed5 + eac93f9 commit bc47698

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+9321
-25
lines changed

CMakeLists.txt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,22 @@ else()
4343
set(CMAKE_JOB_POOL_LINK local_jobs)
4444
endif()
4545

46-
ENABLE_LANGUAGE(C)
46+
enable_language(C)
47+
enable_language(CXX)
48+
49+
# On Windows, use MASM or MARMASM
50+
set(SWIFT_ASM_DIALECT ASM)
51+
set(SWIFT_ASM_EXT S)
52+
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
53+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
54+
set(SWIFT_ASM_DIALECT ASM_MARMASM)
55+
else()
56+
set(SWIFT_ASM_DIALECT ASM_MASM)
57+
endif()
58+
set(SWIFT_ASM_EXT asm)
59+
endif()
60+
61+
enable_language(${SWIFT_ASM_DIALECT})
4762

4863
# Use C++14.
4964
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
@@ -560,6 +575,10 @@ option(SWIFT_IMPLICIT_CONCURRENCY_IMPORT
560575
"Implicitly import the Swift concurrency module"
561576
TRUE)
562577

578+
option(SWIFT_IMPLICIT_BACKTRACING_IMPORT
579+
"Implicitly import the Swift backtracing module"
580+
FALSE)
581+
563582
option(SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
564583
"Enable build of the Swift concurrency module"
565584
FALSE)
@@ -618,7 +637,7 @@ if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
618637
endif()
619638

620639
if(SWIFT_BUILT_STANDALONE)
621-
project(Swift C CXX ASM)
640+
project(Swift C CXX ${SWIFT_ASM_DIALECT})
622641
endif()
623642

624643
if(MSVC OR "${CMAKE_SIMULATE_ID}" STREQUAL MSVC)
@@ -688,6 +707,7 @@ execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} ${version_flag}
688707
message(STATUS "CMake Make Program (${CMAKE_MAKE_PROGRAM}) Version: ${_CMAKE_MAKE_PROGRAM_VERSION}")
689708
message(STATUS "C Compiler (${CMAKE_C_COMPILER}) Version: ${CMAKE_C_COMPILER_VERSION}")
690709
message(STATUS "C++ Compiler (${CMAKE_CXX_COMPILER}) Version: ${CMAKE_CXX_COMPILER_VERSION}")
710+
message(STATUS "Assembler (${CMAKE_${SWIFT_ASM_DIALECT}_COMPILER}) Version: ${CMAKE_${SWIFT_ASM_DIALECT}_COMPILER_VERSION}")
691711
if (CMAKE_Swift_COMPILER)
692712
message(STATUS "Swift Compiler (${CMAKE_Swift_COMPILER}) Version: ${CMAKE_Swift_COMPILER_VERSION}")
693713
else()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Test if the Swift compiler supports -disable-implicit-<module>-module-import
2+
function(swift_supports_implicit_module module_name out_var)
3+
file(WRITE "${CMAKE_BINARY_DIR}/tmp/empty-check-${module_name}.swift" "")
4+
execute_process(
5+
COMMAND
6+
"${CMAKE_Swift_COMPILER}"
7+
-Xfrontend -disable-implicit-${module_name}-module-import
8+
-c - -o /dev/null
9+
INPUT_FILE
10+
"${CMAKE_BINARY_DIR}/tmp/empty-check-${module_name}.swift"
11+
OUTPUT_QUIET ERROR_QUIET
12+
RESULT_VARIABLE
13+
result
14+
)
15+
if(NOT result)
16+
set("${out_var}" "TRUE" PARENT_SCOPE)
17+
else()
18+
set("${out_var}" "FALSE" PARENT_SCOPE)
19+
endif()
20+
endfunction()

docs/Backtracing.rst

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
Backtracing support in Swift
2+
============================
3+
4+
When things go wrong, it's always useful to be able to get a backtrace showing
5+
where the problem occurred in your program.
6+
7+
Broadly speaking there are three circumstances where you might want a backtrace,
8+
namely:
9+
10+
* Program crashes
11+
* Runtime errors
12+
* Specific user-defined program events
13+
14+
Historically, Swift has tended to lean on operating system crash catching
15+
support for the first two of these, and hasn't really provided any built-in
16+
support for the latter. This is fine for Darwin, where the operating system
17+
provides a comprehensive system-wide crash catching facility; it's just about OK
18+
on Windows, which also has system-wide crash logging; but it isn't great
19+
elsewhere, in particular on Linux where a lot of server-side Swift programs
20+
currently rely on a separate package to provide them with some level of
21+
backtrace support when errors happen.
22+
23+
What does Swift now support?
24+
----------------------------
25+
26+
Swift now supports:
27+
28+
* Automatic crash catching and backtrace generation out of the box.
29+
* Built-in symbolication.
30+
* A choice of unwind algorithms, including "fast", DWARF and SEH.
31+
* Interactive(!) crash/runtime error catching.
32+
33+
Crash catching is enabled by default, and won't interfere with any system-wide
34+
crash reporters you might be using.
35+
36+
How do I configure backtracing?
37+
-------------------------------
38+
39+
There is an environment variable, ``SWIFT_BACKTRACE``, that can be used to
40+
configure Swift's crash catching and backtracing support. The variable should
41+
contain a ``,``-separated list of ``key=value`` pairs. Supported keys are as
42+
follows:
43+
44+
+-----------------+---------+--------------------------------------------------+
45+
| Key | Default | Meaning |
46+
+=================+=========+==================================================+
47+
| enable | yes* | Set to ``no`` to disable crash catching, or |
48+
| | | ``tty`` to enable only if stdin is a terminal. |
49+
+-----------------+---------+--------------------------------------------------+
50+
| demangle | yes | Set to ``no`` to disable demangling. |
51+
+-----------------+---------+--------------------------------------------------+
52+
| interactive | tty | Set to ``no`` to disable interaction, or ``yes`` |
53+
| | | to enable always. |
54+
+-----------------+---------+--------------------------------------------------+
55+
| color | tty | Set to ``yes`` to enable always, or ``no`` to |
56+
| | | disable. Uses ANSI escape sequences. |
57+
+-----------------+---------+--------------------------------------------------+
58+
| timeout | 30s | Time to wait for interaction when a crash |
59+
| | | occurs. Setting this to ``none`` or ``0s`` will |
60+
| | | disable interaction. |
61+
+-----------------+---------+--------------------------------------------------+
62+
| unwind | auto | Specifies which unwind algorithm to use. |
63+
| | | ``auto`` means to choose appropriately for the |
64+
| | | platform. Other options are ``fast``, which |
65+
| | | does a naïve stack walk; and ``precise``, which |
66+
| | | uses exception handling data to perform an |
67+
| | | unwind. |
68+
+-----------------+---------+--------------------------------------------------+
69+
| preset | auto | Specifies which set of preset formatting options |
70+
| | | to use. Options are ``friendly``, ``medium`` or |
71+
| | | ``full``. ``auto`` means to use ``friendly`` if |
72+
| | | interactive, and ``full`` otherwise. |
73+
+-----------------+---------+--------------------------------------------------+
74+
| sanitize | preset | If ``yes``, we will try to process paths to |
75+
| | | remove PII. Exact behaviour is platform |
76+
| | | dependent. |
77+
+-----------------+---------+--------------------------------------------------+
78+
| threads | preset | Options are ``all`` to show backtraces for every |
79+
| | | thread, or ``crashed`` to show only the crashing |
80+
| | | thread. |
81+
+-----------------+---------+--------------------------------------------------+
82+
| registers | preset | Options are ``none``, ``all`` or ``crashed``. |
83+
+-----------------+---------+--------------------------------------------------+
84+
| images | preset | Options are ``none``, ``all``, or ``mentioned``, |
85+
| | | which only displays images mentioned in a |
86+
| | | backtrace. |
87+
+-----------------+---------+--------------------------------------------------+
88+
| limit | 64 | Limits the length of the captured backtrace. See |
89+
| | | below for a discussion of its behaviour. Can be |
90+
| | | set to ``none`` to mean no limit. |
91+
+-----------------+---------+--------------------------------------------------+
92+
| top | 16 | Specify a minimum number of frames to capture |
93+
| | | from the top of the stack. See below for more. |
94+
+-----------------+---------+--------------------------------------------------+
95+
| cache | yes | Set to ``no`` to disable symbol caching. This |
96+
| | | only has effect on platforms that have a symbol |
97+
| | | cache that can be controlled by the runtime. |
98+
+-----------------+---------+--------------------------------------------------+
99+
| swift-backtrace | | If specified, gives the full path to the |
100+
| | | swift-backtrace binary to use for crashes. |
101+
| | | Otherwise, Swift will locate the binary relative |
102+
| | | to the runtime library, or using ``SWIFT_ROOT``. |
103+
+-----------------+---------+--------------------------------------------------+
104+
105+
(*) On macOS, this defaults to ``tty`` rather than ``yes``.
106+
107+
Backtrace limits
108+
----------------
109+
110+
The limit settings are provided both to prevent runaway backtraces and to allow
111+
for a sensible backtrace to be produced even when a function has blown the stack
112+
through excessive recursion.
113+
114+
Typically in the latter case you want to capture some frames at the top of the
115+
stack so that you can see how the recursion was entered, and the frames at the
116+
bottom of the stack where the actual fault occurred.
117+
118+
1. There are ``limit`` or fewer frames. In this case we will display all
119+
the frames in the backtrace. Note that this _includes_ the case where there
120+
are exactly ``limit`` frames.
121+
122+
2. There are more than ``limit`` frames.
123+
124+
a. ``top`` is ``0``. We will display the first ``limit - 1`` frames followed
125+
by ``...`` to indicate that more frames exist.
126+
127+
b. ``top`` is less than ``limit - 1``. We will display ``limit - 1 - top``
128+
frames from the bottom of the stack, then a ``...``, then ``top`` frames
129+
from the top of the stack.
130+
131+
c. ``top`` is greater or equal to ``limit - 1``. We will display ``...``,
132+
followed by ``limit - 1`` frames from the top of the stack.
133+
134+
For example, let's say we have a stack containing 10 frames numbered here 1 to
135+
10, with 10 being the innermost frame. With ``limit`` set to 5, you would see::
136+
137+
10
138+
9
139+
8
140+
7
141+
...
142+
143+
With ``limit`` set to 5 and ``top`` to 2, you would instead see::
144+
145+
10
146+
9
147+
...
148+
2
149+
1
150+
151+
And with ``limit`` set to 5 and ``top`` to 4 or above, you would see::
152+
153+
...
154+
4
155+
3
156+
2
157+
1
158+
159+
What is the swift-backtrace binary?
160+
-----------------------------------
161+
162+
``swift-backtrace`` is a program that gets invoked when your program crashes.
163+
We do this because when a program crashes, it is potentially in an invalid state
164+
and there is very little that is safe for us to do. By executing an external
165+
helper program, we ensure that we do not interfere with the way the program was
166+
going to crash (so that system-wide crash catchers will still generate the
167+
correct information), and we are also able to use any functionality we need to
168+
generate a decent backtrace, including symbolication (which might in general
169+
require memory allocation, fetching and reading remote files and so on).
170+
171+
You shouldn't try to run ``swift-backtrace`` yourself; it has unusual
172+
requirements, which vary from platform to platform. Instead, it will be
173+
triggered automatically by the runtime.
174+
175+
System specifics
176+
----------------
177+
178+
macOS
179+
^^^^^
180+
181+
On macOS, we catch crashes and other events using a signal handler. At time of
182+
writing, this is installed for the following signals:
183+
184+
+--------------+--------------------------+-------------------------------------+
185+
| Signal | Description | Comment |
186+
+====+=========+==========================+=====================================+
187+
| 3 | SIGQUIT | Quit program | |
188+
+----+---------+--------------------------+-------------------------------------+
189+
| 4 | SIGILL | Illegal instruction | |
190+
+----+---------+--------------------------+-------------------------------------+
191+
| 5 | SIGTRAP | Trace trap | |
192+
+----+---------+--------------------------+-------------------------------------+
193+
| 6 | SIGABRT | Abort program | |
194+
+----+---------+--------------------------+-------------------------------------+
195+
| 8 | SIGFPE | Floating point exception | On Intel, integer divide by zero |
196+
| | | | also triggers this. |
197+
+----+---------+--------------------------+-------------------------------------+
198+
| 10 | SIGBUS | Bus error | |
199+
+----+---------+--------------------------+-------------------------------------+
200+
| 11 | SIGSEGV | Segmentation violation | |
201+
+----+---------+--------------------------+-------------------------------------+
202+
203+
If crash catching is enabled, the signal handler will be installed for any
204+
process that links the Swift runtime. If you replace the handlers for any of
205+
these signals, your program will no longer produce backtraces for program
206+
failures that lead to the handler you have replaced.
207+
208+
Additionally, the runtime will configure an alternate signal handling stack, so
209+
that stack overflows can be successfully trapped.
210+
211+
Note that the runtime will not install its signal handlers for a signal if it
212+
finds that there is already a handler for that signal. Similarly if something
213+
else has already configured an alternate signal stack, it will leave that
214+
stack alone.
215+
216+
Once the backtracer has finished handling the crash, it will allow the crashing
217+
program to continue and crash normally, which will result in the usual Crash
218+
Reporter log file being generated.
219+
220+
Crash catching *cannot* be enabled for setuid binaries. This is intentional as
221+
doing so might create a security hole.
222+
223+
Other Darwin (iOS, tvOS)
224+
^^^^^^^^^^^^^^^^^^^^^^^^
225+
226+
Crash catching is not enabled for non-macOS Darwin. You should continue to look
227+
at the system-provided crash logs.

docs/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ documentation, please create a thread on the Swift forums under the
136136
operations on [currency](/docs/Lexicon.md#currency-type) data types and
137137
optimizes accordingly.
138138
Includes a thorough discussion of the `@_semantics` attribute.
139+
- Runtime specifics:
140+
- [Backtracing.rst](/docs/Backtracing.rst):
141+
Describes Swift's backtracing and crash catching support.
139142

140143
### SourceKit subsystems
141144

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ WARNING(warn_implicit_concurrency_import_failed,none,
172172
"unable to perform implicit import of \"_Concurrency\" module: no such module found", ())
173173
REMARK(warn_implicit_string_processing_import_failed,none,
174174
"unable to perform implicit import of \"_StringProcessing\" module: no such module found", ())
175+
REMARK(warn_implicit_backtracing_import_failed,none,
176+
"unable to perform implicit import of \"_Backtracing\" module: no such module found", ())
175177

176178
ERROR(error_module_name_required,none, "-module-name is required", ())
177179
ERROR(error_bad_module_name,none,

include/swift/AST/KnownIdentifiers.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ IDENTIFIER(version)
263263
IDENTIFIER_(StringProcessing)
264264
IDENTIFIER(RegexBuilder)
265265

266+
// Backtracing
267+
IDENTIFIER_(Backtracing)
268+
266269
// Distributed actors
267270
IDENTIFIER(ActorID)
268271
IDENTIFIER(ActorSystem)

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ namespace swift {
352352
/// Disable the implicit import of the _StringProcessing module.
353353
bool DisableImplicitStringProcessingModuleImport = false;
354354

355+
/// Disable the implicit import of the _Backtracing module.
356+
bool DisableImplicitBacktracingModuleImport =
357+
!SWIFT_IMPLICIT_BACKTRACING_IMPORT;
358+
355359
/// Should we check the target OSs of serialized modules to see that they're
356360
/// new enough?
357361
bool EnableTargetOSChecking = true;

include/swift/Config.h.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#cmakedefine01 SWIFT_IMPLICIT_CONCURRENCY_IMPORT
1212

13+
#cmakedefine01 SWIFT_IMPLICIT_BACKTRACING_IMPORT
14+
1315
#cmakedefine01 SWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED
1416

1517
#cmakedefine01 SWIFT_ENABLE_GLOBAL_ISEL_ARM64

include/swift/Frontend/Frontend.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,10 @@ class CompilerInvocation {
380380
/// imported.
381381
bool shouldImportSwiftStringProcessing() const;
382382

383+
/// Whether the Swift Backtracing support library should be implicitly
384+
/// imported.
385+
bool shouldImportSwiftBacktracing() const;
386+
383387
/// Performs input setup common to these tools:
384388
/// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm.
385389
/// Return value includes the buffer so caller can keep it alive.
@@ -575,6 +579,14 @@ class CompilerInstance {
575579
/// i.e. if it can be found.
576580
bool canImportSwiftStringProcessing() const;
577581

582+
/// Verify that if an implicit import of the `Backtracing` module if
583+
/// expected, it can actually be imported. Emit a warning, otherwise.
584+
void verifyImplicitBacktracingImport();
585+
586+
/// Whether the Swift Backtracing support library can be imported
587+
/// i.e. if it can be found.
588+
bool canImportSwiftBacktracing() const;
589+
578590
/// Whether the CxxShim library can be imported
579591
/// i.e. if it can be found.
580592
bool canImportCxxShim() const;

include/swift/Option/FrontendOptions.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,14 @@ def disable_implicit_string_processing_module_import : Flag<["-"],
441441
"disable-implicit-string-processing-module-import">,
442442
HelpText<"Disable the implicit import of the _StringProcessing module.">;
443443

444+
def enable_implicit_backtracing_module_import : Flag<["-"],
445+
"enable-implicit-backtracing-module-import">,
446+
HelpText<"Enable the implicit import of the _Backtracing module.">;
447+
448+
def disable_implicit_backtracing_module_import : Flag<["-"],
449+
"disable-implicit-backtracing-module-import">,
450+
HelpText<"Disable the implicit import of the _Backtracing module.">;
451+
444452
def disable_arc_opts : Flag<["-"], "disable-arc-opts">,
445453
HelpText<"Don't run SIL ARC optimization passes.">;
446454
def disable_ossa_opts : Flag<["-"], "disable-ossa-opts">,

0 commit comments

Comments
 (0)