#include <mono/metadata/gc-internal.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/threads-types.h>
+#include <mono/metadata/threadpool-ms.h>
#include <mono/metadata/socket-io.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/runtime.h>
-#include <mono/metadata/threadpool.h>
#include <mono/metadata/verify-internals.h>
#include <mono/utils/mono-semaphore.h>
#include <mono/utils/mono-error-internals.h>
*/
MonoThreadUnwindState filter_state;
- /*
- * The callee address of the last mono_runtime_invoke call
- */
- gpointer invoke_addr;
-
gboolean abort_requested;
/*
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 40
+#define MINOR_VERSION 42
typedef enum {
CMD_SET_VM = 1,
ERR_NO_INVOCATION = 104,
ERR_ABSENT_INFORMATION = 105,
ERR_NO_SEQ_POINT_AT_IL_OFFSET = 106,
+ ERR_INVOKE_ABORTED = 107,
ERR_LOADER_ERROR = 200, /*XXX extend the protocol to pass this information down the pipe */
} ErrorCode;
static gboolean vm_start_event_sent, vm_death_event_sent, disconnected;
/* Maps MonoInternalThread -> DebuggerTlsData */
+/* Protected by the loader lock */
static MonoGHashTable *thread_to_tls;
/* Maps tid -> MonoInternalThread */
+/* Protected by the loader lock */
static MonoGHashTable *tid_to_thread;
/* Maps tid -> MonoThread (not MonoInternalThread) */
+/* Protected by the loader lock */
static MonoGHashTable *tid_to_thread_obj;
static gsize debugger_thread_id;
/* The single step request instance */
static SingleStepReq *ss_req;
-static gpointer ss_invoke_addr;
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
/* Number of single stepping operations in progress */
static gboolean protocol_version_set;
/* A hash table containing all active domains */
+/* Protected by the loader lock */
static GHashTable *domains;
/* The number of times the runtime is suspended */
int nreply_packets;
#define dbg_lock() do { \
- MONO_TRY_BLOCKING \
+ MONO_TRY_BLOCKING; \
mono_mutex_lock (&debug_mutex); \
- MONO_FINISH_TRY_BLOCKING \
+ MONO_FINISH_TRY_BLOCKING; \
} while (0)
#define dbg_unlock() mono_mutex_unlock (&debug_mutex)
static void emit_type_load (gpointer key, gpointer type, gpointer user_data);
-static void start_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
-
-static void end_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
-
static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
static void add_pending_breakpoints (MonoMethod *method, MonoJitInfo *jinfo);
event_requests = g_ptr_array_new ();
mono_mutex_init (&debugger_thread_exited_mutex);
- mono_cond_init (&debugger_thread_exited_cond, NULL);
+ mono_cond_init (&debugger_thread_exited_cond, 0);
mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS);
mono_profiler_install_thread (thread_startup, thread_end);
mono_profiler_install_assembly (NULL, assembly_load, assembly_unload, NULL);
mono_profiler_install_jit_end (jit_end);
- mono_profiler_install_method_invoke (start_runtime_invoke, end_runtime_invoke);
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);
+ thread_to_tls = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
+ MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls, MONO_ROOT_SOURCE_DEBUGGER, "thread-to-tls table");
- tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
- MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread);
+ tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread table");
+ MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread table");
- tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
- MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj);
+ tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread object table");
+ MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj, MONO_ROOT_SOURCE_DEBUGGER, "tid-to-thread object table");
pending_assembly_loads = g_ptr_array_new ();
domains = g_hash_table_new (mono_aligned_addr_hash, NULL);
}
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_connect (agent_config.address);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (!on_startup) {
/* Do some which is usually done after sending the VMStart () event */
}
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
conn_fd = socket_transport_accept (sfd);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (conn_fd == -1)
exit (1);
/* Write handshake message */
sprintf (handshake_msg, "DWP-Handshake");
/* Must use try blocking as this can nest into code that runs blocking */
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
do {
res = transport_send (handshake_msg, strlen (handshake_msg));
} while (res == -1 && get_last_sock_error () == MONO_EINTR);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (res != -1);
/* Read answer */
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
res = transport_recv (buf, strlen (handshake_msg));
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
return FALSE;
if (!inited)
return;
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_close1 ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/*
* Wait for the thread to exit.
*/
if (GetCurrentThreadId () != debugger_thread_id) {
do {
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&debugger_thread_exited_mutex);
if (!debugger_thread_exited)
mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
} while (!debugger_thread_exited);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
transport_close2 ();
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
}
static void
buffer_add_byte (&buf, command);
memcpy (buf.buf + 11, data->buf, data->p - data->buf);
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_send (buf.buf, len);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
buffer_free (&buf);
buffer_add_buffer (&buf, packets [i].data);
}
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_send (buf.buf, len);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
buffer_free (&buf);
} ObjRef;
/* Maps objid -> ObjRef */
+/* Protected by the loader lock */
static GHashTable *objrefs;
+/* Protected by the loader lock */
static GHashTable *obj_to_objref;
/* Protected by the dbg lock */
static MonoGHashTable *suspended_objs;
{
objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref);
obj_to_objref = g_hash_table_new (NULL, NULL);
- suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
- MONO_GC_REGISTER_ROOT_FIXED (suspended_objs);
+ suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
+ MONO_GC_REGISTER_ROOT_FIXED (suspended_objs, MONO_ROOT_SOURCE_DEBUGGER, "suspended objects table");
}
static void
typedef struct {
/* Maps runtime structure -> Id */
+ /* Protected by the dbg lock */
GHashTable *val_to_id [ID_NUM];
/* Classes whose class load event has been sent */
+ /* Protected by the loader lock */
GHashTable *loaded_classes;
/* Maps MonoClass->GPtrArray of file names */
GHashTable *source_files;
if (val == NULL)
return 0;
- mono_loader_lock ();
-
- mono_domain_lock (domain);
-
info = get_agent_domain_info (domain);
+ dbg_lock ();
+
if (info->val_to_id [type] == NULL)
info->val_to_id [type] = g_hash_table_new (mono_aligned_addr_hash, NULL);
id = g_hash_table_lookup (info->val_to_id [type], val);
if (id) {
- mono_domain_unlock (domain);
- mono_loader_unlock ();
+ dbg_unlock ();
return id->id;
}
- dbg_lock ();
-
id = g_new0 (Id, 1);
/* Reserve id 0 */
id->id = ids [type]->len + 1;
dbg_unlock ();
- mono_domain_unlock (domain);
-
- mono_loader_unlock ();
-
return id->id;
}
suspend_init (void)
{
mono_mutex_init (&suspend_mutex);
- mono_cond_init (&suspend_cond, NULL);
+ mono_cond_init (&suspend_cond, 0);
MONO_SEM_INIT (&suspend_sem, 0);
}
{
GetLastFrameUserData *data = user_data;
- if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE)
+ if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE || info->type == FRAME_TYPE_TRAMPOLINE)
return FALSE;
if (!data->last_frame_set) {
// FIXME: Races when the thread leaves managed code before hitting a single step
// event.
- if (ji) {
+ if (ji && !ji->is_trampoline) {
/* Running managed code, will be suspended by the single step code */
DEBUG_PRINTF (1, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip);
} else {
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));
+ ji = mono_jit_info_table_find_internal (
+ 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),
+ TRUE,
+ TRUE);
/* This is signal safe */
thread_interrupt (data->tls, info, ji);
{
mono_loader_lock ();
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
suspend_count ++;
/*
* Suspend creation of new threadpool threads, since they cannot run
*/
- mono_thread_pool_suspend ();
+ mono_threadpool_ms_suspend ();
mono_loader_unlock ();
}
mono_loader_lock ();
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (suspend_count > 0);
suspend_count --;
//g_assert (err == 0);
if (suspend_count == 0)
- mono_thread_pool_resume ();
+ mono_threadpool_ms_resume ();
mono_loader_unlock ();
}
tls = mono_g_hash_table_lookup (thread_to_tls, thread);
g_assert (tls);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
g_assert (suspend_count > 0);
tls = mono_native_tls_get_value (debugger_tls_id);
g_assert (tls);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&suspend_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
tls->suspending = FALSE;
tls->really_suspended = TRUE;
DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ());
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
while (suspend_count - tls->resume_count > 0) {
err = mono_cond_wait (&suspend_cond, &suspend_mutex);
g_assert (err == 0);
}
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
tls->suspended = FALSE;
tls->really_suspended = FALSE;
info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
}
- DEBUG_PRINTF (1, "\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:[il=0x%x, native=0x%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))
g_assert (!tls);
// FIXME: Free this somewhere
tls = g_new0 (DebuggerTlsData, 1);
- MONO_GC_REGISTER_ROOT_SINGLE (tls->thread);
+ MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, "debugger thread reference");
tls->thread = thread;
mono_native_tls_set_value (debugger_tls_id, tls);
clear_types_for_assembly (assembly);
}
-static void
-start_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
-{
-#if defined(HOST_WIN32) && !defined(__GNUC__)
- gpointer stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));
-#else
- gpointer stackptr = __builtin_frame_address (1);
-#endif
- MonoInternalThread *thread = mono_thread_internal_current ();
- DebuggerTlsData *tls;
-
- mono_loader_lock ();
-
- tls = mono_g_hash_table_lookup (thread_to_tls, thread);
- /* Could be the debugger thread with assembly/type load hooks */
- if (tls)
- tls->invoke_addr = stackptr;
-
- mono_loader_unlock ();
-}
-
-static void
-end_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
-{
- int i;
-#if defined(HOST_WIN32) && !defined(__GNUC__)
- gpointer stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));
-#else
- gpointer stackptr = __builtin_frame_address (1);
-#endif
-
- if (!embedding || ss_req == NULL || stackptr != ss_invoke_addr || ss_req->thread != mono_thread_internal_current ())
- return;
-
- /*
- * We need to stop single stepping when exiting a runtime invoke, since if it is
- * a step out, it may return to native code, and thus never end.
- */
- mono_loader_lock ();
- ss_invoke_addr = NULL;
-
- for (i = 0; i < event_requests->len; ++i) {
- EventRequest *req = g_ptr_array_index (event_requests, i);
-
- if (req->event_kind == EVENT_KIND_STEP) {
- ss_destroy (req->info);
- g_ptr_array_remove_index_fast (event_requests, i);
- g_free (req);
- break;
- }
- }
- mono_loader_unlock ();
-}
-
static void
send_type_load (MonoClass *klass)
{
MonoDomain *domain = mono_domain_get ();
AgentDomainInfo *info = NULL;
- mono_loader_lock ();
- mono_domain_lock (domain);
-
info = get_agent_domain_info (domain);
+ mono_loader_lock ();
+
if (!g_hash_table_lookup (info->loaded_classes, klass)) {
type_load = TRUE;
g_hash_table_insert (info->loaded_classes, klass, klass);
}
- mono_domain_unlock (domain);
mono_loader_unlock ();
+
if (type_load)
emit_type_load (klass, klass, NULL);
}
send_types_for_domain (MonoDomain *domain, void *user_data)
{
AgentDomainInfo *info = NULL;
+
+ info = get_agent_domain_info (domain);
+ g_assert (info);
mono_loader_lock ();
- mono_domain_lock (domain);
- info = get_agent_domain_info (domain);
- g_assert (info);
g_hash_table_foreach (info->loaded_classes, emit_type_load, NULL);
- mono_domain_unlock (domain);
mono_loader_unlock ();
}
} MonoBreakpoint;
/* List of breakpoints */
+/* Protected by the loader lock */
static GPtrArray *breakpoints;
/* Maps breakpoint locations to the number of breakpoints at that location */
static GHashTable *bp_locs;
#endif
}
- 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);
+ DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count);
}
static void
#endif
}
+/*
+ * This doesn't take any locks.
+ */
static inline gboolean
bp_matches_method (MonoBreakpoint *bp, MonoMethod *method)
{
}
if (!found) {
+ MonoMethod *declaring = NULL;
+
jmethod = jinfo_get_method (ji);
+ if (jmethod->is_inflated)
+ declaring = mono_method_get_declaring_generic_method (jmethod);
+
mono_domain_lock (domain);
seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, jmethod);
- if (!seq_points && jmethod->is_inflated)
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (jmethod));
+ if (!seq_points && declaring)
+ seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, declaring);
mono_domain_unlock (domain);
if (!seq_points)
/* Could be AOT code */
MonoDomain *domain;
MonoMethod *m;
MonoSeqPointInfo *seq_points;
+ GPtrArray *methods;
+ GPtrArray *method_domains;
+ GPtrArray *method_seq_points;
+ int i;
if (error)
mono_error_init (error);
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 ();
+ methods = g_ptr_array_new ();
+ method_domains = g_ptr_array_new ();
+ method_seq_points = g_ptr_array_new ();
+ mono_loader_lock ();
g_hash_table_iter_init (&iter, domains);
while (g_hash_table_iter_next (&iter, (void**)&domain, NULL)) {
mono_domain_lock (domain);
-
g_hash_table_iter_init (&iter2, domain_jit_info (domain)->seq_points);
while (g_hash_table_iter_next (&iter2, (void**)&m, (void**)&seq_points)) {
- if (bp_matches_method (bp, m))
- set_bp_in_method (domain, m, seq_points, bp, error);
+ if (bp_matches_method (bp, m)) {
+ /* Save the info locally to simplify the code inside the domain lock */
+ g_ptr_array_add (methods, m);
+ g_ptr_array_add (method_domains, domain);
+ g_ptr_array_add (method_seq_points, seq_points);
+ }
}
-
mono_domain_unlock (domain);
}
- mono_loader_unlock ();
+ for (i = 0; i < methods->len; ++i) {
+ m = g_ptr_array_index (methods, i);
+ domain = g_ptr_array_index (method_domains, i);
+ seq_points = g_ptr_array_index (method_seq_points, i);
+ set_bp_in_method (domain, m, seq_points, bp, error);
+ }
- mono_loader_lock ();
g_ptr_array_add (breakpoints, bp);
mono_loader_unlock ();
+ g_ptr_array_free (methods, TRUE);
+ g_ptr_array_free (method_domains, TRUE);
+ g_ptr_array_free (method_seq_points, TRUE);
+
if (error && !mono_error_ok (error)) {
clear_breakpoint (bp);
return NULL;
ip = MONO_CONTEXT_GET_IP (ctx);
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
- g_assert (ji);
+ g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
/* Compute the native offset of the breakpoint from the ip */
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);
+ DEBUG_PRINTF (1, "[%p] Breakpoint hit, method=%s, ip=%p, [il=0x%x,native=0x%x].\n", (gpointer)GetCurrentThreadId (), method->name, ip, sp.il_offset, native_offset);
bp = NULL;
for (i = 0; i < breakpoints->len; ++i) {
mono_loader_unlock ();
process_event (EVENT_KIND_USER_BREAK, NULL, 0, &ctx, events, suspend_policy);
- } else {
+ } else if (debug_options.native_debugger_break) {
G_BREAKPOINT ();
}
}
}
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
- g_assert (ji);
+ g_assert (ji && !ji->is_trampoline);
method = jinfo_get_method (ji);
g_assert (method);
if (val == 1)
mono_arch_start_single_stepping ();
-
- if (ss_req != NULL && ss_invoke_addr == NULL) {
- DebuggerTlsData *tls;
-
- mono_loader_lock ();
-
- tls = mono_g_hash_table_lookup (thread_to_tls, ss_req->thread);
- ss_invoke_addr = tls->invoke_addr;
-
- mono_loader_unlock ();
- }
#else
g_assert_not_reached ();
#endif
if (val == 0)
mono_arch_stop_single_stepping ();
- if (ss_req != NULL)
- ss_invoke_addr = NULL;
#else
g_assert_not_reached ();
#endif
!(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
!(t->type == MONO_TYPE_U && type == MONO_TYPE_VALUETYPE) &&
!(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8) &&
- !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE)) {
+ !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) &&
+ !(t->type == MONO_TYPE_VALUETYPE && type == MONO_TYPE_OBJECT)) {
char *name = mono_type_full_name (t);
DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type);
g_free (name);
/* Fall through */
handle_vtype:
case MONO_TYPE_VALUETYPE:
- err = decode_vtype (t, domain, addr,buf, &buf, limit);
- if (err)
- return err;
+ if (type == MONO_TYPE_OBJECT) {
+ /* Boxed vtype */
+ int objid = decode_objid (buf, &buf, limit);
+ int err;
+ MonoObject *obj;
+
+ err = get_object (objid, (MonoObject**)&obj);
+ if (err)
+ return err;
+ if (!obj)
+ return ERR_INVALID_ARGUMENT;
+ if (obj->vtable->klass != mono_class_from_mono_type (t)) {
+ DEBUG_PRINTF (1, "Expected type '%s', got object '%s'\n", mono_type_full_name (t), obj->vtable->klass->name);
+ return ERR_INVALID_ARGUMENT;
+ }
+ memcpy (addr, mono_object_unbox (obj), mono_class_value_size (obj->vtable->klass, NULL));
+ } else {
+ err = decode_vtype (t, domain, addr, buf, &buf, limit);
+ if (err)
+ return err;
+ }
break;
handle_ref:
default:
/* Can happen during shutdown */
return;
- mono_loader_lock ();
info = get_agent_domain_info (domain);
+
+ mono_loader_lock ();
g_hash_table_foreach_remove (info->loaded_classes, type_comes_from_assembly, assembly);
mono_loader_unlock ();
}
MonoMethodSignature *sig;
guint8 **arg_buf;
void **args;
- MonoObject *this, *res, *exc;
+ MonoObject *this_arg, *res, *exc;
MonoDomain *domain;
guint8 *this_buf;
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
/*
* Invoke this method directly, currently only Environment.Exit () is supported.
*/
- this = 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>");
+ this_arg = NULL;
+ DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
mono_runtime_invoke (invoke->method, NULL, invoke->args, &exc);
g_assert_not_reached ();
}
return ERR_INVALID_ARGUMENT;
}
memset (this_buf, 0, mono_class_instance_size (m->klass));
+ } else if (m->klass->valuetype && !strcmp (m->name, ".ctor")) {
+ /* Could be null */
+ guint8 *tmp_p;
+
+ int type = decode_byte (p, &tmp_p, end);
+ if (type == VALUE_TYPE_ID_NULL) {
+ memset (this_buf, 0, mono_class_instance_size (m->klass));
+ p = tmp_p;
+ } else {
+ err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end);
+ if (err)
+ return err;
+ }
} else {
err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end);
if (err)
}
if (!m->klass->valuetype)
- this = *(MonoObject**)this_buf;
+ this_arg = *(MonoObject**)this_buf;
else
- this = NULL;
+ this_arg = NULL;
if (MONO_CLASS_IS_INTERFACE (m->klass)) {
- if (!this) {
+ if (!this_arg) {
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);
+ m = mono_object_get_virtual_method (this_arg, m);
+ /* Transform this to the format the rest of the code expects it to be */
+ if (m->klass->valuetype) {
+ this_buf = g_alloca (mono_class_instance_size (m->klass));
+ memcpy (this_buf, mono_object_unbox (this_arg), mono_class_instance_size (m->klass));
+ }
} else if ((m->flags & METHOD_ATTRIBUTE_VIRTUAL) && !m->klass->valuetype && invoke->flags & INVOKE_FLAG_VIRTUAL) {
- if (!this) {
+ if (!this_arg) {
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);
+ m = mono_object_get_virtual_method (this_arg, m);
+ if (m->klass->valuetype) {
+ this_buf = g_alloca (mono_class_instance_size (m->klass));
+ memcpy (this_buf, mono_object_unbox (this_arg), mono_class_instance_size (m->klass));
+ }
}
- 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>");
+ DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this_arg ? this_arg->vtable->klass->name : "<null>");
- if (this && this->vtable->domain != domain)
+ if (this_arg && this_arg->vtable->domain != domain)
NOT_IMPLEMENTED;
- if (!m->klass->valuetype && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this) {
+ if (!m->klass->valuetype && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this_arg) {
if (!strcmp (m->name, ".ctor")) {
if (m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT)
return ERR_INVALID_ARGUMENT;
else
- this = mono_object_new (domain, m->klass);
+ this_arg = mono_object_new (domain, m->klass);
} else {
return ERR_INVALID_ARGUMENT;
}
}
- if (this && !obj_is_of_type (this, &m->klass->byval_arg))
+ if (this_arg && !obj_is_of_type (this_arg, &m->klass->byval_arg))
return ERR_INVALID_ARGUMENT;
nargs = decode_int (p, &p, end);
if (m->klass->valuetype)
res = mono_runtime_invoke (m, this_buf, args, &exc);
else
- res = mono_runtime_invoke (m, this, args, &exc);
+ res = mono_runtime_invoke (m, this_arg, args, &exc);
mono_stopwatch_stop (&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) {
out_args = TRUE;
buffer_add_byte (buf, 1 + (out_this ? 2 : 0) + (out_args ? 4 : 0));
if (sig->ret->type == MONO_TYPE_VOID) {
- if (!strcmp (m->name, ".ctor") && !m->klass->valuetype) {
- buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &this, domain);
- }
- else
+ if (!strcmp (m->name, ".ctor")) {
+ if (!m->klass->valuetype)
+ buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &this_arg, domain);
+ else
+ buffer_add_value (buf, &m->klass->byval_arg, this_buf, domain);
+ } else {
buffer_add_value (buf, &mono_defaults.void_class->byval_arg, NULL, domain);
+ }
} 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 || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) {
err = do_invoke_method (tls, &buf, invoke, p, &p);
}
+ if (tls->abort_requested) {
+ if (CHECK_PROTOCOL_VERSION (2, 42))
+ err = ERR_INVOKE_ABORTED;
+ }
+
/* Start suspending before sending the reply */
if (mindex == invoke->nmethods - 1) {
if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) {
g_assert (tls);
if (tls->abort_requested) {
+ DEBUG_PRINTF (1, "Abort already requested.\n");
mono_loader_unlock ();
break;
}
break;
}
case CMD_METHOD_GET_LOCALS_INFO: {
- int i, j, num_locals;
+ int i, num_locals;
MonoDebugLocalsInfo *locals;
int *locals_map = NULL;
buffer_add_int (buf, header->code_size);
}
} else {
- /* Maps between the IL locals index and the index in locals->locals */
- locals_map = g_new0 (int, header->num_locals);
- for (i = 0; i < header->num_locals; ++i)
- locals_map [i] = -1;
num_locals = locals->num_locals;
- for (i = 0; i < num_locals; ++i) {
- g_assert (locals->locals [i].index < header->num_locals);
- locals_map [locals->locals [i].index] = i;
- }
buffer_add_int (buf, num_locals);
/* Types */
- for (i = 0; i < header->num_locals; ++i) {
- if (locals_map [i] != -1)
- buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
+ for (i = 0; i < num_locals; ++i) {
+ g_assert (locals->locals [i].index < header->num_locals);
+ buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [locals->locals [i].index]));
}
-
/* Names */
- for (i = 0; i < header->num_locals; ++i) {
- if (locals_map [i] != -1)
- buffer_add_string (buf, locals->locals [locals_map [i]].name);
- }
-
+ for (i = 0; i < num_locals; ++i)
+ buffer_add_string (buf, locals->locals [i].name);
/* Scopes */
- for (i = 0; i < header->num_locals; ++i) {
- if (locals_map [i] != -1) {
- j = locals_map [i];
- if (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);
- }
+ for (i = 0; i < num_locals; ++i) {
+ if (locals->locals [i].block) {
+ buffer_add_int (buf, locals->locals [i].block->start_offset);
+ buffer_add_int (buf, locals->locals [i].block->end_offset);
+ } else {
+ buffer_add_int (buf, 0);
+ buffer_add_int (buf, header->code_size);
}
}
}
if (pos < 0) {
pos = - pos - 1;
+ DEBUG_PRINTF (4, "[dbg] send arg %d.\n", pos);
+
g_assert (pos >= 0 && pos < jit->num_params);
add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
} else {
+ MonoDebugLocalsInfo *locals;
+
+ locals = mono_debug_lookup_locals (frame->method);
+ if (locals) {
+ g_assert (pos < locals->num_locals);
+ pos = locals->locals [pos].index;
+ mono_debug_free_locals (locals);
+ }
g_assert (pos >= 0 && pos < jit->num_locals);
+ DEBUG_PRINTF (4, "[dbg] send local %d.\n", pos);
+
add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
}
}
t = sig->params [pos];
var = &jit->params [pos];
} else {
+ MonoDebugLocalsInfo *locals;
+
+ locals = mono_debug_lookup_locals (frame->method);
+ if (locals) {
+ g_assert (pos < locals->num_locals);
+ pos = locals->locals [pos].index;
+ mono_debug_free_locals (locals);
+ }
g_assert (pos >= 0 && pos < jit->num_locals);
t = header->locals [pos];
char *s;
int i, index, length;
gunichar2 *c;
+ gboolean use_utf16 = FALSE;
objid = decode_objid (p, &p, end);
err = get_object (objid, (MonoObject**)&str);
switch (command) {
case CMD_STRING_REF_GET_VALUE:
- s = mono_string_to_utf8 (str);
- buffer_add_string (buf, s);
- g_free (s);
+ if (CHECK_PROTOCOL_VERSION (2, 41)) {
+ for (i = 0; i < mono_string_length (str); ++i)
+ if (mono_string_chars (str)[i] == 0)
+ use_utf16 = TRUE;
+ buffer_add_byte (buf, use_utf16 ? 1 : 0);
+ }
+ if (use_utf16) {
+ buffer_add_int (buf, mono_string_length (str) * 2);
+ buffer_add_data (buf, (guint8*)mono_string_chars (str), mono_string_length (str) * 2);
+ } else {
+ s = mono_string_to_utf8 (str);
+ buffer_add_string (buf, s);
+ g_free (s);
+ }
break;
case CMD_STRING_REF_GET_LENGTH:
buffer_add_long (buf, mono_string_length (str));
if (err)
return err;
+ MonoClass *obj_type;
+
+ obj_type = obj->vtable->klass;
+ if (mono_class_is_transparent_proxy (obj_type))
+ obj_type = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+
+ g_assert (obj_type);
+
switch (command) {
case CMD_OBJECT_REF_GET_TYPE:
/* This handles transparent proxies too */
/* Check that the field belongs to the object */
found = FALSE;
- for (k = obj->vtable->klass; k; k = k->parent) {
+ for (k = obj_type; k; k = k->parent) {
if (k == f->parent) {
found = TRUE;
break;
/* Check that the field belongs to the object */
found = FALSE;
- for (k = obj->vtable->klass; k; k = k->parent) {
+ for (k = obj_type; k; k = k->parent) {
if (k == f->parent) {
found = TRUE;
break;
}
/* Block and wait for client connection */
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
conn_fd = socket_transport_accept (listen_fd);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
DEBUG_PRINTF (1, "Accepted connection on %d\n", conn_fd);
if (conn_fd == -1) {
}
while (!attach_failed) {
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_recv (header, HEADER_LENGTH);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
/* This will break if the socket is closed during shutdown too */
if (res != HEADER_LENGTH) {
data = g_malloc (len - HEADER_LENGTH);
if (len - HEADER_LENGTH > 0)
{
- MONO_PREPARE_BLOCKING
+ MONO_PREPARE_BLOCKING;
res = transport_recv (data, len - HEADER_LENGTH);
- MONO_FINISH_BLOCKING
+ MONO_FINISH_BLOCKING;
if (res != len - HEADER_LENGTH) {
DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH);
break;
mono_set_is_debugger_attached (FALSE);
- MONO_TRY_BLOCKING
+ MONO_TRY_BLOCKING;
mono_mutex_lock (&debugger_thread_exited_mutex);
debugger_thread_exited = TRUE;
mono_cond_signal (&debugger_thread_exited_cond);
mono_mutex_unlock (&debugger_thread_exited_mutex);
- MONO_FINISH_TRY_BLOCKING
+ MONO_FINISH_TRY_BLOCKING;
DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");