From 1d05e330c0ebe202015cd6528e209e9116b1840e Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 21 Sep 2023 15:03:51 +0100 Subject: [PATCH 1/3] [Linux] Force the inclusion of the backtracing code when static linking. When we're statically linking the standard library, we need to force the inclusion of the backtracing code in the runtime, otherwise we don't get on-crash backtraces. Also, add a test to make sure that this works. rdar://115774613 --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 6 +++ test/Backtracing/CrashStatic.swift | 60 ++++++++++++++++++++++ test/lit.cfg | 6 +++ 3 files changed, 72 insertions(+) create mode 100644 test/Backtracing/CrashStatic.swift diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index e68103a6a6750..ff3ac5b192a4a 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -12,6 +12,7 @@ #include "ImageInspectionCommon.h" #include "swift/shims/MetadataSections.h" +#include "swift/Runtime/Backtrace.h" #include #include @@ -24,6 +25,11 @@ extern "C" const char __dso_handle[]; static constexpr const void *__dso_handle = nullptr; #endif +// Drag in a symbol from the backtracer, to force the static linker to include +// the code. +static const void *__backtraceRef __attribute__((used)) + = (const void *)swift::runtime::backtrace::_swift_backtrace_isThunkFunction; + // Create empty sections to ensure that the start/stop symbols are synthesized // by the linker. Otherwise, we may end up with undefined symbol references as // the linker table section was never constructed. diff --git a/test/Backtracing/CrashStatic.swift b/test/Backtracing/CrashStatic.swift new file mode 100644 index 0000000000000..9449569675225 --- /dev/null +++ b/test/Backtracing/CrashStatic.swift @@ -0,0 +1,60 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -parse-as-library %import-libdispatch -Onone -static-stdlib -g -o %t/CrashStatic +// RUN: %target-codesign %t/CrashStatic +// RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,swift-backtrace=%backtracer %target-run %t/CrashStatic 2>&1 || true) | %FileCheck %s + +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime +// UNSUPPORTED: asan +// REQUIRES: executable_test +// REQUIRES: backtracing +// REQUIRES: static_stdlib +// REQUIRES: OS=linux-gnu + +func level1() { + level2() +} + +func level2() { + level3() +} + +func level3() { + level4() +} + +func level4() { + level5() +} + +func level5() { + print("About to crash") + let ptr = UnsafeMutablePointer(bitPattern: 4)! + ptr.pointee = 42 +} + +@main +struct CrashStatic { + static func main() { + level1() + } +} + +// CHECK: *** Program crashed: Bad pointer dereference at 0x{{0+}}4 *** + +// CHECK: Thread 0 {{(".*" )?}}crashed: + +// CHECK: 0 0x{{[0-9a-f]+}} level5() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:33:15 +// CHECK-NEXT: 1 [ra] 0x{{[0-9a-f]+}} level4() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:27:3 +// CHECK-NEXT: 2 [ra] 0x{{[0-9a-f]+}} level3() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:23:3 +// CHECK-NEXT: 3 [ra] 0x{{[0-9a-f]+}} level2() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:19:3 +// CHECK-NEXT: 4 [ra] 0x{{[0-9a-f]+}} level1() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:15:3 +// CHECK-NEXT: 5 [ra] 0x{{[0-9a-f]+}} static CrashStatic.main() + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift:39:5 +// CHECK-NEXT: 6 [ra] [system] 0x{{[0-9a-f]+}} static CrashStatic.$main() + {{[0-9]+}} in CrashStatic at {{.*}}/ +// CHECK-NEXT: 7 [ra] 0x{{[0-9a-f]+}} main + {{[0-9]+}} in CrashStatic at {{.*}}/CrashStatic.swift + +// CHECK: Registers: + +// CHECK: Images ({{[0-9]+}} omitted): + +// CHECK: {{0x[0-9a-f]+}}–{{0x[0-9a-f]+}}{{ +}}{{([0-9a-f]+|)}}{{ +}}CrashStatic{{ +}}{{.*}}/CrashStatic diff --git a/test/lit.cfg b/test/lit.cfg index 3d2e305ac69d9..a7a2f96184fa7 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -354,6 +354,7 @@ config.scale_test = make_path(config.swift_utils, 'scale-test') config.PathSanitizingFileCheck = make_path(config.swift_utils, 'PathSanitizingFileCheck') config.swift_bin_dir = make_path(config.swift, '..', '..', 'bin') config.swift_lib_dir = make_path(config.swift, '..', '..', 'lib') +config.swift_libexec_dir = make_path(config.swift, '..', '..', 'libexec') config.swift_share_dir = make_path(config.swift, '..', '..', 'share') config.round_trip_syntax_test = make_path(config.swift_utils, 'round-trip-syntax-test') config.refactor_check_compiles = make_path(config.swift_utils, 'refactor-check-compiles.py') @@ -588,6 +589,7 @@ else: config.substitutions.append( ('%llvm_obj_root', config.llvm_obj_root) ) config.substitutions.append( ('%swift-bin-dir', config.swift_bin_dir) ) config.substitutions.append( ('%swift-lib-dir', config.swift_lib_dir) ) +config.substitutions.append( ('%swift-libexec-dir', config.swift_lib_dir) ) config.substitutions.append( ('%swift-share-dir', config.swift_share_dir) ) config.substitutions.append( ('%swift-plugin-dir', config.swift_plugin_dir) ) config.substitutions.append( ('%llvm_src_root', config.llvm_src_root) ) @@ -1996,6 +1998,10 @@ if run_vendor == 'apple': config.available_features.add('back_deploy_concurrency') concurrency_back_deploy_path = os.path.join(os.path.dirname(swift_obj_root), os.path.basename(swift_obj_root).replace("swift-", "backdeployconcurrency-"), 'lib', 'swift-5.5', xcrun_sdk_name) +backtracer_path = make_path(config.swift_libexec_dir, 'swift', + config.target_sdk_name, 'swift-backtrace') +config.substitutions.append(('%backtracer', backtracer_path)) + def os_stdlib_paths(): if run_vendor == 'apple': if run_os == 'maccatalyst': From 380d41201835cb9638fbda35096649bdc7596dd9 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 22 Sep 2023 15:45:54 +0100 Subject: [PATCH 2/3] [Linux][Build] Use host swiftrt.o when in HOSTTOOLS mode. When we're building with host tools, we should use the host's swiftrt.o and not the one we've just built when we're trying to build tools that we will run on the host system. rdar://115774613 --- cmake/modules/AddSwift.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index b55f7d8071656..44b84c7e1333a 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -543,6 +543,7 @@ function(_add_swift_runtime_link_flags target relpath_to_lib_dir bootstrapping) get_filename_component(swift_bin_dir ${SWIFT_EXEC_FOR_SWIFT_MODULES} DIRECTORY) get_filename_component(swift_dir ${swift_bin_dir} DIRECTORY) set(host_lib_dir "${swift_dir}/lib/swift/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_LIB_SUBDIR}") + set(swiftrt "${host_lib_dir}/${SWIFT_HOST_VARIANT_ARCH}/swiftrt.o") target_link_libraries(${target} PRIVATE ${swiftrt}) target_link_libraries(${target} PRIVATE "swiftCore") From 571e1108e53fe8deac301df13fccd04fae8cef0c Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 25 Sep 2023 17:45:22 +0100 Subject: [PATCH 3/3] [Linux][Test] Use import-static-libdispatch not import-libdispatch. We want the static version of Dispatch here. If we don't use that version, we'll fail the tests on the release branches (but strangely not on main for some reason). rdar://115774613 --- test/Backtracing/CrashStatic.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Backtracing/CrashStatic.swift b/test/Backtracing/CrashStatic.swift index 9449569675225..6ada723f484f5 100644 --- a/test/Backtracing/CrashStatic.swift +++ b/test/Backtracing/CrashStatic.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -parse-as-library %import-libdispatch -Onone -static-stdlib -g -o %t/CrashStatic +// RUN: %target-build-swift %s -parse-as-library %import-static-libdispatch -Onone -static-stdlib -g -o %t/CrashStatic // RUN: %target-codesign %t/CrashStatic // RUN: (env SWIFT_BACKTRACE=enable=yes,cache=no,swift-backtrace=%backtracer %target-run %t/CrashStatic 2>&1 || true) | %FileCheck %s