Skip to content

Commit ae9a0c1

Browse files
authored
Merge pull request #66334 from al45tair/eng/PR-110261430
[Backtracing][Linux] Add Linux crash handler to the runtime.
2 parents fe6f8f5 + 979b749 commit ae9a0c1

File tree

8 files changed

+1087
-7
lines changed

8 files changed

+1087
-7
lines changed

include/swift/Runtime/Backtrace.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@
1717
#ifndef SWIFT_RUNTIME_BACKTRACE_H
1818
#define SWIFT_RUNTIME_BACKTRACE_H
1919

20+
#ifdef __linux__
21+
#include <sys/types.h>
22+
#include <sys/wait.h>
23+
24+
#include <signal.h>
25+
#endif // defined(__linux__)
26+
2027
#include "swift/Runtime/Config.h"
28+
#include "swift/Runtime/CrashInfo.h"
2129

2230
#include "swift/shims/Visibility.h"
23-
#include "swift/shims/CrashInfo.h"
2431

2532
#include <inttypes.h>
2633

@@ -50,7 +57,11 @@ typedef int ErrorCode;
5057

5158
SWIFT_RUNTIME_STDLIB_INTERNAL ErrorCode _swift_installCrashHandler();
5259

60+
#ifdef __linux__
61+
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd);
62+
#else
5363
SWIFT_RUNTIME_STDLIB_INTERNAL bool _swift_spawnBacktracer(const ArgChar * const *argv);
64+
#endif
5465

5566
enum class UnwindAlgorithm {
5667
Auto = 0,
@@ -125,6 +136,39 @@ SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings;
125136

126137
SWIFT_RUNTIME_STDLIB_SPI SWIFT_CC(swift) bool _swift_isThunkFunction(const char *mangledName);
127138

139+
/// Try to demangle a symbol.
140+
///
141+
/// Unlike other entry points that do this, we try both Swift and C++ here.
142+
///
143+
/// @param mangledName is the symbol name to be demangled.
144+
/// @param mangledNameLength is the length of this name.
145+
/// @param outputBuffer is a pointer to a buffer in which to place the result.
146+
/// @param outputBufferSize points to a variable that contains the size of the
147+
/// output buffer.
148+
/// @param status returns the status codes defined in the C++ ABI.
149+
///
150+
/// If outputBuffer is nullptr, the function will allocate memory for the
151+
/// result using malloc(). In this case, outputBufferSize may be nullptr;
152+
/// if it is *not* nullptr, it will be set to the size of buffer that was
153+
/// allocated. This is not necessarily the length of the string (it may be
154+
/// somewhat higher).
155+
///
156+
/// Otherwise, the result will be written into the output buffer, and the
157+
/// size of the result will be written into outputBufferSize. If the buffer
158+
/// is too small, the result will be truncated, but outputBufferSize will
159+
/// still be set to the number of bytes that would have been required to
160+
/// copy out the full result (including a trailing NUL).
161+
///
162+
/// The unusual behaviour here is a consequence of the way the C++ ABI's
163+
/// demangling function works.
164+
///
165+
/// @returns a pointer to the output if demangling was successful.
166+
SWIFT_RUNTIME_STDLIB_SPI
167+
char *_swift_backtrace_demangle(const char *mangledName,
168+
size_t mangledNameLength,
169+
char *outputBuffer,
170+
size_t *outputBufferSize,
171+
int *status);
128172
#ifdef __cplusplus
129173
} // namespace backtrace
130174
} // namespace runtime

