[threads] Use runtime flag to enable cooperative suspend
[mono.git] / mono / mini / debugger-agent.c
index 5763be8c8f4ea1066ac29358213047bfd90e1a77..990ee09e107f394773e825d8f1711094b5a871f3 100644 (file)
@@ -268,7 +268,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 41
+#define MINOR_VERSION 42
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -325,6 +325,7 @@ typedef enum {
        ERR_NO_INVOCATION = 104,
        ERR_ABSENT_INFORMATION = 105,
        ERR_NO_SEQ_POINT_AT_IL_OFFSET = 106,
+       ERR_INVOKE_ABORTED = 107,
        ERR_LOADER_ERROR = 200, /*XXX extend the protocol to pass this information down the pipe */
 } ErrorCode;
 
@@ -661,7 +662,7 @@ static MonoGHashTable *tid_to_thread;
 /* Protected by the loader lock */
 static MonoGHashTable *tid_to_thread_obj;
 
-static gsize debugger_thread_id;
+static MonoNativeThreadId debugger_thread_id;
 
 static HANDLE debugger_thread_handle;
 
@@ -810,7 +811,7 @@ register_socket_transport (void);
 static inline gboolean
 is_debugger_thread (void)
 {
-       return GetCurrentThreadId () == debugger_thread_id;
+       return mono_native_thread_id_equals (mono_native_thread_id_get (), debugger_thread_id);
 }
 
 static int
@@ -973,7 +974,7 @@ mono_debugger_agent_init (void)
        event_requests = g_ptr_array_new ();
 
        mono_mutex_init (&debugger_thread_exited_mutex);
-       mono_cond_init (&debugger_thread_exited_cond, NULL);
+       mono_cond_init (&debugger_thread_exited_cond, 0);
 
        mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
        mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS);
@@ -988,14 +989,14 @@ mono_debugger_agent_init (void)
        /* Needed by the hash_table_new_type () call below */
        mono_gc_base_init ();
 
-       thread_to_tls = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
-       MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls);
+       thread_to_tls = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
+       MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
 
-       tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
-       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread);
+       tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread table");
+       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread table");
 
-       tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
-       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj);
+       tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread object table");
+       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread object table");
 
        pending_assembly_loads = g_ptr_array_new ();
        domains = g_hash_table_new (mono_aligned_addr_hash, NULL);
@@ -1601,7 +1602,7 @@ stop_debugger_thread (void)
         * If we continue with the shutdown without waiting for it, then the client might
         * not receive an answer to its last command like a resume.
         */
-       if (GetCurrentThreadId () != debugger_thread_id) {
+       if (!is_debugger_thread ()) {
                do {
                        MONO_TRY_BLOCKING;
                        mono_mutex_lock (&debugger_thread_exited_mutex);
@@ -1928,8 +1929,8 @@ objrefs_init (void)
 {
        objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref);
        obj_to_objref = g_hash_table_new (NULL, NULL);
-       suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
-       MONO_GC_REGISTER_ROOT_FIXED (suspended_objs);
+       suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
+       MONO_GC_REGISTER_ROOT_FIXED (suspended_objs, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
 }
 
 static void
@@ -2391,10 +2392,10 @@ buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
                char *s;
 
                s = mono_type_full_name (&klass->byval_arg);
-               if (GetCurrentThreadId () == debugger_thread_id)
+               if (is_debugger_thread ())
                        DEBUG_PRINTF (2, "[dbg]   send class [%s]\n", s);
                else
-                       DEBUG_PRINTF (2, "[%p]   send class [%s]\n", (gpointer)GetCurrentThreadId (), s);
+                       DEBUG_PRINTF (2, "[%p]   send class [%s]\n", (gpointer)mono_native_thread_id_get (), s);
                g_free (s);
        }
 }
@@ -2491,7 +2492,7 @@ static void
 suspend_init (void)
 {
        mono_mutex_init (&suspend_mutex);
-       mono_cond_init (&suspend_cond, NULL);   
+       mono_cond_init (&suspend_cond, 0);      
        MONO_SEM_INIT (&suspend_sem, 0);
 }
 
@@ -2501,6 +2502,7 @@ typedef struct
        gboolean last_frame_set;
        MonoContext ctx;
        gpointer lmf;
+       MonoDomain *domain;
 } GetLastFrameUserData;
 
 static gboolean
@@ -2520,19 +2522,32 @@ get_last_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
                /* Store the context/lmf for the frame above the last frame */
                memcpy (&data->ctx, ctx, sizeof (MonoContext));
                data->lmf = info->lmf;
+               data->domain = info->domain;
                return TRUE;
        }
 }
 
+static void
+copy_unwind_state_from_frame_data (MonoThreadUnwindState *to, GetLastFrameUserData *data, gpointer jit_tls)
+{
+       memcpy (&to->ctx, &data->ctx, sizeof (MonoContext));
+
+       to->unwind_data [MONO_UNWIND_DATA_DOMAIN] = data->domain;
+       to->unwind_data [MONO_UNWIND_DATA_LMF] = data->lmf;
+       to->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
+       to->valid = TRUE;
+}
+
 /*
  * thread_interrupt:
  *
  *   Process interruption of a thread. This should be signal safe.
+ *
+ * This always runs in the debugger thread.
  */
 static void
 thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
 {
-       gboolean res;
        gpointer ip;
        MonoNativeThreadId tid;
 
@@ -2555,7 +2570,6 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
                 * tls->suspending flag to avoid races when that happens.
                 */
                if (!tls->suspended && !tls->suspending) {
-                       MonoContext ctx;
                        GetLastFrameUserData data;
 
                        // FIXME: printf is not signal safe, but this is only used during
@@ -2581,15 +2595,12 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
                        data.last_frame_set = FALSE;
                        mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &data);
                        if (data.last_frame_set) {
+                               gpointer jit_tls = ((MonoThreadInfo*)tls->thread->thread_info)->jit_data;
+
                                memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
-                               res = mono_thread_state_init_from_monoctx (&tls->async_state, &ctx);
-                               g_assert (res);
-                               mono_thread_state_init_from_monoctx (&tls->context, &ctx);
-                               g_assert (res);
 
-                               memcpy (&tls->async_state.ctx, &data.ctx, sizeof (MonoContext));
-                               tls->async_state.unwind_data [MONO_UNWIND_DATA_LMF] = data.lmf;
-                               tls->async_state.unwind_data [MONO_UNWIND_DATA_JIT_TLS] = ((MonoThreadInfo*)tls->thread->thread_info)->jit_data;
+                               copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
+                               copy_unwind_state_from_frame_data (&tls->context, &data, jit_tls);
                        } else {
                                tls->async_state.valid = FALSE;
                        }
@@ -2657,12 +2668,12 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
 {
        MonoInternalThread *thread = key;
        DebuggerTlsData *tls = value;
-       gsize tid = thread->tid;
+       MonoNativeThreadId tid = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
 
-       if (GetCurrentThreadId () == tid || tls->terminated)
+       if (mono_native_thread_id_equals (mono_native_thread_id_get (), tid) || tls->terminated)
                return;
 
-       DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid);
+       DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer)mono_native_thread_id_get (), (gpointer)tid);
 
        /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
        InterruptData interrupt_data = { 0 };
@@ -2670,7 +2681,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
 
        mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE, debugger_interrupt_critical, &interrupt_data);
        if (!interrupt_data.valid_info) {
-               DEBUG_PRINTF (1, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid);
+               DEBUG_PRINTF (1, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer)mono_native_thread_id_get (), (gpointer)tid);
                /* 
                 * Attached thread which died without detaching.
                 */
@@ -2694,14 +2705,14 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
                return;
        }
 
