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
     }
 }