include/swift/Runtime/CrashInfo.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===--- CrashInfo.h - Swift Backtracing Crash Information ------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2023 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+
// Defines the CrashInfo type that holds information about why the program
14+
// crashed.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_CRASHINFO_H
19+
#define SWIFT_CRASHINFO_H
20+
21+
#include <inttypes.h>
22+
23+
#ifdef __cplusplus
24+
namespace swift {
25+
namespace runtime {
26+
namespace backtrace {
27+
extern "C" {
28+
#endif
29+
30+
// Note: The "pointers" below are pointers in a different process's address
31+
// space, which might not even share our bitness. That is why they are
32+
// `uint64_t`s, rather than pointers or `uintptr_t`s.
33+
34+
// The address of this structure in memory is passed to swift-backtrace.
35+
struct CrashInfo {
36+
// The thread ID for the crashing thread.
37+
uint64_t crashing_thread;
38+
39+
// The signal number corresponding to this crash.
40+
uint64_t signal;
41+
42+
// The fault address.
43+
uint64_t fault_address;
44+
45+
#ifdef __APPLE__
46+
// Points to the mcontext_t structure for the crashing thread; other
47+
// threads' contexts can be recovered using Mach APIs later.
48+
uint64_t mctx;
49+
#elif defined(__linux__)
50+
// The head of the thread list; points at a "struct thread" (see below).
51+
uint64_t thread_list;
52+
#endif
53+
};
54+
55+
#ifdef __linux__
56+
57+
// A memory server request packet.
58+
struct memserver_req {
59+
// Address to read.
60+
uint64_t addr;
61+
62+
// Number of bytes to read.
63+
uint64_t len;
64+
};
65+
66+
// A memory server response packet.
67+
struct memserver_resp {
68+
// Address that was read from.
69+
uint64_t addr;
70+
71+
// Number of bytes, *or* negative to indicate an error.
72+
int64_t len;
73+
74+
// Followed by len bytes of data if len > 0
75+
};
76+
77+
// Holds details of a running thread.
78+
struct thread {
79+
// Points at the next thread.
80+
uint64_t next;
81+
82+
// The thread ID for this thread.
83+
int64_t tid;
84+
85+
// Points to the Linux ucontext_t structure.
86+
uint64_t uctx;
87+
};
88+
89+
#endif
90+
91+
#ifdef __cplusplus
92+
} // extern "C"
93+
} // namespace backtrace
94+
} // namespace runtime
95+
} // namespace swift
96+
#endif
97+
98+
#endif // SWIFT_CRASHINFO_H

include/swift/Runtime/Debug.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ swift_dynamicCastFailure(const void *sourceType, const char *sourceName,
124124
SWIFT_RUNTIME_EXPORT
125125
void swift_reportError(uint32_t flags, const char *message);
126126

127+
SWIFT_RUNTIME_EXPORT
128+
void swift_reportWarning(uint32_t flags, const char *message);
129+
127130
// Halt due to an overflow in swift_retain().
128131
SWIFT_RUNTIME_ATTRIBUTE_NORETURN SWIFT_RUNTIME_ATTRIBUTE_NOINLINE
129132
void swift_abortRetainOverflow();

stdlib/public/runtime/Backtrace.cpp

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
#include <cstring>
5353
#include <cerrno>
5454

55+
#ifdef _WIN32
56+
// We'll probably want dbghelp.h here
57+
#else
58+
#include <cxxabi.h>
59+
#endif
60+
5561
#define DEBUG_BACKTRACING_SETTINGS 0
5662

5763
#ifndef lengthof
@@ -773,6 +779,54 @@ _swift_backtraceSetupEnvironment()
773779
*penv = 0;
774780
}
775781

782+
#ifdef __linux__
783+
struct spawn_info {
784+
const char *path;
785+
char * const *argv;
786+
char * const *envp;
787+
int memserver;
788+
};
789+
790+
uint8_t spawn_stack[4096];
791+
792+
int
793+
do_spawn(void *ptr) {
794+
struct spawn_info *pinfo = (struct spawn_info *)ptr;
795+
796+
/* Ensure that the memory server is always on fd 4 */
797+
if (pinfo->memserver != 4) {
798+
dup2(pinfo->memserver, 4);
799+
close(pinfo->memserver);
800+
}
801+
802+
/* Clear the signal mask */
803+
sigset_t mask;
804+
sigfillset(&mask);
805+
sigprocmask(SIG_UNBLOCK, &mask, NULL);
806+
807+
return execvpe(pinfo->path, pinfo->argv, pinfo->envp);
808+
}
809+
810+
int
811+
safe_spawn(pid_t *ppid, const char *path, int memserver,
812+
char * const argv[], char * const envp[])
813+
{
814+
struct spawn_info info = { path, argv, envp, memserver };
815+
816+
/* The CLONE_VFORK is *required* because info is on the stack; we don't
817+
want to return until *after* the subprocess has called execvpe(). */
818+
int ret = clone(do_spawn, spawn_stack + sizeof(spawn_stack),
819+
CLONE_VFORK|CLONE_VM, &info);
820+
if (ret < 0)
821+
return ret;
822+
823+
close(memserver);
824+
825+
*ppid = ret;
826+
return 0;
827+
}
828+
#endif // defined(__linux__)
829+
776830
#endif // SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
777831

778832
} // namespace
@@ -796,13 +850,93 @@ _swift_isThunkFunction(const char *mangledName) {
796850
return ctx.isThunkSymbol(mangledName);
797851
}
798852

853+
// Try to demangle a symbol.
854+
SWIFT_RUNTIME_STDLIB_SPI char *
855+
_swift_backtrace_demangle(const char *mangledName,
856+
size_t mangledNameLength,
857+
char *outputBuffer,
858+
size_t *outputBufferSize,
859+
int *status) {
860+
llvm::StringRef name = llvm::StringRef(mangledName, mangledNameLength);
861+
862+
// You must provide buffer size if you're providing your own output buffer
863+
if (outputBuffer && !outputBufferSize) {
864+
return nullptr;
865+
}
866+
867+
if (Demangle::isSwiftSymbol(name)) {
868+
// This is a Swift mangling
869+
auto options = DemangleOptions::SimplifiedUIDemangleOptions();
870+
auto result = Demangle::demangleSymbolAsString(name, options);
871+
size_t bufferSize;
872+
873+
if (outputBufferSize) {
874+
bufferSize = *outputBufferSize;
875+
*outputBufferSize = result.length() + 1;
876+
}
877+
878+
if (outputBuffer == nullptr) {
879+
outputBuffer = (char *)::malloc(result.length() + 1);
880+
bufferSize = result.length() + 1;
881+
}
882+
883+
size_t toCopy = std::min(bufferSize - 1, result.length());
884+
::memcpy(outputBuffer, result.data(), toCopy);
885+
outputBuffer[toCopy] = '\0';
886+
887+
*status = 0;
888+
return outputBuffer;
889+
#ifndef _WIN32
890+
} else if (name.startswith("_Z")) {
891+
// Try C++
892+
size_t resultLen;
893+
char *result = abi::__cxa_demangle(mangledName, nullptr, &resultLen, status);
894+
895+
if (result) {
896+
size_t bufferSize;
897+
898+
if (outputBufferSize) {
899+
bufferSize = *outputBufferSize;
900+
*outputBufferSize = resultLen;
901+
}
902+
903+
if (outputBuffer == nullptr) {
904+
return result;
905+
}
906+
907+
size_t toCopy = std::min(bufferSize - 1, resultLen - 1);
908+
::memcpy(outputBuffer, result, toCopy);
909+
outputBuffer[toCopy] = '\0';
910+
911+
free(result);
912+
913+
*status = 0;
914+
return outputBuffer;
915+
}
916+
#else
917+
// On Windows, the mangling is different.
918+
// ###TODO: Call __unDName()
919+
#endif
920+
} else {
921+
*status = -2;
922+
}
923+
924+
return nullptr;
925+
}
926+
799927
// N.B. THIS FUNCTION MUST BE SAFE TO USE FROM A CRASH HANDLER. On Linux
800928
// and macOS, that means it must be async-signal-safe. On Windows, there
801929
// isn't an equivalent notion but a similar restriction applies.
802930
SWIFT_RUNTIME_STDLIB_INTERNAL bool
931+
#ifdef __linux__
932+
_swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd)
933+
#else
803934
_swift_spawnBacktracer(const ArgChar * const *argv)
935+
#endif
804936
{
805-
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
937+
#if !SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
938+
return false;
939+
#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST || defined(__linux__)
806940
pid_t child;
807941
const char *env[BACKTRACE_MAX_ENV_VARS + 1];
808942

@@ -817,10 +951,16 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
817951

818952
// SUSv3 says argv and envp are "completely constant" and that the reason
819953
// posix_spawn() et al use char * const * is for compatibility.
954+
#ifdef __linux__
955+
int ret = safe_spawn(&child, swiftBacktracePath, memserver_fd,
956+
const_cast<char * const *>(argv),
957+
const_cast<char * const *>(env));
958+
#else
820959
int ret = posix_spawn(&child, swiftBacktracePath,
821960
&backtraceFileActions, &backtraceSpawnAttrs,
822961
const_cast<char * const *>(argv),
823962
const_cast<char * const *>(env));
963+
#endif
824964
if (ret < 0)
825965
return false;
826966

@@ -835,10 +975,7 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
835975

836976
return false;
837977

838-
// ###TODO: Linux
839978
// ###TODO: Windows
840-
#else
841-
return false;
842979
#endif
843980
}
844981

stdlib/public/runtime/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ set(swift_runtime_sources
8181

8282
set(swift_runtime_backtracing_sources
8383
Backtrace.cpp
84-
CrashHandlerMacOS.cpp)
84+
CrashHandlerMacOS.cpp
85+
CrashHandlerLinux.cpp)
8586

8687
# Acknowledge that the following sources are known.
8788
set(LLVM_OPTIONAL_SOURCES

0 commit comments

Comments
 (0)