Skip to content

Commit 2dcaa6f

Browse files
committed
[Backtracing][Linux] Add Linux crash handler to the runtime.
This also adds a function to demangle a symbol, and a way for the backtracing code to report warning messages to the same place as the main runtime. I'd like to rename the _swift_isThunkFunction() SPI also, but we can't do that until we've made the changes to the _Backtracing library, so we'll do that there instead. rdar://110261430
1 parent 73df9f2 commit 2dcaa6f

File tree

7 files changed

+959
-9
lines changed

7 files changed

+959
-9
lines changed

include/swift/Runtime/Backtrace.h

Lines changed: 18 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,12 @@ SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings;
125136

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

139+
SWIFT_RUNTIME_STDLIB_SPI
140+
char *_swift_backtrace_demangle(const char *mangledName,
141+
size_t mangledNameLength,
142+
char *outputBuffer,
143+
size_t *outputBufferSize,
144+
int *status);
128145
#ifdef __cplusplus
129146
} // namespace backtrace
130147
} // namespace runtime

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: 159 additions & 6 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
@@ -70,7 +76,7 @@ SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings = {
7076
// enabled
7177
#if TARGET_OS_OSX
7278
OnOffTty::TTY,
73-
#elif 0 // defined(__linux__) || defined(_WIN32)
79+
#elif defined(__linux__) // || defined(_WIN32)
7480
OnOffTty::On,
7581
#else
7682
OnOffTty::Off,
@@ -80,7 +86,7 @@ SWIFT_RUNTIME_STDLIB_INTERNAL BacktraceSettings _swift_backtraceSettings = {
8086
true,
8187

8288
// interactive
83-
#if TARGET_OS_OSX // || defined(__linux__) || defined(_WIN32)
89+
#if TARGET_OS_OSX || defined(__linux__) // || defined(_WIN32)
8490
OnOffTty::TTY,
8591
#else
8692
OnOffTty::Off,
@@ -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,109 @@ _swift_isThunkFunction(const char *mangledName) {
796850
return ctx.isThunkSymbol(mangledName);
797851
}
798852

853+
/// Try to demangle a symbol.
854+
///
855+
/// Unlike other entry points that do this, we try both Swift and C++ here.
856+
///
857+
/// @param mangledName is the symbol name to be demangled.
858+
/// @param mangledNameLength is the length of this name.
859+
/// @param outputBuffer is a pointer to a buffer in which to place the result.
860+
/// @param outputBufferSize points to a variable that will be filled in with
861+
/// the size of the allocated buffer (NOT the length of the result).
862+
/// @param status returns the status codes defined in the C++ ABI.
863+
///
864+
/// If outputBuffer and outputBufferSize are both nullptr, this function will
865+
/// allocate memory for the result using malloc().
866+
///
867+
/// If outputBuffer is nullptr but outputBufferSize is not, the function will
868+
/// fill outputBufferSize with the required buffer size and return nullptr.
869+
///
870+
/// Otherwise, the result will be written into the output buffer, and the
871+
/// size of the result will be written into outputBufferSize. If the buffer
872+
/// is too small, the result will be truncated, but outputBufferSize will
873+
/// still be set to the number of bytes that would have been required to
874+
/// copy out the full result (including a trailing NUL).
875+
///
876+
/// @returns `true` if demangling was successful.
877+
SWIFT_RUNTIME_STDLIB_SPI char *
878+
_swift_backtrace_demangle(const char *mangledName,
879+
size_t mangledNameLength,
880+
char *outputBuffer,
881+
size_t *outputBufferSize,
882+
int *status) {
883+
llvm::StringRef name = llvm::StringRef(mangledName, mangledNameLength);
884+
885+
if (Demangle::isSwiftSymbol(name)) {
886+
// This is a Swift mangling
887+
auto options = DemangleOptions::SimplifiedUIDemangleOptions();
888+
auto result = Demangle::demangleSymbolAsString(name, options);
889+
size_t bufferSize;
890+
891+
if (outputBufferSize) {
892+
bufferSize = *outputBufferSize;
893+
*outputBufferSize = result.length() + 1;
894+
}
895+
896+
if (outputBuffer == nullptr) {
897+
outputBuffer = (char *)::malloc(result.length() + 1);
898+
bufferSize = result.length() + 1;
899+
}
900+
901+
size_t toCopy = std::min(bufferSize - 1, result.length());
902+
::memcpy(outputBuffer, result.data(), toCopy);
903+
outputBuffer[toCopy] = '\0';
904+
905+
*status = 0;
906+
return outputBuffer;
907+
#ifndef _WIN32
908+
} else if (name.startswith("_Z")) {
909+
// Try C++
910+
size_t resultLen;
911+
char *result = abi::__cxa_demangle(mangledName, nullptr, &resultLen, status);
912+
913+
if (result) {
914+
size_t bufferSize;
915+
916+
if (outputBufferSize) {
917+
bufferSize = *outputBufferSize;
918+
*outputBufferSize = resultLen;
919+
}
920+
921+
if (outputBuffer == nullptr) {
922+
return result;
923+
}
924+
925+
size_t toCopy = std::min(bufferSize - 1, resultLen - 1);
926+
::memcpy(outputBuffer, result, toCopy);
927+
outputBuffer[toCopy] = '\0';
928+
929+
*status = 0;
930+
return outputBuffer;
931+
}
932+
#else
933+
// On Windows, the mangling is different.
934+
// ###TODO: Call __unDName()
935+
#endif
936+
} else {
937+
*status = -2;
938+
}
939+
940+
return nullptr;
941+
}
942+
799943
// N.B. THIS FUNCTION MUST BE SAFE TO USE FROM A CRASH HANDLER. On Linux
800944
// and macOS, that means it must be async-signal-safe. On Windows, there
801945
// isn't an equivalent notion but a similar restriction applies.
802946
SWIFT_RUNTIME_STDLIB_INTERNAL bool
947+
#ifdef __linux__
948+
_swift_spawnBacktracer(const ArgChar * const *argv, int memserver_fd)
949+
#else
803950
_swift_spawnBacktracer(const ArgChar * const *argv)
951+
#endif
804952
{
805-
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
953+
#if !SWIFT_BACKTRACE_ON_CRASH_SUPPORTED
954+
return false;
955+
#elif TARGET_OS_OSX || TARGET_OS_MACCATALYST || defined(__linux__)
806956
pid_t child;
807957
const char *env[BACKTRACE_MAX_ENV_VARS + 1];
808958

@@ -817,10 +967,16 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
817967

818968
// SUSv3 says argv and envp are "completely constant" and that the reason
819969
// posix_spawn() et al use char * const * is for compatibility.
970+
#ifdef __linux__
971+
int ret = safe_spawn(&child, swiftBacktracePath, memserver_fd,
972+
const_cast<char * const *>(argv),
973+
const_cast<char * const *>(env));
974+
#else
820975
int ret = posix_spawn(&child, swiftBacktracePath,
821976
&backtraceFileActions, &backtraceSpawnAttrs,
822977
const_cast<char * const *>(argv),
823978
const_cast<char * const *>(env));
979+
#endif
824980
if (ret < 0)
825981
return false;
826982

@@ -835,10 +991,7 @@ _swift_spawnBacktracer(const ArgChar * const *argv)
835991

836992
return false;
837993

838-
// ###TODO: Linux
839994
// ###TODO: Windows
840-
#else
841-
return false;
842995
#endif
843996
}
844997

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)