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.
802946SWIFT_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
0 commit comments