-       if (debugger_thread_id == GetCurrentThreadId ())
+       if (is_debugger_thread ())
                return;
 
        /* Prevent races with mono_debugger_agent_thread_interrupt () */
        if (suspend_count - tls->resume_count > 0)
                tls->suspending = TRUE;
 
-       DEBUG_PRINTF (1, "[%p] Received single step event for suspending.\n", (gpointer)GetCurrentThreadId ());
+       DEBUG_PRINTF (1, "[%p] Received single step event for suspending.\n", (gpointer)mono_native_thread_id_get ());
 
        if (suspend_count - tls->resume_count == 0) {
                /* 
@@ -2709,7 +2720,7 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
                 * suspending is still active.
                 * FIXME: This slows down single threaded invokes.
                 */
-               DEBUG_PRINTF (1, "[%p] Ignored during single threaded invoke.\n", (gpointer)GetCurrentThreadId ());
+               DEBUG_PRINTF (1, "[%p] Ignored during single threaded invoke.\n", (gpointer)mono_native_thread_id_get ());
                return;
        }
 
@@ -2742,7 +2753,7 @@ suspend_vm (void)
 
        suspend_count ++;
 
-       DEBUG_PRINTF (1, "[%p] Suspending vm...\n", (gpointer)GetCurrentThreadId ());
+       DEBUG_PRINTF (1, "[%p] Suspending vm...\n", (gpointer)mono_native_thread_id_get ());
 
        if (suspend_count == 1) {
                // FIXME: Is it safe to call this inside the lock ?
@@ -2772,7 +2783,7 @@ resume_vm (void)
 {
        int err;
 
-       g_assert (debugger_thread_id == GetCurrentThreadId ());
+       g_assert (is_debugger_thread ());
 
        mono_loader_lock ();
 
@@ -2783,7 +2794,7 @@ resume_vm (void)
        g_assert (suspend_count > 0);
        suspend_count --;
 
-       DEBUG_PRINTF (1, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)GetCurrentThreadId (), suspend_count);
+       DEBUG_PRINTF (1, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)mono_native_thread_id_get (), suspend_count);
 
        if (suspend_count == 0) {
                // FIXME: Is it safe to call this inside the lock ?
@@ -2815,7 +2826,7 @@ resume_thread (MonoInternalThread *thread)
        int err;
        DebuggerTlsData *tls;
 
-       g_assert (debugger_thread_id == GetCurrentThreadId ());
+       g_assert (is_debugger_thread ());
 
        mono_loader_lock ();
 
@@ -2886,7 +2897,7 @@ suspend_current (void)
        DebuggerTlsData *tls;
        int err;
 
-       g_assert (debugger_thread_id != GetCurrentThreadId ());
+       g_assert (!is_debugger_thread ());
 
        if (mono_loader_lock_is_owned_by_self ()) {
                /*
@@ -2911,7 +2922,7 @@ suspend_current (void)
                MONO_SEM_POST (&suspend_sem);
        }
 
-       DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ());
+       DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)mono_native_thread_id_get ());
 
        MONO_TRY_BLOCKING;
        while (suspend_count - tls->resume_count > 0) {
@@ -2927,7 +2938,7 @@ suspend_current (void)
 
        mono_mutex_unlock (&suspend_mutex);
 
-       DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer)GetCurrentThreadId ());
+       DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer)mono_native_thread_id_get ());
 
        if (tls->pending_invoke) {
                /* Save the original context */
@@ -3008,12 +3019,12 @@ is_suspended (void)
 }
 
 static void
-no_seq_points_found (MonoMethod *method)
+no_seq_points_found (MonoMethod *method, int offset)
 {
        /*
         * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
         */
-       printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
+       printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method, TRUE), offset);
 }
 
 typedef struct {
@@ -3242,7 +3253,7 @@ emit_appdomain_load (gpointer key, gpointer value, gpointer user_data)
 static void
 emit_thread_start (gpointer key, gpointer value, gpointer user_data)
 {
-       if (GPOINTER_TO_INT (key) != debugger_thread_id)
+       if (!mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (key)), debugger_thread_id))
                process_profiler_event (EVENT_KIND_THREAD_START, value);
 }
 
@@ -3599,14 +3610,14 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
 
                if (agent_config.defer) {
                        /* Make sure the thread id is always set when doing deferred debugging */
-                       if (debugger_thread_id == GetCurrentThreadId ()) {
+                       if (is_debugger_thread ()) {
                                /* Don't suspend on events from the debugger thread */
                                suspend_policy = SUSPEND_POLICY_NONE;
                                thread = mono_thread_get_main ();
                        }
                        else thread = mono_thread_current ();
                } else {
-                       if (debugger_thread_id == GetCurrentThreadId () && event != EVENT_KIND_VM_DEATH)
+                       if (is_debugger_thread () && event != EVENT_KIND_VM_DEATH)
                                // FIXME: Send these with a NULL thread, don't suspend the current thread
                                return;
                }
@@ -3743,7 +3754,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
                vm_start_event_sent = TRUE;
        }
 
-       DEBUG_PRINTF (1, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer)GetCurrentThreadId (), nevents, event_to_string (event), ecount, suspend_policy);
+       DEBUG_PRINTF (1, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer)mono_native_thread_id_get (), nevents, event_to_string (event), ecount, suspend_policy);
 
        switch (suspend_policy) {
        case SUSPEND_POLICY_NONE:
@@ -3801,13 +3812,13 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
        MonoInternalThread *old_thread;
        DebuggerTlsData *tls;
 
-       if (tid == debugger_thread_id)
+       if (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), debugger_thread_id))
                return;
 
-       g_assert (thread->tid == tid);
+       g_assert (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid)));
 
        mono_loader_lock ();
-       old_thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid);
+       old_thread = mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
        mono_loader_unlock ();
        if (old_thread) {
                if (thread == old_thread) {
@@ -3815,18 +3826,18 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
                         * For some reason, thread_startup () might be called for the same thread
                         * multiple times (attach ?).
                         */
-                       DEBUG_PRINTF (1, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer)tid, (gpointer)tid);
+                       DEBUG_PRINTF (1, "[%p] thread_start () called multiple times for %p, ignored.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
                        return;
                } else {
                        /*
                         * thread_end () might not be called for some threads, and the tid could
                         * get reused.
                         */
-                       DEBUG_PRINTF (1, "[%p] Removing stale data for tid %p.\n", (gpointer)tid, (gpointer)tid);
+                       DEBUG_PRINTF (1, "[%p] Removing stale data for tid %p.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
                        mono_loader_lock ();
                        mono_g_hash_table_remove (thread_to_tls, old_thread);
-                       mono_g_hash_table_remove (tid_to_thread, (gpointer)tid);
-                       mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid);
+                       mono_g_hash_table_remove (tid_to_thread, GUINT_TO_POINTER (tid));
+                       mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
                        mono_loader_unlock ();
                }
        }
@@ -3835,7 +3846,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
        g_assert (!tls);
        // FIXME: Free this somewhere
        tls = g_new0 (DebuggerTlsData, 1);
-       MONO_GC_REGISTER_ROOT_SINGLE (tls->thread);
+       MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, "debugger thread reference");
        tls->thread = thread;
        mono_native_tls_set_value (debugger_tls_id, tls);
 
@@ -3844,7 +3855,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
        mono_loader_lock ();
        mono_g_hash_table_insert (thread_to_tls, thread, tls);
        mono_g_hash_table_insert (tid_to_thread, (gpointer)tid, thread);
-       mono_g_hash_table_insert (tid_to_thread_obj, (gpointer)tid, mono_thread_current ());
+       mono_g_hash_table_insert (tid_to_thread_obj, GUINT_TO_POINTER (tid), mono_thread_current ());
        mono_loader_unlock ();
 
        process_profiler_event (EVENT_KIND_THREAD_START, thread);
