Implement passing of this as the first argument for ia64 correctly.
[mono.git] / mono / mini / debugger-agent.c
index b1fe15568158dc4680e310ba0d5d8ffbfcdba94b..86315e332230fc0320f999ba32301853d5016f39 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * debugger-agent.c: Debugger back-end module
+ * debugger-agent.c: Soft Debugger back-end module
  *
  * Author:
  *   Zoltan Varga (vargaz@gmail.com)
  *
- * (C) 2009 Novell, Inc.
+ * Copyright 2009-2010 Novell, Inc.
  */
 
 #include <config.h>
@@ -70,6 +70,7 @@ int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/socket-io.h>
+#include <mono/metadata/assembly.h>
 #include <mono/utils/mono-semaphore.h>
 #include "debugger-agent.h"
 #include "mini.h"
@@ -102,6 +103,7 @@ typedef struct {
        GSList *onthrow;
        int timeout;
        char *launch;
+       gboolean embedding;
 } AgentConfig;
 
 typedef struct
@@ -231,7 +233,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 1
+#define MINOR_VERSION 2
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -533,6 +535,8 @@ static HANDLE debugger_thread_handle;
 
 static int log_level;
 
+static gboolean embedding;
+
 static FILE *log_file;
 
 /* Classes whose class load event has been sent */
@@ -581,9 +585,9 @@ static void runtime_initialized (MonoProfiler *prof);
 
 static void runtime_shutdown (MonoProfiler *prof);
 
-static void thread_startup (MonoProfiler *prof, intptr_t tid);
+static void thread_startup (MonoProfiler *prof, uintptr_t tid);
 
-static void thread_end (MonoProfiler *prof, intptr_t tid);
+static void thread_end (MonoProfiler *prof, uintptr_t tid);
 
 static void appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result);
 
@@ -613,6 +617,8 @@ static void clear_event_requests_for_assembly (MonoAssembly *assembly);
 
 static void clear_breakpoints_for_domain (MonoDomain *domain);
 
+static void clear_types_for_assembly (MonoAssembly *assembly);
+
 /* Submodule init/cleanup */
 static void breakpoints_init (void);
 static void breakpoints_cleanup (void);
@@ -724,6 +730,8 @@ mono_debugger_agent_parse_options (char *options)
                        agent_config.timeout = atoi (arg + 8);
                } else if (strncmp (arg, "launch=", 7) == 0) {
                        agent_config.launch = g_strdup (arg + 7);
+               } else if (strncmp (arg, "embedding=", 10) == 0) {
+                       agent_config.embedding = atoi (arg + 10) == 1;
                } else {
                        print_usage ();
                        exit (1);
@@ -776,13 +784,13 @@ mono_debugger_agent_init (void)
        debugger_tls_id = TlsAlloc ();
 
        thread_to_tls = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
-       MONO_GC_REGISTER_ROOT (thread_to_tls);
+       MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls);
 
        tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
-       MONO_GC_REGISTER_ROOT (tid_to_thread);
+       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread);
 
        tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
-       MONO_GC_REGISTER_ROOT (tid_to_thread_obj);
+       MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj);
 
        loaded_classes = g_hash_table_new (mono_aligned_addr_hash, NULL);
        pending_assembly_loads = g_ptr_array_new ();
@@ -791,6 +799,8 @@ mono_debugger_agent_init (void)
 
        log_level = agent_config.log_level;
 
