static void mono_init_merp (const intptr_t crashed_pid, const char *signal, MonoStackHash *hashes, MERPStruct *merp, const char *version) { g_assert (mono_merp_enabled ()); // If these aren't set, icall wasn't made // don't do merp? / don't set the variable to use merp; g_assert (config.appBundleID); g_assert (config.appVersion); merp->bundleIDArg = config.appSignature; merp->versionArg = config.appVersion; merp->archArg = get_merp_arch (); merp->exceptionArg = parse_exception_type (signal); merp->serviceNameArg = config.appBundleID; // FIXME: Not really a posix way to associated a process with a single executable // path? Linux gets bogged down in /proc merp->servicePathArg = NULL; if (crashed_pid) { size_t servicePathSize = sizeof (gchar) * 1200; merp->servicePathArg = g_malloc0 (servicePathSize); int result = proc_pidpath (crashed_pid, (void *) merp->servicePathArg, 1200); if (result <= 0) { g_free ((void *) merp->servicePathArg); merp->servicePathArg = NULL; } } merp->moduleName = "Mono Exception"; merp->moduleVersion = version; merp->moduleOffset = 0; ERROR_DECL (error); merp->uiLidArg = ves_icall_System_Threading_Thread_current_lcid (error); mono_error_assert_ok (error); merp->osVersion = os_version_string (); // FIXME: THis is apple-only for now merp->systemManufacturer = "apple"; get_apple_model ((char *) merp->systemModel, sizeof (merp->systemModel)); merp->hashes = *hashes; }
static void mono_init_merp (const intptr_t crashed_pid, const char *signal, MonoStackHash *hashes, MERPStruct *merp) { mono_memory_barrier (); g_assert (mono_merp_enabled ()); merp->merpFilePath = config.merpFilePath; merp->crashLogPath = config.crashLogPath; merp->werXmlPath = config.werXmlPath; // If these aren't set, icall wasn't made // don't do merp? / don't set the variable to use merp; g_assert (config.appBundleID); g_assert (config.appVersion); merp->bundleIDArg = config.appSignature; merp->versionArg = config.appVersion; merp->archArg = get_merp_arch (); merp->exceptionArg = parse_exception_type (signal); merp->serviceNameArg = config.appBundleID; merp->servicePathArg = config.appPath; merp->moduleName = "Mono Exception"; merp->moduleVersion = config.moduleVersion; merp->moduleOffset = 0; merp->uiLidArg = MONO_LOCALE_INVARIANT; merp->osVersion = os_version_string (); // FIXME: THis is apple-only for now merp->systemManufacturer = "apple"; get_apple_model ((char *) merp->systemModel, sizeof (merp->systemModel)); merp->eventType = config.eventType; merp->hashes = *hashes; merp->annotations = config.annotations; }
static void dump_native_stacktrace (const char *signal, void *ctx) { #ifdef HAVE_BACKTRACE_SYMBOLS void *array [256]; char **names; int i, size; mono_runtime_printf_err ("\nNative stacktrace:\n"); size = backtrace (array, 256); names = backtrace_symbols (array, size); for (i = 0; i < size; ++i) { mono_runtime_printf_err ("\t%s", names [i]); } g_free (names); /* Try to get more meaningful information using gdb */ char *debugger_log = mono_debugger_state_str (); if (debugger_log) { fprintf (stderr, "\n\tDebugger session state:\n%s\n", debugger_log); } #if !defined(HOST_WIN32) && defined(HAVE_SYS_SYSCALL_H) && (defined(SYS_fork) || HAVE_FORK) if (!mini_get_debug_options ()->no_gdb_backtrace) { /* From g_spawn_command_line_sync () in eglib */ pid_t pid; int status; pid_t crashed_pid = getpid (); #if defined(TARGET_OSX) MonoStackHash hashes; #endif gchar *output = NULL; MonoContext mctx; if (ctx) { gboolean leave = FALSE; gboolean dump_for_merp = FALSE; #if defined(TARGET_OSX) dump_for_merp = mono_merp_enabled (); #endif if (!dump_for_merp) { #ifdef DISABLE_STRUCTURED_CRASH leave = TRUE; #elif defined(TARGET_OSX) mini_register_sigterm_handler (); #endif } #ifdef TARGET_OSX if (!leave) { mono_sigctx_to_monoctx (ctx, &mctx); // Do before forking if (!mono_threads_summarize (&mctx, &output, &hashes)) g_assert_not_reached (); } // We want our crash, and don't have telemetry // So we dump to disk if (!leave && !dump_for_merp) mono_crash_dump (output); #endif } /* * glibc fork acquires some locks, so if the crash happened inside malloc/free, * it will deadlock. Call the syscall directly instead. */ #if defined(HOST_ANDROID) /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */ g_assert_not_reached (); #elif !defined(HOST_DARWIN) && defined(SYS_fork) pid = (pid_t) syscall (SYS_fork); #elif HAVE_FORK pid = (pid_t) fork (); #else g_assert_not_reached (); #endif #if defined (HAVE_PRCTL) && defined(PR_SET_PTRACER) if (pid > 0) { // Allow gdb to attach to the process even if ptrace_scope sysctl variable is set to // a value other than 0 (the most permissive ptrace scope). Most modern Linux // distributions set the scope to 1 which allows attaching only to direct children of // the current process prctl (PR_SET_PTRACER, pid, 0, 0, 0); } #endif #if defined(TARGET_OSX) if (mono_merp_enabled ()) { if (pid == 0) { if (!ctx) { mono_runtime_printf_err ("\nMust always pass non-null context when using merp.\n"); exit (1); } char *full_version = mono_get_runtime_build_info (); mono_merp_invoke (crashed_pid, signal, output, &hashes, full_version); exit (1); } } #endif if (pid == 0) { dup2 (STDERR_FILENO, STDOUT_FILENO); mono_gdb_render_native_backtraces (crashed_pid); exit (1); } mono_runtime_printf_err ("\nDebug info from gdb:\n"); waitpid (pid, &status, 0); } #endif #else #ifdef HOST_ANDROID /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see: * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206 * this has changed on later versions of Android. Also, we don't want to * set this on start-up as DUMPABLE has security implications. */ prctl (PR_SET_DUMPABLE, 1); mono_runtime_printf_err ("\nNo native Android stacktrace (see debuggerd output).\n"); #endif #endif }
void mono_summarize_timeline_phase_log (MonoSummaryStage next) { if (log.level == MonoSummaryNone) return; if (!log.directory) return; MonoSummaryStage out_level; switch (log.level) { case MonoSummarySetup: out_level = MonoSummarySuspendHandshake; break; case MonoSummarySuspendHandshake: out_level = MonoSummaryUnmanagedStacks; break; case MonoSummaryUnmanagedStacks: out_level = MonoSummaryManagedStacks; break; case MonoSummaryManagedStacks: out_level = MonoSummaryStateWriter; break; case MonoSummaryStateWriter: out_level = MonoSummaryStateWriterDone; break; case MonoSummaryStateWriterDone: #ifdef TARGET_OSX if (mono_merp_enabled ()) { out_level = MonoSummaryMerpWriter; } else #endif { out_level = MonoSummaryCleanup; } break; case MonoSummaryMerpWriter: out_level = MonoSummaryMerpInvoke; break; case MonoSummaryMerpInvoke: out_level = MonoSummaryCleanup; break; case MonoSummaryCleanup: out_level = MonoSummaryDone; break; case MonoSummaryDone: g_async_safe_printf ("Trying to log crash reporter timeline, already at done %d\n", log.level); return; default: g_async_safe_printf ("Trying to log crash reporter timeline, illegal state %d\n", log.level); return; } g_assertf(out_level == next, "Log Error: Log transition to %d, actual expected next step is %d\n", next, out_level); char out_file [200]; memset (out_file, 0, sizeof(out_file)); file_for_summary_stage (log.directory, out_level, out_file, sizeof(out_file)); int handle = g_open (out_file, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); close(handle); // To check, comment out normally // DO NOT MERGE UNCOMMENTED // As this does a lot of FILE io // // g_assert (out_level == mono_summarize_timeline_read_level (log.directory, FALSE)); log.level = out_level; if (out_level == MonoSummaryDone) memset (&log, 0, sizeof (log)); return; }