minidumper: use breakpad-providen ExceptionHandler
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt
index 25c57d1..32a6de9 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt
@@ -108,7 +108,7 @@
val stackProtector by option<StackProtectorMode>()
- val miniDumpFile by stringOption()
+ val minidumpLocation by stringOption()
}
open class BinaryOption<T : Any>(
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
index cb109ee..bf1d2dc 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt
@@ -394,8 +394,8 @@
}
}
- val miniDumpFile by lazy {
- configuration.get(BinaryOptions.miniDumpFile)
+ val minidumpLocation by lazy {
+ configuration.get(BinaryOptions.minidumpLocation)
}
val swiftExport by lazy {
diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
index e661178..3f0933f 100644
--- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
+++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt
@@ -2686,7 +2686,7 @@
overrideRuntimeGlobal("Kotlin_latin1Strings", llvm.constInt32(if (context.config.latin1Strings) 1 else 0))
overrideRuntimeGlobal("Kotlin_mmapTag", llvm.constUInt8(context.config.mmapTag))
// FIXME should be weak non-cached global
- val miniDumpFile = context.config.miniDumpFile?.let {
+ val minidumpLocation = context.config.minidumpLocation?.let {
val cstr = ConstArray(
llvm.int8Type,
stringAsBytes(it).map { llvm.constInt8(it) } + listOf(llvm.constInt8(0))
@@ -2696,7 +2696,7 @@
global.setConstant(true)
global.pointer
} ?: constValue(llvm.kNullInt8Ptr)
- overrideRuntimeGlobal("Kotlin_miniDumpFile", miniDumpFile)
+ overrideRuntimeGlobal("Kotlin_minidumpLocation", minidumpLocation)
}
//-------------------------------------------------------------------------//
diff --git a/kotlin-native/runtime/build.gradle.kts b/kotlin-native/runtime/build.gradle.kts
index 97ce1ef..f25cce2 100644
--- a/kotlin-native/runtime/build.gradle.kts
+++ b/kotlin-native/runtime/build.gradle.kts
@@ -92,12 +92,14 @@
module("breakpad") {
srcRoot.set(breakpadLocation)
val sources = listOf(
+ "client/mac/crash_generation/crash_generation_client.cc",
"client/mac/handler/breakpad_nlist_64.cc",
"client/mac/handler/dynamic_images.cc",
"client/mac/handler/exception_handler.cc",
"client/mac/handler/minidump_generator.cc",
"client/mac/handler/protected_memory_allocator.cc",
"client/minidump_file_writer.cc",
+ "common/mac/MachIPC.mm",
"common/mac/arch_utilities.cc",
"common/mac/file_id.cc",
"common/mac/macho_id.cc",
@@ -125,7 +127,6 @@
"-std=c++17",
"-DHAVE_MACH_O_NLIST_H",
"-DHAVE_CONFIG_H",
- "-DTARGET_OS_IPHONE",
))
onlyIf { it.family == Family.OSX }
diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp
index 9137c5f..19e9db7 100644
--- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp
+++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp
@@ -36,7 +36,7 @@
RUNTIME_WEAK int32_t Kotlin_swiftExport = 0;
RUNTIME_WEAK int32_t Kotlin_latin1Strings = 0;
RUNTIME_WEAK uint8_t Kotlin_mmapTag = 0;
-RUNTIME_WEAK const int8_t* Kotlin_miniDumpFile = nullptr;
+RUNTIME_WEAK const int8_t* Kotlin_minidumpLocation = nullptr;
ALWAYS_INLINE bool compiler::gcMutatorsCooperate() noexcept {
return Kotlin_gcMutatorsCooperate != 0;
@@ -103,6 +103,6 @@
ALWAYS_INLINE uint8_t compiler::mmapTag() noexcept {
return Kotlin_mmapTag;
}
-ALWAYS_INLINE const char* compiler::miniDumpFile() noexcept{
-return reinterpret_cast<const char*>(Kotlin_miniDumpFile);
+ALWAYS_INLINE const char* compiler::minidumpLocation() noexcept{
+return reinterpret_cast<const char*>(Kotlin_minidumpLocation);
}
\ No newline at end of file
diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp
index a3cb51d..0e3f75f 100644
--- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp
+++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp
@@ -98,7 +98,7 @@
bool swiftExport() noexcept;
bool latin1Strings() noexcept;
uint8_t mmapTag() noexcept;
-const char* miniDumpFile() noexcept;
+const char* minidumpLocation() noexcept;
#ifdef KONAN_ANDROID
bool printToAndroidLogcat() noexcept;
diff --git a/kotlin-native/runtime/src/main/cpp/CrashHandler.cpp b/kotlin-native/runtime/src/main/cpp/CrashHandler.cpp
index 8a04056..b2c6c31 100644
--- a/kotlin-native/runtime/src/main/cpp/CrashHandler.cpp
+++ b/kotlin-native/runtime/src/main/cpp/CrashHandler.cpp
@@ -10,13 +10,16 @@
#include "Logging.hpp"
#if KONAN_APPLE
-#include "client/mac/handler/minidump_generator.h"
+
+// TODO include no_mach on TVOS/WATCHOS
+#include "client/mac/handler/exception_handler.h"
+
#include <mach/exception_types.h>
#include <mach/mach_init.h>
#endif
namespace {
- constexpr int kSignals[] = {
+ [[maybe_unused]] int kHandledSignals[] = {
//SIGABRT,
SIGBUS,
SIGFPE,
@@ -24,68 +27,30 @@
SIGSEGV,
//SIGTRAP
};
- constexpr auto kNumSignals = std::size(kSignals);
- struct sigaction prevActions[kNumSignals];
-
- // TODO what if we crush from two threads simultaneously?
bool minidumpsEnabled() {
- return kotlin::compiler::miniDumpFile() != nullptr;
+ return kotlin::compiler::minidumpLocation() != nullptr;
}
#if KONAN_APPLE
- bool WriteMinidumpWithException(breakpad_ucontext_t *task_context) {
- google_breakpad::MinidumpGenerator md(mach_task_self(), MACH_PORT_NULL);
- md.SetTaskContext(task_context);
- // FIXME macOS version of minidump generator expect us to catch mach exceptions instead of POSIX signals
- md.SetExceptionInformation(EXC_SOFTWARE, MD_EXCEPTION_CODE_MAC_ABORT, 0, mach_thread_self());
- const char* dumpFile = kotlin::compiler::miniDumpFile();
- if (dumpFile == nullptr) {
- konan::consoleErrorf("No minidump will be written\n");
- return false;
- }
+ std::unique_ptr<google_breakpad::ExceptionHandler> gExceptionHandler = nullptr;
- bool written = md.Write(dumpFile);
- if (written) {
- konan::consoleErrorf("Minidump written to \"%s\"\n", dumpFile);
+ bool exceptionFilter(void* context) {
+ // TODO handle only certain signals?
+ return true;
+ }
+
+ bool minidumpCallback(const char* dump_dir,
+ const char* minidump_id,
+ void* context,
+ bool succeeded) {
+ // TODO handle only certain signals?
+ if (succeeded) {
+ konan::consoleErrorf("Minidump written to \"%s/%s.dmp\"\n", dump_dir, minidump_id);
} else {
- konan::consoleErrorf("Failed to write minidump to \"%s\"\n", dumpFile);
+ konan::consoleErrorf("Failed to write minidump to \"%s/%s.dmp\"\n", dump_dir, minidump_id);
}
- return written;
- }
-
- void CrashRecoverySignalHandler(int signal, siginfo_t* info, void* uc) {
- // TODO llvm checks for context here
-
- // unblock the signal handling
- sigset_t sigMask;
- sigemptyset(&sigMask);
- sigaddset(&sigMask, signal);
- sigprocmask(SIG_UNBLOCK, &sigMask, nullptr); // TODO ONSTACK?
-
- // TODO doublecheck that we are not out of bounds here
- konan::consoleErrorf("A fatal error has been detected: %s\n", sys_siglist[signal]);
- // TODO chack manually, that a SEGFAULT somewhere here will be properly handled
- WriteMinidumpWithException(static_cast<breakpad_ucontext_t*>(uc));
- std::abort();
- }
-
- void installExceptionOrSignalHandlers() {
- struct sigaction handler{};
- handler.sa_sigaction = CrashRecoverySignalHandler;
- handler.sa_flags = SA_SIGINFO;
- sigemptyset(&handler.sa_mask);
-
- for (unsigned i = 0; i != kNumSignals; ++i) {
- sigaction(kSignals[i], &handler, &prevActions[i]);
- }
- }
-
- // TODO should we do this somewhere?
- [[maybe_unused]] void uninstallExceptionOrSignalHandlers() {
- for (unsigned i = 0; i != kNumSignals; ++i) {
- sigaction(kSignals[i], &prevActions[i], nullptr);
- }
+ return false; // false -> do not abort the process and let other handlers to be called
}
#endif
}
@@ -93,8 +58,17 @@
void kotlin::crashHandlerInit() noexcept {
if (minidumpsEnabled()) {
#if KONAN_APPLE
- RuntimeLogInfo({logging::Tag::kRT}, "Initializing crash handler, minidumps will be written to \"%s\"", compiler::miniDumpFile());
- installExceptionOrSignalHandlers();
+ RuntimeLogInfo({logging::Tag::kRT}, "Initializing crash handler, minidumps will be written to \"%s\"",
+ compiler::minidumpLocation());
+
+ gExceptionHandler = std::make_unique<google_breakpad::ExceptionHandler>(
+ kotlin::compiler::minidumpLocation(),
+ exceptionFilter,
+ minidumpCallback,
+ nullptr,
+ true,
+ nullptr // in-process generation
+ );
#endif
}
}
@@ -102,7 +76,7 @@
void kotlin::writeMinidump() noexcept {
if (minidumpsEnabled()) {
#if KONAN_APPLE
- WriteMinidumpWithException(nullptr);
+ gExceptionHandler->WriteMinidump();
#endif
}
}