+       embedding = agent_config.embedding;
+
        if (agent_config.log_file) {
                log_file = fopen (agent_config.log_file, "w+");
                if (!log_file) {
@@ -896,7 +906,7 @@ mono_debugger_agent_cleanup (void)
        //WaitForSingleObject (debugger_thread_handle, INFINITE);
        if (GetCurrentThreadId () != debugger_thread_id) {
                mono_mutex_lock (&debugger_thread_exited_mutex);
-               if (!debugger_thread_exited) {
+               while (!debugger_thread_exited) {
 #ifdef HOST_WIN32
                        if (WAIT_TIMEOUT == WaitForSingleObject(debugger_thread_exited_cond, 0)) {
                                mono_mutex_unlock (&debugger_thread_exited_mutex);
@@ -1392,26 +1402,42 @@ static ObjRef*
 get_objref (MonoObject *obj)
 {
        ObjRef *ref;
+       GSList *reflist = NULL, *l;
+       int hash = 0;
 
        if (obj == NULL)
                return 0;
 
-#ifdef HAVE_SGEN_GC
-       NOT_IMPLEMENTED;
-#endif
-
-       /* Use a hash table with masked pointers to internalize object references */
-       /* FIXME: This can grow indefinitely */
        mono_loader_lock ();
 
        if (!obj_to_objref)
                obj_to_objref = g_hash_table_new (NULL, NULL);
+       
+       /* FIXME: The tables can grow indefinitely */
 
-       ref = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
-       /* ref might refer to a different object with the same addr which was GCd */
-       if (ref && mono_gchandle_get_target (ref->handle) == obj) {
-               mono_loader_unlock ();
-               return ref;
+       if (mono_gc_is_moving ()) {
+               /*
+                * Objects can move, so use a hash table mapping hash codes to lists of
+                * ObjRef structures.
+                */
+               hash = mono_object_hash (obj);
+
+               reflist = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (hash));
+               for (l = reflist; l; l = l->next) {
+                       ref = l->data;
+                       if (ref && mono_gchandle_get_target (ref->handle) == obj) {
+                               mono_loader_unlock ();
+                               return ref;
+                       }
+               }
+       } else {
+               /* Use a hash table with masked pointers to internalize object references */
+               ref = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
+               /* ref might refer to a different object with the same addr which was GCd */
+               if (ref && mono_gchandle_get_target (ref->handle) == obj) {
+                       mono_loader_unlock ();
+                       return ref;
+               }
        }
 
        ref = g_new0 (ObjRef, 1);
@@ -1419,7 +1445,13 @@ get_objref (MonoObject *obj)
        ref->handle = mono_gchandle_new_weakref (obj, FALSE);
 
        g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
-       g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
+
+       if (mono_gc_is_moving ()) {
+               reflist = g_slist_append (reflist, ref);
+               g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (hash), reflist);
+       } else {
+               g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
+       }
 
        mono_loader_unlock ();
 
@@ -2009,7 +2041,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
 #ifdef HOST_WIN32
        QueueUserAPC (notify_thread_apc, thread->handle, NULL);
 #else
-       pthread_kill ((pthread_t) tid, mono_thread_get_abort_signal ());
+       mono_thread_kill (thread, mono_thread_get_abort_signal ());
 #endif
 }
 
@@ -2808,7 +2840,7 @@ runtime_shutdown (MonoProfiler *prof)
 }
 
 static void
-thread_startup (MonoProfiler *prof, intptr_t tid)
+thread_startup (MonoProfiler *prof, uintptr_t tid)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
        MonoInternalThread *old_thread;
@@ -2849,7 +2881,7 @@ thread_startup (MonoProfiler *prof, intptr_t tid)
        // FIXME: Free this somewhere
        tls = g_new0 (DebuggerTlsData, 1);
        tls->resume_event = CreateEvent (NULL, FALSE, FALSE, NULL);
-       MONO_GC_REGISTER_ROOT (tls->thread);
+       MONO_GC_REGISTER_ROOT_SINGLE (tls->thread);
        tls->thread = thread;
        TlsSetValue (debugger_tls_id, tls);
 
@@ -2870,7 +2902,7 @@ thread_startup (MonoProfiler *prof, intptr_t tid)
 }
 
 static void
-thread_end (MonoProfiler *prof, intptr_t tid)
+thread_end (MonoProfiler *prof, uintptr_t tid)
 {
        MonoInternalThread *thread;
        DebuggerTlsData *tls = NULL;
@@ -2941,6 +2973,7 @@ assembly_unload (MonoProfiler *prof, MonoAssembly *assembly)
        process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
 
        clear_event_requests_for_assembly (assembly);
+       clear_types_for_assembly (assembly);
 }
 
 static void
@@ -2974,7 +3007,7 @@ end_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
        gpointer stackptr = __builtin_frame_address (1);
 #endif
 
-       if (ss_req == NULL || stackptr != ss_invoke_addr || ss_req->thread != mono_thread_internal_current ())
+       if (!embedding || ss_req == NULL || stackptr != ss_invoke_addr || ss_req->thread != mono_thread_internal_current ())
                return;
 
        /*
@@ -4587,6 +4620,30 @@ clear_event_requests_for_assembly (MonoAssembly *assembly)
        mono_loader_unlock ();
 }
 
+/*
+ * type_comes_from_assembly:
+ *
+ *   GHRFunc that returns TRUE if klass comes from assembly
+ */
+static gboolean
+type_comes_from_assembly (gpointer klass, gpointer also_klass, gpointer assembly)
+{
+       return (mono_class_get_image ((MonoClass*)klass) == mono_assembly_get_image ((MonoAssembly*)assembly));
+}
+
+/*
+ * clear_types_for_assembly:
+ *
+ *   Clears types from loaded_classes for a given assembly
+ */
+static void
+clear_types_for_assembly (MonoAssembly *assembly)
+{
+       mono_loader_lock ();
+       g_hash_table_foreach_remove (loaded_classes, type_comes_from_assembly, assembly);
+       mono_loader_unlock ();
+}
+
 static void
 add_thread (gpointer key, gpointer value, gpointer user_data)
 {
@@ -4609,7 +4666,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
        MonoObject *this, *res, *exc;
        MonoDomain *domain;
        guint8 *this_buf;
-#ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        MonoLMFExt ext;
 #endif
 
@@ -4704,7 +4761,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
         * Add an LMF frame to link the stack frames on the invoke method with our caller.
         */
        /* FIXME: Move this to arch specific code */
-#ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        if (invoke->has_ctx) {
                MonoLMF **lmf_addr;
 
@@ -4770,7 +4827,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
 
        tls->disable_breakpoints = FALSE;
 
-#ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        if (invoke->has_ctx)
                mono_set_lmf ((gpointer)(((gssize)ext.lmf.previous_lmf) & ~3));
 #endif
@@ -5983,8 +6040,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
        }
        case CMD_METHOD_GET_LOCALS_INFO: {
                int i, j, num_locals;
-               char **local_names;
-               int *local_indexes;
+               MonoDebugLocalsInfo *locals;
 
                header = mono_method_get_header (method);
                g_assert (header);
@@ -5996,27 +6052,39 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                        buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
 
                /* Names */
-               num_locals = mono_debug_lookup_locals (method, &local_names, &local_indexes);
+               locals = mono_debug_lookup_locals (method);
+               if (locals)
+                       num_locals = locals->num_locals;
+               else
+                       num_locals = 0;
                for (i = 0; i < header->num_locals; ++i) {
                        for (j = 0; j < num_locals; ++j)
-                               if (local_indexes [j] == i)
+                               if (locals->locals [j].index == i)
                                        break;
                        if (j < num_locals)
-                               buffer_add_string (buf, local_names [j]);
+                               buffer_add_string (buf, locals->locals [j].name);
                        else
                                buffer_add_string (buf, "");
                }
-               g_free (local_names);
-               g_free (local_indexes);
 
-               /* Live ranges */
-               /* FIXME: This works because we set debug_options.mdb_optimizations */
+               /* Scopes */
                for (i = 0; i < header->num_locals; ++i) {
-                       buffer_add_int (buf, 0);
-                       buffer_add_int (buf, header->code_size);
+                       for (j = 0; j < num_locals; ++j)
+                               if (locals->locals [j].index == i)
+                                       break;
+                       if (j < num_locals && locals->locals [j].block) {
+                               buffer_add_int (buf, locals->locals [j].block->start_offset);
+                               buffer_add_int (buf, locals->locals [j].block->end_offset);
+                       } else {
+                               buffer_add_int (buf, 0);
+                               buffer_add_int (buf, header->code_size);
+                       }
                }
                mono_metadata_free_mh (header);
 
+               if (locals)
+                       mono_debug_symfile_free_locals (locals);
+
                break;
        }
        case CMD_METHOD_GET_INFO: