Remove warnings
[mono.git] / mono / mini / debugger-agent.c
index 989a28b9754e209cd23b36603475d756e549cba5..e205ede5c8f1f64f423e1b88ec7e284f4d92459b 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);
 
@@ -611,6 +615,10 @@ static void suspend_current (void);
 
 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);
@@ -722,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);
@@ -774,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 ();
@@ -789,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) {
@@ -894,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);
@@ -1390,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);
@@ -1417,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 ();
 
@@ -2806,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;
@@ -2847,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);
 
@@ -2868,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;
@@ -2908,6 +2942,7 @@ appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
 {
        /* Invalidate each thread's frame stack */
        mono_g_hash_table_foreach (thread_to_tls, invalidate_each_thread, NULL);
+       clear_breakpoints_for_domain (domain);
        process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD, domain);
 }
 
@@ -2938,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
@@ -2971,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;
 
        /*
@@ -3075,6 +3111,7 @@ typedef struct {
        long il_offset, native_offset;
        guint8 *ip;
        MonoJitInfo *ji;
+       MonoDomain *domain;
 } BreakpointInstance;
 
 /*
@@ -3110,22 +3147,6 @@ breakpoints_init (void)
        bp_locs = g_hash_table_new (NULL, NULL);
 }      
 
-static void
-breakpoints_cleanup (void)
-{
-       int i;
-
-       mono_loader_lock ();
-
-       for (i = 0; i < breakpoints->len; ++i)
-               g_free (g_ptr_array_index (breakpoints, i));
-
-       g_ptr_array_free (breakpoints, TRUE);
-       g_hash_table_destroy (bp_locs);
-
-       mono_loader_unlock ();
-}
-
 /*
  * insert_breakpoint:
  *
@@ -3133,7 +3154,7 @@ breakpoints_cleanup (void)
  * JI.
  */
 static void
-insert_breakpoint (MonoSeqPointInfo *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
+insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, MonoBreakpoint *bp)
 {
        int i, count;
        gint32 il_offset = -1, native_offset;
@@ -3157,6 +3178,7 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoJitInfo *ji, MonoBreakpoint
        inst->native_offset = native_offset;
        inst->ip = (guint8*)ji->code_start + native_offset;
        inst->ji = ji;
+       inst->domain = domain;
 
        mono_loader_lock ();
 
@@ -3248,7 +3270,7 @@ add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
                                continue;
                        g_assert (seq_points);
 
-                       insert_breakpoint (seq_points, ji, bp);
+                       insert_breakpoint (seq_points, domain, ji, bp);
                }
        }
 
@@ -3271,7 +3293,7 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_
        }
        g_assert (code);
 
-       insert_breakpoint (seq_points, ji, bp);
+       insert_breakpoint (seq_points, domain, ji, bp);
 }
 
 typedef struct
@@ -3370,6 +3392,73 @@ clear_breakpoint (MonoBreakpoint *bp)
        g_free (bp);
 }
 
+static void
+breakpoints_cleanup (void)
+{
+       int i;
+
+       mono_loader_lock ();
+       i = 0;
+       while (i < event_requests->len) {
+               EventRequest *req = g_ptr_array_index (event_requests, i);
+
+               if (req->event_kind == EVENT_KIND_BREAKPOINT) {
+                       clear_breakpoint (req->info);
+                       g_ptr_array_remove_index_fast (event_requests, i);
+                       g_free (req);
+               } else {
+                       i ++;
+               }
+       }
+
+       for (i = 0; i < breakpoints->len; ++i)
+               g_free (g_ptr_array_index (breakpoints, i));
+
+       g_ptr_array_free (breakpoints, TRUE);
+       g_hash_table_destroy (bp_locs);
+
+       breakpoints = NULL;
+       bp_locs = NULL;
+
+       mono_loader_unlock ();
+}
+
+/*
+ * clear_breakpoints_for_domain:
+ *
+ *   Clear breakpoint instances which reference DOMAIN.
+ */
+static void
+clear_breakpoints_for_domain (MonoDomain *domain)
+{
+       int i, j;
+
+       /* This could be called after shutdown */
+       if (!breakpoints)
+               return;
+
+       mono_loader_lock ();
+       for (i = 0; i < breakpoints->len; ++i) {
+               MonoBreakpoint *bp = g_ptr_array_index (breakpoints, i);
+
+               j = 0;
+               while (j < bp->children->len) {
+                       BreakpointInstance *inst = g_ptr_array_index (bp->children, j);
+
+                       if (inst->domain == domain) {
+                               remove_breakpoint (inst);
+
+                               g_free (inst);
+
+                               g_ptr_array_remove_index_fast (bp->children, j);
+                       } else {
+                               j ++;
+                       }
+               }
+       }
+       mono_loader_unlock ();
+}
+
 static gboolean
 breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
 {
@@ -4531,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)
 {
@@ -5927,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);
@@ -5940,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: