Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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
}
Example #4
0
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;
}