[runtime] Call error_init instead of mono_error_init (#4425)
[mono.git] / mono / mini / mini-exceptions.c
index 857bbefef3690bbb093ce76f4aace5cc6f4f0678..e130eb59411d6d759ca059e13d4fff1c39a03365 100644 (file)
@@ -108,7 +108,13 @@ first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
        if (!frame->managed)
                return FALSE;
 
-       *data = MONO_CONTEXT_GET_SP(ctx);
+       if (!ctx) {
+               // FIXME: Happens with llvm_only
+               *data = NULL;
+               return TRUE;
+       }
+
+       *data = MONO_CONTEXT_GET_SP (ctx);
        g_assert (*data);
        return TRUE;
 }
@@ -161,7 +167,10 @@ static inline gboolean
 mini_above_abort_threshold (void)
 {
        gpointer sp = mono_thread_get_managed_sp ();
-       MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData*) mono_tls_get_jit_tls ();
+
+       if (!sp)
+               return TRUE;
 
        gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0;
 
@@ -171,6 +180,15 @@ mini_above_abort_threshold (void)
        return above_threshold;
 }
 
+static int
+mono_get_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
+{
+       SeqPoint sp;
+       if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
+               return sp.il_offset;
+       return -1;
+}
+
 void
 mono_exceptions_init (void)
 {
@@ -216,6 +234,7 @@ mono_exceptions_init (void)
        cbs.mono_clear_abort_threshold = mini_clear_abort_threshold;
        cbs.mono_above_abort_threshold = mini_above_abort_threshold;
        mono_install_eh_callbacks (&cbs);
+       mono_install_get_seq_point (mono_get_seq_point_for_native_offset);
 }
 
 gpointer
@@ -882,7 +901,7 @@ static void
 mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data)
 {
        if (!start_ctx) {
-               MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                if (jit_tls && jit_tls->orig_ex_ctx_set)
                        start_ctx = &jit_tls->orig_ex_ctx;
        }
@@ -1089,7 +1108,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 {
        MonoError error;
        MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji = NULL;
        MonoContext ctx, new_ctx;
@@ -1282,7 +1301,7 @@ mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domai
 }
 
 /* Class lazy loading functions */
-static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, System.Runtime.CompilerServices, RuntimeCompatibilityAttribute)
+static GENERATE_GET_CLASS_WITH_CACHE (runtime_compat_attr, "System.Runtime.CompilerServices", "RuntimeCompatibilityAttribute")
 
 /*
  * wrap_non_exception_throws:
@@ -1356,7 +1375,7 @@ wrap_non_exception_throws (MonoMethod *m)
 static MonoArray*
 build_native_trace (MonoError *error)
 {
-       mono_error_init (error);
+       error_init (error);
 /* This puppy only makes sense on mobile, IOW, ARM. */
 #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM)
        MonoArray *res;
@@ -1381,9 +1400,9 @@ build_native_trace (MonoError *error)
 }
 
 static void
-setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, MonoArray *initial_trace_ips, GList **trace_ips)
+setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, GList **trace_ips)
 {
-       if (mono_ex && !initial_trace_ips) {
+       if (mono_ex) {
                *trace_ips = g_list_reverse (*trace_ips);
                MonoError error;
                MonoArray *ips_arr = mono_glist_to_array (*trace_ips, mono_defaults.int_class, &error);
@@ -1435,9 +1454,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji = NULL;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
-       MonoArray *initial_trace_ips = NULL;
        GList *trace_ips = NULL;
        GSList *dynamic_methods = NULL;
        MonoException *mono_ex;
@@ -1455,12 +1473,19 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                stack_overflow = TRUE;
 
        mono_ex = (MonoException*)obj;
-       initial_trace_ips = mono_ex->trace_ips;
+       MonoArray *initial_trace_ips = mono_ex->trace_ips;
+       if (initial_trace_ips) {
+               int len = mono_array_length (initial_trace_ips) >> 1;
+
+               for (i = 0; i < (len - 1); i++) {
+                       gpointer ip = mono_array_get (initial_trace_ips, gpointer, i * 2 + 0);
+                       gpointer generic_info = mono_array_get (initial_trace_ips, gpointer, i * 2 + 1);
+                       trace_ips = g_list_prepend (trace_ips, ip);
+                       trace_ips = g_list_prepend (trace_ips, generic_info);
+               }
+       }
 
-       if (mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
-               mono_ex = (MonoException*)obj;
-               initial_trace_ips = mono_ex->trace_ips;
-       } else {
+       if (!mono_object_isinst_checked (obj, mono_defaults.exception_class, &error)) {
                mono_error_assert_ok (&error);
                mono_ex = NULL;
        }
@@ -1504,7 +1529,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                }
 
                if (!unwind_res) {
-                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                       setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
                        g_slist_free (dynamic_methods);
                        return FALSE;
                }
@@ -1520,15 +1545,10 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                }
 
                if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
-                       /* 
-                        * Avoid overwriting the stack trace if the exception is
-                        * rethrown. Also avoid giant stack traces during a stack
-                        * overflow.
-                        */
-                       if (!initial_trace_ips && (frame_count < 1000)) {
+                       // avoid giant stack traces during a stack overflow
+                       if (frame_count < 1000) {
                                trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx));
-                               trace_ips = g_list_prepend (trace_ips,
-                                                                                       get_generic_info_from_stack_frame (ji, ctx));
+                               trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx));
                        }
                }
 
