Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / debugger-agent.c
index 7b0b052f4503743808c91874901a3e239398ae27..29f94ba1e06e0b4870e9d4bda438e4ab39a9718d 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * debugger-agent.c: Soft Debugger back-end module
+/**
+ * \file
+ * Soft Debugger back-end module
  *
  * Author:
  *   Zoltan Varga (vargaz@gmail.com)
 #include <ws2tcpip.h>
 #endif
 
-#ifdef PLATFORM_ANDROID
+#ifdef HOST_ANDROID
 #include <linux/in.h>
 #include <linux/tcp.h>
 #include <sys/endian.h>
 #endif
 
 #include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-debug-debugger.h>
-#include <mono/metadata/debug-mono-symfile.h>
+#include <mono/metadata/debug-internals.h>
 #include <mono/metadata/gc-internals.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/networking.h>
 #include <mono/utils/mono-proclib.h>
+#include <mono/utils/w32api.h>
 #include "debugger-agent.h"
 #include "mini.h"
 #include "seq-points.h"
-#include <mono/utils/w32api.h>
+#include "interp/interp.h"
 
 /*
  * On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -137,6 +138,7 @@ typedef struct
        MonoContext ctx;
        MonoDebugMethodJitInfo *jit;
        MonoJitInfo *ji;
+       MonoInterpFrameHandle interp_frame;
        int flags;
        mgreg_t *reg_locations [MONO_MAX_IREGS];
        /*
@@ -273,7 +275,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 44
+#define MINOR_VERSION 45
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -450,7 +452,8 @@ typedef enum {
        CMD_ASSEMBLY_GET_MANIFEST_MODULE = 3,
        CMD_ASSEMBLY_GET_OBJECT = 4,
        CMD_ASSEMBLY_GET_TYPE = 5,
-       CMD_ASSEMBLY_GET_NAME = 6
+       CMD_ASSEMBLY_GET_NAME = 6,
+       CMD_ASSEMBLY_GET_DOMAIN = 7
 } CmdAssembly;
 
 typedef enum {
@@ -592,11 +595,6 @@ typedef struct {
        MonoClass *klass;
 } EventInfo;
 
-/* Dummy structure used for the profiler callbacks */
-typedef struct {
-       void* dummy;
-} DebuggerProfiler;
-
 typedef struct {
        guint8 *buf, *p, *end;
 } Buffer;
@@ -609,7 +607,7 @@ typedef struct ReplyPacket {
 
 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
 
-#ifdef PLATFORM_ANDROID
+#ifdef HOST_ANDROID
 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { g_print (__VA_ARGS__); } } while (0)
 #else
 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (log_file, __VA_ARGS__); fflush (log_file); } } while (0)
@@ -697,8 +695,6 @@ static MonoCoopCond debugger_thread_exited_cond;
 /* Mutex for the cond var above */
 static MonoCoopMutex debugger_thread_exited_mutex;
 
-static DebuggerProfiler debugger_profiler;
-
 /* The single step request instance */
 static SingleStepReq *ss_req;
 
@@ -746,7 +742,7 @@ static void thread_startup (MonoProfiler *prof, uintptr_t tid);
 
 static void thread_end (MonoProfiler *prof, uintptr_t tid);
 
-static void appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result);
+static void appdomain_load (MonoProfiler *prof, MonoDomain *domain);
 
 static void appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain);
 
@@ -758,7 +754,7 @@ static void emit_thread_start (gpointer key, gpointer value, gpointer user_data)
 
 static void invalidate_each_thread (gpointer key, gpointer value, gpointer user_data);
 
-static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result);
+static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly);
 
 static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly);
 
@@ -766,7 +762,11 @@ static void emit_assembly_load (gpointer assembly, gpointer user_data);
 
 static void emit_type_load (gpointer key, gpointer type, gpointer user_data);
 
-static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
+static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
+
+static void jit_failed (MonoProfiler *prof, MonoMethod *method);
+
+static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
 
 static void add_pending_breakpoints (MonoMethod *method, MonoJitInfo *jinfo);
 
@@ -818,7 +818,13 @@ register_socket_transport (void);
 static inline gboolean
 is_debugger_thread (void)
 {
-       return mono_native_thread_id_equals (mono_native_thread_id_get (), debugger_thread_id);
+       MonoInternalThread *internal;
+
+       internal = mono_thread_internal_current ();
+       if (!internal)
+               return FALSE;
+
+       return internal->debugger_thread;
 }
 
 static int
@@ -829,9 +835,10 @@ parse_address (char *address, char **host, int *port)
        if (pos == NULL || pos == address)
                return 1;
 
-       *host = (char *)g_malloc (pos - address + 1);
-       strncpy (*host, address, pos - address);
-       (*host) [pos - address] = '\0';
+       size_t len = pos - address;
+       *host = (char *)g_malloc (len + 1);
+       memcpy (*host, address, len);
+       (*host) [len] = '\0';
 
        *port = atoi (pos + 1);
 
@@ -875,7 +882,7 @@ mono_debugger_agent_parse_options (char *options)
        char **args, **ptr;
        char *host;
        int port;
-       const char *extra;
+       char *extra;
 
 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        fprintf (stderr, "--debugger-agent is not supported on this platform.\n");
@@ -883,8 +890,10 @@ mono_debugger_agent_parse_options (char *options)
 #endif
 
        extra = g_getenv ("MONO_SDB_ENV_OPTIONS");
-       if (extra)
+       if (extra) {
                options = g_strdup_printf ("%s,%s", options, extra);
+               g_free (extra);
+       }
 
        agent_config.enabled = TRUE;
        agent_config.suspend = TRUE;
@@ -983,27 +992,29 @@ mono_debugger_agent_init (void)
        mono_coop_mutex_init (&debugger_thread_exited_mutex);
        mono_coop_cond_init (&debugger_thread_exited_cond);
 
-       mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
-       mono_profiler_set_events ((MonoProfileFlags)(MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS));
-       mono_profiler_install_runtime_initialized (runtime_initialized);
-       mono_profiler_install_appdomain (NULL, appdomain_load, appdomain_start_unload, appdomain_unload);
-       mono_profiler_install_thread (thread_startup, thread_end);
-       mono_profiler_install_assembly (NULL, assembly_load, assembly_unload, NULL);
-       mono_profiler_install_jit_end (jit_end);
+       MonoProfilerHandle prof = mono_profiler_create (NULL);
+       mono_profiler_set_runtime_shutdown_end_callback (prof, runtime_shutdown);
+       mono_profiler_set_runtime_initialized_callback (prof, runtime_initialized);
+       mono_profiler_set_domain_loaded_callback (prof, appdomain_load);
+       mono_profiler_set_domain_unloading_callback (prof, appdomain_start_unload);
+       mono_profiler_set_domain_unloaded_callback (prof, appdomain_unload);
+       mono_profiler_set_thread_started_callback (prof, thread_startup);
+       mono_profiler_set_thread_stopped_callback (prof, thread_end);
+       mono_profiler_set_assembly_loaded_callback (prof, assembly_load);
+       mono_profiler_set_assembly_unloading_callback (prof, assembly_unload);
+       mono_profiler_set_jit_done_callback (prof, jit_done);
+       mono_profiler_set_jit_failed_callback (prof, jit_failed);
 
        mono_native_tls_alloc (&debugger_tls_id, NULL);
 
        /* 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_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
-       MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
+       thread_to_tls = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
 
        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_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);
@@ -1636,7 +1647,13 @@ stop_debugger_thread (void)
 static void
 start_debugger_thread (void)
 {
-       debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, NULL, NULL);
+       MonoError error;
+       MonoInternalThread *thread;
+
+       thread = mono_thread_create_internal (mono_get_root_domain (), debugger_thread, NULL, MONO_THREAD_CREATE_FLAGS_DEBUGGER, &error);
+       mono_error_assert_ok (&error);
+
+       debugger_thread_handle = mono_threads_open_thread_handle (thread->handle);
        g_assert (debugger_thread_handle);
 }
 
@@ -1940,8 +1957,7 @@ 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_ROOT_SOURCE_DEBUGGER, "suspended objects table");
-       MONO_GC_REGISTER_ROOT_FIXED (suspended_objs, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
+       suspended_objs = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
 }
 
 static void
@@ -2468,6 +2484,35 @@ static void invoke_method (void);
  * SUSPEND/RESUME
  */
 
+static MonoJitInfo*
+get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip)
+{
+       MonoJitInfo *ji;
+
+       if (out_ip)
+               *out_ip = ip;
+
+       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain);
+       if (!ji) {
+               /* Could be an interpreter method */
+
+               MonoLMF *lmf = mono_get_lmf ();
+               MonoInterpFrameHandle *frame;
+
+               g_assert (((guint64)lmf->previous_lmf) & 2);
+               MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+               g_assert (ext->interp_exit);
+               frame = ext->interp_exit_data;
+               ji = mono_interp_frame_get_jit_info (frame);
+               if (domain)
+                       *domain = mono_domain_get ();
+               if (out_ip)
+                       *out_ip = mono_interp_frame_get_ip (frame);
+       }
+       return ji;
+}
+
 /*
  * save_thread_context:
  *
@@ -2607,15 +2652,25 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
                         * suspended when it returns to managed code, so the parent's ctx should
                         * remain valid.
                         */
+                       MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info);
+
                        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);
+                       mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, 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));
 
+                               if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED) {
+                                       /*
+                                        * Store the current lmf instead of the parent one, since that
+                                        * contains the interp exit data.
+                                        */
+                                       data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF];
+                               }
+
                                copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
-                               copy_unwind_state_from_frame_data (&tls->context, &data, jit_tls);
+                               /* Don't set tls->context, it could race with the thread processing a breakpoint etc. */
                        } else {
                                tls->async_state.valid = FALSE;
                        }
@@ -2685,7 +2740,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
        DebuggerTlsData *tls = (DebuggerTlsData *)value;
        MonoNativeThreadId tid = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
 
-       if (mono_native_thread_id_equals (mono_native_thread_id_get (), tid) || tls->terminated)
+       if (mono_thread_internal_is_current (thread) || tls->terminated)
                return;
 
        DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer) (gsize) mono_native_thread_id_get (), (gpointer)tid);
@@ -2739,8 +2794,8 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
                return;
        }
 
-       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
-
+       ji = get_top_method_ji (ip, NULL, NULL);
+       g_assert (ji);
        /* Can't suspend in these methods */
        method = jinfo_get_method (ji);
        if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
@@ -2957,7 +3012,7 @@ count_thread (gpointer key, gpointer value, gpointer user_data)
 {
        DebuggerTlsData *tls = (DebuggerTlsData *)value;
 
-       if (!tls->suspended && !tls->terminated)
+       if (!tls->suspended && !tls->terminated && !mono_thread_internal_is_current (tls->thread))
                *(int*)user_data = *(int*)user_data + 1;
 }
 
@@ -3039,7 +3094,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        SeqPoint sp;
        int flags = 0;
 
-       if (info->type != FRAME_TYPE_MANAGED) {
+       if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) {
                if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
                        /* Mark the last frame as an invoke frame */
                        if (ud->frames)
@@ -3092,6 +3147,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        frame->native_offset = info->native_offset;
        frame->flags = flags;
        frame->ji = info->ji;
+       frame->interp_frame = info->interp_frame;
        if (info->reg_locations)
                memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*));
        if (ctx) {
@@ -3251,8 +3307,8 @@ emit_appdomain_load (gpointer key, gpointer value, gpointer user_data)
 static void
 emit_thread_start (gpointer key, gpointer value, gpointer user_data)
 {
-       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);
+       g_assert (!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);
 }
 
 /*
@@ -3606,13 +3662,10 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
                        return;
 
                if (agent_config.defer) {
-                       /* Make sure the thread id is always set when doing deferred debugging */
                        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 (is_debugger_thread () && event != EVENT_KIND_VM_DEATH)
                                // FIXME: Send these with a NULL thread, don't suspend the current thread
@@ -3635,7 +3688,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
                        thread = NULL;
                } else {
                        if (!thread)
-                               thread = mono_thread_current ();
+                               thread = is_debugger_thread () ? mono_thread_get_main () : mono_thread_current ();
 
                        if (event == EVENT_KIND_VM_START && arg != NULL)
                                thread = (MonoThread *)arg;
@@ -3813,7 +3866,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
        MonoInternalThread *old_thread;
        DebuggerTlsData *tls;
 
-       if (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), debugger_thread_id))
+       if (is_debugger_thread ())
                return;
 
        g_assert (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid)));
@@ -3892,8 +3945,7 @@ 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 (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)
+               if (mono_thread_internal_is_current (thread) && !mono_native_tls_get_value (debugger_tls_id)
                ) {
                        /*
                         * This can happen on darwin since we deregister threads using pthread dtors.
@@ -3907,7 +3959,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid)
 }
 
 static void
-appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result)
+appdomain_load (MonoProfiler *prof, MonoDomain *domain)
 {
        mono_loader_lock ();
        g_hash_table_insert (domains, domain, domain);
@@ -3969,7 +4021,7 @@ invalidate_each_thread (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result)
+assembly_load (MonoProfiler *prof, MonoAssembly *assembly)
 {
        /* Sent later in jit_end () */
        dbg_lock ();
@@ -4019,18 +4071,57 @@ send_type_load (MonoClass *klass)
 static void
 send_types_for_domain (MonoDomain *domain, void *user_data)
 {
+       MonoDomain* old_domain;
        AgentDomainInfo *info = NULL;
 
        info = get_agent_domain_info (domain);
        g_assert (info);
+
+       old_domain = mono_domain_get ();
+
+       mono_domain_set (domain, TRUE);
        
        mono_loader_lock ();
        g_hash_table_foreach (info->loaded_classes, emit_type_load, NULL);
        mono_loader_unlock ();
+
+       mono_domain_set (old_domain, TRUE);
+}
+
+static void
+send_assemblies_for_domain (MonoDomain *domain, void *user_data)
+{
+       GSList *tmp;
+       MonoDomain* old_domain;
+
+       old_domain = mono_domain_get ();
+
+       mono_domain_set (domain, TRUE);
+
+       mono_domain_assemblies_lock (domain);
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               MonoAssembly* ass = (MonoAssembly *)tmp->data;
+               emit_assembly_load (ass, NULL);
+       }
+       mono_domain_assemblies_unlock (domain);
+
+       mono_domain_set (old_domain, TRUE);
 }
 
 static void
-jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result)
+jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
+{
+       jit_end (prof, method, jinfo);
+}
+
+static void
+jit_failed (MonoProfiler *prof, MonoMethod *method)
+{
+       jit_end (prof, method, NULL);
+}
+
+static void
+jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
 {
        /*
         * We emit type load events when the first method of the type is JITted,
@@ -4058,7 +4149,7 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result)
 
        send_type_load (method->klass);
 
-       if (!result)
+       if (jinfo)
                add_pending_breakpoints (method, jinfo);
 }
 
@@ -4125,7 +4216,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        gboolean it_has_sp = FALSE;
 
        if (error)
-               mono_error_init (error);
+               error_init (error);
 
        mono_seq_point_iterator_init (&it, seq_points);
        while (mono_seq_point_iterator_next (&it)) {
@@ -4191,11 +4282,15 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
                DEBUG_PRINTF (1, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset);
        } else if (count == 0) {
+               if (ji->is_interp) {
+                       mono_interp_set_breakpoint (ji, inst->ip);
+               } else {
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
-               mono_arch_set_breakpoint (ji, inst->ip);
+                       mono_arch_set_breakpoint (ji, inst->ip);
 #else
-               NOT_IMPLEMENTED;
+                       NOT_IMPLEMENTED;
 #endif
+               }
        }
 
        DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count);
@@ -4217,7 +4312,10 @@ remove_breakpoint (BreakpointInstance *inst)
        g_assert (count > 0);
 
        if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
-               mono_arch_clear_breakpoint (ji, ip);
+               if (ji->is_interp)
+                       mono_interp_clear_breakpoint (ji, ip);
+               else
+                       mono_arch_clear_breakpoint (ji, ip);
                DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip);
        }
 #else
@@ -4325,7 +4423,7 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_
        MonoJitInfo *ji;
 
        if (error)
-               mono_error_init (error);
+               error_init (error);
 
        code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
        if (!code) {
@@ -4334,12 +4432,15 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_
                /* Might be AOTed code */
                mono_class_init (method->klass);
                code = mono_aot_get_method_checked (domain, method, &oerror);
-               g_assert (code);
-               mono_error_assert_ok (&oerror);
-               ji = mono_jit_info_table_find (domain, (char *)code);
+               if (code) {
+                       mono_error_assert_ok (&oerror);
+                       ji = mono_jit_info_table_find (domain, (char *)code);
+               } else {
+                       /* Might be interpreted */
+                       ji = mono_interp_find_jit_info (domain, method);
+               }
                g_assert (ji);
        }
-       g_assert (code);
 
        insert_breakpoint (seq_points, domain, ji, bp, error);
 }
@@ -4371,7 +4472,7 @@ set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req, MonoError
        int i;
 
        if (error)
-               mono_error_init (error);
+               error_init (error);
 
        // FIXME:
        // - suspend/resume the vm to prevent code patching problems
@@ -4598,16 +4699,15 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                }
        }
 
-       MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
-       if (asyncMethod) {
-               for (int i = 0; i < asyncMethod->num_awaits; i++)
-               {
-                       if (asyncMethod->yield_offsets[i] == sp->il_offset || asyncMethod->resume_offsets[i] == sp->il_offset) {
-                               mono_debug_free_method_async_debug_info (asyncMethod);
+       MonoDebugMethodAsyncInfo* async_method = mono_debug_lookup_method_async_debug_info (method);
+       if (async_method) {
+               for (int i = 0; i < async_method->num_awaits; i++) {
+                       if (async_method->yield_offsets[i] == sp->il_offset || async_method->resume_offsets[i] == sp->il_offset) {
+                               mono_debug_free_method_async_debug_info (async_method);
                                return FALSE;
                        }
                }
-               mono_debug_free_method_async_debug_info (asyncMethod);
+               mono_debug_free_method_async_debug_info (async_method);
        }
 
        if (req->size != STEP_SIZE_LINE)
@@ -4646,69 +4746,131 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
        return bp->method && bp->method->klass->image->assembly == assembly;
 }
 
-static MonoObject*
-get_this (StackFrame *frame)
+static gpointer
+get_this_addr (StackFrame *frame)
 {
        //Logic inspiered by "add_var" method and took out path that happens in async method for getting this
        MonoDebugVarInfo *var = frame->jit->this_var;
        if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET)
                return NULL;
 
-       guint8 * addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS);
+       guint8 *addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS);
        addr += (gint32)var->offset;
-       return *(MonoObject**)addr;
+       return addr;
 }
 
-//This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
-//since thread probably changed...
-static int
-get_this_async_id (StackFrame *frame)
+static MonoMethod*
+get_set_notification_method (MonoClass* async_builder_class)
 {
-       return get_objid (get_this (frame));
+       MonoError error;
+       GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, FALSE, FALSE, &error);
+       mono_error_assert_ok (&error);
+       g_assert (array->len == 1);
+       MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0);
+       g_ptr_array_free (array, TRUE);
+       return set_notification_method;
 }
 
-static MonoMethod* set_notification_method_cache = NULL;
-
 static MonoMethod*
-get_set_notification_method ()
+get_object_id_for_debugger_method (MonoClass* async_builder_class)
 {
-       if(set_notification_method_cache != NULL)
-               return set_notification_method_cache;
        MonoError error;
-       MonoClass* async_builder_class = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.CompilerServices", "AsyncTaskMethodBuilder");
-       GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, FALSE, FALSE, &error);
+       GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, FALSE, FALSE, &error);
        mono_error_assert_ok (&error);
        g_assert (array->len == 1);
-       set_notification_method_cache = (MonoMethod *)g_ptr_array_index (array, 0);
+       MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
        g_ptr_array_free (array, TRUE);
-       return set_notification_method_cache;
+       return method;
 }
 
-static void
-set_set_notification_for_wait_completion_flag (StackFrame *frame)
+/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */
+static gpointer
+get_async_method_builder (StackFrame *frame)
 {
-       MonoObject* obj = get_this (frame);
-       g_assert (obj);
-       MonoClassField *builder_field = mono_class_get_field_from_name (obj->vtable->klass, "<>t__builder");
+       MonoObject *this_obj;
+       MonoClassField *builder_field;
+       gpointer builder;
+       guint8 *this_addr;
+
+       builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder");
        g_assert (builder_field);
-       MonoObject* builder;
+
+       this_addr = get_this_addr (frame);
+       if (!this_addr)
+               return NULL;
+
+       if (frame->method->klass->valuetype) {
+               guint8 *vtaddr = *(guint8**)this_addr;
+               builder = (char*)vtaddr + builder_field->offset - sizeof (MonoObject);
+       } else {
+               this_obj = *(MonoObject**)this_addr;
+               builder = (char*)this_obj + builder_field->offset;
+       }
+
+       return builder;
+}
+
+//This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
+//since thread probably changed...
+static int
+get_this_async_id (StackFrame *frame)
+{
+       MonoClassField *builder_field;
+       gpointer builder;
+       MonoMethod *method;
+       MonoObject *ex;
        MonoError error;
-       builder = mono_field_get_value_object_checked (frame->domain, builder_field, obj, &error);
+       MonoObject *obj;
+       gboolean old_disable_breakpoints = FALSE;
+       DebuggerTlsData *tls;
+
+       /*
+        * FRAME points to a method in a state machine class/struct.
+        * Call the ObjectIdForDebugger method of the associated method builder type.
+        */
+       builder = get_async_method_builder (frame);
+       if (!builder)
+               return 0;
+
+       builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder");
+       g_assert (builder_field);
+
+       tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
+       if (tls) {
+               old_disable_breakpoints = tls->disable_breakpoints;
+               tls->disable_breakpoints = TRUE;
+       }
+
+       method = get_object_id_for_debugger_method (mono_class_from_mono_type (builder_field->type));
+       obj = mono_runtime_try_invoke (method, builder, NULL, &ex, &error);
        mono_error_assert_ok (&error);
+
+       if (tls)
+               tls->disable_breakpoints = old_disable_breakpoints;
+
+       return get_objid (obj);
+}
+
+static void
+set_set_notification_for_wait_completion_flag (StackFrame *frame)
+{
+       MonoClassField *builder_field = mono_class_get_field_from_name (frame->method->klass, "<>t__builder");
+       g_assert (builder_field);
+       gpointer builder = get_async_method_builder (frame);
        g_assert (builder);
 
        void* args [1];
        gboolean arg = TRUE;
+       MonoError error;
        args [0] = &arg;
-       mono_runtime_invoke_checked (get_set_notification_method(), mono_object_unbox (builder), args, &error);
+       mono_runtime_invoke_checked (get_set_notification_method (mono_class_from_mono_type (builder_field->type)), builder, args, &error);
        mono_error_assert_ok (&error);
-       mono_field_set_value (obj, builder_field, mono_object_unbox (builder));
 }
 
 static MonoMethod* notify_debugger_of_wait_completion_method_cache = NULL;
 
 static MonoMethod*
-get_notify_debugger_of_wait_completion_method ()
+get_notify_debugger_of_wait_completion_method (void)
 {
        if (notify_debugger_of_wait_completion_method_cache != NULL)
                return notify_debugger_of_wait_completion_method_cache;
@@ -4723,7 +4885,7 @@ get_notify_debugger_of_wait_completion_method ()
 }
 
 static void
-process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
+process_breakpoint (DebuggerTlsData *tls, gboolean from_signal)
 {
        MonoJitInfo *ji;
        guint8 *ip;
@@ -4744,11 +4906,27 @@ process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
 
        ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
        ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
+
+       if (!ji) {
+               /* Interpreter */
+               // FIXME: Pass a flag instead to detect this
+               MonoLMF *lmf = mono_get_lmf ();
+               MonoInterpFrameHandle *frame;
+
+               g_assert (((guint64)lmf->previous_lmf) & 2);
+               MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+               g_assert (ext->interp_exit);
+               frame = ext->interp_exit_data;
+               ji = mono_interp_frame_get_jit_info (frame);
+               ip = mono_interp_frame_get_ip (frame);
+       }
+
        g_assert (ji && !ji->is_trampoline);
        method = jinfo_get_method (ji);
 
        /* Compute the native offset of the breakpoint from the ip */
-       native_offset = ip - (guint8*)ji->code_start;   
+       native_offset = ip - (guint8*)ji->code_start;
 
        /* 
         * Skip the instruction causing the breakpoint signal.
@@ -4903,9 +5081,9 @@ process_signal_event (void (*func) (DebuggerTlsData*, gboolean))
 }
 
 static void
-process_breakpoint (void)
+process_breakpoint_from_signal (void)
 {
-       process_signal_event (process_breakpoint_inner);
+       process_signal_event (process_breakpoint);
 }
 
 static void
@@ -4947,19 +5125,30 @@ mono_debugger_agent_breakpoint_hit (void *sigctx)
         * problems, like the original signal is disabled, libgc can't handle altstack, etc.
         * So set up the signal context to return to the real breakpoint handler function.
         */
-       resume_from_signal_handler (sigctx, process_breakpoint);
+       resume_from_signal_handler (sigctx, process_breakpoint_from_signal);
 }
 
+typedef struct {
+       gboolean found;
+       MonoContext *ctx;
+} UserBreakCbData;
+
 static gboolean
-user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
+user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data)
 {
+       UserBreakCbData *data = user_data;
+
+       if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) {
+               data->found = TRUE;
+               return TRUE;
+       }
        if (frame->managed) {
-               *(MonoContext*)data = *ctx;
+               data->found = TRUE;
+               *data->ctx = *ctx;
 
                return TRUE;
-       } else {
-               return FALSE;
        }
+       return FALSE;
 }
 
 /*
@@ -4972,11 +5161,15 @@ mono_debugger_agent_user_break (void)
                MonoContext ctx;
                int suspend_policy;
                GSList *events;
+               UserBreakCbData data;
+
+               memset (&data, 0, sizeof (UserBreakCbData));
+               data.ctx = &ctx;
 
                /* Obtain a context */
                MONO_CONTEXT_SET_IP (&ctx, NULL);
-               mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &ctx);
-               g_assert (MONO_CONTEXT_GET_IP (&ctx) != NULL);
+               mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data);
+               g_assert (data.found);
 
                mono_loader_lock ();
                events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy);
@@ -5018,8 +5211,6 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        SeqPoint sp;
        MonoSeqPointInfo *info;
 
-       ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
-
        /* Skip the instruction causing the single step */
        if (from_signal)
                mono_arch_skip_single_step (ctx);
@@ -5039,14 +5230,15 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        if (mono_thread_internal_current () != ss_req->thread)
                return;
 
-       if (log_level > 0) {
-               ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
+       ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
+
+       ji = get_top_method_ji (ip, &domain, (gpointer*)&ip);
+       g_assert (ji && !ji->is_trampoline);
 
+       if (log_level > 0) {
                DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer) (gsize) 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);
-       g_assert (ji && !ji->is_trampoline);
        method = jinfo_get_method (ji);
        g_assert (method);
 
@@ -5081,8 +5273,10 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
         * The ip points to the instruction causing the single step event, which is before
         * the offset recorded in the seq point map, so find the next seq point after ip.
         */
-       if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
+       if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp)) {
+               g_assert_not_reached ();
                return;
+       }
 
        il_offset = sp.il_offset;
 
@@ -5197,7 +5391,7 @@ debugger_agent_breakpoint_from_context (MonoContext *ctx)
        mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
        memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
 
-       process_breakpoint_inner (tls, FALSE);
+       process_breakpoint (tls, FALSE);
 
        memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
        memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
@@ -5217,8 +5411,10 @@ start_single_stepping (void)
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        int val = InterlockedIncrement (&ss_count);
 
-       if (val == 1)
+       if (val == 1) {
                mono_arch_start_single_stepping ();
+               mono_interp_start_single_stepping ();
+       }
 #else
        g_assert_not_reached ();
 #endif
@@ -5230,8 +5426,10 @@ stop_single_stepping (void)
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        int val = InterlockedDecrement (&ss_count);
 
-       if (val == 0)
+       if (val == 0) {
                mono_arch_stop_single_stepping ();
+               mono_interp_stop_single_stepping ();
+       }
 #else
        g_assert_not_reached ();
 #endif
@@ -5807,7 +6005,7 @@ mono_debugger_agent_debug_log_is_enabled (void)
        return agent_config.enabled;
 }
 
-#if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
+#if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
 void
 mono_debugger_agent_unhandled_exception (MonoException *exc)
 {
@@ -6674,6 +6872,24 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai
        }
 }
 
+static void
+set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf)
+{
+       int size;
+
+       if (t->byref) {
+               addr = *(gpointer*)addr;
+               g_assert (addr);
+       }
+
+       if (MONO_TYPE_IS_REFERENCE (t))
+               size = sizeof (gpointer);
+       else
+               size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
+
+       memcpy (addr, val_buf, size);
+}
+
 static void
 clear_event_request (int req_id, int etype)
 {
@@ -6830,7 +7046,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
        MonoMethodSignature *sig;
        guint8 **arg_buf;
        void **args;
-       MonoObject *this_arg, *res, *exc;
+       MonoObject *this_arg, *res, *exc = NULL;
        MonoDomain *domain;
        guint8 *this_buf;
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
@@ -6958,11 +7174,17 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                                args [i] = arg_buf [i];
                        }
                } else {
-                       arg_buf [i] = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig->params [i])));
+                       MonoClass *arg_class = mono_class_from_mono_type (sig->params [i]);
+                       arg_buf [i] = (guint8 *)g_alloca (mono_class_instance_size (arg_class));
                        err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end);
                        if (err != ERR_NONE)
                                break;
-                       args [i] = arg_buf [i];
+                       if (mono_class_is_nullable (arg_class)) {
+                               args [i] = mono_nullable_box (arg_buf [i], arg_class, &error);
+                               mono_error_assert_ok (&error);
+                       } else {
+                               args [i] = arg_buf [i];
+                       }
                }
        }
 
@@ -6996,7 +7218,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
 
        mono_stopwatch_start (&watch);
        res = mono_runtime_try_invoke (m, m->klass->valuetype ? (gpointer) this_buf : (gpointer) this_arg, args, &exc, &error);
-       if (exc == NULL && !mono_error_ok (&error)) {
+       if (!mono_error_ok (&error) && exc == NULL) {
                exc = (MonoObject*) mono_error_convert_to_exception (&error);
        } else {
                mono_error_cleanup (&error); /* FIXME report error */
@@ -7015,7 +7237,9 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_ARGS) && CHECK_PROTOCOL_VERSION (2, 35))
                        out_args = TRUE;
                buffer_add_byte (buf, 1 + (out_this ? 2 : 0) + (out_args ? 4 : 0));
-               if (sig->ret->type == MONO_TYPE_VOID) {
+               if (m->string_ctor) {
+                       buffer_add_value (buf, &mono_get_string_class ()->byval_arg, &res, domain);
+               } else if (sig->ret->type == MONO_TYPE_VOID && !m->string_ctor) {
                        if (!strcmp (m->name, ".ctor")) {
                                if (!m->klass->valuetype)
                                        buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &this_arg, domain);
@@ -7467,7 +7691,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
 
                tls->abort_requested = TRUE;
 
-               mono_thread_internal_abort (THREAD_TO_INTERNAL (thread));
+               mono_thread_internal_abort (THREAD_TO_INTERNAL (thread), FALSE);
                mono_loader_unlock ();
                break;
        }
@@ -7821,7 +8045,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                break;
                        case EVENT_KIND_ASSEMBLY_LOAD:
                                /* Emit load events for currently loaded assemblies */
-                               mono_assembly_foreach (emit_assembly_load, NULL);
+                               mono_domain_foreach (send_assemblies_for_domain, NULL);
                                break;
                        case EVENT_KIND_THREAD_START:
                                /* Emit start events for currently started threads */
@@ -7935,13 +8159,19 @@ domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
        case CMD_APPDOMAIN_CREATE_STRING: {
                char *s;
                MonoString *o;
+               MonoError error;
 
                domain = decode_domainid (p, &p, end, NULL, &err);
                if (err != ERR_NONE)
                        return err;
                s = decode_string (p, &p, end);
 
-               o = mono_string_new (domain, s);
+               o = mono_string_new_checked (domain, s, &error);
+               if (!is_ok (&error)) {
+                       DEBUG_PRINTF (1, "[dbg] Failed to allocate String object '%s': %s\n", s, mono_error_get_message (&error));
+                       mono_error_cleanup (&error);
+                       return ERR_INVALID_OBJECT;
+               }
                buffer_add_objid (buf, (MonoObject*)o);
                break;
        }
@@ -7983,7 +8213,7 @@ get_assembly_object_command (MonoDomain *domain, MonoAssembly *ass, Buffer *buf,
 {
        HANDLE_FUNCTION_ENTER();
        ErrorCode err = ERR_NONE;
-       mono_error_init (error);
+       error_init (error);
        MonoReflectionAssemblyHandle o = mono_assembly_get_object_handle (domain, ass, error);
        if (MONO_HANDLE_IS_NULL (o)) {
                err = ERR_INVALID_OBJECT;
@@ -8041,6 +8271,10 @@ assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                mono_error_cleanup (&error);
                return err;
        }
+       case CMD_ASSEMBLY_GET_DOMAIN: {
+               buffer_add_domainid (buf, domain);
+               break;
+       }
        case CMD_ASSEMBLY_GET_TYPE: {
                MonoError error;
                char *s = decode_string (p, &p, end);
@@ -8630,7 +8864,7 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
                MonoError error;
                GPtrArray *array;
 
-               mono_error_init (&error);
+               error_init (&error);
                array = mono_class_get_methods_by_name (klass, name, flags & ~BINDING_FLAGS_IGNORE_CASE, (flags & BINDING_FLAGS_IGNORE_CASE) != 0, TRUE, &error);
                if (!is_ok (&error)) {
                        mono_error_cleanup (&error);
@@ -9333,7 +9567,13 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                // FIXME: Check that the ip change is safe
 
                DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset);
-               MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+
+               if (tls->frames [0]->ji->is_interp) {
+                       MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data;
+                       mono_interp_set_resume_state (jit_data, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+               } else {
+                       MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+               }
                break;
        }
        default:
@@ -9399,7 +9639,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
        sig = mono_method_signature (frame->actual_method);
 
-       if (!jit->has_var_info || !mono_get_seq_points (frame->domain, frame->actual_method))
+       if (!(jit->has_var_info || frame->ji->is_interp) || !mono_get_seq_points (frame->domain, frame->actual_method))
                /*
                 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
                 */
@@ -9420,9 +9660,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                DEBUG_PRINTF (4, "[dbg]   send arg %d.\n", pos);
 
-                               g_assert (pos >= 0 && pos < jit->num_params);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
 
-                               add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+                                       buffer_add_value_full (buf, sig->params [pos], addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       g_assert (pos >= 0 && pos < jit->num_params);
+
+                                       add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+                               }
                        } else {
                                MonoDebugLocalsInfo *locals;
 
@@ -9432,30 +9680,57 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                        pos = locals->locals [pos].index;
                                        mono_debug_free_locals (locals);
                                }
-                               g_assert (pos >= 0 && pos < jit->num_locals);
 
                                DEBUG_PRINTF (4, "[dbg]   send local %d.\n", pos);
 
-                               add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+
+                                       buffer_add_value_full (buf, header->locals [pos], addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       g_assert (pos >= 0 && pos < jit->num_locals);
+
+                                       add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+                               }
                        }
                }
                mono_metadata_free_mh (header);
                break;
        }
        case CMD_STACK_FRAME_GET_THIS: {
+               if (frame->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+                       return ERR_ABSENT_INFORMATION;
                if (frame->api_method->klass->valuetype) {
                        if (!sig->hasthis) {
                                MonoObject *p = NULL;
                                buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
                        } else {
-                               add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_this (frame->interp_frame);
+
+                                       buffer_add_value_full (buf, &frame->actual_method->klass->this_arg, addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               }
                        }
                } else {
                        if (!sig->hasthis) {
                                MonoObject *p = NULL;
                                buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain);
                        } else {
-                               add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_this (frame->interp_frame);
+
+                                       buffer_add_value_full (buf, &frame->api_method->klass->byval_arg, addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               }
                        }
                }
                break;
@@ -9464,7 +9739,8 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                MonoError error;
                guint8 *val_buf;
                MonoType *t;
-               MonoDebugVarInfo *var;
+               MonoDebugVarInfo *var = NULL;
+               gboolean is_arg = FALSE;
 
                len = decode_int (p, &p, end);
                header = mono_method_get_header_checked (frame->actual_method, &error);
@@ -9480,6 +9756,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                t = sig->params [pos];
                                var = &jit->params [pos];
+                               is_arg = TRUE;
                        } else {
                                MonoDebugLocalsInfo *locals;
 
@@ -9503,7 +9780,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                        if (err != ERR_NONE)
                                return err;
 
-                       set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+                       if (frame->ji->is_interp) {
+                               guint8 *addr;
+
+                               if (is_arg)
+                                       addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
+                               else
+                                       addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+                               set_interp_var (t, addr, val_buf);
+                       } else {
+                               set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+                       }
                }
                mono_metadata_free_mh (header);
                break;
@@ -9521,15 +9808,23 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                t = &frame->actual_method->klass->byval_arg;
                /* Checked by the sender */
                g_assert (MONO_TYPE_ISSTRUCT (t));
-               var = jit->this_var;
-               g_assert (var);
 
                val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (t)));
                err = decode_value (t, frame->domain, val_buf, p, &p, end);
                if (err != ERR_NONE)
                        return err;
 
-               set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+               if (frame->ji->is_interp) {
+                       guint8 *addr;
+
+                       addr = mono_interp_frame_get_this (frame->interp_frame);
+                       set_interp_var (&frame->actual_method->klass->this_arg, addr, val_buf);
+               } else {
+                       var = jit->this_var;
+                       g_assert (var);
+
+                       set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+               }
                break;
        }
        default:
@@ -9901,7 +10196,8 @@ static const char* assembly_cmds_str[] = {
        "GET_MANIFEST_MODULE",
        "GET_OBJECT",
        "GET_TYPE",
-       "GET_NAME"
+       "GET_NAME",
+       "GET_DOMAIN"
 };
 
 static const char* module_cmds_str[] = {
@@ -10102,12 +10398,14 @@ debugger_thread (void *arg)
 
        debugger_thread_id = mono_native_thread_id_get ();
 
-       MonoThread *thread = mono_thread_attach (mono_get_root_domain ());
-       mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Debugger agent"), TRUE, &error);
+       MonoInternalThread *internal = mono_thread_internal_current ();
+       MonoString *str = mono_string_new_checked (mono_domain_get (), "Debugger agent", &error);
+       mono_error_assert_ok (&error);
+       mono_thread_set_name_internal (internal, str, TRUE, FALSE, &error);
        mono_error_assert_ok (&error);
 
-       thread->internal_thread->state |= ThreadState_Background;
-       thread->internal_thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
+       internal->state |= ThreadState_Background;
+       internal->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
 
        if (agent_config.defer) {
                if (!wait_for_attach ()) {