+static gboolean
+first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
+{
+ gpointer **data = (gpointer **)addr;
+
+ if (!frame->managed)
+ return FALSE;
+
+ if (!ctx) {
+ // FIXME: Happens with llvm_only
+ *data = NULL;
+ return TRUE;
+ }
+
+ *data = MONO_CONTEXT_GET_SP (ctx);
+ g_assert (*data);
+ return TRUE;
+}
+
+static gpointer
+mono_thread_get_managed_sp (void)
+{
+ gpointer addr = NULL;
+ mono_walk_stack (first_managed, MONO_UNWIND_SIGNAL_SAFE, &addr);
+ return addr;
+}
+
+static inline int
+mini_abort_threshold_offset (gpointer threshold, gpointer sp)
+{
+ intptr_t stack_threshold = (intptr_t) threshold;
+ intptr_t stack_pointer = (intptr_t) sp;
+
+ const int direction = MONO_ARCH_STACK_GROWS_UP ? -1 : 1;
+ intptr_t magnitude = stack_pointer - stack_threshold;
+
+ return direction * magnitude;
+}
+
+static inline void
+mini_clear_abort_threshold (void)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ jit_tls->abort_exc_stack_threshold = NULL;
+}
+
+static inline void
+mini_set_abort_threshold (MonoContext *ctx)
+{
+ gpointer sp = MONO_CONTEXT_GET_SP (ctx);
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ // Only move it up, to avoid thrown/caught
+ // exceptions lower in the stack from triggering
+ // a rethrow
+ gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0;
+ if (!jit_tls->abort_exc_stack_threshold || above_threshold) {
+ jit_tls->abort_exc_stack_threshold = sp;
+ }
+}
+
+// Note: In the case that the frame is above where the thread abort
+// was set we bump the threshold so that functions called from the new,
+// higher threshold don't trigger the thread abort exception
+static inline gboolean
+mini_above_abort_threshold (void)
+{
+ gpointer sp = mono_thread_get_managed_sp ();
+ 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;
+
+ if (above_threshold)
+ jit_tls->abort_exc_stack_threshold = sp;
+
+ 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;
+}
+