@@ -1569,18 +1589,9 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                        ex_obj = obj;
 
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
-                                       gboolean is_user_frame = method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD;
 #ifndef DISABLE_PERFCOUNTERS
                                        mono_perfcounters->exceptions_filters++;
 #endif
-                                       /*
-                                       Here's the thing, if this is a filter clause done by a wrapper like runtime invoke, we don't want to
-                                       trim the stackframe since if it returns FALSE we lose information.
-
-                                       FIXME Not 100% sure if it's a good idea even with user clauses.
-                                       */
-                                       if (is_user_frame)
-                                               setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
 
 #ifndef MONO_CROSS_COMPILE
 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
@@ -1617,8 +1628,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                        filter_idx ++;
 
                                        if (filtered) {
-                                               if (!is_user_frame)
-                                                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                                               setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
                                                g_slist_free (dynamic_methods);
                                                /* mono_debugger_agent_handle_exception () needs this */
                                                mini_set_abort_threshold (ctx);
@@ -1628,9 +1638,9 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
                                }
 
                                MonoError isinst_error;
-                               mono_error_init (&isinst_error);
+                               error_init (&isinst_error);
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) {
-                                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                                       setup_stack_trace (mono_ex, dynamic_methods, &trace_ips);
                                        g_slist_free (dynamic_methods);
 
                                        if (out_ji)
@@ -1663,7 +1673,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji, *prev_ji;
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoException *mono_ex;
        gboolean stack_overflow = FALSE;
@@ -1936,7 +1946,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                        filter_idx ++;
                                }
 
-                               mono_error_init (&error);
+                               error_init (&error);
                                if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
                                     mono_object_isinst_checked (ex_obj, catch_class, &error)) || filtered) {
                                        /*
@@ -2064,7 +2074,7 @@ mono_debugger_run_finally (MonoContext *start_ctx)
 {
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
        MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoLMF *lmf = mono_get_lmf ();
        MonoContext ctx, new_ctx;
        MonoJitInfo *ji, rji;
@@ -2212,7 +2222,7 @@ try_restore_stack_protection (MonoJitTlsData *jit_tls, int extra_bytes)
 static G_GNUC_UNUSED void
 try_more_restore (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        if (try_restore_stack_protection (jit_tls, 500))
                jit_tls->restore_stack_prot = NULL;
 }
@@ -2220,7 +2230,7 @@ try_more_restore (void)
 static G_GNUC_UNUSED void
 restore_stack_protection (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoException *ex = mono_domain_get ()->stack_overflow_ex;
        /* if we can't restore the stack protection, keep a callback installed so
         * we'll try to restore as much stack as we can at each return from unmanaged
@@ -2413,28 +2423,57 @@ print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer d
 
 #ifndef MONO_CROSS_COMPILE
 
+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:");
+
+       while (fgets (line, sizeof (line), fp)) {
+               // strip newline
+               size_t len = strlen (line) - 1;
+               if (len >= 0 && line [len] == '\n')
+                       line [len] = '\0';
+
+               mono_runtime_printf_err ("%s", line);
+       }
+
+       fclose (fp);
+#else
+       /* do nothing */
+#endif
+}
+
 static gboolean handling_sigsegv = FALSE;
 
 /*
- * mono_handle_native_sigsegv:
+ * mono_handle_native_crash:
  *
- *   Handle a SIGSEGV received while in native code by printing diagnostic 
- * information and aborting.
+ *   Handle a native crash (e.g. SIGSEGV) while in native code by
+ *   printing diagnostic information and aborting.
  */
 void
-mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
 {
 #ifdef MONO_ARCH_USE_SIGACTION
        struct sigaction sa;
 #endif
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
-       const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
 
-       if (handling_sigsegv)
+       gboolean is_sigsegv = !strcmp ("SIGSEGV", signal);
+
+       if (handling_sigsegv && is_sigsegv)
                return;
 
-       if (mini_get_debug_options ()->suspend_on_sigsegv) {
-               mono_runtime_printf_err ("Received SIGSEGV, suspending...");
+       if (mini_get_debug_options ()->suspend_on_native_crash) {
+               mono_runtime_printf_err ("Received %s, suspending...", signal);
 #ifdef HOST_WIN32
                while (1)
                        ;
@@ -2446,7 +2485,8 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
        }
 
        /* To prevent infinite loops when the stack walk causes a crash */
-       handling_sigsegv = TRUE;
+       if (is_sigsegv)
+               handling_sigsegv = TRUE;
 
        /* !jit_tls means the thread was not registered with the runtime */
        if (jit_tls && mono_thread_internal_current ()) {
@@ -2456,6 +2496,8 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
                mono_walk_stack (print_stack_frame_to_stderr, MONO_UNWIND_LOOKUP_IL_OFFSET, NULL);
        }
 
+       print_process_map ();
+
 #ifdef HAVE_BACKTRACE_SYMBOLS
  {
        void *array [256];
@@ -2480,12 +2522,21 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
                int status;
                pid_t crashed_pid = getpid ();
 
-               //pid = fork ();
                /*
                 * glibc fork acquires some locks, so if the crash happened inside malloc/free,
                 * it will deadlock. Call the syscall directly instead.
                 */
-               pid = mono_runtime_syscall_fork ();
+#if defined(PLATFORM_ANDROID)
+               /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */
+               g_assert_not_reached ();
+#elif !defined(PLATFORM_MACOSX) && defined(SYS_fork)
+               pid = (pid_t) syscall (SYS_fork);
+#elif defined(PLATFORM_MACOSX) && 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
@@ -2508,7 +2559,15 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
 #endif
  }
 #else
-       mono_exception_native_unwind (ctx, info);
+#ifdef PLATFORM_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
 
        /*
@@ -2523,18 +2582,19 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
                         "a fatal error in the mono runtime or one of the native libraries \n"
                         "used by your application.\n"
                         "=================================================================\n",
-                       signal_str);
-
+                       signal);
 
 #ifdef MONO_ARCH_USE_SIGACTION
-
-       /* Remove our SIGABRT handler */
        sa.sa_handler = SIG_DFL;
        sigemptyset (&sa.sa_mask);
        sa.sa_flags = 0;
 
+       /* Remove our SIGABRT handler */
        g_assert (sigaction (SIGABRT, &sa, NULL) != -1);
 
+       /* On some systems we get a SIGILL when calling abort (), because it might
+        * fail to raise SIGABRT */
+       g_assert (sigaction (SIGILL, &sa, NULL) != -1);
 #endif
 
        if (!mono_do_crash_chaining) {
@@ -2550,7 +2610,7 @@ mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *i
 #else
 
 void
-mono_handle_native_sigsegv (int signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
+mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *info)
 {
        g_assert_not_reached ();
 }
@@ -2639,7 +2699,7 @@ mono_resume_unwind (MonoContext *ctx)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        MonoContext new_ctx;
 
        MONO_CONTEXT_SET_IP (ctx, MONO_CONTEXT_GET_IP (&jit_tls->resume_state.ctx));
@@ -2761,7 +2821,7 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx)
 static gboolean
 mono_current_thread_has_handle_block_guard (void)
 {
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        return jit_tls && jit_tls->handler_block_return_address != NULL;
 }
 
@@ -2786,7 +2846,7 @@ mono_set_cast_details (MonoClass *from, MonoClass *to)
        MonoJitTlsData *jit_tls = NULL;
 
        if (mini_get_debug_options ()->better_cast_details) {
-               jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+               jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
                jit_tls->class_cast_from = from;
                jit_tls->class_cast_to = to;
        }
@@ -2801,7 +2861,6 @@ mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
        MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
        if (!thread) {
                ctx->valid = FALSE;
-               g_error ("Invoked mono_thread_state_init_from_sigctx from non-Mono thread");
                return FALSE;
        }
 
@@ -2902,7 +2961,7 @@ void
 mono_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
 {
 #ifdef MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK
-       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
+       MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
        jit_tls->ex_ctx = *ctx;
 
        mono_arch_setup_async_callback (ctx, async_cb, user_data);