#include <mono/metadata/threads-types.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>
#include <mono/utils/mono-stack-unwinding.h>
#ifndef DISABLE_DEBUGGER_AGENT
-#include <mono/io-layer/mono-mutex.h>
+#include <mono/utils/mono-mutex.h>
/* Definitions to make backporting to 2.6 easier */
//#define MonoInternalThread MonoThread
* The context where single stepping should resume while the thread is suspended because
* of an EXCEPTION event.
*/
- MonoContext catch_ctx;
-
- gboolean has_catch_ctx;
+ MonoThreadUnwindState catch_state;
/*
* The context which needs to be restored after handling a single step/breakpoint
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 22
+#define MINOR_VERSION 24
typedef enum {
CMD_SET_VM = 1,
CMD_METHOD_GET_BODY = 7,
CMD_METHOD_RESOLVE_TOKEN = 8,
CMD_METHOD_GET_CATTRS = 9,
+ CMD_METHOD_MAKE_GENERIC_METHOD = 10
} CmdMethod;
typedef enum {
CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
CMD_TYPE_GET_INTERFACES = 16,
CMD_TYPE_GET_INTERFACE_MAP = 17,
+ CMD_TYPE_IS_INITIALIZED = 18
} CmdType;
typedef enum {
event_requests = g_ptr_array_new ();
- mono_mutex_init (&debugger_thread_exited_mutex, NULL);
+ mono_mutex_init (&debugger_thread_exited_mutex);
mono_cond_init (&debugger_thread_exited_cond, NULL);
mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
static inline MonoClass*
decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
{
- return decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err);
+ MonoClass *klass;
+
+ klass = decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err);
+ if (G_UNLIKELY (log_level >= 2) && klass) {
+ char *s;
+
+ s = mono_type_full_name (&klass->byval_arg);
+ DEBUG(2, fprintf (log_file, "[dbg] recv class [%s]\n", s));
+ g_free (s);
+ }
+ return klass;
}
static inline MonoAssembly*
buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
{
buffer_add_ptr_id (buf, domain, ID_TYPE, klass);
+ if (G_UNLIKELY (log_level >= 2) && klass) {
+ char *s;
+
+ s = mono_type_full_name (&klass->byval_arg);
+ if (GetCurrentThreadId () == debugger_thread_id)
+ DEBUG(2, fprintf (log_file, "[dbg] send class [%s]\n", s));
+ else
+ DEBUG(2, fprintf (log_file, "[%p] send class [%s]\n", (gpointer)GetCurrentThreadId (), s));
+ g_free (s);
+ }
}
static inline void
buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method)
{
buffer_add_ptr_id (buf, domain, ID_METHOD, method);
+ if (G_UNLIKELY (log_level >= 2) && method) {
+ char *s;
+
+ s = mono_method_full_name (method, 1);
+ DEBUG(2, fprintf (log_file, "[dbg] send method [%s]\n", s));
+ g_free (s);
+ }
}
static inline void
static void
suspend_init (void)
{
- mono_mutex_init (&suspend_mutex, NULL);
+ mono_mutex_init (&suspend_mutex);
mono_cond_init (&suspend_cond, NULL);
MONO_SEM_INIT (&suspend_sem, 0);
}
mono_mutex_unlock (&suspend_mutex);
+ if (suspend_count == 1)
+ /*
+ * Suspend creation of new threadpool threads, since they cannot run
+ */
+ mono_thread_pool_suspend ();
+
mono_loader_unlock ();
}
mono_mutex_unlock (&suspend_mutex);
//g_assert (err == 0);
+ if (suspend_count == 0)
+ mono_thread_pool_resume ();
+
mono_loader_unlock ();
}
return seq_points;
}
-static MonoSeqPointInfo*
-find_seq_points (MonoDomain *domain, MonoMethod *method)
+static void
+no_seq_points_found (MonoMethod *method)
{
- MonoSeqPointInfo *seq_points = get_seq_points (domain, method);
-
- if (!seq_points)
- printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
- g_assert (seq_points);
-
- return seq_points;
+ /*
+ * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
+ */
+ printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
}
/*
MonoSeqPointInfo *seq_points;
int i;
- seq_points = find_seq_points (domain, method);
+ seq_points = get_seq_points (domain, method);
+ if (!seq_points) {
+ if (info)
+ *info = NULL;
+ return NULL;
+ }
+ g_assert (seq_points);
if (info)
*info = seq_points;
MonoSeqPointInfo *seq_points;
int i;
- seq_points = find_seq_points (domain, method);
+ seq_points = get_seq_points (domain, method);
if (info)
*info = seq_points;
+ if (!seq_points)
+ return NULL;
for (i = seq_points->len - 1; i >= 0; --i) {
if (seq_points->seq_points [i].native_offset <= native_offset)
s = strdup_tolower (sinfo->source_file);
if (g_hash_table_lookup (mod->data.source_files, s))
found = TRUE;
+ else {
+ char *s2 = g_path_get_basename (sinfo->source_file);
+ char *s3 = strdup_tolower (s2);
+
+ if (g_hash_table_lookup (mod->data.source_files, s3))
+ found = TRUE;
+ g_free (s2);
+ g_free (s3);
+ }
g_free (s);
}
g_ptr_array_free (source_file_list, TRUE);
GSList *l;
MonoDomain *domain = mono_domain_get ();
MonoThread *thread = NULL;
+ MonoObject *keepalive_obj = NULL;
gboolean send_success = FALSE;
static int ecount;
int nevents;
case EVENT_KIND_EXCEPTION: {
EventInfo *ei = arg;
buffer_add_objid (&buf, ei->exc);
+ /*
+ * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it
+ * later after the suspension. (#12494).
+ */
+ keepalive_obj = ei->exc;
break;
}
case EVENT_KIND_USER_BREAK:
*/
save_thread_context (ctx);
suspend_vm ();
+
+ if (keepalive_obj)
+ /* This will keep this object alive */
+ get_objref (keepalive_obj);
}
send_success = send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf);
if (error) {
mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
+ g_warning ("%s", s);
g_free (s);
return;
} else {
- g_error ("%s", s);
+ g_warning ("%s", s);
g_free (s);
+ return;
}
}
g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
mono_loader_unlock ();
- if (count == 0) {
+ if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
+ DEBUG (1, fprintf (log_file, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset));
+ } else if (count == 0) {
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
mono_arch_set_breakpoint (ji, inst->ip);
#else
g_assert (count > 0);
- if (count == 1) {
+ if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
mono_arch_clear_breakpoint (ji, ip);
}
#else
mono_loader_unlock ();
}
+/*
+ * ss_update:
+ *
+ * Return FALSE if single stepping needs to continue because we are at the same line.
+ */
+static gboolean
+ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp)
+{
+ MonoDebugMethodInfo *minfo;
+ MonoDebugSourceLocation *loc = NULL;
+ gboolean hit = TRUE;
+
+ if (req->size != STEP_SIZE_LINE)
+ return TRUE;
+
+ /* Have to check whenever a different source line was reached */
+ minfo = mono_debug_lookup_method (ji->method);
+
+ if (minfo)
+ loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
+
+ if (!loc || (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line)) {
+ /* Have to continue single stepping */
+ DEBUG(1, fprintf (log_file, "[%p] Same source line, continuing single stepping.\n", (gpointer)GetCurrentThreadId ()));
+ hit = FALSE;
+ }
+
+ if (loc) {
+ ss_req->last_method = ji->method;
+ ss_req->last_line = loc->row;
+ mono_debug_free_source_location (loc);
+ }
+
+ return hit;
+}
+
static gboolean
breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
{
* the offset recorded in the seq point map, so find the prev seq point before ip.
*/
sp = find_prev_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info);
+ if (!sp)
+ no_seq_points_found (ji->method);
+ g_assert (sp);
DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, ip, native_offset, sp ? sp->il_offset : -1));
for (i = 0; i < ss_reqs_orig->len; ++i) {
EventRequest *req = g_ptr_array_index (ss_reqs_orig, i);
SingleStepReq *ss_req = req->info;
- gboolean hit = TRUE;
-
- if (ss_req->size == STEP_SIZE_LINE) {
- /* Have to check whenever a different source line was reached */
- MonoDebugMethodInfo *minfo;
- MonoDebugSourceLocation *loc = NULL;
-
- minfo = mono_debug_lookup_method (ji->method);
-
- if (minfo)
- loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
-
- if (!loc || (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line)) {
- /* Have to continue single stepping */
- DEBUG(1, fprintf (log_file, "[%p] Same source line, continuing single stepping.\n", (gpointer)GetCurrentThreadId ()));
- hit = FALSE;
- }
-
- if (loc) {
- ss_req->last_method = ji->method;
- ss_req->last_line = loc->row;
- mono_debug_free_source_location (loc);
- }
- }
+ gboolean hit;
+ hit = ss_update (ss_req, ji, sp);
if (hit)
g_ptr_array_add (ss_reqs, req);
/* Save the original context in TLS */
// FIXME: This might not work on an altstack ?
tls = mono_native_tls_get_value (debugger_tls_id);
+ if (!tls)
+ fprintf (stderr, "Thread %p is not attached to the JIT.\n", (gpointer)GetCurrentThreadId ());
g_assert (tls);
// FIXME: MonoContext usually doesn't include the fp registers, so these are
return;
il_offset = sp->il_offset;
- // FIXME: No tests fail if this is disabled
-#if 0
- if (ss_req->size == STEP_SIZE_LINE) {
- // FIXME:
- NOT_IMPLEMENTED;
-
- /* Step until a different source line is reached */
- MonoDebugMethodInfo *minfo;
-
- minfo = mono_debug_lookup_method (ji->method);
-
- if (minfo) {
- MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, il_offset);
-
- if (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line) {
- mono_debug_free_source_location (loc);
- return;
- }
- if (!loc)
- /*
- * Step until we reach a location with line number info,
- * otherwise the client can't show a location.
- * This can happen for example with statics initialized inline
- * outside of a cctor.
- */
- return;
-
- if (loc) {
- ss_req->last_method = ji->method;
- ss_req->last_line = loc->row;
- mono_debug_free_source_location (loc);
- }
- }
- }
-#endif
+ if (!ss_update (ss_req, ji, sp))
+ return;
/* Start single stepping again from the current sequence point */
ss_start (ss_req, ji->method, sp, info, ctx, tls, FALSE);
if (val == 0)
mono_arch_stop_single_stepping ();
+ if (ss_req != NULL)
+ ss_invoke_addr = NULL;
#else
g_assert_not_reached ();
#endif
// There could be method calls before the next seq point in the caller when using nested calls
//enable_global = TRUE;
} else {
- while (sp && sp->next_len == 0) {
+ if (sp && sp->next_len == 0) {
sp = NULL;
- if (frame_index < tls->frame_count) {
+ while (frame_index < tls->frame_count) {
StackFrame *frame = tls->frames [frame_index];
method = frame->method;
sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+ if (sp && sp->next_len != 0)
+ break;
+ sp = NULL;
frame_index ++;
}
}
g_assert (tls->context.valid);
ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx);
- if (tls->has_catch_ctx) {
+ if (tls->catch_state.valid) {
gboolean res;
StackFrameInfo frame;
MonoContext new_ctx;
*/
/* Find the the jit info for the catch context */
- res = mono_find_jit_info_ext (mono_domain_get (), thread->jit_data, NULL, &tls->catch_ctx, &new_ctx, NULL, &lmf, NULL, &frame);
+ res = mono_find_jit_info_ext (tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], thread->jit_data, NULL, &tls->catch_state.ctx, &new_ctx, NULL, &lmf, NULL, &frame);
g_assert (res);
g_assert (frame.type == FRAME_TYPE_MANAGED);
* point after ip.
*/
sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info);
+ if (!sp)
+ no_seq_points_found (frame.method);
g_assert (sp);
method = frame.method;
if (!method && frame->il_offset != -1) {
/* FIXME: Sort the table and use a binary search */
sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info);
+ if (!sp)
+ no_seq_points_found (frame->method);
g_assert (sp);
method = frame->method;
}
mono_loader_unlock ();
if (tls && ei.caught && catch_ctx) {
- tls->catch_ctx = *catch_ctx;
- tls->has_catch_ctx = TRUE;
+ memset (&tls->catch_state, 0, sizeof (tls->catch_state));
+ tls->catch_state.ctx = *catch_ctx;
+ tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+ tls->catch_state.valid = TRUE;
}
process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, suspend_policy);
if (tls)
- tls->has_catch_ctx = FALSE;
+ tls->catch_state.valid = FALSE;
}
void
MonoObject *obj;
if (t->byref) {
+ if (!(*(void**)addr)) {
+ /* This can happen with compiler generated locals */
+ //printf ("%s\n", mono_type_full_name (t));
+ buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
+ return;
+ }
g_assert (*(void**)addr);
addr = *(void**)addr;
}
{
MonoClass *klass = obj->vtable->klass;
if (!mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) {
- if (klass == mono_defaults.transparent_proxy_class) {
+ if (mono_class_is_transparent_proxy (klass)) {
klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
if (mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) {
return TRUE;
static ErrorCode
decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit);
+static ErrorCode
+decode_vtype (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
+{
+ gboolean is_enum;
+ MonoClass *klass;
+ MonoClassField *f;
+ int nfields;
+ gpointer iter = NULL;
+ MonoDomain *d;
+ int err;
+
+ is_enum = decode_byte (buf, &buf, limit);
+ /* Enums are sent as a normal vtype */
+ if (is_enum)
+ return ERR_NOT_IMPLEMENTED;
+ klass = decode_typeid (buf, &buf, limit, &d, &err);
+ if (err)
+ return err;
+
+ if (t && klass != mono_class_from_mono_type (t)) {
+ char *name = mono_type_full_name (t);
+ char *name2 = mono_type_full_name (&klass->byval_arg);
+ DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got %s.\n", (gpointer)GetCurrentThreadId (), name, name2));
+ g_free (name);
+ g_free (name2);
+ return ERR_INVALID_ARGUMENT;
+ }
+
+ nfields = decode_int (buf, &buf, limit);
+ while ((f = mono_class_get_fields (klass, &iter))) {
+ if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
+ continue;
+ if (mono_field_is_deleted (f))
+ continue;
+ err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit);
+ if (err)
+ return err;
+ nfields --;
+ }
+ g_assert (nfields == 0);
+ return 0;
+}
+
static ErrorCode
decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
{
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:
- case MONO_TYPE_VALUETYPE: {
- gboolean is_enum = decode_byte (buf, &buf, limit);
- MonoClass *klass;
- MonoClassField *f;
- int nfields;
- gpointer iter = NULL;
- MonoDomain *d;
-
- /* Enums are sent as a normal vtype */
- if (is_enum)
- return ERR_NOT_IMPLEMENTED;
- klass = decode_typeid (buf, &buf, limit, &d, &err);
+ case MONO_TYPE_VALUETYPE:
+ err = decode_vtype (t, domain, addr,buf, &buf, limit);
if (err)
return err;
-
- if (klass != mono_class_from_mono_type (t))
- return ERR_INVALID_ARGUMENT;
-
- nfields = decode_int (buf, &buf, limit);
- while ((f = mono_class_get_fields (klass, &iter))) {
- if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
- continue;
- if (mono_field_is_deleted (f))
- continue;
- err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit);
- if (err)
- return err;
- nfields --;
- }
- g_assert (nfields == 0);
break;
- }
handle_ref:
default:
if (MONO_TYPE_IS_REFERENCE (t)) {
mono_gc_wbarrier_generic_store (addr, obj);
} else if (type == VALUE_TYPE_ID_NULL) {
*(MonoObject**)addr = NULL;
+ } else if (type == MONO_TYPE_VALUETYPE) {
+ guint8 *buf2;
+ gboolean is_enum;
+ MonoClass *klass;
+ MonoDomain *d;
+ guint8 *vtype_buf;
+ int vtype_buf_size;
+
+ /* This can happen when round-tripping boxed vtypes */
+ /*
+ * Obtain vtype class.
+ * Same as the beginning of the handle_vtype case above.
+ */
+ buf2 = buf;
+ is_enum = decode_byte (buf, &buf, limit);
+ if (is_enum)
+ return ERR_NOT_IMPLEMENTED;
+ klass = decode_typeid (buf, &buf, limit, &d, &err);
+ if (err)
+ return err;
+
+ /* Decode the vtype into a temporary buffer, then box it. */
+ vtype_buf_size = mono_class_value_size (klass, NULL);
+ vtype_buf = g_malloc0 (vtype_buf_size);
+ g_assert (vtype_buf);
+
+ buf = buf2;
+ err = decode_vtype (NULL, domain, vtype_buf, buf, &buf, limit);
+ if (err) {
+ g_free (vtype_buf);
+ return err;
+ }
+ *(MonoObject**)addr = mono_value_box (d, klass, vtype_buf);
+ g_free (vtype_buf);
} else {
+ char *name = mono_type_full_name (t);
+ DEBUG(1, fprintf (log_file, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer)GetCurrentThreadId (), name, type));
+ g_free (name);
return ERR_INVALID_ARGUMENT;
}
} else {
}
static void
-add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
+add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
{
guint32 flags;
int reg;
- guint8 *addr;
+ guint8 *addr, *gaddr;
mgreg_t reg_val;
flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
NOT_IMPLEMENTED;
break;
+ case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
+ /* Same as regoffset, but with an indirection */
+ addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ addr += (gint32)var->offset;
+
+ gaddr = *(gpointer*)addr;
+ g_assert (gaddr);
+ buffer_add_value_full (buf, t, gaddr, domain, as_vtype);
+ break;
+ case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: {
+ MonoDebugVarInfo *info_var = jit->gsharedvt_info_var;
+ MonoDebugVarInfo *locals_var = jit->gsharedvt_locals_var;
+ MonoGSharedVtMethodRuntimeInfo *info;
+ guint8 *locals;
+ int idx;
+
+ idx = reg;
+
+ g_assert (info_var);
+ g_assert (locals_var);
+
+ flags = info_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
+ reg = info_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
+ if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
+ addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ addr += (gint32)info_var->offset;
+ info = *(gpointer*)addr;
+ } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
+ info = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ } else {
+ g_assert_not_reached ();
+ }
+ g_assert (info);
+
+ flags = locals_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
+ reg = locals_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
+ if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
+ addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ addr += (gint32)locals_var->offset;
+ locals = *(gpointer*)addr;
+ } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
+ locals = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ } else {
+ g_assert_not_reached ();
+ }
+ g_assert (locals);
+
+ addr = locals + GPOINTER_TO_INT (info->entries [idx]);
+
+ buffer_add_value_full (buf, t, addr, domain, as_vtype);
+ break;
+ }
+
default:
g_assert_not_reached ();
}
{
guint32 flags;
int reg, size;
- guint8 *addr;
+ guint8 *addr, *gaddr;
flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
// FIXME: Write barriers
mono_gc_memmove (addr, val, size);
break;
+ case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
+ /* Same as regoffset, but with an indirection */
+ addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+ addr += (gint32)var->offset;
+
+ gaddr = *(gpointer*)addr;
+ g_assert (gaddr);
+ // FIXME: Write barriers
+ mono_gc_memmove (gaddr, val, size);
+ break;
case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
NOT_IMPLEMENTED;
break;
if (m->klass->valuetype && (m->flags & METHOD_ATTRIBUTE_STATIC)) {
/* Should be null */
int type = decode_byte (p, &p, end);
- if (type != VALUE_TYPE_ID_NULL)
+ if (type != VALUE_TYPE_ID_NULL) {
+ DEBUG (1, fprintf (log_file, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer)GetCurrentThreadId ()));
return ERR_INVALID_ARGUMENT;
+ }
memset (this_buf, 0, mono_class_instance_size (m->klass));
} else {
err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end);
tls->resume_count -= invoke->suspend_count;
}
- DEBUG (1, fprintf (log_file, "[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count));
+ DEBUG (1, fprintf (log_file, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer)GetCurrentThreadId (), err, tls->resume_count));
/*
* Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
case CMD_VM_EXIT: {
MonoInternalThread *thread;
DebuggerTlsData *tls;
+#ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
MonoClass *env_class;
+#endif
MonoMethod *exit_method = NULL;
gpointer *args;
int exit_code;
while (suspend_count > 0)
resume_vm ();
- mono_runtime_set_shutting_down ();
-
- mono_threads_set_shutting_down ();
+ if (!mono_runtime_try_shutdown ())
+ break;
/* Suspend all managed threads since the runtime is going away */
DEBUG(1, fprintf (log_file, "Suspending all threads...\n"));
MonoArray *typed_args, *named_args;
MonoType *t;
CattrNamedArg *arginfo;
+ MonoError error;
- mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo);
+ mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error);
+ g_assert (mono_error_ok (&error));
buffer_add_methodid (buf, domain, attr->ctor);
}
break;
}
+ case CMD_TYPE_IS_INITIALIZED: {
+ MonoVTable *vtable = mono_class_vtable (domain, klass);
+
+ if (vtable)
+ buffer_add_int (buf, (vtable->initialized || vtable->init_failed) ? 1 : 0);
+ else
+ buffer_add_int (buf, 0);
+ break;
+ }
default:
return ERR_NOT_IMPLEMENTED;
}
buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo);
break;
}
+ case CMD_METHOD_MAKE_GENERIC_METHOD: {
+ MonoType **type_argv;
+ int i, type_argc;
+ MonoDomain *d;
+ MonoClass *klass;
+ MonoGenericInst *ginst;
+ MonoGenericContext tmp_context;
+ MonoMethod *inflated;
+
+ type_argc = decode_int (p, &p, end);
+ type_argv = g_new0 (MonoType*, type_argc);
+ for (i = 0; i < type_argc; ++i) {
+ klass = decode_typeid (p, &p, end, &d, &err);
+ if (err) {
+ g_free (type_argv);
+ return err;
+ }
+ if (domain != d) {
+ g_free (type_argv);
+ return ERR_INVALID_ARGUMENT;
+ }
+ type_argv [i] = &klass->byval_arg;
+ }
+ ginst = mono_metadata_get_generic_inst (type_argc, type_argv);
+ g_free (type_argv);
+ tmp_context.class_inst = method->klass->generic_class ? method->klass->generic_class->context.class_inst : NULL;
+ tmp_context.method_inst = ginst;
+
+ inflated = mono_class_inflate_generic_method (method, &tmp_context);
+ if (!mono_verifier_is_method_valid_generic_instantiation (inflated))
+ return ERR_INVALID_ARGUMENT;
+ buffer_add_methodid (buf, domain, inflated);
+ break;
+ }
default:
return ERR_NOT_IMPLEMENTED;
}
frame = tls->frames [frame_idx];
if (!frame->has_ctx)
- // FIXME:
- return ERR_INVALID_FRAMEID;
+ return ERR_ABSENT_INFORMATION;
if (!frame->jit) {
frame->jit = mono_debug_find_method (frame->api_method, frame->domain);
var = &jit->params [pos];
- add_var (buf, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+ add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
} else {
g_assert (pos >= 0 && pos < jit->num_locals);
var = &jit->locals [pos];
- add_var (buf, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+ add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
}
}
mono_metadata_free_mh (header);
MonoObject *p = NULL;
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
} else {
- add_var (buf, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
}
} else {
if (!sig->hasthis) {
MonoObject *p = NULL;
buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain);
} else {
- add_var (buf, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
}
}
break;
}
}
+static const char* vm_cmds_str [] = {
+ "VERSION",
+ "ALL_THREADS",
+ "SUSPEND",
+ "RESUME",
+ "EXIT",
+ "DISPOSE",
+ "INVOKE_METHOD",
+ "SET_PROTOCOL_VERSION",
+ "ABORT_INVOKE",
+ "SET_KEEPALIVE"
+ "GET_TYPES_FOR_SOURCE_FILE",
+ "GET_TYPES",
+ "INVOKE_METHODS"
+};
+
+static const char* thread_cmds_str[] = {
+ "GET_FRAME_INFO",
+ "GET_NAME",
+ "GET_STATE",
+ "GET_INFO",
+ "GET_ID",
+ "GET_TID"
+};
+
+static const char* event_cmds_str[] = {
+ "REQUEST_SET",
+ "REQUEST_CLEAR",
+ "REQUEST_CLEAR_ALL_BREAKPOINTS"
+};
+
+static const char* appdomain_cmds_str[] = {
+ "GET_ROOT_DOMAIN",
+ "GET_FRIENDLY_NAME",
+ "GET_ASSEMBLIES",
+ "GET_ENTRY_ASSEMBLY",
+ "CREATE_STRING",
+ "GET_CORLIB",
+ "CREATE_BOXED_VALUE"
+};
+
+static const char* assembly_cmds_str[] = {
+ "GET_LOCATION",
+ "GET_ENTRY_POINT",
+ "GET_MANIFEST_MODULE",
+ "GET_OBJECT",
+ "GET_TYPE",
+ "GET_NAME"
+};
+
+static const char* module_cmds_str[] = {
+ "GET_INFO",
+};
+
+static const char* method_cmds_str[] = {
+ "GET_NAME",
+ "GET_DECLARING_TYPE",
+ "GET_DEBUG_INFO",
+ "GET_PARAM_INFO",
+ "GET_LOCALS_INFO",
+ "GET_INFO",
+ "GET_BODY",
+ "RESOLVE_TOKEN",
+ "GET_CATTRS ",
+ "MAKE_GENERIC_METHOD"
+};
+
+static const char* type_cmds_str[] = {
+ "GET_INFO",
+ "GET_METHODS",
+ "GET_FIELDS",
+ "GET_VALUES",
+ "GET_OBJECT",
+ "GET_SOURCE_FILES",
+ "SET_VALUES",
+ "IS_ASSIGNABLE_FROM",
+ "GET_PROPERTIES ",
+ "GET_CATTRS",
+ "GET_FIELD_CATTRS",
+ "GET_PROPERTY_CATTRS",
+ "GET_SOURCE_FILES_2",
+ "GET_VALUES_2",
+ "GET_METHODS_BY_NAME_FLAGS",
+ "GET_INTERFACES",
+ "GET_INTERFACE_MAP",
+ "IS_INITIALIZED"
+};
+
+static const char* stack_frame_cmds_str[] = {
+ "GET_VALUES",
+ "GET_THIS",
+ "SET_VALUES"
+};
+
+static const char* array_cmds_str[] = {
+ "GET_LENGTH",
+ "GET_VALUES",
+ "SET_VALUES",
+};
+
+static const char* string_cmds_str[] = {
+ "GET_VALUE",
+ "GET_LENGTH",
+ "GET_CHARS"
+};
+
+static const char* object_cmds_str[] = {
+ "GET_TYPE",
+ "GET_VALUES",
+ "IS_COLLECTED",
+ "GET_ADDRESS",
+ "GET_DOMAIN",
+ "SET_VALUES",
+ "GET_INFO",
+};
+
static const char*
cmd_to_string (CommandSet set, int command)
{
+ const char **cmds;
+ int cmds_len = 0;
+
switch (set) {
- case CMD_SET_VM: {
- switch (command) {
- case CMD_VM_VERSION:
- return "VERSION";
- case CMD_VM_ALL_THREADS:
- return "ALL_THREADS";
- case CMD_VM_SUSPEND:
- return "SUSPEND";
- case CMD_VM_RESUME:
- return "RESUME";
- case CMD_VM_EXIT:
- return "EXIT";
- case CMD_VM_DISPOSE:
- return "DISPOSE";
- case CMD_VM_INVOKE_METHOD:
- return "INVOKE_METHOD";
- case CMD_VM_SET_PROTOCOL_VERSION:
- return "SET_PROTOCOL_VERSION";
- case CMD_VM_ABORT_INVOKE:
- return "ABORT_INVOKE";
- case CMD_VM_SET_KEEPALIVE:
- return "SET_KEEPALIVE";
- default:
- break;
- }
+ case CMD_SET_VM:
+ cmds = vm_cmds_str;
+ cmds_len = G_N_ELEMENTS (vm_cmds_str);
+ break;
+ case CMD_SET_OBJECT_REF:
+ cmds = object_cmds_str;
+ cmds_len = G_N_ELEMENTS (object_cmds_str);
+ break;
+ case CMD_SET_STRING_REF:
+ cmds = string_cmds_str;
+ cmds_len = G_N_ELEMENTS (string_cmds_str);
+ break;
+ case CMD_SET_THREAD:
+ cmds = thread_cmds_str;
+ cmds_len = G_N_ELEMENTS (thread_cmds_str);
+ break;
+ case CMD_SET_ARRAY_REF:
+ cmds = array_cmds_str;
+ cmds_len = G_N_ELEMENTS (array_cmds_str);
+ break;
+ case CMD_SET_EVENT_REQUEST:
+ cmds = event_cmds_str;
+ cmds_len = G_N_ELEMENTS (event_cmds_str);
+ break;
+ case CMD_SET_STACK_FRAME:
+ cmds = stack_frame_cmds_str;
+ cmds_len = G_N_ELEMENTS (stack_frame_cmds_str);
+ break;
+ case CMD_SET_APPDOMAIN:
+ cmds = appdomain_cmds_str;
+ cmds_len = G_N_ELEMENTS (appdomain_cmds_str);
+ break;
+ case CMD_SET_ASSEMBLY:
+ cmds = assembly_cmds_str;
+ cmds_len = G_N_ELEMENTS (assembly_cmds_str);
+ break;
+ case CMD_SET_METHOD:
+ cmds = method_cmds_str;
+ cmds_len = G_N_ELEMENTS (method_cmds_str);
+ break;
+ case CMD_SET_TYPE:
+ cmds = type_cmds_str;
+ cmds_len = G_N_ELEMENTS (type_cmds_str);
+ break;
+ case CMD_SET_MODULE:
+ cmds = module_cmds_str;
+ cmds_len = G_N_ELEMENTS (module_cmds_str);
+ break;
+ case CMD_SET_EVENT:
+ cmds = event_cmds_str;
+ cmds_len = G_N_ELEMENTS (event_cmds_str);
break;
- }
default:
break;
}
- return NULL;
+ if (command > 0 && command <= cmds_len)
+ return cmds [command - 1];
+ else
+ return NULL;
}
static gboolean
cmd_str = cmd_num;
}
- DEBUG (1, fprintf (log_file, "[dbg] Received command %s(%s), id=%d.\n", command_set_to_string (command_set), cmd_str, id));
+ DEBUG (1, fprintf (log_file, "[dbg] Command %s(%s) [%d].\n", command_set_to_string (command_set), cmd_str, id));
}
data = g_malloc (len - HEADER_LENGTH);
g_free (data);
buffer_free (&buf);
- if (command_set == CMD_SET_VM && command == CMD_VM_DISPOSE)
+ if (command_set == CMD_SET_VM && (command == CMD_VM_DISPOSE || command == CMD_VM_EXIT))
break;
}