/*
- * 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>
#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"
GSList *onthrow;
int timeout;
char *launch;
+ gboolean embedding;
} AgentConfig;
typedef struct
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 1
+#define MINOR_VERSION 2
typedef enum {
CMD_SET_VM = 1,
static int log_level;
+static gboolean embedding;
+
static FILE *log_file;
/* Classes whose class load event has been sent */
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);
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);
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);
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 ();
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) {
//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);
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);
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 ();
#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
}
}
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;
// 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);
}
static void
-thread_end (MonoProfiler *prof, intptr_t tid)
+thread_end (MonoProfiler *prof, uintptr_t tid)
{
MonoInternalThread *thread;
DebuggerTlsData *tls = NULL;
process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
clear_event_requests_for_assembly (assembly);
+ clear_types_for_assembly (assembly);
}
static void
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;
/*
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)
{
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
* 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;
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
}
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);
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: