s390x-codegen.h : Fix instruction definition and add instruction format variant
[mono.git] / mono / mini / debugger-agent.c
index 1599f6aba13bf4f0c5b2fb803e49a7c02c871176..346f964678147d40d64fb585e940ed35d5065209 100644 (file)
@@ -27,9 +27,6 @@
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <process.h>
 #endif
 #include <ws2tcpip.h>
-#ifdef __GNUC__
-/* cygwin's headers do not seem to define these */
-void WSAAPI freeaddrinfo (struct addrinfo*);
-int WSAAPI getaddrinfo (const char*,const char*,const struct addrinfo*,
-                        struct addrinfo**);
-int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
-                       char*,DWORD,int);
-#endif
 #endif
 
 #ifdef PLATFORM_ANDROID
@@ -82,8 +71,10 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
 #include <mono/utils/mono-stack-unwinding.h>
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/networking.h>
 #include "debugger-agent.h"
 #include "mini.h"
+#include "seq-points.h"
 
 /*
 On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -267,7 +258,10 @@ typedef struct {
         * event. This is the same as the ctx at step/breakpoint site, but includes changes
         * to caller saved registers done by set_var ().
         */
-       MonoContext restore_ctx;
+       MonoThreadUnwindState restore_state;
+       /* Frames computed from restore_state */
+       int restore_frame_count;
+       StackFrame **restore_frames;
 
        /* The currently unloading appdomain */
        MonoDomain *domain_unloading;
@@ -289,7 +283,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 37
+#define MINOR_VERSION 40
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -514,7 +508,8 @@ typedef enum {
 typedef enum {
        CMD_STACK_FRAME_GET_VALUES = 1,
        CMD_STACK_FRAME_GET_THIS = 2,
-       CMD_STACK_FRAME_SET_VALUES = 3
+       CMD_STACK_FRAME_SET_VALUES = 3,
+       CMD_STACK_FRAME_GET_DOMAIN = 4,
 } CmdStackFrame;
 
 typedef enum {
@@ -573,6 +568,7 @@ typedef struct {
        StepFilter filter;
        gpointer last_sp;
        gpointer start_sp;
+       MonoMethod *start_method;
        MonoMethod *last_method;
        int last_line;
        /* Whenever single stepping is performed using start/stop_single_stepping () */
@@ -615,6 +611,12 @@ typedef struct ReplyPacket {
 
 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
 
+#ifdef PLATFORM_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)
+#endif
+
 #ifdef HOST_WIN32
 #define get_last_sock_error() WSAGetLastError()
 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
@@ -797,8 +799,9 @@ static void ids_cleanup (void);
 
 static void suspend_init (void);
 
-static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch);
-static ErrorCode ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
+static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch,
+                                         StackFrame **frames, int nframes);
+static ErrorCode ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilter filter, EventRequest *req);
 static void ss_destroy (SingleStepReq *req);
 
 static void start_debugger_thread (void);
@@ -815,6 +818,12 @@ static void
 register_socket_transport (void);
 #endif
 
+static inline gboolean
+is_debugger_thread (void)
+{
+       return GetCurrentThreadId () == debugger_thread_id;
+}
+
 static int
 parse_address (char *address, char **host, int *port)
 {
@@ -988,6 +997,9 @@ mono_debugger_agent_init (void)
 
        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_GC_REGISTER_ROOT_FIXED (thread_to_tls);
 
@@ -1020,7 +1032,7 @@ mono_debugger_agent_init (void)
        breakpoints_init ();
        suspend_init ();
 
-       mini_get_debug_options ()->gen_seq_points = TRUE;
+       mini_get_debug_options ()->gen_seq_points_debug_data = TRUE;
        /* 
         * This is needed because currently we don't handle liveness info.
         */
@@ -1152,10 +1164,6 @@ socket_transport_recv (void *buf, int len)
        } while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR));
        return total;
 }
-
-#ifndef TARGET_PS3
-#define HAVE_GETADDRINFO 1
-#endif
  
 static void
 set_keepalive (void)
@@ -1180,7 +1188,7 @@ socket_transport_accept (int socket_fd)
        if (conn_fd == -1) {
                fprintf (stderr, "debugger-agent: Unable to listen on %d\n", socket_fd);
        } else {
-               DEBUG (1, fprintf (log_file, "Accepted connection from client, connection fd=%d.\n", conn_fd));
+               DEBUG_PRINTF (1, "Accepted connection from client, connection fd=%d.\n", conn_fd);
        }
        
        return conn_fd;
@@ -1208,14 +1216,9 @@ socket_transport_send (void *data, int len)
 static void
 socket_transport_connect (const char *address)
 {
-#ifdef HAVE_GETADDRINFO
-       struct addrinfo hints;
-       struct addrinfo *result, *rp;
-#else
-       struct hostent *result;
-#endif
+       MonoAddressInfo *result;
+       MonoAddressEntry *rp;
        int sfd = -1, s, res;
-       char port_string [128];
        char *host;
        int port;
 
@@ -1231,34 +1234,18 @@ socket_transport_connect (const char *address)
        listen_fd = -1;
 
        if (host) {
-               sprintf (port_string, "%d", port);
 
                mono_network_init ();
 
                /* Obtain address(es) matching host/port */
-#ifdef HAVE_GETADDRINFO
-               memset (&hints, 0, sizeof (struct addrinfo));
-               hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
-               hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
-               hints.ai_flags = 0;
-               hints.ai_protocol = 0;          /* Any protocol */
-
-               s = getaddrinfo (host, port_string, &hints, &result);
+               s = mono_get_address_info (host, port, MONO_HINT_UNSPECIFIED, &result);
                if (s != 0) {
-                       fprintf (stderr, "debugger-agent: Unable to resolve %s:%d: %s\n", host, port, gai_strerror (s));
+                       fprintf (stderr, "debugger-agent: Unable to resolve %s:%d: %d\n", host, port, s); // FIXME add portable error conversion functions
                        exit (1);
                }
-#else
-               /* The PS3 doesn't even have _r or hstrerror () */
-               result = gethostbyname (host);
-               if (!result) {
-                       fprintf (stderr, "debugger-agent: Unable to resolve %s:%d: %d\n", host, port, h_errno);
-               }
-#endif
        }
 
        if (agent_config.server) {
-#ifdef HAVE_GETADDRINFO
                /* Wait for a connection */
                if (!host) {
                        struct sockaddr_in addr;
@@ -1289,18 +1276,22 @@ socket_transport_connect (const char *address)
                        printf ("%s:%d\n", host, port);
                } else {
                        /* Listen on the provided address */
-                       for (rp = result; rp != NULL; rp = rp->ai_next) {
+                       for (rp = result->entries; rp != NULL; rp = rp->next) {
+                               MonoSocketAddress sockaddr;
+                               socklen_t sock_len;
                                int n = 1;
 
-                               sfd = socket (rp->ai_family, rp->ai_socktype,
-                                                         rp->ai_protocol);
+                               mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
+
+                               sfd = socket (rp->family, rp->socktype,
+                                                         rp->protocol);
                                if (sfd == -1)
                                        continue;
 
                                if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
                                        continue;
 
-                               res = bind (sfd, rp->ai_addr, rp->ai_addrlen);
+                               res = bind (sfd, &sockaddr.addr, sock_len);
                                if (res == -1)
                                        continue;
 
@@ -1311,23 +1302,13 @@ socket_transport_connect (const char *address)
                                break;
                        }
 
-#ifndef HOST_WIN32
-                       /*
-                        * this function is not present on win2000 which we still support, and the
-                        * workaround described here:
-                        * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
-                        * only works with MSVC.
-                        */
-#ifdef HAVE_GETADDRINFO
-                       freeaddrinfo (result);
-#endif
-#endif
+                       mono_free_address_info (result);
                }
 
                if (agent_config.defer)
                        return;
 
-               DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
+               DEBUG_PRINTF (1, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout);
 
                if (agent_config.timeout) {
                        fd_set readfds;
@@ -1348,21 +1329,22 @@ socket_transport_connect (const char *address)
                if (conn_fd == -1)
                        exit (1);
 
-               DEBUG (1, fprintf (log_file, "Accepted connection from client, socket fd=%d.\n", conn_fd));
-#else
-               NOT_IMPLEMENTED;
-#endif /* HAVE_GETADDRINFO */
+               DEBUG_PRINTF (1, "Accepted connection from client, socket fd=%d.\n", conn_fd);
        } else {
                /* Connect to the specified address */
-#ifdef HAVE_GETADDRINFO
                /* FIXME: Respect the timeout */
-               for (rp = result; rp != NULL; rp = rp->ai_next) {
-                       sfd = socket (rp->ai_family, rp->ai_socktype,
-                                                 rp->ai_protocol);
+               for (rp = result->entries; rp != NULL; rp = rp->next) {
+                       MonoSocketAddress sockaddr;
+                       socklen_t sock_len;
+
+                       mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
+
+                       sfd = socket (rp->family, rp->socktype,
+                                                 rp->protocol);
                        if (sfd == -1)
                                continue;
 
-                       if (connect (sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+                       if (connect (sfd, &sockaddr.addr, sock_len) != -1)
                                break;       /* Success */
                        
                        close (sfd);
@@ -1372,23 +1354,10 @@ socket_transport_connect (const char *address)
                        fprintf (stderr, "debugger-agent: Unable to connect to %s:%d\n", host, port);
                        exit (1);
                }
-#else
-                       sfd = socket (result->h_addrtype, SOCK_STREAM, 0);
-                       if (sfd == -1)
-                               g_assert_not_reached ();
-                       res = connect (sfd, (void*)result->h_addr_list [0], result->h_length);
-                       if (res == -1)
-                               g_assert_not_reached ();
-#endif
 
                conn_fd = sfd;
 
-#ifndef HOST_WIN32
-               /* See the comment above */
-#ifdef HAVE_GETADDRINFO
-               freeaddrinfo (result);
-#endif
-#endif
+               mono_free_address_info (result);
        }
        
        if (!transport_handshake ())
@@ -1486,7 +1455,7 @@ static DebuggerTransport *transport;
 static DebuggerTransport transports [MAX_TRANSPORTS];
 static int ntransports;
 
-void
+MONO_API void
 mono_debugger_agent_register_transport (DebuggerTransport *trans);
 
 void
@@ -1901,7 +1870,7 @@ send_buffered_reply_packets (void)
        send_reply_packets (nreply_packets, reply_packets);
        for (i = 0; i < nreply_packets; ++i)
                buffer_free (reply_packets [i].data);
-       DEBUG (1, fprintf (log_file, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets, (long)mono_100ns_ticks () / 10000));
+       DEBUG_PRINTF (1, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets, (long)mono_100ns_ticks () / 10000);
        nreply_packets = 0;
 }
 
@@ -2340,7 +2309,7 @@ decode_ptr_id (guint8 *buf, guint8 **endbuf, guint8 *limit, IdType type, MonoDom
        dbg_unlock ();
 
        if (res->domain == NULL) {
-               DEBUG (0, fprintf (log_file, "ERR_UNLOADED, id=%d, type=%d.\n", id, type));
+               DEBUG_PRINTF (0, "ERR_UNLOADED, id=%d, type=%d.\n", id, type);
                *err = ERR_UNLOADED;
                return NULL;
        }
@@ -2370,7 +2339,7 @@ decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain,
                char *s;
 
                s = mono_type_full_name (&klass->byval_arg);
-               DEBUG(2, fprintf (log_file, "[dbg]   recv class [%s]\n", s));
+               DEBUG_PRINTF (2, "[dbg]   recv class [%s]\n", s);
                g_free (s);
        }
        return klass;
@@ -2398,7 +2367,7 @@ decode_methodid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domai
                char *s;
 
                s = mono_method_full_name (m, TRUE);
-               DEBUG(2, fprintf (log_file, "[dbg]   recv method [%s]\n", s));
+               DEBUG_PRINTF (2, "[dbg]   recv method [%s]\n", s);
                g_free (s);
        }
        return m;
@@ -2431,9 +2400,9 @@ buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
 
                s = mono_type_full_name (&klass->byval_arg);
                if (GetCurrentThreadId () == debugger_thread_id)
-                       DEBUG(2, fprintf (log_file, "[dbg]   send class [%s]\n", s));
+                       DEBUG_PRINTF (2, "[dbg]   send class [%s]\n", s);
                else
-                       DEBUG(2, fprintf (log_file, "[%p]   send class [%s]\n", (gpointer)GetCurrentThreadId (), s));
+                       DEBUG_PRINTF (2, "[%p]   send class [%s]\n", (gpointer)GetCurrentThreadId (), s);
                g_free (s);
        }
 }
@@ -2446,7 +2415,7 @@ buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method)
                char *s;
 
                s = mono_method_full_name (method, 1);
-               DEBUG(2, fprintf (log_file, "[dbg]   send method [%s]\n", s));
+               DEBUG_PRINTF (2, "[dbg]   send method [%s]\n", s);
                g_free (s);
        }
 }
@@ -2458,7 +2427,7 @@ buffer_add_assemblyid (Buffer *buf, MonoDomain *domain, MonoAssembly *assembly)
 
        id = buffer_add_ptr_id (buf, domain, ID_ASSEMBLY, assembly);
        if (G_UNLIKELY (log_level >= 2) && assembly)
-               DEBUG(2, fprintf (log_file, "[dbg]   send assembly [%s][%s][%d]\n", assembly->aname.name, domain->friendly_name, id));
+               DEBUG_PRINTF (2, "[dbg]   send assembly [%s][%s][%d]\n", assembly->aname.name, domain->friendly_name, id);
 }
 
 static inline void
@@ -2603,7 +2572,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
        if (sigctx)
                ip = mono_arch_ip_from_context (sigctx);
        else if (info)
-               ip = MONO_CONTEXT_GET_IP (&info->suspend_state.ctx);
+               ip = MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx);
        else
                ip = NULL;
 
@@ -2617,7 +2586,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
 
        if (ji) {
                /* Running managed code, will be suspended by the single step code */
-               DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip));
+               DEBUG_PRINTF (1, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip);
                return TRUE;
        } else {
                /* 
@@ -2633,7 +2602,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
                        // FIXME: printf is not signal safe, but this is only used during
                        // debugger debugging
                        if (ip)
-                               DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)(gsize)tid, ip));
+                               DEBUG_PRINTF (1, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)(gsize)tid, ip);
                        //save_thread_context (&ctx);
 
                        if (!tls->thread)
@@ -2660,7 +2629,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
                                 */
                                mono_walk_stack_with_ctx (get_last_frame, &ctx, MONO_UNWIND_NONE, &data);
                        } else if (info) {
-                               mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &data);
+                               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) {
                                memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
@@ -2701,7 +2670,7 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
 
        tls = mono_native_tls_get_value (debugger_tls_id);
        if (!tls) {
-               DEBUG (1, fprintf (log_file, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer)GetCurrentThreadId ()));
+               DEBUG_PRINTF (1, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer)GetCurrentThreadId ());
                return FALSE;
        }
 
@@ -2738,6 +2707,24 @@ reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_d
        }
 }
 
+typedef struct {
+       DebuggerTlsData *tls;
+       gboolean valid_info;
+} InterruptData;
+
+static SuspendThreadResult
+debugger_interrupt_critical (MonoThreadInfo *info, gpointer user_data)
+{
+       InterruptData *data = user_data;
+       MonoJitInfo *ji;
+
+       data->valid_info = TRUE;
+       ji = mono_jit_info_table_find (mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
+
+       thread_interrupt (data->tls, info, NULL, ji);
+       return MonoResumeThread;
+}
+
 /*
  * notify_thread:
  *
@@ -2756,7 +2743,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
        if (GetCurrentThreadId () == tid || tls->terminated)
                return;
 
-       DEBUG(1, fprintf (log_file, "[%p] Interrupting %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid));
+       DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid);
 
        /*
         * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
@@ -2778,22 +2765,16 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
 
        /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
        if (mono_thread_info_new_interrupt_enabled ()) {
-               MonoThreadInfo *info;
-               MonoJitInfo *ji;
+               InterruptData interrupt_data = { 0 };
+               interrupt_data.tls = tls;
 
-               info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
-               if (!info) {
-                       DEBUG(1, fprintf (log_file, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid));
+               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);
                        /* 
                         * Attached thread which died without detaching.
                         */
                        tls->terminated = TRUE;
-               } else {
-                       ji = mono_jit_info_table_find (info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
-
-                       thread_interrupt (tls, info, NULL, ji);
-
-                       mono_thread_info_finish_suspend_and_resume (info);
                }
        } else {
 #ifdef HOST_WIN32
@@ -2802,7 +2783,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
 #else
                res = mono_thread_kill (thread, mono_thread_get_abort_signal ());
                if (res) {
-                       DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res));
+                       DEBUG_PRINTF (1, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res);
                        /* 
                         * Attached thread which died without detaching.
                         */
@@ -2835,7 +2816,7 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
        if (suspend_count - tls->resume_count > 0)
                tls->suspending = TRUE;
 
-       DEBUG(1, fprintf (log_file, "[%p] Received single step event for suspending.\n", (gpointer)GetCurrentThreadId ()));
+       DEBUG_PRINTF (1, "[%p] Received single step event for suspending.\n", (gpointer)GetCurrentThreadId ());
 
        if (suspend_count - tls->resume_count == 0) {
                /* 
@@ -2843,7 +2824,7 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
                 * suspending is still active.
                 * FIXME: This slows down single threaded invokes.
                 */
-               DEBUG(1, fprintf (log_file, "[%p] Ignored during single threaded invoke.\n", (gpointer)GetCurrentThreadId ()));
+               DEBUG_PRINTF (1, "[%p] Ignored during single threaded invoke.\n", (gpointer)GetCurrentThreadId ());
                return;
        }
 
@@ -2874,7 +2855,7 @@ suspend_vm (void)
 
        suspend_count ++;
 
-       DEBUG(1, fprintf (log_file, "[%p] Suspending vm...\n", (gpointer)GetCurrentThreadId ()));
+       DEBUG_PRINTF (1, "[%p] Suspending vm...\n", (gpointer)GetCurrentThreadId ());
 
        if (suspend_count == 1) {
                // FIXME: Is it safe to call this inside the lock ?
@@ -2913,7 +2894,7 @@ resume_vm (void)
        g_assert (suspend_count > 0);
        suspend_count --;
 
-       DEBUG(1, fprintf (log_file, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)GetCurrentThreadId (), suspend_count));
+       DEBUG_PRINTF (1, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)GetCurrentThreadId (), suspend_count);
 
        if (suspend_count == 0) {
                // FIXME: Is it safe to call this inside the lock ?
@@ -2956,7 +2937,7 @@ resume_thread (MonoInternalThread *thread)
 
        g_assert (suspend_count > 0);
 
-       DEBUG(1, fprintf (log_file, "[sdb] Resuming thread %p...\n", (gpointer)(gssize)thread->tid));
+       DEBUG_PRINTF (1, "[sdb] Resuming thread %p...\n", (gpointer)(gssize)thread->tid);
 
        tls->resume_count += suspend_count;
 
@@ -2974,22 +2955,32 @@ resume_thread (MonoInternalThread *thread)
 }
 
 static void
-invalidate_frames (DebuggerTlsData *tls)
+free_frames (StackFrame **frames, int nframes)
 {
        int i;
 
+       for (i = 0; i < nframes; ++i) {
+               if (frames [i]->jit)
+                       mono_debug_free_method_jit_info (frames [i]->jit);
+               g_free (frames [i]);
+       }
+       g_free (frames);
+}
+
+static void
+invalidate_frames (DebuggerTlsData *tls)
+{
        if (!tls)
                tls = mono_native_tls_get_value (debugger_tls_id);
        g_assert (tls);
 
-       for (i = 0; i < tls->frame_count; ++i) {
-               if (tls->frames [i]->jit)
-                       mono_debug_free_method_jit_info (tls->frames [i]->jit);
-               g_free (tls->frames [i]);
-       }
-       g_free (tls->frames);
+       free_frames (tls->frames, tls->frame_count);
        tls->frame_count = 0;
        tls->frames = NULL;
+
+       free_frames (tls->restore_frames, tls->restore_frame_count);
+       tls->restore_frame_count = 0;
+       tls->restore_frames = NULL;
 }
 
 /*
@@ -3029,7 +3020,7 @@ suspend_current (void)
                MONO_SEM_POST (&suspend_sem);
        }
 
-       DEBUG(1, fprintf (log_file, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ()));
+       DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ());
 
        while (suspend_count - tls->resume_count > 0) {
 #ifdef HOST_WIN32
@@ -3055,7 +3046,7 @@ suspend_current (void)
 
        mono_mutex_unlock (&suspend_mutex);
 
-       DEBUG(1, fprintf (log_file, "[%p] Resumed.\n", (gpointer)GetCurrentThreadId ()));
+       DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer)GetCurrentThreadId ());
 
        if (tls->pending_invoke) {
                /* Save the original context */
@@ -3111,7 +3102,7 @@ wait_for_suspend (void)
        while (TRUE) {
                nwait = count_threads_to_wait_for ();
                if (nwait) {
-                       DEBUG(1, fprintf (log_file, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads));
+                       DEBUG_PRINTF (1, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads);
                        err = MONO_SEM_WAIT (&suspend_sem);
                        g_assert (err == 0);
                        waited = TRUE;
@@ -3121,7 +3112,7 @@ wait_for_suspend (void)
        }
 
        if (waited)
-               DEBUG(1, fprintf (log_file, "%d threads suspended.\n", nthreads));
+               DEBUG_PRINTF (1, "%d threads suspended.\n", nthreads);
 }
 
 /*
@@ -3135,24 +3126,6 @@ is_suspended (void)
        return count_threads_to_wait_for () == 0;
 }
 
-static MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
-{
-       MonoSeqPointInfo *seq_points;
-
-       mono_domain_lock (domain);
-       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
-       if (!seq_points && method->is_inflated) {
-               /* generic sharing + aot */
-               seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
-               if (!seq_points)
-                       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
-       }
-       mono_domain_unlock (domain);
-
-       return seq_points;
-}
-
 static void
 no_seq_points_found (MonoMethod *method)
 {
@@ -3162,87 +3135,6 @@ no_seq_points_found (MonoMethod *method)
        printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
 }
 
-/*
- * find_next_seq_point_for_native_offset:
- *
- *   Find the first sequence point after NATIVE_OFFSET.
- */
-static SeqPoint*
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       seq_points = get_seq_points (domain, method);
-       if (!seq_points) {
-               if (info)
-                       *info = NULL;
-               return NULL;
-       }
-       g_assert (seq_points);
-       if (info)
-               *info = seq_points;
-
-       for (i = 0; i < seq_points->len; ++i) {
-               if (seq_points->seq_points [i].native_offset >= native_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
-/*
- * find_prev_seq_point_for_native_offset:
- *
- *   Find the first sequence point before NATIVE_OFFSET.
- */
-static SeqPoint*
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       seq_points = get_seq_points (domain, method);
-       if (info)
-               *info = seq_points;
-       if (!seq_points)
-               return NULL;
-
-       for (i = seq_points->len - 1; i >= 0; --i) {
-               if (seq_points->seq_points [i].native_offset <= native_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
-/*
- * find_seq_point:
- *
- *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
- * should be the location of a sequence point.
- */
-static G_GNUC_UNUSED SeqPoint*
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
-{
-       MonoSeqPointInfo *seq_points;
-       int i;
-
-       *info = NULL;
-
-       seq_points = get_seq_points (domain, method);
-       if (!seq_points)
-               return NULL;
-       *info = seq_points;
-
-       for (i = 0; i < seq_points->len; ++i) {
-               if (seq_points->seq_points [i].il_offset == il_offset)
-                       return &seq_points->seq_points [i];
-       }
-
-       return NULL;
-}
-
 typedef struct {
        DebuggerTlsData *tls;
        GSList *frames;
@@ -3254,7 +3146,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        ComputeFramesUserData *ud = user_data;
        StackFrame *frame;
        MonoMethod *method, *actual_method, *api_method;
-       SeqPoint *sp;
+       SeqPoint sp;
        int flags = 0;
 
        if (info->type != FRAME_TYPE_MANAGED) {
@@ -3282,15 +3174,14 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        if (info->il_offset == -1) {
                /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
                if (ud->frames == NULL) {
-                       sp = find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL);
-                       if (sp)
-                               info->il_offset = sp->il_offset;
+                       if (find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL, &sp))
+                               info->il_offset = sp.il_offset;
                }
                if (info->il_offset == -1)
                        info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
        }
 
-       DEBUG (1, fprintf (log_file, "\tFrame: %s:%x(%x) %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed));
+       DEBUG_PRINTF (1, "\tFrame: %s:%x(%x) %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed);
 
        if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
                if (!CHECK_PROTOCOL_VERSION (2, 17))
@@ -3343,6 +3234,35 @@ process_filter_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data
        return process_frame (info, ctx, user_data);
 }
 
+/*
+ * Return a malloc-ed list of StackFrame structures.
+ */
+static StackFrame**
+compute_frame_info_from (MonoInternalThread *thread, DebuggerTlsData *tls, MonoThreadUnwindState *state, int *out_nframes)
+{
+       ComputeFramesUserData user_data;
+       MonoUnwindOptions opts = MONO_UNWIND_DEFAULT|MONO_UNWIND_REG_LOCATIONS;
+       StackFrame **res;
+       int i, nframes;
+       GSList *l;
+
+       user_data.tls = tls;
+       user_data.frames = NULL;
+
+       mono_walk_stack_with_state (process_frame, state, opts, &user_data);
+
+       nframes = g_slist_length (user_data.frames);
+       res = g_new0 (StackFrame*, nframes);
+       l = user_data.frames;
+       for (i = 0; i < nframes; ++i) {
+               res [i] = l->data;
+               l = l->next;
+       }
+       *out_nframes = nframes;
+
+       return res;
+}
+
 static void
 compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls)
 {
@@ -3356,7 +3276,7 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls)
        if (tls->frames && tls->frames_up_to_date)
                return;
 
-       DEBUG(1, fprintf (log_file, "Frames for %p(tid=%lx):\n", thread, (glong)thread->tid));
+       DEBUG_PRINTF (1, "Frames for %p(tid=%lx):\n", thread, (glong)thread->tid);
 
        user_data.tls = tls;
        user_data.frames = NULL;
@@ -3478,6 +3398,89 @@ strdup_tolower (char *s)
        return s2;
 }
 
+/*
+ * Same as g_path_get_basename () but handles windows paths as well,
+ * which can occur in .mdb files created by pdb2mdb.
+ */
+static char*
+dbg_path_get_basename (const char *filename)
+{
+       char *r;
+
+       if (!filename || strchr (filename, '/') || !strchr (filename, '\\'))
+               return g_path_get_basename (filename);
+
+       /* From gpath.c */
+
+       /* No separator -> filename */
+       r = strrchr (filename, '\\');
+       if (r == NULL)
+               return g_strdup (filename);
+
+       /* Trailing slash, remove component */
+       if (r [1] == 0){
+               char *copy = g_strdup (filename);
+               copy [r-filename] = 0;
+               r = strrchr (copy, '\\');
+
+               if (r == NULL){
+                       g_free (copy);
+                       return g_strdup ("/");
+               }
+               r = g_strdup (&r[1]);
+               g_free (copy);
+               return r;
+       }
+
+       return g_strdup (&r[1]);
+}
+
+static void
+init_jit_info_dbg_attrs (MonoJitInfo *ji)
+{
+       static MonoClass *hidden_klass, *step_through_klass, *non_user_klass;
+       MonoCustomAttrInfo *ainfo;
+
+       if (ji->dbg_attrs_inited)
+               return;
+
+       if (!hidden_klass) {
+               hidden_klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute");
+               g_assert (hidden_klass);
+       }
+       if (!step_through_klass) {
+               step_through_klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerStepThroughAttribute");
+               g_assert (step_through_klass);
+       }
+       if (!non_user_klass) {
+               non_user_klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerNonUserCodeAttribute");
+               g_assert (non_user_klass);
+       }
+
+       ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
+       if (ainfo) {
+               if (mono_custom_attrs_has_attr (ainfo, hidden_klass))
+                       ji->dbg_hidden = TRUE;
+               if (mono_custom_attrs_has_attr (ainfo, step_through_klass))
+                       ji->dbg_step_through = TRUE;
+               if (mono_custom_attrs_has_attr (ainfo, non_user_klass))
+                       ji->dbg_non_user_code = TRUE;
+               mono_custom_attrs_free (ainfo);
+       }
+
+       ainfo = mono_custom_attrs_from_class (jinfo_get_method (ji)->klass);
+       if (ainfo) {
+               if (mono_custom_attrs_has_attr (ainfo, step_through_klass))
+                       ji->dbg_step_through = TRUE;
+               if (mono_custom_attrs_has_attr (ainfo, non_user_klass))
+                       ji->dbg_non_user_code = TRUE;
+               mono_custom_attrs_free (ainfo);
+       }
+
+       mono_memory_barrier ();
+       ji->dbg_attrs_inited = TRUE;
+}
+
 /*
  * EVENT HANDLING
  */
@@ -3572,7 +3575,7 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo
                                                                if (g_hash_table_lookup (mod->data.source_files, s))
                                                                        found = TRUE;
                                                                else {
-                                                                       char *s2 = g_path_get_basename (sinfo->source_file);
+                                                                       char *s2 = dbg_path_get_basename (sinfo->source_file);
                                                                        char *s3 = strdup_tolower (s2);
 
                                                                        if (g_hash_table_lookup (mod->data.source_files, s3))
@@ -3597,77 +3600,21 @@ create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo
                                } else if (mod->kind == MOD_KIND_STEP) {
                                        if ((mod->data.filter & STEP_FILTER_STATIC_CTOR) && ji &&
                                                (jinfo_get_method (ji)->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
-                                               !strcmp (jinfo_get_method (ji)->name, ".cctor"))
+                                               !strcmp (jinfo_get_method (ji)->name, ".cctor") &&
+                                               (jinfo_get_method (ji) != ((SingleStepReq*)req->info)->start_method))
                                                filtered = TRUE;
                                        if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) {
-                                               MonoCustomAttrInfo *ainfo;
-                                               static MonoClass *klass;
-
-                                               if (!klass) {
-                                                       klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute");
-                                                       g_assert (klass);
-                                               }
-                                               if (!ji->dbg_hidden_inited) {
-                                                       ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
-                                                       if (ainfo) {
-                                                               if (mono_custom_attrs_has_attr (ainfo, klass))
-                                                                       ji->dbg_hidden = TRUE;
-                                                               mono_custom_attrs_free (ainfo);
-                                                       }
-                                                       ji->dbg_hidden_inited = TRUE;
-                                               }
+                                               init_jit_info_dbg_attrs (ji);
                                                if (ji->dbg_hidden)
                                                        filtered = TRUE;
                                        }
                                        if ((mod->data.filter & STEP_FILTER_DEBUGGER_STEP_THROUGH) && ji) {
-                                               MonoCustomAttrInfo *ainfo;
-                                               static MonoClass *klass;
-
-                                               if (!klass) {
-                                                       klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerStepThroughAttribute");
-                                                       g_assert (klass);
-                                               }
-                                               if (!ji->dbg_step_through_inited) {
-                                                       ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
-                                                       if (ainfo) {
-                                                               if (mono_custom_attrs_has_attr (ainfo, klass))
-                                                                       ji->dbg_step_through = TRUE;
-                                                               mono_custom_attrs_free (ainfo);
-                                                       }
-                                                       ainfo = mono_custom_attrs_from_class (jinfo_get_method (ji)->klass);
-                                                       if (ainfo) {
-                                                               if (mono_custom_attrs_has_attr (ainfo, klass))
-                                                                       ji->dbg_step_through = TRUE;
-                                                               mono_custom_attrs_free (ainfo);
-                                                       }
-                                                       ji->dbg_step_through_inited = TRUE;
-                                               }
+                                               init_jit_info_dbg_attrs (ji);
                                                if (ji->dbg_step_through)
                                                        filtered = TRUE;
                                        }
                                        if ((mod->data.filter & STEP_FILTER_DEBUGGER_NON_USER_CODE) && ji) {
-                                               MonoCustomAttrInfo *ainfo;
-                                               static MonoClass *klass;
-
-                                               if (!klass) {
-                                                       klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerNonUserCodeAttribute");
-                                                       g_assert (klass);
-                                               }
-                                               if (!ji->dbg_non_user_code_inited) {
-                                                       ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
-                                                       if (ainfo) {
-                                                               if (mono_custom_attrs_has_attr (ainfo, klass))
-                                                                       ji->dbg_non_user_code = TRUE;
-                                                               mono_custom_attrs_free (ainfo);
-                                                       }
-                                                       ainfo = mono_custom_attrs_from_class (jinfo_get_method (ji)->klass);
-                                                       if (ainfo) {
-                                                               if (mono_custom_attrs_has_attr (ainfo, klass))
-                                                                       ji->dbg_non_user_code = TRUE;
-                                                               mono_custom_attrs_free (ainfo);
-                                                       }
-                                                       ji->dbg_non_user_code_inited = TRUE;
-                                               }
+                                               init_jit_info_dbg_attrs (ji);
                                                if (ji->dbg_non_user_code)
                                                        filtered = TRUE;
                                        }
@@ -3738,28 +3685,28 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
        int nevents;
 
        if (!inited) {
-               DEBUG (2, fprintf (log_file, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event));
                return;
        }
 
        if (!vm_start_event_sent && event != EVENT_KIND_VM_START) {
                // FIXME: We miss those events
-               DEBUG (2, fprintf (log_file, "VM start event not sent yet: dropping %s\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "VM start event not sent yet: dropping %s\n", event_to_string (event));
                return;
        }
 
        if (vm_death_event_sent) {
-               DEBUG (2, fprintf (log_file, "VM death event has been sent: dropping %s\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "VM death event has been sent: dropping %s\n", event_to_string (event));
                return;
        }
 
        if (mono_runtime_is_shutting_down () && event != EVENT_KIND_VM_DEATH) {
-               DEBUG (2, fprintf (log_file, "Mono runtime is shutting down: dropping %s\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "Mono runtime is shutting down: dropping %s\n", event_to_string (event));
                return;
        }
 
        if (disconnected) {
-               DEBUG (2, fprintf (log_file, "Debugger client is not connected: dropping %s\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "Debugger client is not connected: dropping %s\n", event_to_string (event));
                return;
        }
 
@@ -3907,7 +3854,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
        events = NULL;
 
        if (!send_success) {
-               DEBUG (2, fprintf (log_file, "Sending command %s failed.\n", event_to_string (event)));
+               DEBUG_PRINTF (2, "Sending command %s failed.\n", event_to_string (event));
                return;
        }
        
@@ -3915,7 +3862,7 @@ process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx
                vm_start_event_sent = TRUE;
        }
 
-       DEBUG (1, fprintf (log_file, "[%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)GetCurrentThreadId (), nevents, event_to_string (event), ecount, suspend_policy);
 
        switch (suspend_policy) {
        case SUSPEND_POLICY_NONE:
@@ -3987,14 +3934,14 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
                         * For some reason, thread_startup () might be called for the same thread
                         * multiple times (attach ?).
                         */
-                       DEBUG (1, fprintf (log_file, "[%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", (gpointer)tid, (gpointer)tid);
                        return;
                } else {
                        /*
                         * thread_end () might not be called for some threads, and the tid could
                         * get reused.
                         */
-                       DEBUG (1, fprintf (log_file, "[%p] Removing stale data for tid %p.\n", (gpointer)tid, (gpointer)tid));
+                       DEBUG_PRINTF (1, "[%p] Removing stale data for tid %p.\n", (gpointer)tid, (gpointer)tid);
                        mono_loader_lock ();
                        mono_g_hash_table_remove (thread_to_tls, old_thread);
                        mono_g_hash_table_remove (tid_to_thread, (gpointer)tid);
@@ -4011,7 +3958,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid)
        tls->thread = thread;
        mono_native_tls_set_value (debugger_tls_id, tls);
 
-       DEBUG (1, fprintf (log_file, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls));
+       DEBUG_PRINTF (1, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls);
 
        mono_loader_lock ();
        mono_g_hash_table_insert (thread_to_tls, thread, tls);
@@ -4050,7 +3997,16 @@ thread_end (MonoProfiler *prof, uintptr_t tid)
 
        /* We might be called for threads started before we registered the start callback */
        if (thread) {
-               DEBUG (1, fprintf (log_file, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls));
+               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)) {
+                       /*
+                        * 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.
+                        */
+                       return;
+               }
+
                process_profiler_event (EVENT_KIND_THREAD_DEATH, thread);
        }
 }
@@ -4070,6 +4026,10 @@ appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain)
 {
        DebuggerTlsData *tls;
 
+       /* This might be called during shutdown on the debugger thread from the CMD_VM_EXIT code */
+       if (is_debugger_thread ())
+               return;
+
        /*
         * Remember the currently unloading appdomain as it is needed to generate
         * proper ids for unloading assemblies.
@@ -4084,6 +4044,9 @@ appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
 {
        DebuggerTlsData *tls;
 
+       if (is_debugger_thread ())
+               return;
+
        tls = mono_native_tls_get_value (debugger_tls_id);
        g_assert (tls);
        tls->domain_unloading = NULL;
@@ -4122,6 +4085,9 @@ assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result)
 static void
 assembly_unload (MonoProfiler *prof, MonoAssembly *assembly)
 {
+       if (is_debugger_thread ())
+               return;
+
        process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
 
        clear_event_requests_for_assembly (assembly);
@@ -4269,7 +4235,6 @@ typedef struct {
        guint8 *ip;
        MonoJitInfo *ji;
        MonoDomain *domain;
-       SeqPoint *sp;
 } BreakpointInstance;
 
 /*
@@ -4314,38 +4279,44 @@ breakpoints_init (void)
 static void
 insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, MonoBreakpoint *bp, MonoError *error)
 {
-       int i, count;
+       int count;
        BreakpointInstance *inst;
-       SeqPoint *sp = NULL;
+       SeqPointIterator it;
+       gboolean it_has_sp = FALSE;
 
        if (error)
                mono_error_init (error);
 
-       for (i = 0; i < seq_points->len; ++i) {
-               sp = &seq_points->seq_points [i];
-
-               if (sp->il_offset == bp->il_offset)
+       seq_point_iterator_init (&it, seq_points);
+       while (seq_point_iterator_next (&it)) {
+               if (it.seq_point.il_offset == bp->il_offset) {
+                       it_has_sp = TRUE;
                        break;
+               }
        }
 
-       if (i == seq_points->len) {
+       if (!it_has_sp) {
                /*
                 * The set of IL offsets with seq points doesn't completely match the
                 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
                 */
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
-
-                       if (sp->il_offset != METHOD_ENTRY_IL_OFFSET && sp->il_offset != METHOD_EXIT_IL_OFFSET && sp->il_offset + 1 == bp->il_offset)
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it)) {
+                       if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET &&
+                               it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET &&
+                               it.seq_point.il_offset + 1 == bp->il_offset) {
+                               it_has_sp = TRUE;
                                break;
+                       }
                }
        }
 
-       if (i == seq_points->len) {
-               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset, seq_points->len);
+       if (!it_has_sp) {
+               char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset);
 
-               for (i = 0; i < seq_points->len; ++i)
-                       DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
+               seq_point_iterator_init (&it, seq_points);
+               while (seq_point_iterator_next (&it))
+                       DEBUG_PRINTF (1, "%d\n", it.seq_point.il_offset);
 
                if (error) {
                        mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
@@ -4360,9 +4331,9 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        }
 
        inst = g_new0 (BreakpointInstance, 1);
-       inst->sp = sp;
-       inst->native_offset = sp->native_offset;
-       inst->ip = (guint8*)ji->code_start + sp->native_offset;
+       inst->il_offset = it.seq_point.il_offset;
+       inst->native_offset = it.seq_point.native_offset;
+       inst->ip = (guint8*)ji->code_start + it.seq_point.native_offset;
        inst->ji = ji;
        inst->domain = domain;
 
@@ -4377,8 +4348,8 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
        dbg_unlock ();
 
-       if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
-               DEBUG (1, fprintf (log_file, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset));
+       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) {
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
                mono_arch_set_breakpoint (ji, inst->ip);
@@ -4387,7 +4358,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
 #endif
        }
 
-       DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)sp->il_offset, inst->ip, count));
+       DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, inst->ip, count);
 }
 
 static void
@@ -4407,7 +4378,7 @@ remove_breakpoint (BreakpointInstance *inst)
 
        if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
                mono_arch_clear_breakpoint (ji, ip);
-               DEBUG(1, fprintf (log_file, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip));
+               DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip);
        }
 #else
        NOT_IMPLEMENTED;
@@ -4558,7 +4529,7 @@ set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req, MonoError
        bp->req = req;
        bp->children = g_ptr_array_new ();
 
-       DEBUG(1, fprintf (log_file, "[dbg] Setting %sbreakpoint at %s:0x%x.\n", (req->event_kind == EVENT_KIND_STEP) ? "single step " : "", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
+       DEBUG_PRINTF (1, "[dbg] Setting %sbreakpoint at %s:0x%x.\n", (req->event_kind == EVENT_KIND_STEP) ? "single step " : "", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset);
 
        mono_loader_lock ();
 
@@ -4695,7 +4666,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 (1, fprintf (log_file, "[%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)GetCurrentThreadId (), sp->il_offset);
                return FALSE;
        }
 
@@ -4705,7 +4676,18 @@ 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 (1, fprintf (log_file, "[%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)GetCurrentThreadId ());
+                       return FALSE;
+               }
+       }
+
+       if (req->depth == STEP_DEPTH_INTO && req->size == STEP_SIZE_MIN && (sp->flags & MONO_SEQ_POINT_FLAG_NONEMPTY_STACK) && ss_req->start_method){
+               method = jinfo_get_method (ji);
+               if (!tls->context.valid)
+                       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);
                        return FALSE;
                }
        }
@@ -4720,12 +4702,12 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
        if (minfo)
                loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
 
-       if (!loc || (loc && method == ss_req->last_method && loc->row == ss_req->last_line)) {
-               /* Have to continue single stepping */
-               if (!loc)
-                       DEBUG(1, fprintf (log_file, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset));
-               else
-                       DEBUG(1, fprintf (log_file, "[%p] Same source line (%d), continuing single stepping.\n", (gpointer)GetCurrentThreadId (), loc->row));
+       if (!loc) {
+               DEBUG_PRINTF (1, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), 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);
                hit = FALSE;
        }
                                
@@ -4756,10 +4738,11 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        GPtrArray *bp_reqs, *ss_reqs_orig, *ss_reqs;
        GSList *bp_events = NULL, *ss_events = NULL, *enter_leave_events = NULL;
        EventKind kind = EVENT_KIND_BREAKPOINT;
-       MonoContext *ctx = &tls->restore_ctx;
+       MonoContext *ctx = &tls->restore_state.ctx;
        MonoMethod *method;
        MonoSeqPointInfo *info;
-       SeqPoint *sp;
+       SeqPoint sp;
+       gboolean found_sp;
 
        // FIXME: Speed this up
 
@@ -4789,12 +4772,14 @@ process_breakpoint_inner (DebuggerTlsData *tls)
         * The ip points to the instruction causing the breakpoint event, which is after
         * the offset recorded in the seq point map, so find the prev seq point before ip.
         */
-       sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info);
-       if (!sp)
+       found_sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp);
+
+       if (!found_sp)
                no_seq_points_found (method);
-       g_assert (sp);
 
-       DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp ? sp->il_offset : -1));
+       g_assert (found_sp);
+
+       DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), method->name, ip, native_offset, sp.il_offset);
 
        bp = NULL;
        for (i = 0; i < breakpoints->len; ++i) {
@@ -4805,7 +4790,7 @@ process_breakpoint_inner (DebuggerTlsData *tls)
 
                for (j = 0; j < bp->children->len; ++j) {
                        inst = g_ptr_array_index (bp->children, j);
-                       if (inst->ji == ji && inst->sp == sp) {
+                       if (inst->ji == ji && inst->il_offset == sp.il_offset && inst->native_offset == sp.native_offset) {
                                if (bp->req->event_kind == EVENT_KIND_STEP) {
                                        g_ptr_array_add (ss_reqs_orig, bp->req);
                                } else {
@@ -4816,9 +4801,9 @@ process_breakpoint_inner (DebuggerTlsData *tls)
        }
        if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
                /* Maybe a method entry/exit event */
-               if (sp->il_offset == METHOD_ENTRY_IL_OFFSET)
+               if (sp.il_offset == METHOD_ENTRY_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_ENTRY;
-               else if (sp->il_offset == METHOD_EXIT_IL_OFFSET)
+               else if (sp.il_offset == METHOD_EXIT_IL_OFFSET)
                        kind = EVENT_KIND_METHOD_EXIT;
        }
 
@@ -4831,12 +4816,12 @@ process_breakpoint_inner (DebuggerTlsData *tls)
                if (mono_thread_internal_current () != ss_req->thread)
                        continue;
 
-               hit = ss_update (ss_req, ji, sp, tls, ctx);
+               hit = ss_update (ss_req, ji, &sp, tls, ctx);
                if (hit)
                        g_ptr_array_add (ss_reqs, req);
 
                /* Start single stepping again from the current sequence point */
-               ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+               ss_start (ss_req, method, &sp, info, ctx, tls, FALSE, NULL, 0);
        }
        
        if (ss_reqs->len > 0)
@@ -4868,18 +4853,19 @@ static void
 process_signal_event (void (*func) (DebuggerTlsData*))
 {
        DebuggerTlsData *tls;
-       MonoContext orig_restore_ctx, ctx;
+       MonoThreadUnwindState orig_restore_state;
+       MonoContext ctx;
 
        tls = mono_native_tls_get_value (debugger_tls_id);
        /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
-       memcpy (&orig_restore_ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, &tls->handler_ctx, sizeof (MonoContext));
+       memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
+       mono_thread_state_init_from_monoctx (&tls->restore_state, &tls->handler_ctx);
 
        func (tls);
 
        /* This is called when resuming from a signal handler, so it shouldn't return */
-       memcpy (&ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, &orig_restore_ctx, sizeof (MonoContext));
+       memcpy (&ctx, &tls->restore_state.ctx, sizeof (MonoContext));
+       memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
        mono_restore_context (&ctx);
        g_assert_not_reached ();
 }
@@ -4995,9 +4981,9 @@ process_single_step_inner (DebuggerTlsData *tls)
        int il_offset, suspend_policy;
        MonoDomain *domain;
        GSList *events;
-       MonoContext *ctx = &tls->restore_ctx;
+       MonoContext *ctx = &tls->restore_state.ctx;
        MonoMethod *method;
-       SeqPoint *sp;
+       SeqPoint sp;
        MonoSeqPointInfo *info;
 
        ip = MONO_CONTEXT_GET_IP (ctx);
@@ -5020,7 +5006,7 @@ process_single_step_inner (DebuggerTlsData *tls)
        if (log_level > 0) {
                ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
 
-               DEBUG (1, fprintf (log_file, "[%p] Single step event (depth=%s) at %s (%p), 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), 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)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);
        }
 
        ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
@@ -5043,16 +5029,16 @@ process_single_step_inner (DebuggerTlsData *tls)
         * 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.
         */
-       sp = find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info);
-       if (!sp)
+       if (!find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
                return;
-       il_offset = sp->il_offset;
 
-       if (!ss_update (ss_req, ji, sp, tls, ctx))
+       il_offset = sp.il_offset;
+
+       if (!ss_update (ss_req, ji, &sp, tls, ctx))
                return;
 
        /* Start single stepping again from the current sequence point */
-       ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+       ss_start (ss_req, method, &sp, info, ctx, tls, FALSE, NULL, 0);
 
        if ((ss_req->filter & STEP_FILTER_STATIC_CTOR) &&
                (method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
@@ -5117,36 +5103,36 @@ void
 debugger_agent_single_step_from_context (MonoContext *ctx)
 {
        DebuggerTlsData *tls;
-       MonoContext orig_restore_ctx;
+       MonoThreadUnwindState orig_restore_state;
 
        tls = mono_native_tls_get_value (debugger_tls_id);
        g_assert (tls);
 
        /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
-       memcpy (&orig_restore_ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, ctx, sizeof (MonoContext));
+       memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
+       mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
 
        process_single_step_inner (tls);
 
-       memcpy (ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, &orig_restore_ctx, sizeof (MonoContext));
+       memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
+       memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
 }
 
 void
 debugger_agent_breakpoint_from_context (MonoContext *ctx)
 {
        DebuggerTlsData *tls;
-       MonoContext orig_restore_ctx;
+       MonoThreadUnwindState orig_restore_state;
 
        tls = mono_native_tls_get_value (debugger_tls_id);
        g_assert (tls);
-       memcpy (&orig_restore_ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, ctx, sizeof (MonoContext));
+       memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoContext));
+       mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
 
        process_breakpoint_inner (tls);
 
-       memcpy (ctx, &tls->restore_ctx, sizeof (MonoContext));
-       memcpy (&tls->restore_ctx, &orig_restore_ctx, sizeof (MonoContext));
+       memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
+       memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
 }
 
 /*
@@ -5224,13 +5210,19 @@ ss_stop (SingleStepReq *ss_req)
  *   Start the single stepping operation given by SS_REQ from the sequence point SP.
  * If CTX is not set, then this can target any thread. If CTX is set, then TLS should
  * belong to the same thread as CTX.
+ * If FRAMES is not-null, use that instead of tls->frames for placing breakpoints etc.
  */
 static void
-ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint* sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls,
+                 gboolean step_to_catch, StackFrame **frames, int nframes)
 {
        int i, j, frame_index;
-       SeqPoint *next_sp;
+       SeqPoint *next_sp, *parent_sp = NULL;
+       SeqPoint local_sp, local_parent_sp;
+       gboolean found_sp;
        MonoBreakpoint *bp;
+       MonoSeqPointInfo *parent_info;
+       MonoMethod *parent_sp_method = NULL;
        gboolean enable_global = FALSE;
 
        /* Stop the previous operation */
@@ -5245,11 +5237,13 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
        } else {
                frame_index = 1;
 
-               if ((!sp || sp->next_len == 0 || ss_req->depth == STEP_DEPTH_OUT || ss_req->depth == STEP_DEPTH_OVER) && ctx) {
+               if (ctx && !frames) {
                        /* Need parent frames */
                        if (!tls->context.valid)
                                mono_thread_state_init_from_monoctx (&tls->context, ctx);
                        compute_frame_info (tls->thread, tls);
+                       frames = tls->frames;
+                       nframes = tls->frame_count;
                }
 
                /*
@@ -5258,11 +5252,12 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                 */
                if (ss_req->depth == STEP_DEPTH_OUT) {
                        /* Ignore seq points in current method */
-                       while (frame_index < tls->frame_count) {
-                               StackFrame *frame = tls->frames [frame_index];
+                       while (frame_index < nframes) {
+                               StackFrame *frame = frames [frame_index];
 
                                method = frame->method;
-                               sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                               found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+                               sp = (found_sp)? &local_sp : NULL;
                                frame_index ++;
                                if (sp && sp->next_len != 0)
                                        break;
@@ -5272,41 +5267,73 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                } else {
                        if (sp && sp->next_len == 0) {
                                sp = NULL;
-                               while (frame_index < tls->frame_count) {
-                                       StackFrame *frame = tls->frames [frame_index];
+                               while (frame_index < nframes) {
+                                       StackFrame *frame = frames [frame_index];
 
                                        method = frame->method;
-                                       sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                                       found_sp = 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 && sp->next_len != 0)
                                                break;
                                        sp = NULL;
                                        frame_index ++;
                                }
+                       } else {
+                               /* Have to put a breakpoint into a parent frame since the seq points might not cover all control flow out of the method */
+                               while (frame_index < nframes) {
+                                       StackFrame *frame = frames [frame_index];
+
+                                       parent_sp_method = frame->method;
+                                       found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &parent_info, &local_parent_sp);
+                                       parent_sp = found_sp ? &local_parent_sp : NULL;
+                                       if (found_sp && parent_sp->next_len != 0)
+                                               break;
+                                       parent_sp = NULL;
+                                       frame_index ++;
+                               }
                        }
                }
 
                if (sp && sp->next_len > 0) {
-                       for (i = 0; i < sp->next_len; ++i) {
-                               next_sp = &info->seq_points [sp->next [i]];
+                       SeqPoint* next = g_new(SeqPoint, sp->next_len);
+
+                       seq_point_init_next (info, *sp, next);
+                       for (i = 0; i < sp->next_len; i++) {
+                               next_sp = &next[i];
 
                                bp = set_breakpoint (method, next_sp->il_offset, ss_req->req, NULL);
                                ss_req->bps = g_slist_append (ss_req->bps, bp);
                        }
+                       g_free (next);
+               }
+
+               if (parent_sp) {
+                       SeqPoint* next = g_new(SeqPoint, parent_sp->next_len);
+
+                       seq_point_init_next (parent_info, *parent_sp, next);
+                       for (i = 0; i < parent_sp->next_len; i++) {
+                               next_sp = &next[i];
+
+                               bp = set_breakpoint (parent_sp_method, next_sp->il_offset, ss_req->req, NULL);
+                               ss_req->bps = g_slist_append (ss_req->bps, bp);
+                       }
+                       g_free (next);
                }
 
+               if (ss_req->nframes == 0)
+                       ss_req->nframes = nframes;
                if (ss_req->depth == STEP_DEPTH_OVER) {
-                       if (ss_req->nframes == 0)
-                               ss_req->nframes = tls->frame_count;
                        /* Need to stop in catch clauses as well */
-                       for (i = 0; i < tls->frame_count; ++i) {
-                               StackFrame *frame = tls->frames [i];
+                       for (i = 0; i < nframes; ++i) {
+                               StackFrame *frame = frames [i];
 
                                if (frame->ji) {
                                        MonoJitInfo *jinfo = frame->ji;
                                        for (j = 0; j < jinfo->num_clauses; ++j) {
                                                MonoJitExceptionInfo *ei = &jinfo->clauses [j];
 
-                                               sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL);
+                                               found_sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL, &local_sp);
+                                               sp = (found_sp)? &local_sp : NULL;
                                                if (sp) {
                                                        bp = set_breakpoint (frame->method, sp->il_offset, ss_req->req, NULL);
                                                        ss_req->bps = g_slist_append (ss_req->bps, bp);
@@ -5316,7 +5343,6 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
                        }
                }
 
-
                if (ss_req->depth == STEP_DEPTH_INTO) {
                        /* Enable global stepping so we stop at method entry too */
                        enable_global = TRUE;
@@ -5331,11 +5357,11 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
        }
 
        if (enable_global) {
-               DEBUG (1, fprintf (log_file, "[dbg] Turning on global single stepping.\n"));
+               DEBUG_PRINTF (1, "[dbg] Turning on global single stepping.\n");
                ss_req->global = TRUE;
                start_single_stepping ();
        } else if (!ss_req->bps) {
-               DEBUG (1, fprintf (log_file, "[dbg] Turning on global single stepping.\n"));
+               DEBUG_PRINTF (1, "[dbg] Turning on global single stepping.\n");
                ss_req->global = TRUE;
                start_single_stepping ();
        } else {
@@ -5347,14 +5373,19 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
  * Start single stepping of thread THREAD
  */
 static ErrorCode
-ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
+ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilter filter, EventRequest *req)
 {
        DebuggerTlsData *tls;
        MonoSeqPointInfo *info = NULL;
        SeqPoint *sp = NULL;
+       SeqPoint local_sp;
+       gboolean found_sp;
        MonoMethod *method = NULL;
        MonoDebugMethodInfo *minfo;
        gboolean step_to_catch = FALSE;
+       gboolean set_ip = FALSE;
+       StackFrame **frames = NULL;
+       int nframes = 0;
 
        if (suspend_count == 0)
                return ERR_NOT_SUSPENDED;
@@ -5363,17 +5394,18 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
 
        // FIXME: Multiple requests
        if (ss_req) {
-               DEBUG (0, fprintf (log_file, "Received a single step request while the previous one was still active.\n"));
+               DEBUG_PRINTF (0, "Received a single step request while the previous one was still active.\n");
                return ERR_NOT_IMPLEMENTED;
        }
 
-       DEBUG (1, fprintf (log_file, "[dbg] Starting single step of thread %p (depth=%s).\n", thread, ss_depth_to_string (depth)));
+       DEBUG_PRINTF (1, "[dbg] Starting single step of thread %p (depth=%s).\n", thread, ss_depth_to_string (depth));
 
        ss_req = g_new0 (SingleStepReq, 1);
        ss_req->req = req;
        ss_req->thread = thread;
        ss_req->size = size;
        ss_req->depth = depth;
+       ss_req->filter = filter;
        req->info = ss_req;
 
        mono_loader_lock ();
@@ -5381,6 +5413,15 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
        mono_loader_unlock ();
        g_assert (tls);
        g_assert (tls->context.valid);
+
+       if (tls->restore_state.valid && MONO_CONTEXT_GET_IP (&tls->context.ctx) != MONO_CONTEXT_GET_IP (&tls->restore_state.ctx)) {
+               /*
+                * Need to start single stepping from restore_state and not from the current state
+                */
+               set_ip = TRUE;
+               frames = compute_frame_info_from (thread, tls, &tls->restore_state, &nframes);
+       }
+
        ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx);
 
        if (tls->catch_state.valid) {
@@ -5402,7 +5443,8 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
                 * Find the seq point corresponding to the landing site ip, which is the first seq
                 * point after ip.
                 */
-               sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info);
+               found_sp = 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);
                g_assert (sp);
@@ -5414,41 +5456,41 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
                ss_req->last_sp = NULL;
        }
 
-       if (!step_to_catch && ss_req->size == STEP_SIZE_LINE) {
-               StackFrame *frame;
+       if (!step_to_catch) {
+               StackFrame *frame = NULL;
 
-               /* Compute the initial line info */
-               compute_frame_info (thread, tls);
+               if (set_ip) {
+                       if (frames && nframes)
+                               frame = frames [0];
+               } else {
+                       compute_frame_info (thread, tls);
 
-               if (tls->frame_count) {
-                       frame = tls->frames [0];
+                       if (tls->frame_count)
+                               frame = tls->frames [0];
+               }
 
-                       ss_req->last_method = frame->method;
-                       ss_req->last_line = -1;
+               if (ss_req->size == STEP_SIZE_LINE) {
+                       if (frame) {
+                               ss_req->last_method = frame->method;
+                               ss_req->last_line = -1;
 
-                       minfo = mono_debug_lookup_method (frame->method);
-                       if (minfo && frame->il_offset != -1) {
-                               MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, frame->il_offset);
+                               minfo = mono_debug_lookup_method (frame->method);
+                               if (minfo && frame->il_offset != -1) {
+                                       MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, frame->il_offset);
 
-                               if (loc) {
-                                       ss_req->last_line = loc->row;
-                                       g_free (loc);
+                                       if (loc) {
+                                               ss_req->last_line = loc->row;
+                                               g_free (loc);
+                                       }
                                }
                        }
                }
-       }
-
-       if (!step_to_catch) {
-               StackFrame *frame;
-
-               compute_frame_info (thread, tls);
-
-               if (tls->frame_count) {
-                       frame = tls->frames [0];
 
+               if (frame) {
                        if (!method && frame->il_offset != -1) {
                                /* FIXME: Sort the table and use a binary search */
-                               sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+                               found_sp = 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);
                                g_assert (sp);
@@ -5457,7 +5499,12 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
                }
        }
 
-       ss_start (ss_req, method, sp, info, &tls->context.ctx, tls, step_to_catch);
+       ss_req->start_method = method;
+
+       ss_start (ss_req, method, sp, info, set_ip ? &tls->restore_state.ctx : &tls->context.ctx, tls, step_to_catch, frames, nframes);
+
+       if (frames)
+               free_frames (frames, nframes);
 
        return 0;
 }
@@ -5958,7 +6005,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(1, fprintf (log_file, "[%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)GetCurrentThreadId (), name, name2);
                g_free (name);
                g_free (name2);
                return ERR_INVALID_ARGUMENT;
@@ -5993,7 +6040,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                !(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8) &&
                !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE)) {
                char *name = mono_type_full_name (t);
-               DEBUG(1, fprintf (log_file, "[%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)GetCurrentThreadId (), name, type);
                g_free (name);
                return ERR_INVALID_ARGUMENT;
        }
@@ -6073,7 +6120,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
 
                                if (obj) {
                                        if (!obj_is_of_type (obj, t)) {
-                                               DEBUG (1, fprintf (log_file, "Expected type '%s', got '%s'\n", mono_type_full_name (t), obj->vtable->klass->name));
+                                               DEBUG_PRINTF (1, "Expected type '%s', got '%s'\n", mono_type_full_name (t), obj->vtable->klass->name);
                                                return ERR_INVALID_ARGUMENT;
                                        }
                                }
@@ -6119,7 +6166,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(1, fprintf (log_file, "[%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)GetCurrentThreadId (), name, type);
                                g_free (name);
                                return ERR_INVALID_ARGUMENT;
                        }
@@ -6316,11 +6363,11 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai
                /* Set value on the stack or in the return ctx */
                if (reg_locations [reg]) {
                        /* Saved on the stack */
-                       DEBUG (1, fprintf (log_file, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations [reg], reg, (gpointer)v));
+                       DEBUG_PRINTF (1, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations [reg], reg, (gpointer)v);
                        *(reg_locations [reg]) = v;
                } else {
                        /* Not saved yet */
-                       DEBUG (1, fprintf (log_file, "[dbg] Setting context location for reg %x to %p.\n", reg, (gpointer)v));
+                       DEBUG_PRINTF (1, "[dbg] Setting context location for reg %x to %p.\n", reg, (gpointer)v);
                        mono_arch_context_set_int_reg (restore_ctx, reg, v);
                }                       
 
@@ -6490,6 +6537,10 @@ clear_types_for_assembly (MonoAssembly *assembly)
        MonoDomain *domain = mono_domain_get ();
        AgentDomainInfo *info = NULL;
 
+       if (!domain || !domain_jit_info (domain))
+               /* Can happen during shutdown */
+               return;
+
        mono_loader_lock ();
        info = get_agent_domain_info (domain);
        g_hash_table_foreach_remove (info->loaded_classes, type_comes_from_assembly, assembly);
@@ -6527,7 +6578,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
                 * Invoke this method directly, currently only Environment.Exit () is supported.
                 */
                this = NULL;
-               DEBUG (1, fprintf (log_file, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this ? this->vtable->klass->name : "<null>"));
+               DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this ? this->vtable->klass->name : "<null>");
                mono_runtime_invoke (invoke->method, NULL, invoke->args, &exc);
                g_assert_not_reached ();
        }
@@ -6545,7 +6596,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 (1, fprintf (log_file, "[%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)GetCurrentThreadId ());
                        return ERR_INVALID_ARGUMENT;
                }
                memset (this_buf, 0, mono_class_instance_size (m->klass));
@@ -6562,19 +6613,19 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
 
        if (MONO_CLASS_IS_INTERFACE (m->klass)) {
                if (!this) {
-                       DEBUG (1, fprintf (log_file, "[%p] Error: Interface method invoked without this argument.\n", (gpointer)GetCurrentThreadId ()));
+                       DEBUG_PRINTF (1, "[%p] Error: Interface method invoked without this argument.\n", (gpointer)GetCurrentThreadId ());
                        return ERR_INVALID_ARGUMENT;
                }
                m = mono_object_get_virtual_method (this, m);
-       } else if (invoke->flags & INVOKE_FLAG_VIRTUAL) {
+       } else if ((m->flags & METHOD_ATTRIBUTE_VIRTUAL) && !m->klass->valuetype && invoke->flags & INVOKE_FLAG_VIRTUAL) {
                if (!this) {
-                       DEBUG (1, fprintf (log_file, "[%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)GetCurrentThreadId ());
                        return ERR_INVALID_ARGUMENT;
                }
                m = mono_object_get_virtual_method (this, m);
        }
 
-       DEBUG (1, fprintf (log_file, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "<null>"));
+       DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "<null>");
 
        if (this && this->vtable->domain != domain)
                NOT_IMPLEMENTED;
@@ -6656,7 +6707,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
        else
                res = mono_runtime_invoke (m, this, args, &exc);
        mono_stopwatch_stop (&watch);
-       DEBUG (1, fprintf (log_file, "[%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)GetCurrentThreadId (), 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);
@@ -6795,7 +6846,7 @@ invoke_method (void)
                tls->resume_count -= invoke->suspend_count;
        }
 
-       DEBUG (1, fprintf (log_file, "[%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)GetCurrentThreadId (), err, tls->resume_count);
 
        /*
         * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
@@ -6890,7 +6941,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                major_version = decode_int (p, &p, end);
                minor_version = decode_int (p, &p, end);
                protocol_version_set = TRUE;
-               DEBUG(1, fprintf (log_file, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION, MINOR_VERSION, major_version, minor_version));
+               DEBUG_PRINTF (1, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION, MINOR_VERSION, major_version, minor_version);
                break;
        }
        case CMD_VM_ALL_THREADS: {
@@ -7002,12 +7053,12 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                        mono_environment_exitcode_set (exit_code);
 
                        /* Suspend all managed threads since the runtime is going away */
-                       DEBUG(1, fprintf (log_file, "Suspending all threads...\n"));
+                       DEBUG_PRINTF (1, "Suspending all threads...\n");
                        mono_thread_suspend_all_other_threads ();
-                       DEBUG(1, fprintf (log_file, "Shutting down the runtime...\n"));
+                       DEBUG_PRINTF (1, "Shutting down the runtime...\n");
                        mono_runtime_quit ();
                        transport_close2 ();
-                       DEBUG(1, fprintf (log_file, "Exiting...\n"));
+                       DEBUG_PRINTF (1, "Exiting...\n");
 
                        exit (exit_code);
                }
@@ -7139,7 +7190,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                fname = decode_string (p, &p, end);
                ignore_case = decode_byte (p, &p, end);
 
-               basename = g_path_get_basename (fname);
+               basename = dbg_path_get_basename (fname);
 
                res_classes = g_ptr_array_new ();
                res_domains = g_ptr_array_new ();
@@ -7158,7 +7209,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
 
                                        for (i = 0; i < files->len; ++i) {
                                                char *s = g_ptr_array_index (files, i);
-                                               char *s2 = g_path_get_basename (s);
+                                               char *s2 = dbg_path_get_basename (s);
                                                char *s3;
 
                                                class_list = g_hash_table_lookup (info->source_file_to_class, s2);
@@ -7351,7 +7402,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                        req->modifiers [i].subclasses = decode_byte (p, &p, end);
                                else
                                        req->modifiers [i].subclasses = TRUE;
-                               DEBUG(1, fprintf (log_file, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class ? exc_class->name : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : ""));
+                               DEBUG_PRINTF (1, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class ? exc_class->name : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : "");
                                if (exc_class) {
                                        req->modifiers [i].data.exc_class = exc_class;
 
@@ -7412,7 +7463,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                        req->info = set_breakpoint (method, location, req, &error);
                        if (!mono_error_ok (&error)) {
                                g_free (req);
-                               DEBUG(1, fprintf (log_file, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (&error)));
+                               DEBUG_PRINTF (1, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (&error));
                                mono_error_cleanup (&error);
                                return ERR_NO_SEQ_POINT_AT_IL_OFFSET;
                        }
@@ -7425,7 +7476,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                return err;
                        }
 
-                       err = ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, req);
+                       err = ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, filter, req);
                        if (err) {
                                g_free (req);
                                return err;
@@ -7793,7 +7844,7 @@ buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass
 
                        mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error);
                        if (!mono_error_ok (&error)) {
-                               DEBUG(2, fprintf (log_file, "[dbg] mono_reflection_create_custom_attr_data_args () failed with: '%s'\n", mono_error_get_message (&error)));
+                               DEBUG_PRINTF (2, "[dbg] mono_reflection_create_custom_attr_data_args () failed with: '%s'\n", mono_error_get_message (&error));
                                mono_error_cleanup (&error);
                                return ERR_LOADER_ERROR;
                        }
@@ -8188,7 +8239,7 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
                        if (command == CMD_TYPE_GET_SOURCE_FILES_2) {
                                buffer_add_string (buf, source_file);
                        } else {
-                               base = g_path_get_basename (source_file);
+                               base = dbg_path_get_basename (source_file);
                                buffer_add_string (buf, base);
                                g_free (base);
                        }
@@ -8390,7 +8441,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                        buffer_add_string (buf, source_file);
                }
                buffer_add_int (buf, n_il_offsets);
-               DEBUG (10, fprintf (log_file, "Line number table for method %s:\n", mono_method_full_name (method,  TRUE)));
+               DEBUG_PRINTF (10, "Line number table for method %s:\n", mono_method_full_name (method,  TRUE));
                for (i = 0; i < n_il_offsets; ++i) {
                        const char *srcfile = "";
 
@@ -8398,7 +8449,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                                MonoDebugSourceInfo *sinfo = g_ptr_array_index (source_file_list, source_files [i]);
                                srcfile = sinfo->source_file;
                        }
-                       DEBUG (10, fprintf (log_file, "IL%x -> %s:%d %d\n", il_offsets [i], srcfile, line_numbers [i], column_numbers ? column_numbers [i] : -1));
+                       DEBUG_PRINTF (10, "IL%x -> %s:%d %d %d %d\n", il_offsets [i], srcfile, line_numbers [i], column_numbers ? column_numbers [i] : -1, end_line_numbers ? end_line_numbers [i] : -1, end_column_numbers ? end_column_numbers [i] : -1);
                        buffer_add_int (buf, il_offsets [i]);
                        buffer_add_int (buf, line_numbers [i]);
                        if (CHECK_PROTOCOL_VERSION (2, 13))
@@ -8520,8 +8571,11 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                                        if (imethod->context.class_inst) {
                                                MonoClass *klass = ((MonoMethod *) imethod)->klass;
                                                /*Generic methods gets the context of the GTD.*/
-                                               if (mono_class_get_context (klass))
-                                                       result = mono_class_inflate_generic_method_full (result, klass, mono_class_get_context (klass));
+                                               if (mono_class_get_context (klass)) {
+                                                       MonoError error;
+                                                       result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), &error);
+                                                       g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+                                               }
                                        }
                                }
 
@@ -8632,8 +8686,10 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                                        break;
                                }
                        } else {
-                               val = mono_ldtoken (method->klass->image, token, &handle_class, NULL);
-                               g_assert (val);
+                               MonoError error;
+                               val = mono_ldtoken_checked (method->klass->image, token, &handle_class, NULL, &error);
+                               if (!val)
+                                       g_error ("Could not load token due to %s", mono_error_get_message (&error));
                        }
 
                        if (handle_class == mono_defaults.typehandle_class) {
@@ -8680,6 +8736,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                break;
        }
        case CMD_METHOD_MAKE_GENERIC_METHOD: {
+               MonoError error;
                MonoType **type_argv;
                int i, type_argc;
                MonoDomain *d;
@@ -8707,7 +8764,8 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                tmp_context.class_inst = method->klass->generic_class ? method->klass->generic_class->context.class_inst : NULL;
                tmp_context.method_inst = ginst;
 
-               inflated = mono_class_inflate_generic_method (method, &tmp_context);
+               inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, &error);
+               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
                if (!mono_verifier_is_method_valid_generic_instantiation (inflated))
                        return ERR_INVALID_ARGUMENT;
                buffer_add_methodid (buf, domain, inflated);
@@ -8839,9 +8897,9 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                MonoMethod *method;
                MonoDomain *domain;
                MonoSeqPointInfo *seq_points;
-               SeqPoint *sp = NULL;
+               SeqPoint sp;
+               gboolean found_sp;
                gint64 il_offset;
-               int i;
 
                method = decode_methodid (p, &p, end, &domain, &err);
                if (err)
@@ -8862,22 +8920,17 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
                        return ERR_INVALID_ARGUMENT;
 
-               seq_points = get_seq_points (domain, method);
-               g_assert (seq_points);
+               found_sp = find_seq_point (domain, method, il_offset, &seq_points, &sp);
 
-               for (i = 0; i < seq_points->len; ++i) {
-                       sp = &seq_points->seq_points [i];
+               g_assert (seq_points);
 
-                       if (sp->il_offset == il_offset)
-                               break;
-               }
-               if (i == seq_points->len)
+               if (!found_sp)
                        return ERR_INVALID_ARGUMENT;
 
                // FIXME: Check that the ip change is safe
 
-               DEBUG (1, fprintf (log_file, "[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_ctx, (guint8*)tls->frames [0]->ji->code_start + sp->native_offset);
+               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);
                break;
        }
        default:
@@ -8898,7 +8951,6 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
        DebuggerTlsData *tls;
        StackFrame *frame;
        MonoDebugMethodJitInfo *jit;
-       MonoDebugVarInfo *var;
        MonoMethodSignature *sig;
        gssize id;
        MonoMethodHeader *header;
@@ -8927,6 +8979,13 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
        frame_idx = i;
        frame = tls->frames [frame_idx];
 
+       /* This is supported for frames without has_ctx etc. set */
+       if (command == CMD_STACK_FRAME_GET_DOMAIN) {
+               if (CHECK_PROTOCOL_VERSION (2, 38))
+                       buffer_add_domainid (buf, frame->domain);
+               return ERR_NONE;
+       }
+
        if (!frame->has_ctx)
                return ERR_ABSENT_INFORMATION;
 
@@ -8939,7 +8998,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                        /* This could happen for aot images with no jit debug info */
                        s = mono_method_full_name (frame->api_method, TRUE);
-                       DEBUG (1, fprintf (log_file, "[dbg] No debug information found for '%s'.\n", s));
+                       DEBUG_PRINTF (1, "[dbg] No debug information found for '%s'.\n", s);
                        g_free (s);
                        return ERR_ABSENT_INFORMATION;
                }
@@ -8967,14 +9026,10 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                g_assert (pos >= 0 && pos < jit->num_params);
 
-                               var = &jit->params [pos];
-
                                add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
                        } else {
                                g_assert (pos >= 0 && pos < jit->num_locals);
 
-                               var = &jit->locals [pos];
-                               
                                add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
                        }
                }
@@ -9032,11 +9087,16 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                        if (err)
                                return err;
 
-                       set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_ctx);
+                       set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
                }
                mono_metadata_free_mh (header);
                break;
        }
+       case CMD_STACK_FRAME_GET_DOMAIN: {
+               if (CHECK_PROTOCOL_VERSION (2, 38))
+                       buffer_add_domainid (buf, frame->domain);
+               break;
+       }
        default:
                return ERR_NOT_IMPLEMENTED;
        }
@@ -9405,7 +9465,8 @@ static const char* type_cmds_str[] = {
 static const char* stack_frame_cmds_str[] = {
        "GET_VALUES",
        "GET_THIS",
-       "SET_VALUES"
+       "SET_VALUES",
+       "GET_DOMAIN",
 };
 
 static const char* array_cmds_str[] = {
@@ -9507,15 +9568,15 @@ wait_for_attach (void)
 {
 #ifndef DISABLE_SOCKET_TRANSPORT
        if (listen_fd == -1) {
-               DEBUG (1, fprintf (log_file, "[dbg] Invalid listening socket\n"));
+               DEBUG_PRINTF (1, "[dbg] Invalid listening socket\n");
                return FALSE;
        }
 
        /* Block and wait for client connection */
        conn_fd = socket_transport_accept (listen_fd);
-       DEBUG (1, fprintf (log_file, "Accepted connection on %d\n", conn_fd));
+       DEBUG_PRINTF (1, "Accepted connection on %d\n", conn_fd);
        if (conn_fd == -1) {
-               DEBUG (1, fprintf (log_file, "[dbg] Bad client connection\n"));
+               DEBUG_PRINTF (1, "[dbg] Bad client connection\n");
                return FALSE;
        }
 #else
@@ -9525,7 +9586,7 @@ wait_for_attach (void)
        /* Handshake */
        disconnected = !transport_handshake ();
        if (disconnected) {
-               DEBUG (1, fprintf (log_file, "Transport handshake failed!\n"));
+               DEBUG_PRINTF (1, "Transport handshake failed!\n");
                return FALSE;
        }
        
@@ -9549,7 +9610,7 @@ debugger_thread (void *arg)
        gboolean no_reply;
        gboolean attach_failed = FALSE;
 
-       DEBUG (1, fprintf (log_file, "[dbg] Agent thread started, pid=%p\n", (gpointer)GetCurrentThreadId ()));
+       DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer)GetCurrentThreadId ());
 
        debugger_thread_id = GetCurrentThreadId ();
 
@@ -9561,7 +9622,7 @@ debugger_thread (void *arg)
        
        if (agent_config.defer) {
                if (!wait_for_attach ()) {
-                       DEBUG (1, fprintf (log_file, "[dbg] Can't attach, aborting debugger thread.\n"));
+                       DEBUG_PRINTF (1, "[dbg] Can't attach, aborting debugger thread.\n");
                        attach_failed = TRUE; // Don't abort process when we can't listen
                } else {
                        /* Send start event to client */
@@ -9574,7 +9635,7 @@ debugger_thread (void *arg)
 
                /* This will break if the socket is closed during shutdown too */
                if (res != HEADER_LENGTH) {
-                       DEBUG (1, fprintf (log_file, "[dbg] transport_recv () returned %d, expected %d.\n", res, HEADER_LENGTH));
+                       DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, HEADER_LENGTH);
                        break;
                }
 
@@ -9599,7 +9660,7 @@ debugger_thread (void *arg)
                                cmd_str = cmd_num;
                        }
                        
-                       DEBUG (1, fprintf (log_file, "[dbg] Command %s(%s) [%d][at=%lx].\n", command_set_to_string (command_set), cmd_str, id, (long)mono_100ns_ticks () / 10000));
+                       DEBUG_PRINTF (1, "[dbg] Command %s(%s) [%d][at=%lx].\n", command_set_to_string (command_set), cmd_str, id, (long)mono_100ns_ticks () / 10000);
                }
 
                data = g_malloc (len - HEADER_LENGTH);
@@ -9607,7 +9668,7 @@ debugger_thread (void *arg)
                {
                        res = transport_recv (data, len - HEADER_LENGTH);
                        if (res != len - HEADER_LENGTH) {
-                               DEBUG (1, fprintf (log_file, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH));
+                               DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH);
                                break;
                        }
                }
@@ -9677,7 +9738,7 @@ debugger_thread (void *arg)
                                buffer_reply_packet (id, err, &buf);
                        } else {
                                send_reply_packet (id, err, &buf);
-                               //DEBUG (1, fprintf (log_file, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000));
+                               //DEBUG_PRINTF (1, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000);
                        }
                }
 
@@ -9700,10 +9761,10 @@ debugger_thread (void *arg)
        mono_cond_signal (&debugger_thread_exited_cond);
        mono_mutex_unlock (&debugger_thread_exited_mutex);
 
-       DEBUG (1, fprintf (log_file, "[dbg] Debugger thread exited.\n"));
+       DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");
        
        if (!attach_failed && command_set == CMD_SET_VM && command == CMD_VM_DISPOSE && !(vm_death_event_sent || mono_runtime_is_shutting_down ())) {
-               DEBUG (2, fprintf (log_file, "[dbg] Detached - restarting clean debugger thread.\n"));
+               DEBUG_PRINTF (2, "[dbg] Detached - restarting clean debugger thread.\n");
                start_debugger_thread ();
        }
        
@@ -9784,4 +9845,3 @@ mono_debugger_agent_unhandled_exception (MonoException *exc)
 }
 
 #endif
-