#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-stack-unwinding.h>
#include <mono/utils/mono-time.h>
+#include <mono/utils/mono-threads.h>
#include "debugger-agent.h"
#include "mini.h"
#define DISABLE_DEBUGGER_AGENT 1
#endif
-#if defined(__MACH__)
-#include <mono/utils/mono-threads.h>
-#endif
-
#ifndef DISABLE_DEBUGGER_AGENT
#include <mono/io-layer/mono-mutex.h>
* method.
*/
MonoMethod *actual_method;
+ /*
+ * This is the method which is visible to debugger clients. Same as method,
+ * except for native-to-managed wrappers.
+ */
+ MonoMethod *api_method;
MonoContext ctx;
MonoDebugMethodJitInfo *jit;
+ MonoJitInfo *ji;
int flags;
mgreg_t *reg_locations [MONO_MAX_IREGS];
/*
MonoMethod *method;
gpointer *args;
guint32 suspend_count;
+ int nmethods;
InvokeData *last_invoke;
};
typedef struct {
MonoThreadUnwindState context;
- gpointer resume_event;
/* This is computed on demand when it is requested using the wire protocol */
/* It is freed up when the thread is resumed */
int frame_count;
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 17
+#define MINOR_VERSION 22
typedef enum {
CMD_SET_VM = 1,
typedef enum {
STEP_FILTER_NONE = 0,
- STEP_FILTER_STATIC_CTOR = 1
+ STEP_FILTER_STATIC_CTOR = 1,
+ STEP_FILTER_DEBUGGER_HIDDEN = 2
} StepFilter;
typedef enum {
CMD_VM_ABORT_INVOKE = 9,
CMD_VM_SET_KEEPALIVE = 10,
CMD_VM_GET_TYPES_FOR_SOURCE_FILE = 11,
- CMD_VM_GET_TYPES = 12
+ CMD_VM_GET_TYPES = 12,
+ CMD_VM_INVOKE_METHODS = 13
} CmdVM;
typedef enum {
CMD_METHOD_GET_INFO = 6,
CMD_METHOD_GET_BODY = 7,
CMD_METHOD_RESOLVE_TOKEN = 8,
+ CMD_METHOD_GET_CATTRS = 9,
} CmdMethod;
typedef enum {
static void process_profiler_event (EventKind event, gpointer arg);
+static void invalidate_frames (DebuggerTlsData *tls);
+
#ifndef DISABLE_SOCKET_TRANSPORT
static void
register_socket_transport (void);
}
}
+ //agent_config.log_level = 0;
+
if (agent_config.transport == NULL) {
fprintf (stderr, "debugger-agent: The 'transport' option is mandatory.\n");
exit (1);
if (!agent_config.onuncaught && !agent_config.onthrow)
finish_agent_init (TRUE);
-
- /* FIXME: Is this still needed ? */
-#if defined(__MACH__)
- mono_thread_info_disable_new_interrupt (TRUE);
-#endif
}
/*
int total = 0;
int fd = conn_fd;
int flags = 0;
+ static gint32 last_keepalive;
+ gint32 msecs;
do {
again:
res = recv (fd, (char *) buf + total, len - total, flags);
if (res > 0)
total += res;
- if (agent_config.keepalive && res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) {
- process_profiler_event (EVENT_KIND_KEEPALIVE, NULL);
- goto again;
+ if (agent_config.keepalive) {
+ gboolean need_keepalive = FALSE;
+ if (res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) {
+ need_keepalive = TRUE;
+ } else if (res == -1) {
+ /* This could happen if recv () is interrupted repeatedly */
+ msecs = mono_msec_ticks ();
+ if (msecs - last_keepalive >= agent_config.keepalive) {
+ need_keepalive = TRUE;
+ last_keepalive = msecs;
+ }
+ }
+ if (need_keepalive) {
+ process_profiler_event (EVENT_KIND_KEEPALIVE, NULL);
+ goto again;
+ }
}
} while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR));
return total;
struct timeval tv;
int result;
- if (!agent_config.keepalive)
+ if (!agent_config.keepalive || !conn_fd)
return;
tv.tv_sec = agent_config.keepalive / 1000;
addrlen = sizeof (addr);
memset (&addr, 0, sizeof (addr));
- res = getsockname (sfd, &addr, &addrlen);
+ res = getsockname (sfd, (struct sockaddr*)&addr, &addrlen);
g_assert (res == 0);
host = (char*)"127.0.0.1";
#endif
}
- disconnected = !transport_handshake ();
- if (disconnected)
+ if (!transport_handshake ())
exit (1);
}
guint8 buf [128];
int res;
+ disconnected = TRUE;
+
/* Write handshake message */
sprintf (handshake_msg, "DWP-Handshake");
do {
* Set TCP_NODELAY on the socket so the client receives events/command
* results immediately.
*/
- {
+ if (conn_fd) {
int flag = 1;
int result = setsockopt (conn_fd,
IPPROTO_TCP,
set_keepalive ();
#endif
+ disconnected = FALSE;
return TRUE;
}
/* Store the context/lmf for the frame above the last frame */
memcpy (&data->ctx, ctx, sizeof (MonoContext));
data->lmf = info->lmf;
-
return TRUE;
}
}
if (info)
tid = mono_thread_info_get_tid (info);
else
- tid = GetCurrentThreadId ();
+ tid = (MonoNativeThreadId)GetCurrentThreadId ();
// FIXME: Races when the thread leaves managed code before hitting a single step
// event.
return FALSE;
tls = mono_native_tls_get_value (debugger_tls_id);
- if (!tls)
- return FALSE;
+ if (!tls) {
+ DEBUG (1, fprintf (log_file, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer)GetCurrentThreadId ()));
+ return FALSE;
+ }
return thread_interrupt (tls, NULL, sigctx, ji);
}
/*
* reset_native_thread_suspend_state:
*
- * Reset the suspended flag on native threads
+ * Reset the suspended flag and state on native threads
*/
static void
reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_data)
{
DebuggerTlsData *tls = value;
- if (!tls->really_suspended && tls->suspended)
+ if (!tls->really_suspended && tls->suspended) {
tls->suspended = FALSE;
+ /*
+ * The thread might still be running if it was executing native code, so the state won't be invalided by
+ * suspend_current ().
+ */
+ tls->context.valid = FALSE;
+ tls->async_state.valid = FALSE;
+ invalidate_frames (tls);
+ }
}
/*
mono_thread_info_resume (mono_thread_info_get_tid (info));
} else {
res = mono_thread_kill (thread, mono_thread_get_abort_signal ());
- if (res)
+ if (res) {
+ DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res));
/*
* Attached thread which died without detaching.
*/
tls->terminated = TRUE;
+ }
}
#endif
}
g_assert (suspend_count > 0);
suspend_count --;
- DEBUG(1, fprintf (log_file, "[%p] Resuming vm...\n", (gpointer)GetCurrentThreadId ()));
+ DEBUG(1, fprintf (log_file, "[%p] Resuming vm, suspend count=%d...\n", (gpointer)GetCurrentThreadId (), suspend_count));
if (suspend_count == 0) {
// FIXME: Is it safe to call this inside the lock ?
/* The frame info becomes invalid after a resume */
tls->context.valid = FALSE;
tls->async_state.valid = FALSE;
- invalidate_frames (NULL);
+ invalidate_frames (tls);
}
static void
{
ComputeFramesUserData *ud = user_data;
StackFrame *frame;
- MonoMethod *method, *actual_method;
+ MonoMethod *method, *actual_method, *api_method;
SeqPoint *sp;
int flags = 0;
else
method = info->method;
actual_method = info->actual_method;
+ api_method = method;
if (!method)
return FALSE;
if (!CHECK_PROTOCOL_VERSION (2, 17))
/* Older clients can't handle this flag */
return FALSE;
- method = mono_marshal_method_from_wrapper (method);
- if (!method)
+ api_method = mono_marshal_method_from_wrapper (method);
+ if (!api_method)
return FALSE;
- actual_method = method;
+ actual_method = api_method;
flags |= FRAME_FLAG_NATIVE_TRANSITION;
}
frame = g_new0 (StackFrame, 1);
frame->method = method;
frame->actual_method = actual_method;
+ frame->api_method = api_method;
frame->il_offset = info->il_offset;
frame->native_offset = info->native_offset;
frame->flags = flags;
+ frame->ji = info->ji;
if (info->reg_locations)
memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*));
if (ctx) {
MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
if (minfo) {
- mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL);
+ mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL, NULL);
for (i = 0; i < source_file_list->len; ++i) {
sinfo = g_ptr_array_index (source_file_list, i);
/*
(ji->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
!strcmp (ji->method->name, ".cctor"))
filtered = TRUE;
+ if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) {
+ MonoCustomAttrInfo *ainfo;
+ static MonoClass *klass;
+
+ if (!klass) {
+ klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute");
+ g_assert (klass);
+ }
+ if (!ji->dbg_hidden_inited) {
+ ainfo = mono_custom_attrs_from_method (ji->method);
+ if (ainfo) {
+ if (mono_custom_attrs_has_attr (ainfo, klass))
+ ji->dbg_hidden = TRUE;
+ mono_custom_attrs_free (ainfo);
+ }
+ ji->dbg_hidden_inited = TRUE;
+ }
+ if (ji->dbg_hidden)
+ filtered = TRUE;
+ }
}
}
g_assert (!tls);
// FIXME: Free this somewhere
tls = g_new0 (DebuggerTlsData, 1);
- tls->resume_event = CreateEvent (NULL, FALSE, FALSE, NULL);
MONO_GC_REGISTER_ROOT_SINGLE (tls->thread);
tls->thread = thread;
mono_native_tls_set_value (debugger_tls_id, tls);
mono_loader_lock ();
thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid);
if (thread) {
- tls = mono_g_hash_table_lookup (thread_to_tls, thread);
- /* FIXME: Maybe we need to free this instead, but some code can't handle that */
- tls->terminated = TRUE;
mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid);
- /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
- MONO_GC_UNREGISTER_ROOT (tls->thread);
- tls->thread = NULL;
+ tls = mono_g_hash_table_lookup (thread_to_tls, thread);
+ if (tls) {
+ /* FIXME: Maybe we need to free this instead, but some code can't handle that */
+ tls->terminated = TRUE;
+ /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
+ MONO_GC_UNREGISTER_ROOT (tls->thread);
+ tls->thread = NULL;
+ }
}
mono_loader_unlock ();
char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (ji->method, TRUE), bp->il_offset, seq_points->len);
for (i = 0; i < seq_points->len; ++i)
- printf ("%d\n", seq_points->seq_points [i].il_offset);
+ DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
if (error) {
mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
ss_reqs = g_ptr_array_new ();
ss_reqs_orig = g_ptr_array_new ();
- DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, native_offset));
-
mono_loader_lock ();
/*
*/
sp = find_prev_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info);
+ 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));
+
bp = NULL;
for (i = 0; i < breakpoints->len; ++i) {
bp = g_ptr_array_index (breakpoints, i);
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))
+ 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;
* problems, like the original signal is disabled, libgc can't handle altstack, etc.
* So set up the signal context to return to the real breakpoint handler function.
*/
-
resume_from_signal_handler (sigctx, process_breakpoint);
}
static void
ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
{
- int i, frame_index;
+ int i, j, frame_index;
SeqPoint *next_sp;
MonoBreakpoint *bp;
gboolean enable_global = FALSE;
} else {
frame_index = 1;
- if ((!sp || sp->next_len == 0 || ss_req->depth == STEP_DEPTH_OUT) && ctx) {
+ if ((!sp || sp->next_len == 0 || ss_req->depth == STEP_DEPTH_OUT || ss_req->depth == STEP_DEPTH_OVER) && ctx) {
/* Need parent frames */
if (!tls->context.valid)
mono_thread_state_init_from_monoctx (&tls->context, ctx);
if (sp && sp->next_len != 0)
break;
}
+ // 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) {
sp = NULL;
}
}
+ if (ss_req->depth == STEP_DEPTH_OVER) {
+ /* Need to stop in catch clauses as well */
+ for (i = 0; i < tls->frame_count; ++i) {
+ StackFrame *frame = tls->frames [i];
+
+ if (frame->ji) {
+ MonoJitInfo *jinfo = frame->ji;
+ for (j = 0; j < jinfo->num_clauses; ++j) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [j];
+
+ sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL);
+ if (sp) {
+ bp = set_breakpoint (frame->method, sp->il_offset, ss_req->req, NULL);
+ ss_req->bps = g_slist_append (ss_req->bps, bp);
+ }
+ }
+ }
+ }
+ }
+
+
if (ss_req->depth == STEP_DEPTH_INTO) {
/* Enable global stepping so we stop at method entry too */
enable_global = TRUE;
buffer_add_value_full (buf, t, addr, domain, FALSE);
}
+static gboolean
+obj_is_of_type (MonoObject *obj, MonoType *t)
+{
+ 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) {
+ klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
+ if (mono_class_is_assignable_from (mono_class_from_mono_type (t), klass)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
static ErrorCode
-decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
+decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit);
+
+static ErrorCode
+decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
{
int err;
- int type = decode_byte (buf, &buf, limit);
if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) &&
!(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
if (err)
return err;
- if (obj && !mono_class_is_assignable_from (mono_class_from_mono_type (t), obj->vtable->klass))
- return ERR_INVALID_ARGUMENT;
+ if (obj) {
+ if (!obj_is_of_type (obj, t)) {
+ DEBUG (1, fprintf (log_file, "Expected type '%s', got '%s'\n", mono_type_full_name (t), obj->vtable->klass->name));
+ return ERR_INVALID_ARGUMENT;
+ }
+ }
if (obj && obj->vtable->domain != domain)
return ERR_INVALID_ARGUMENT;
return 0;
}
+static ErrorCode
+decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
+{
+ int err;
+ int type = decode_byte (buf, &buf, limit);
+
+ if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
+ MonoType *targ = t->data.generic_class->context.class_inst->type_argv [0];
+ guint8 *nullable_buf;
+
+ /*
+ * First try decoding it as a Nullable`1
+ */
+ err = decode_value_internal (t, type, domain, addr, buf, endbuf, limit);
+ if (!err)
+ return err;
+
+ /*
+ * Then try decoding as a primitive value or null.
+ */
+ if (targ->type == type) {
+ nullable_buf = g_malloc (mono_class_instance_size (mono_class_from_mono_type (targ)));
+ err = decode_value_internal (targ, type, domain, nullable_buf, buf, endbuf, limit);
+ if (err) {
+ g_free (nullable_buf);
+ return err;
+ }
+ mono_nullable_init (addr, mono_value_box (domain, mono_class_from_mono_type (targ), nullable_buf), mono_class_from_mono_type (t));
+ g_free (nullable_buf);
+ *endbuf = buf;
+ return ERR_NONE;
+ } else if (type == VALUE_TYPE_ID_NULL) {
+ mono_nullable_init (addr, NULL, mono_class_from_mono_type (t));
+ *endbuf = buf;
+ return ERR_NONE;
+ }
+ }
+
+ return decode_value_internal (t, type, domain, addr, buf, endbuf, limit);
+}
+
static void
add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
{
g_assert_not_reached ();
}
+ if (t->byref)
+ NOT_IMPLEMENTED;
+
/* Set value on the stack or in the return ctx */
if (reg_locations [reg]) {
/* Saved on the stack */
//printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
+ if (t->byref) {
+ addr = *(guint8**)addr;
+
+ if (!addr)
+ break;
+ }
+
// FIXME: Write barriers
- memcpy (addr, val, size);
+ mono_gc_memmove (addr, val, size);
break;
case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
NOT_IMPLEMENTED;
}
static ErrorCode
-do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
+do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp)
{
- guint8 *p = invoke->p;
guint8 *end = invoke->endp;
MonoMethod *m;
int i, err, nargs;
}
}
- if (this && !mono_class_is_assignable_from (m->klass, this->vtable->klass))
+ if (this && !obj_is_of_type (this, &m->klass->byval_arg))
return ERR_INVALID_ARGUMENT;
nargs = decode_int (p, &p, end);
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) {
+ } else if (mono_class_from_mono_type (sig->ret)->valuetype || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) {
if (mono_class_is_nullable (mono_class_from_mono_type (sig->ret))) {
- if (!res)
- buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &res, domain);
- else
- buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
+ MonoClass *k = mono_class_from_mono_type (sig->ret);
+ guint8 *nullable_buf = g_alloca (mono_class_value_size (k, NULL));
+
+ g_assert (nullable_buf);
+ mono_nullable_init (nullable_buf, res, k);
+ buffer_add_value (buf, sig->ret, nullable_buf, domain);
} else {
g_assert (res);
buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
mono_set_lmf ((gpointer)(((gssize)ext.lmf.previous_lmf) & ~3));
#endif
+ *endp = p;
// FIXME: byref arguments
// FIXME: varargs
return ERR_NONE;
DebuggerTlsData *tls;
InvokeData *invoke;
int id;
- int err;
+ int i, err, mindex;
Buffer buf;
static void (*restore_context) (void *);
MonoContext restore_ctx;
+ guint8 *p;
if (!restore_context)
restore_context = mono_get_restore_context ();
id = invoke->id;
- buffer_init (&buf, 128);
+ p = invoke->p;
+ err = 0;
+ for (mindex = 0; mindex < invoke->nmethods; ++mindex) {
+ buffer_init (&buf, 128);
- err = do_invoke_method (tls, &buf, invoke);
+ if (err) {
+ /* Fail the other invokes as well */
+ } else {
+ err = do_invoke_method (tls, &buf, invoke, p, &p);
+ }
- /* Start suspending before sending the reply */
- if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED))
- suspend_vm ();
+ /* Start suspending before sending the reply */
+ if (mindex == invoke->nmethods - 1) {
+ if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) {
+ for (i = 0; i < invoke->suspend_count; ++i)
+ suspend_vm ();
+ }
+ }
- send_reply_packet (id, err, &buf);
+ send_reply_packet (id, err, &buf);
- buffer_free (&buf);
+ buffer_free (&buf);
+ }
memcpy (&restore_ctx, &invoke->ctx, sizeof (MonoContext));
GPtrArray *source_file_list;
if (minfo) {
- mono_debug_symfile_get_line_numbers_full (minfo, NULL, &source_file_list, NULL, NULL, NULL, NULL);
+ mono_debug_symfile_get_line_numbers_full (minfo, NULL, &source_file_list, NULL, NULL, NULL, NULL, NULL);
for (j = 0; j < source_file_list->len; ++j) {
sinfo = g_ptr_array_index (source_file_list, j);
for (i = 0; i < files->len; ++i)
tls->pending_invoke = g_new0 (InvokeData, 1);
tls->pending_invoke->method = exit_method;
tls->pending_invoke->args = args;
+ tls->pending_invoke->nmethods = 1;
while (suspend_count > 0)
resume_vm ();
}
break;
}
- case CMD_VM_INVOKE_METHOD: {
+ case CMD_VM_INVOKE_METHOD:
+ case CMD_VM_INVOKE_METHODS: {
int objid = decode_objid (p, &p, end);
MonoThread *thread;
DebuggerTlsData *tls;
- int err, flags;
+ int i, count, err, flags, nmethods;
err = get_object (objid, (MonoObject**)&thread);
if (err)
flags = decode_int (p, &p, end);
+ if (command == CMD_VM_INVOKE_METHODS)
+ nmethods = decode_int (p, &p, end);
+ else
+ nmethods = 1;
+
// Wait for suspending if it already started
if (suspend_count)
wait_for_suspend ();
* resumed.
*/
if (tls->pending_invoke)
- NOT_IMPLEMENTED;
+ return ERR_NOT_SUSPENDED;
tls->pending_invoke = g_new0 (InvokeData, 1);
tls->pending_invoke->id = id;
tls->pending_invoke->flags = flags;
memcpy (tls->pending_invoke->p, p, end - p);
tls->pending_invoke->endp = tls->pending_invoke->p + (end - p);
tls->pending_invoke->suspend_count = suspend_count;
+ tls->pending_invoke->nmethods = nmethods;
- if (flags & INVOKE_FLAG_SINGLE_THREADED)
+ if (flags & INVOKE_FLAG_SINGLE_THREADED) {
resume_thread (THREAD_TO_INTERNAL (thread));
- else
- resume_vm ();
+ }
+ else {
+ count = suspend_count;
+ for (i = 0; i < count; ++i)
+ resume_vm ();
+ }
break;
}
case CMD_VM_ABORT_INVOKE: {
break;
}
case CMD_ASSEMBLY_GET_OBJECT: {
- MonoObject *o = (MonoObject*)mono_assembly_get_object (mono_domain_get (), ass);
+ MonoObject *o = (MonoObject*)mono_assembly_get_object (domain, ass);
buffer_add_objid (buf, o);
break;
}
break;
}
case CMD_TYPE_GET_OBJECT: {
- MonoObject *o = (MonoObject*)mono_type_get_object (mono_domain_get (), &klass->byval_arg);
+ MonoObject *o = (MonoObject*)mono_type_get_object (domain, &klass->byval_arg);
buffer_add_objid (buf, o);
break;
}
method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf)
{
MonoMethodHeader *header;
+ int err;
switch (command) {
case CMD_METHOD_GET_NAME: {
int i, j, n_il_offsets;
int *il_offsets;
int *line_numbers;
+ int *column_numbers;
int *source_files;
GPtrArray *source_file_list;
break;
}
- mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, &n_il_offsets, &il_offsets, &line_numbers, &source_files);
+ mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, &n_il_offsets, &il_offsets, &line_numbers, &column_numbers, &source_files);
buffer_add_int (buf, header->code_size);
if (CHECK_PROTOCOL_VERSION (2, 13)) {
buffer_add_int (buf, source_file_list->len);
buffer_add_string (buf, source_file);
}
buffer_add_int (buf, n_il_offsets);
- DEBUG (10, printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE)));
+ DEBUG (10, fprintf (log_file, "Line number table for method %s:\n", mono_method_full_name (method, TRUE)));
for (i = 0; i < n_il_offsets; ++i) {
const char *srcfile = "";
MonoDebugSourceInfo *sinfo = g_ptr_array_index (source_file_list, source_files [i]);
srcfile = sinfo->source_file;
}
- DEBUG (10, printf ("IL%x -> %s:%d\n", il_offsets [i], srcfile, line_numbers [i]));
+ DEBUG (10, fprintf (log_file, "IL%x -> %s:%d %d\n", il_offsets [i], srcfile, line_numbers [i], column_numbers ? column_numbers [i] : -1));
buffer_add_int (buf, il_offsets [i]);
buffer_add_int (buf, line_numbers [i]);
if (CHECK_PROTOCOL_VERSION (2, 13))
buffer_add_int (buf, source_files [i]);
+ if (CHECK_PROTOCOL_VERSION (2, 19))
+ buffer_add_int (buf, column_numbers ? column_numbers [i] : -1);
}
g_free (source_file);
g_free (il_offsets);
header = mono_method_get_header (method);
if (!header) {
buffer_add_int (buf, 0);
+
+ if (CHECK_PROTOCOL_VERSION (2, 18))
+ buffer_add_int (buf, 0);
} else {
buffer_add_int (buf, header->code_size);
for (i = 0; i < header->code_size; ++i)
buffer_add_byte (buf, header->code [i]);
+
+ if (CHECK_PROTOCOL_VERSION (2, 18)) {
+ buffer_add_int (buf, header->num_clauses);
+ for (i = 0; i < header->num_clauses; ++i) {
+ MonoExceptionClause *clause = &header->clauses [i];
+
+ buffer_add_int (buf, clause->flags);
+ buffer_add_int (buf, clause->try_offset);
+ buffer_add_int (buf, clause->try_len);
+ buffer_add_int (buf, clause->handler_offset);
+ buffer_add_int (buf, clause->handler_len);
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
+ buffer_add_typeid (buf, domain, clause->data.catch_class);
+ else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+ buffer_add_int (buf, clause->data.filter_offset);
+ }
+ }
+
+ mono_metadata_free_mh (header);
}
- mono_metadata_free_mh (header);
+
break;
}
case CMD_METHOD_RESOLVE_TOKEN: {
}
break;
}
+ case CMD_METHOD_GET_CATTRS: {
+ MonoClass *attr_klass;
+ MonoCustomAttrInfo *cinfo;
+
+ attr_klass = decode_typeid (p, &p, end, NULL, &err);
+ /* attr_klass can be NULL */
+ if (err)
+ return err;
+
+ cinfo = mono_custom_attrs_from_method (method);
+
+ buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo);
+ break;
+ }
default:
return ERR_NOT_IMPLEMENTED;
}
return ERR_INVALID_FRAMEID;
if (!frame->jit) {
- frame->jit = mono_debug_find_method (frame->method, frame->domain);
- if (!frame->jit && frame->method->is_inflated)
- frame->jit = mono_debug_find_method (mono_method_get_declaring_generic_method (frame->method), frame->domain);
+ frame->jit = mono_debug_find_method (frame->api_method, frame->domain);
+ if (!frame->jit && frame->api_method->is_inflated)
+ frame->jit = mono_debug_find_method (mono_method_get_declaring_generic_method (frame->api_method), frame->domain);
if (!frame->jit) {
char *s;
/* This could happen for aot images with no jit debug info */
- s = mono_method_full_name (frame->method, TRUE);
+ s = mono_method_full_name (frame->api_method, TRUE);
DEBUG (1, fprintf (log_file, "[dbg] No debug information found for '%s'.\n", s));
g_free (s);
return ERR_ABSENT_INFORMATION;
break;
}
case CMD_STACK_FRAME_GET_THIS: {
- if (frame->method->klass->valuetype) {
+ if (frame->api_method->klass->valuetype) {
if (!sig->hasthis) {
MonoObject *p = NULL;
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
MonoObject *p = NULL;
buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain);
} else {
- add_var (buf, &frame->method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+ add_var (buf, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
}
}
break;
switch (command) {
case CMD_OBJECT_REF_GET_TYPE:
- buffer_add_typeid (buf, obj->vtable->domain, obj->vtable->klass);
+ /* This handles transparent proxies too */
+ buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type (((MonoReflectionType*)obj->vtable->type)->type));
break;
case CMD_OBJECT_REF_GET_VALUES:
len = decode_int (p, &p, end);
buffer_add_domainid (buf, obj->vtable->domain);
break;
case CMD_OBJECT_REF_GET_INFO:
- buffer_add_typeid (buf, obj->vtable->domain, obj->vtable->klass);
+ buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type (((MonoReflectionType*)obj->vtable->type)->type));
buffer_add_domainid (buf, obj->vtable->domain);
break;
default:
return "SET_PROTOCOL_VERSION";
case CMD_VM_ABORT_INVOKE:
return "ABORT_INVOKE";
+ case CMD_VM_SET_KEEPALIVE:
+ return "SET_KEEPALIVE";
default:
break;
}