Introduce MonoThreadUnwindState and a bunch overloads to mono_walk_stack.
[mono.git] / mono / mini / debugger-agent.c
index 7b84af11b61c200b903501da0816c580c8c82f4f..7a8a42b81df0f2e648372b9e374e11388d99b198 100644 (file)
@@ -1127,11 +1127,11 @@ transport_connect (const char *host, int port)
 #endif
                }
 
-               DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
-
                if (agent_config.defer)
                        return;
 
+               DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
+
                if (agent_config.timeout) {
                        fd_set readfds;
                        struct timeval tv;
@@ -1143,8 +1143,7 @@ transport_connect (const char *host, int port)
                        res = select (sfd + 1, &readfds, NULL, NULL, &tv);
                        if (res == 0) {
                                fprintf (stderr, "debugger-agent: Timed out waiting to connect.\n");
-                               if (!agent_config.defer)
-                                       exit (1);
+                               exit (1);
                        }
                }
 
@@ -1757,7 +1756,8 @@ mono_debugger_agent_on_attach (void)
        mono_loader_unlock ();
 }
 
-static AgentDomainInfo* get_agent_domain_info (MonoDomain *domain)
+static AgentDomainInfo*
+get_agent_domain_info (MonoDomain *domain)
 {
        AgentDomainInfo *info = NULL;
 
@@ -1785,10 +1785,10 @@ get_id (MonoDomain *domain, IdType type, gpointer val)
 
        mono_loader_lock ();
 
-       info = get_agent_domain_info (domain);
-
        mono_domain_lock (domain);
 
+       info = get_agent_domain_info (domain);
+
        if (info->val_to_id [type] == NULL)
                info->val_to_id [type] = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
@@ -2075,7 +2075,7 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
 
        if (ji) {
                /* Running managed code, will be suspended by the single step code */
-               DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)GetCurrentThreadId (), ji->method->name, mono_arch_ip_from_context (sigctx)));
+               DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)GetCurrentThreadId (), ji->method->name, mono_arch_ip_from_context (sigctx)));
                return TRUE;
        } else {
                /* 
@@ -2091,7 +2091,7 @@ mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
                        // FIXME: printf is not signal safe, but this is only used during
                        // debugger debugging
                        if (sigctx)
-                               DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx)));
+                               DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx)));
                        //save_thread_context (&ctx);
 
                        if (!tls->thread)
@@ -2204,6 +2204,15 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
        guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
        MonoJitInfo *ji;
 
+       if (mono_loader_lock_is_owned_by_self ()) {
+               /*
+                * Shortcut for the check in suspend_current (). This speeds up processing
+                * when executing long running code inside the loader lock, i.e. assembly load
+                * hooks.
+                */
+               return;
+       }
+
        if (debugger_thread_id == GetCurrentThreadId ())
                return;
 
@@ -3358,9 +3367,10 @@ send_type_load (MonoClass *klass)
        AgentDomainInfo *info = NULL;
 
        mono_loader_lock ();
-       info = get_agent_domain_info (domain);
        mono_domain_lock (domain);
 
+       info = get_agent_domain_info (domain);
+
        if (!g_hash_table_lookup (info->loaded_classes, klass)) {
                type_load = TRUE;
                g_hash_table_insert (info->loaded_classes, klass, klass);
@@ -4316,7 +4326,7 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointI
        }
 
        if (!ss_req->bps) {
-               DEBUG (1, printf ("[dbg] Turning on global single stepping.\n"));
+               DEBUG (1, fprintf (log_file, "[dbg] Turning on global single stepping.\n"));
                ss_req->global = TRUE;
                start_single_stepping ();
        } else {
@@ -4344,11 +4354,11 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequ
 
        // FIXME: Multiple requests
        if (ss_req) {
-               DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
+               DEBUG (0, fprintf (log_file, "Received a single step request while the previous one was still active.\n"));
                return ERR_NOT_IMPLEMENTED;
        }
 
-       DEBUG (1, printf ("[dbg] Starting single step of thread %p (depth=%s).\n", thread, ss_depth_to_string (depth)));
+       DEBUG (1, fprintf (log_file, "[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;
@@ -5097,7 +5107,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
                 * Invoke this method directly, currently only Environment.Exit () is supported.
                 */
                this = NULL;
-               DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this ? this->vtable->klass->name : "<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>"));
                mono_runtime_invoke (invoke->method, NULL, invoke->args, &exc);
                g_assert_not_reached ();
        }
@@ -5128,7 +5138,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
        else
                this = NULL;
 
-       DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "<null>"));
+       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>"));
 
        if (this && this->vtable->domain != domain)
                NOT_IMPLEMENTED;
@@ -5239,8 +5249,15 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
                } else if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
                        buffer_add_value (buf, sig->ret, &res, domain);
                } else if (mono_class_from_mono_type (sig->ret)->valuetype) {
-                       g_assert (res);
-                       buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
+                       if (mono_class_is_nullable (mono_class_from_mono_type (sig->ret))) {
+                               if (!res)
+                                       buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &res, domain);
+                               else
+                                       buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
+                       } else {
+                               g_assert (res);
+                               buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
+                       }
                } else {
                        NOT_IMPLEMENTED;
                }
@@ -5322,7 +5339,7 @@ invoke_method (void)
                tls->resume_count -= invoke->suspend_count;
        }
 
-       DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count));
+       DEBUG (1, fprintf (log_file, "[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count));
 
        /*
         * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
@@ -5455,15 +5472,14 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
                wait_for_suspend ();
 
                env_class = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
-               g_assert (env_class);
-               exit_method = mono_class_get_method_from_name (env_class, "Exit", 1);
-               g_assert (exit_method);
+               if (env_class)
+                       exit_method = mono_class_get_method_from_name (env_class, "Exit", 1);
 
                mono_loader_lock ();
                thread = mono_g_hash_table_find (tid_to_thread, is_really_suspended, NULL);
                mono_loader_unlock ();
 
-               if (thread) {
+               if (thread && exit_method) {
                        mono_loader_lock ();
                        tls = mono_g_hash_table_lookup (thread_to_tls, thread);
                        mono_loader_unlock ();
@@ -7332,7 +7348,7 @@ debugger_thread (void *arg)
        mono_cond_signal (&debugger_thread_exited_cond);
        mono_mutex_unlock (&debugger_thread_exited_mutex);
 
-       DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
+       DEBUG (1, fprintf (log_file, "[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"));