@@ -3862,9 +3873,9 @@ thread_end (MonoProfiler *prof, uintptr_t tid)
        DebuggerTlsData *tls = NULL;
 
        mono_loader_lock ();
-       thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid);
+       thread = mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
        if (thread) {
-               mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid);
+               mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
                tls = mono_g_hash_table_lookup (thread_to_tls, thread);
                if (tls) {
                        /* FIXME: Maybe we need to free this instead, but some code can't handle that */
@@ -3880,7 +3891,9 @@ thread_end (MonoProfiler *prof, uintptr_t tid)
        if (thread) {
                DEBUG_PRINTF (1, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls);
 
-               if (GetCurrentThreadId () == tid && !mono_native_tls_get_value (debugger_tls_id)) {
+               if (mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (tid))
+                    && !mono_native_tls_get_value (debugger_tls_id)
+               ) {
                        /*
                         * This can happen on darwin since we deregister threads using pthread dtors.
                         * process_profiler_event () and the code it calls cannot handle a null TLS value.
@@ -4517,7 +4530,7 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                /*
                 * These seq points are inserted by the JIT after calls, step over needs to skip them.
                 */
-               DEBUG_PRINTF (1, "[%p] Seq point at nonempty stack %x while stepping over, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset);
+               DEBUG_PRINTF (1, "[%p] Seq point at nonempty stack %x while stepping over, continuing single stepping.\n", (gpointer)mono_native_thread_id_get (), sp->il_offset);
                return FALSE;
        }
 
@@ -4527,7 +4540,7 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                compute_frame_info (tls->thread, tls);
                if (req->nframes && tls->frame_count && tls->frame_count > req->nframes) {
                        /* Hit the breakpoint in a recursive call */
-                       DEBUG_PRINTF (1, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer)GetCurrentThreadId ());
+                       DEBUG_PRINTF (1, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer)mono_native_thread_id_get ());
                        return FALSE;
                }
        }
@@ -4538,7 +4551,7 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                        mono_thread_state_init_from_monoctx (&tls->context, ctx);
                compute_frame_info (tls->thread, tls);
                if (ss_req->start_method == method && req->nframes && tls->frame_count == req->nframes) {//Check also frame count(could be recursion)
-                       DEBUG_PRINTF (1, "[%p] Seq point at nonempty stack %x while stepping in, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset);
+                       DEBUG_PRINTF (1, "[%p] Seq point at nonempty stack %x while stepping in, continuing single stepping.\n", (gpointer)mono_native_thread_id_get (), sp->il_offset);
                        return FALSE;
                }
        }
@@ -4554,11 +4567,11 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
 
        if (!loc) {
-               DEBUG_PRINTF (1, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset);
+               DEBUG_PRINTF (1, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)mono_native_thread_id_get (), sp->il_offset);
                ss_req->last_method = method;
                hit = FALSE;
        } else if (loc && method == ss_req->last_method && loc->row == ss_req->last_line) {
-               DEBUG_PRINTF (1, "[%p] Same source line (%d), continuing single stepping.\n", (gpointer)GetCurrentThreadId (), loc->row);
+               DEBUG_PRINTF (1, "[%p] Same source line (%d), continuing single stepping.\n", (gpointer)mono_native_thread_id_get (), loc->row);
                hit = FALSE;
        }
                                
@@ -4627,11 +4640,11 @@ process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
        found_sp = mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp);
 
        if (!found_sp)
-               no_seq_points_found (method);
+               no_seq_points_found (method, native_offset);
 
        g_assert (found_sp);
 
