コード例 #1
0
static char *
mono_extension_handle_native_sigsegv_libunwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
{
    char *dl_err;
    int unw_err;

    unw_init_local_t unw_init_local_fn;
    unw_get_reg_t unw_get_reg_fn;
    unw_get_proc_name_t unw_get_proc_name_fn;
    unw_step_t unw_step_fn;

    unw_cursor_t cursor;

    size_t frames = 0;

    MonoDl *dl = mono_dl_open ("libunwind.so", MONO_DL_LAZY, &dl_err);

    if (!dl)
        return dl_err;

    LOAD_SYM (dl, dl_err, UNW_OBJ (init_local), unw_init_local_fn);
    LOAD_SYM (dl, dl_err, UNW_OBJ (get_reg), unw_get_reg_fn);
    LOAD_SYM (dl, dl_err, UNW_OBJ (get_proc_name), unw_get_proc_name_fn);
    LOAD_SYM (dl, dl_err, UNW_OBJ (step), unw_step_fn);

    if ((unw_err = unw_init_local_fn (&cursor, ctx))) {
        mono_dl_close (dl);

        return g_strdup_printf ("unw_init_local () returned %d", unw_err);
    }

    do {
        int reg_err;

        unw_word_t ip, off;
        char name [FUNC_NAME_LENGTH];

        if ((reg_err = unw_get_reg_fn (&cursor, UNW_REG_IP, &ip))) {
            mono_runtime_printf_err ("unw_get_reg (UNW_REG_IP) returned %d", reg_err);
            break;
        }

        reg_err = unw_get_proc_name_fn (&cursor, name, FUNC_NAME_LENGTH, &off);

        if (reg_err == -UNW_ENOINFO)
            strcpy (name, "???");

        mono_runtime_printf_err (" at %s+%zu [0x%zx]", name, off, ip);

        unw_err = unw_step_fn (&cursor);
        frames++;
    } while (unw_err > 0 && frames < FRAMES_TO_UNWIND);

    if (unw_err < 0)
        mono_runtime_printf_err ("unw_step () returned %d", unw_err);

    mono_dl_close (dl);

    return NULL;
}
コード例 #2
0
static void
print_process_map (void)
{
#ifdef __linux__
	FILE *fp = fopen ("/proc/self/maps", "r");
	char line [256];

	if (fp == NULL) {
		mono_runtime_printf_err ("no /proc/self/maps, not on linux?\n");
		return;
	}

	mono_runtime_printf_err ("/proc/self/maps:");
	const int max_lines = 25;
	int i = 0;

	while (fgets (line, sizeof (line), fp) && i++ < max_lines) {
		// strip newline
		size_t len = strlen (line);
		if (len > 0 && line [len - 1] == '\n')
			line [len - 1] = '\0';

		mono_runtime_printf_err ("%s", line);
	}

	fclose (fp);
#else
	/* do nothing */
#endif
}
コード例 #3
0
void
mono_exception_native_unwind (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
{
    char *unwind_err, *corkscrew_err;

    mono_runtime_printf_err ("\nAttempting native Android stacktrace:\n");

    unwind_err = mono_extension_handle_native_sigsegv_libunwind (ctx, info);

    if (unwind_err) {
        corkscrew_err = mono_extension_handle_native_sigsegv_libcorkscrew (ctx, info);

        if (corkscrew_err) {
            mono_runtime_printf_err ("\tCould not unwind with `libunwind.so`: %s", unwind_err);
            mono_runtime_printf_err ("\tCould not unwind with `libcorkscrew.so`: %s", corkscrew_err);
            mono_runtime_printf_err ("\n\tNo options left to get a native stacktrace :-(");

            g_free (corkscrew_err);
        }

        g_free (unwind_err);
    }
}
コード例 #4
0
ファイル: exception.c プロジェクト: ItsVeryWindy/mono
void
mono_invoke_unhandled_exception_hook (MonoObject *exc)
{
	if (unhandled_exception_hook) {
		unhandled_exception_hook (exc, unhandled_exception_hook_data);
	} else {
		MonoError inner_error;
		MonoObject *other = NULL;
		MonoString *str = mono_object_try_to_string (exc, &other, &inner_error);
		char *msg = NULL;
		
		if (str && is_ok (&inner_error)) {
			msg = mono_string_to_utf8_checked (str, &inner_error);
			if (!is_ok (&inner_error)) {
				msg = g_strdup_printf ("Nested exception while formatting original exception");
				mono_error_cleanup (&inner_error);
			}
		} else if (other) {
			char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
			char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other);

			msg = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
				original_backtrace, nested_backtrace);

			g_free (original_backtrace);
			g_free (nested_backtrace);
		} else {
			msg = g_strdup ("Nested exception trying to figure out what went wrong");
		}
		mono_runtime_printf_err ("[ERROR] FATAL UNHANDLED EXCEPTION: %s", msg);
		g_free (msg);
#if defined(HOST_IOS)
		g_assertion_message ("Terminating runtime due to unhandled exception");
#else
		exit (mono_environment_exitcode_get ());
#endif
	}

	g_assert_not_reached ();
}
コード例 #5
0
static char *
mono_extension_handle_native_sigsegv_libcorkscrew (void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
{
#if defined (__arm__) || defined (__i386__)
    char *dl_err;

    get_backtrace_symbols_t get_backtrace_symbols;
    free_backtrace_symbols_t free_backtrace_symbols;
    unwind_backtrace_signal_arch_t unwind_backtrace_signal_arch;
    acquire_my_map_info_list_t acquire_my_map_info_list;
    release_my_map_info_list_t release_my_map_info_list;

    backtrace_frame_t frames [FRAMES_TO_UNWIND];
    backtrace_symbol_t symbols [FRAMES_TO_UNWIND];

    map_info_t *map_info;
    ssize_t frames_unwound;
    size_t i;

    MonoDl *dl = mono_dl_open ("libcorkscrew.so", MONO_DL_LAZY, &dl_err);

    if (!dl)
        return dl_err;

    LOAD_SYM (dl, dl_err, get_backtrace_symbols, get_backtrace_symbols);
    LOAD_SYM (dl, dl_err, free_backtrace_symbols, free_backtrace_symbols);
    LOAD_SYM (dl, dl_err, unwind_backtrace_signal_arch, unwind_backtrace_signal_arch);
    LOAD_SYM (dl, dl_err, acquire_my_map_info_list, acquire_my_map_info_list);
    LOAD_SYM (dl, dl_err, release_my_map_info_list, release_my_map_info_list);

    map_info = acquire_my_map_info_list ();
    frames_unwound = unwind_backtrace_signal_arch (info, ctx, map_info, frames, 0, FRAMES_TO_UNWIND);
    release_my_map_info_list (map_info);

    if (frames_unwound == -1) {
        mono_dl_close (dl);

        return g_strdup ("unwind_backtrace_signal_arch () returned -1");
    }

    get_backtrace_symbols (frames, frames_unwound, symbols);

    for (i = 0; i < frames_unwound; i++) {
        backtrace_frame_t *frame = frames + i;
        backtrace_symbol_t *symbol = symbols + i;

        const char *name = symbol->demangled_name ? symbol->demangled_name : (symbol->symbol_name ? symbol->symbol_name : "???");
        uintptr_t off = symbol->relative_pc - symbol->relative_symbol_addr;
        uintptr_t ip = frame->absolute_pc;

        mono_runtime_printf_err ("  at %s+%zu [0x%zx]", name, off, ip);
    }

    free_backtrace_symbols (symbols, frames_unwound);

    mono_dl_close (dl);

    return NULL;
#else
    return g_strdup ("libcorkscrew is only supported on 32-bit ARM/x86");
#endif
}
コード例 #6
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
}