-       DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, [il=0x%x,native=0x%x].\n", (gpointer)GetCurrentThreadId (), method->name, ip, sp.il_offset, native_offset);
+       DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, [il=0x%x,native=0x%x].\n", (gpointer)mono_native_thread_id_get (), method->name, ip, sp.il_offset, native_offset);
 
        bp = NULL;
        for (i = 0; i < breakpoints->len; ++i) {
@@ -4738,7 +4751,7 @@ resume_from_signal_handler (void *sigctx, void *func)
        // FIXME: This might not work on an altstack ?
        tls = mono_native_tls_get_value (debugger_tls_id);
        if (!tls)
-               fprintf (stderr, "Thread %p is not attached to the JIT.\n", (gpointer)GetCurrentThreadId ());
+               fprintf (stderr, "Thread %p is not attached to the JIT.\n", (gpointer)mono_native_thread_id_get ());
        g_assert (tls);
 
        // FIXME: MonoContext usually doesn't include the fp registers, so these are 
@@ -4803,7 +4816,7 @@ mono_debugger_agent_user_break (void)
                mono_loader_unlock ();
 
                process_event (EVENT_KIND_USER_BREAK, NULL, 0, &ctx, events, suspend_policy);
-       } else {
+       } else if (debug_options.native_debugger_break) {
                G_BREAKPOINT ();
        }
 }
@@ -4859,7 +4872,7 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        if (log_level > 0) {
                ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
 
-               DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer)GetCurrentThreadId (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), (int)((guint8*)MONO_CONTEXT_GET_IP (ctx) - (guint8*)ji->code_start), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp);
+               DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer)mono_native_thread_id_get (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), (int)((guint8*)MONO_CONTEXT_GET_IP (ctx) - (guint8*)ji->code_start), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp);
        }
 
        ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
@@ -4935,7 +4948,7 @@ mono_debugger_agent_single_step_event (void *sigctx)
        // be as fast as possible. Move the relevant code from process_single_step_inner ()
        // here
 
-       if (GetCurrentThreadId () == debugger_thread_id) {
+       if (is_debugger_thread ()) {
                /* 
                 * This could happen despite our best effors when the runtime calls 
                 * assembly/type resolve hooks.
@@ -4958,7 +4971,7 @@ debugger_agent_single_step_from_context (MonoContext *ctx)
        DebuggerTlsData *tls;
        MonoThreadUnwindState orig_restore_state;
 
-       if (GetCurrentThreadId () == debugger_thread_id)
+       if (is_debugger_thread ())
                return;
 
        tls = mono_native_tls_get_value (debugger_tls_id);
@@ -4982,7 +4995,7 @@ debugger_agent_breakpoint_from_context (MonoContext *ctx)
        MonoThreadUnwindState orig_restore_state;
        guint8 *orig_ip;
 
-       if (GetCurrentThreadId () == debugger_thread_id)
+       if (is_debugger_thread ())
                return;
 
        orig_ip = MONO_CONTEXT_GET_IP (ctx);
@@ -5312,7 +5325,7 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilte
                found_sp = mono_find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &local_sp);
                sp = (found_sp)? &local_sp : NULL;
                if (!sp)
-                       no_seq_points_found (frame.method);
+                       no_seq_points_found (frame.method, frame.native_offset);
                g_assert (sp);
 
                method = frame.method;
@@ -5358,7 +5371,7 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilte
                                found_sp = mono_find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
                                sp = (found_sp)? &local_sp : NULL;
                                if (!sp)
-                                       no_seq_points_found (frame->method);
+                                       no_seq_points_found (frame->method, frame->native_offset);
                                g_assert (sp);
                                method = frame->method;
                        }
@@ -5872,7 +5885,7 @@ decode_vtype (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8
        if (t && klass != mono_class_from_mono_type (t)) {
                char *name = mono_type_full_name (t);
                char *name2 = mono_type_full_name (&klass->byval_arg);
-               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got %s.\n", (gpointer)GetCurrentThreadId (), name, name2);
+               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got %s.\n", (gpointer)mono_native_thread_id_get (), name, name2);
                g_free (name);
                g_free (name2);
                return ERR_INVALID_ARGUMENT;
@@ -5908,7 +5921,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) &&
                !(t->type == MONO_TYPE_VALUETYPE && type == MONO_TYPE_OBJECT)) {
                char *name = mono_type_full_name (t);
-               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type);
+               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)mono_native_thread_id_get (), name, type);
                g_free (name);
                return ERR_INVALID_ARGUMENT;
        }
@@ -6052,7 +6065,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                                g_free (vtype_buf);
                        } else {
                                char *name = mono_type_full_name (t);
-                               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type);
+                               DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)mono_native_thread_id_get (), name, type);
                                g_free (name);
                                return ERR_INVALID_ARGUMENT;
                        }
@@ -6465,7 +6478,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                 * Invoke this method directly, currently only Environment.Exit () is supported.
                 */
                this_arg = NULL;
-               DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
+               DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)mono_native_thread_id_get (), mono_method_full_name (invoke->method, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
                mono_runtime_invoke (invoke->method, NULL, invoke->args, &exc);
                g_assert_not_reached ();
        }
@@ -6483,7 +6496,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                /* Should be null */
                int type = decode_byte (p, &p, end);
                if (type != VALUE_TYPE_ID_NULL) {
-                       DEBUG_PRINTF (1, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer)GetCurrentThreadId ());
+                       DEBUG_PRINTF (1, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer)mono_native_thread_id_get ());
                        return ERR_INVALID_ARGUMENT;
                }
                memset (this_buf, 0, mono_class_instance_size (m->klass));
@@ -6513,7 +6526,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
 
        if (MONO_CLASS_IS_INTERFACE (m->klass)) {
                if (!this_arg) {
-                       DEBUG_PRINTF (1, "[%p] Error: Interface method invoked without this argument.\n", (gpointer)GetCurrentThreadId ());
+                       DEBUG_PRINTF (1, "[%p] Error: Interface method invoked without this argument.\n", (gpointer)mono_native_thread_id_get ());
                        return ERR_INVALID_ARGUMENT;
                }
                m = mono_object_get_virtual_method (this_arg, m);
@@ -6524,7 +6537,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                }
        } else if ((m->flags & METHOD_ATTRIBUTE_VIRTUAL) && !m->klass->valuetype && invoke->flags & INVOKE_FLAG_VIRTUAL) {
                if (!this_arg) {
-                       DEBUG_PRINTF (1, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer)GetCurrentThreadId ());
+                       DEBUG_PRINTF (1, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer)mono_native_thread_id_get ());
                        return ERR_INVALID_ARGUMENT;
                }
                m = mono_object_get_virtual_method (this_arg, m);
@@ -6534,7 +6547,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                }
        }
 
-       DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
+       DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)mono_native_thread_id_get (), mono_method_full_name (m, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
 
        if (this_arg && this_arg->vtable->domain != domain)
                NOT_IMPLEMENTED;
@@ -6616,7 +6629,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
        else
                res = mono_runtime_invoke (m, this_arg, args, &exc);
        mono_stopwatch_stop (&watch);
-       DEBUG_PRINTF (1, "[%p] Invoke result: %p, exc: %s, time: %ld ms.\n", (gpointer)GetCurrentThreadId (), res, exc ? exc->vtable->klass->name : NULL, (long)mono_stopwatch_elapsed_ms (&watch));
+       DEBUG_PRINTF (1, "[%p] Invoke result: %p, exc: %s, time: %ld ms.\n", (gpointer)mono_native_thread_id_get (), res, exc ? exc->vtable->klass->name : NULL, (long)mono_stopwatch_elapsed_ms (&watch));
        if (exc) {
                buffer_add_byte (buf, 0);
                buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &exc, domain);
@@ -6735,6 +6748,11 @@ invoke_method (void)
                        err = do_invoke_method (tls, &buf, invoke, p, &p);
                }
 
+               if (tls->abort_requested) {
+                       if (CHECK_PROTOCOL_VERSION (2, 42))
+                               err = ERR_INVOKE_ABORTED;
+               }
+
                /* Start suspending before sending the reply */
                if (mindex == invoke->nmethods - 1) {
                        if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) {
@@ -6758,7 +6776,7 @@ invoke_method (void)
                tls->resume_count -= invoke->suspend_count;
        }
 
-       DEBUG_PRINTF (1, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer)GetCurrentThreadId (), err, tls->resume_count);
+       DEBUG_PRINTF (1, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer)mono_native_thread_id_get (), err, tls->resume_count);
 
        /*
         * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
@@ -7013,7 +7031,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                 * Store the invoke data into tls, the thread will execute it after it is
                 * resumed.
                 */
-               if (tls->pending_invoke || tls->invoke)
+               if (tls->pending_invoke)
                        return ERR_NOT_SUSPENDED;
                tls->pending_invoke = g_new0 (InvokeData, 1);
                tls->pending_invoke->id = id;
@@ -7051,6 +7069,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                g_assert (tls);
 
                if (tls->abort_requested) {
+                       DEBUG_PRINTF (1, "Abort already requested.\n");
                        mono_loader_unlock ();
                        break;
                }
@@ -8404,7 +8423,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                break;
        }
        case CMD_METHOD_GET_LOCALS_INFO: {
-               int i, j, num_locals;
+               int i, num_locals;
                MonoDebugLocalsInfo *locals;
                int *locals_map = NULL;
 
@@ -8431,40 +8450,25 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                                buffer_add_int (buf, header->code_size);
                        }
                } else {
-                       /* Maps between the IL locals index and the index in locals->locals */
-                       locals_map = g_new0 (int, header->num_locals);
-                       for (i = 0; i < header->num_locals; ++i)
-                               locals_map [i] = -1;
                        num_locals = locals->num_locals;
-                       for (i = 0; i < num_locals; ++i) {
-                               g_assert (locals->locals [i].index < header->num_locals);
-                               locals_map [locals->locals [i].index] = i;
-                       }
                        buffer_add_int (buf, num_locals);
 
                        /* Types */
-                       for (i = 0; i < header->num_locals; ++i) {
-                               if (locals_map [i] != -1)
-                                       buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
+                       for (i = 0; i < num_locals; ++i) {
+                               g_assert (locals->locals [i].index < header->num_locals);
+                               buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [locals->locals [i].index]));
                        }
-
                        /* Names */
-                       for (i = 0; i < header->num_locals; ++i) {
-                               if (locals_map [i] != -1)
-                                       buffer_add_string (buf, locals->locals [locals_map [i]].name);
-                       }
-
+                       for (i = 0; i < num_locals; ++i)
+                               buffer_add_string (buf, locals->locals [i].name);
                        /* Scopes */
-                       for (i = 0; i < header->num_locals; ++i) {
-                               if (locals_map [i] != -1) {
-                                       j = locals_map [i];
-                                       if (locals->locals [j].block) {
-                                               buffer_add_int (buf, locals->locals [j].block->start_offset);
-                                               buffer_add_int (buf, locals->locals [j].block->end_offset);
-                                       } else {
-                                               buffer_add_int (buf, 0);
-                                               buffer_add_int (buf, header->code_size);
-                                       }
+                       for (i = 0; i < num_locals; ++i) {
+                               if (locals->locals [i].block) {
+                                       buffer_add_int (buf, locals->locals [i].block->start_offset);
+                                       buffer_add_int (buf, locals->locals [i].block->end_offset);
+                               } else {
+                                       buffer_add_int (buf, 0);
+                                       buffer_add_int (buf, header->code_size);
                                }
                        }
                }
@@ -9581,9 +9585,9 @@ debugger_thread (void *arg)
        gboolean no_reply;
        gboolean attach_failed = FALSE;
 
-       DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer)GetCurrentThreadId ());
+       DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer)mono_native_thread_id_get ());
 
-       debugger_thread_id = GetCurrentThreadId ();
+       debugger_thread_id = mono_native_thread_id_get ();
 
        mono_jit_thread_attach (mono_get_root_domain ());