#ifdef HOST_WIN32
#ifdef _MSC_VER
#include <winsock2.h>
+#include <process.h>
#endif
#include <ws2tcpip.h>
#ifdef __GNUC__
#include <mono/utils/mono-threads.h>
#include "debugger-agent.h"
#include "mini.h"
+#include "seq-points.h"
/*
On iOS we can't use System.Environment.Exit () as it will do the wrong
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 34
+#define MINOR_VERSION 38
typedef enum {
CMD_SET_VM = 1,
typedef enum {
INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
- INVOKE_FLAG_SINGLE_THREADED = 2
+ INVOKE_FLAG_SINGLE_THREADED = 2,
+ INVOKE_FLAG_RETURN_OUT_THIS = 4,
+ INVOKE_FLAG_RETURN_OUT_ARGS = 8,
+ INVOKE_FLAG_VIRTUAL = 16
} InvokeFlags;
typedef enum {
typedef enum {
CMD_STACK_FRAME_GET_VALUES = 1,
CMD_STACK_FRAME_GET_THIS = 2,
- CMD_STACK_FRAME_SET_VALUES = 3
+ CMD_STACK_FRAME_SET_VALUES = 3,
+ CMD_STACK_FRAME_GET_DOMAIN = 4,
} CmdStackFrame;
typedef enum {
static FILE *log_file;
/* Assemblies whose assembly load event has no been sent yet */
+/* Protected by the dbg lock */
static GPtrArray *pending_assembly_loads;
/* Whenever the debugger thread has exited */
static DebuggerProfiler debugger_profiler;
/* The single step request instance */
-static SingleStepReq *ss_req = NULL;
-static gpointer ss_invoke_addr = NULL;
+static SingleStepReq *ss_req;
+static gpointer ss_invoke_addr;
#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
/* Number of single stepping operations in progress */
static ReplyPacket reply_packets [128];
int nreply_packets;
+#define dbg_lock() mono_mutex_lock (&debug_mutex)
+#define dbg_unlock() mono_mutex_unlock (&debug_mutex)
+static mono_mutex_t debug_mutex;
+
static void transport_init (void);
static void transport_connect (const char *address);
static gboolean transport_handshake (void);
register_socket_transport (void);
#endif
+static inline gboolean
+is_debugger_thread (void)
+{
+ return GetCurrentThreadId () == debugger_thread_id;
+}
+
static int
parse_address (char *address, char **host, int *port)
{
void
mono_debugger_agent_init (void)
{
+ mono_mutex_init_recursive (&debug_mutex);
+
if (!agent_config.enabled)
return;
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);
breakpoints_init ();
suspend_init ();
- mini_get_debug_options ()->gen_seq_points = TRUE;
+ mini_get_debug_options ()->gen_seq_points_debug_data = TRUE;
/*
* This is needed because currently we don't handle liveness info.
*/
register_transport (&trans);
}
+/*
+ * socket_fd_transport_connect:
+ *
+ */
+static void
+socket_fd_transport_connect (const char *address)
+{
+ int res;
+
+ res = sscanf (address, "%d", &conn_fd);
+ if (res != 1) {
+ fprintf (stderr, "debugger-agent: socket-fd transport address is invalid: '%s'\n", address);
+ exit (1);
+ }
+
+ if (!transport_handshake ())
+ exit (1);
+}
+
+static void
+register_socket_fd_transport (void)
+{
+ DebuggerTransport trans;
+
+ /* This is the same as the 'dt_socket' transport, but receives an already connected socket fd */
+ trans.name = "socket-fd";
+ trans.connect = socket_fd_transport_connect;
+ trans.close1 = socket_transport_close1;
+ trans.close2 = socket_transport_close2;
+ trans.send = socket_transport_send;
+ trans.recv = socket_transport_recv;
+
+ register_transport (&trans);
+}
+
#endif /* DISABLE_SOCKET_TRANSPORT */
/*
#ifndef DISABLE_SOCKET_TRANSPORT
register_socket_transport ();
+ register_socket_fd_transport ();
#endif
for (i = 0; i < ntransports; ++i) {
/* Read answer */
res = transport_recv (buf, strlen (handshake_msg));
- if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg) != 0))) {
+ if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
return FALSE;
}
/* Maps objid -> ObjRef */
static GHashTable *objrefs;
+static GHashTable *obj_to_objref;
+/* Protected by the dbg lock */
+static MonoGHashTable *suspended_objs;
static void
free_objref (gpointer value)
objrefs_init (void)
{
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);
}
static void
objrefs = NULL;
}
-static GHashTable *obj_to_objref;
-static MonoGHashTable *suspended_objs;
-
/*
* Return an ObjRef for OBJ.
*/
if (obj == NULL)
return 0;
- mono_loader_lock ();
-
- if (!obj_to_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);
- }
-
if (suspend_count) {
/*
* Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
*/
+ dbg_lock ();
mono_g_hash_table_insert (suspended_objs, obj, NULL);
+ dbg_unlock ();
}
+
+ mono_loader_lock ();
/* FIXME: The tables can grow indefinitely */
static void
clear_suspended_objs (void)
{
- mono_loader_lock ();
+ dbg_lock ();
mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL);
- mono_loader_unlock ();
+ dbg_unlock ();
}
static inline int
} AgentDomainInfo;
/* Maps id -> Id */
+/* Protected by the dbg lock */
static GPtrArray *ids [ID_NUM];
static void
domain_jit_info (domain)->agent_info = NULL;
/* Clear ids referencing structures in the domain */
+ dbg_lock ();
for (i = 0; i < ID_NUM; ++i) {
if (ids [i]) {
for (j = 0; j < ids [i]->len; ++j) {
}
}
}
+ dbg_unlock ();
mono_loader_lock ();
g_hash_table_remove (domains, domain);
return id->id;
}
+ dbg_lock ();
+
id = g_new0 (Id, 1);
/* Reserve id 0 */
id->id = ids [type]->len + 1;
id->data.val = val;
g_hash_table_insert (info->val_to_id [type], val, id);
+ g_ptr_array_add (ids [type], id);
- mono_domain_unlock (domain);
+ dbg_unlock ();
- g_ptr_array_add (ids [type], id);
+ mono_domain_unlock (domain);
mono_loader_unlock ();
return NULL;
// FIXME: error handling
- mono_loader_lock ();
+ dbg_lock ();
g_assert (id > 0 && id <= ids [type]->len);
res = g_ptr_array_index (ids [type], GPOINTER_TO_INT (id - 1));
- mono_loader_unlock ();
+ dbg_unlock ();
if (res->domain == NULL) {
DEBUG (0, fprintf (log_file, "ERR_UNLOADED, id=%d, type=%d.\n", id, type));
*/
data.last_frame_set = FALSE;
if (sigctx) {
- mono_arch_sigctx_to_monoctx (sigctx, &ctx);
+ mono_sigctx_to_monoctx (sigctx, &ctx);
/*
* Don't pass MONO_UNWIND_ACTUAL_METHOD, its not signal safe, and
* get_last_frame () doesn't need it, the last frame cannot be a ginst
MonoInternalThread *thread = key;
DebuggerTlsData *tls = value;
gsize tid = thread->tid;
+#ifndef HOST_WIN32
int res;
+#endif
if (GetCurrentThreadId () == tid || tls->terminated)
return;
#endif
/* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
-#ifdef HOST_WIN32
- QueueUserAPC (notify_thread_apc, thread->handle, NULL);
-#else
if (mono_thread_info_new_interrupt_enabled ()) {
MonoThreadInfo *info;
MonoJitInfo *ji;
mono_thread_info_finish_suspend_and_resume (info);
}
} else {
+#ifdef HOST_WIN32
+ // FIXME: Remove this since new interrupt is used on win32 now
+ QueueUserAPC (notify_thread_apc, thread->handle, (ULONG_PTR)NULL);
+#else
res = mono_thread_kill (thread, mono_thread_get_abort_signal ());
if (res) {
DEBUG(1, fprintf (log_file, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid, res));
*/
tls->terminated = TRUE;
}
- }
#endif
+ }
}
static void
static void
suspend_current (void)
{
+#ifndef HOST_WIN32
int err;
+#endif
DebuggerTlsData *tls;
g_assert (debugger_thread_id != GetCurrentThreadId ());
return count_threads_to_wait_for () == 0;
}
-static MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
-{
- MonoSeqPointInfo *seq_points;
-
- mono_domain_lock (domain);
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
- if (!seq_points && method->is_inflated) {
- /* generic sharing + aot */
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
- if (!seq_points)
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
- }
- mono_domain_unlock (domain);
-
- return seq_points;
-}
-
static void
no_seq_points_found (MonoMethod *method)
{
printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
}
-/*
- * find_next_seq_point_for_native_offset:
- *
- * Find the first sequence point after NATIVE_OFFSET.
- */
-static SeqPoint*
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- 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;
-
- for (i = 0; i < seq_points->len; ++i) {
- if (seq_points->seq_points [i].native_offset >= native_offset)
- return &seq_points->seq_points [i];
- }
-
- return NULL;
-}
-
-/*
- * find_prev_seq_point_for_native_offset:
- *
- * Find the first sequence point before NATIVE_OFFSET.
- */
-static SeqPoint*
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- 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)
- return &seq_points->seq_points [i];
- }
-
- return NULL;
-}
-
-/*
- * find_seq_point:
- *
- * Find the sequence point corresponding to the IL offset IL_OFFSET, which
- * should be the location of a sequence point.
- */
-static G_GNUC_UNUSED SeqPoint*
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- *info = NULL;
-
- seq_points = get_seq_points (domain, method);
- if (!seq_points)
- return NULL;
- *info = seq_points;
-
- for (i = 0; i < seq_points->len; ++i) {
- if (seq_points->seq_points [i].il_offset == il_offset)
- return &seq_points->seq_points [i];
- }
-
- return NULL;
-}
-
typedef struct {
DebuggerTlsData *tls;
GSList *frames;
ComputeFramesUserData *ud = user_data;
StackFrame *frame;
MonoMethod *method, *actual_method, *api_method;
- SeqPoint *sp;
+ SeqPoint sp;
int flags = 0;
if (info->type != FRAME_TYPE_MANAGED) {
if (info->il_offset == -1) {
/* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
if (ud->frames == NULL) {
- sp = find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL);
- if (sp)
- info->il_offset = sp->il_offset;
+ if (find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL, &sp))
+ info->il_offset = sp.il_offset;
}
if (info->il_offset == -1)
info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
{
DebuggerTlsData *tls;
+ /* This might be called during shutdown on the debugger thread from the CMD_VM_EXIT code */
+ if (is_debugger_thread ())
+ return;
+
/*
* Remember the currently unloading appdomain as it is needed to generate
* proper ids for unloading assemblies.
{
DebuggerTlsData *tls;
+ if (is_debugger_thread ())
+ return;
+
tls = mono_native_tls_get_value (debugger_tls_id);
g_assert (tls);
tls->domain_unloading = NULL;
assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result)
{
/* Sent later in jit_end () */
- mono_loader_lock ();
+ dbg_lock ();
g_ptr_array_add (pending_assembly_loads, assembly);
- mono_loader_unlock ();
+ dbg_unlock ();
}
static void
MonoAssembly *assembly = NULL;
// FIXME: Maybe store this in TLS so the thread of the event is correct ?
- mono_loader_lock ();
+ dbg_lock ();
if (pending_assembly_loads->len > 0) {
assembly = g_ptr_array_index (pending_assembly_loads, 0);
g_ptr_array_remove_index (pending_assembly_loads, 0);
}
- mono_loader_unlock ();
+ dbg_unlock ();
if (assembly) {
process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly);
guint8 *ip;
MonoJitInfo *ji;
MonoDomain *domain;
- SeqPoint *sp;
} BreakpointInstance;
/*
static void
insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo *ji, MonoBreakpoint *bp, MonoError *error)
{
- int i, count;
+ int count;
BreakpointInstance *inst;
- SeqPoint *sp = NULL;
+ SeqPointIterator it;
+ gboolean it_has_sp = FALSE;
if (error)
mono_error_init (error);
- for (i = 0; i < seq_points->len; ++i) {
- sp = &seq_points->seq_points [i];
-
- if (sp->il_offset == bp->il_offset)
+ seq_point_iterator_init (&it, seq_points);
+ while (seq_point_iterator_next (&it)) {
+ if (it.seq_point.il_offset == bp->il_offset) {
+ it_has_sp = TRUE;
break;
+ }
}
- if (i == seq_points->len) {
+ if (!it_has_sp) {
/*
* The set of IL offsets with seq points doesn't completely match the
* info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
*/
- for (i = 0; i < seq_points->len; ++i) {
- sp = &seq_points->seq_points [i];
-
- if (sp->il_offset != METHOD_ENTRY_IL_OFFSET && sp->il_offset != METHOD_EXIT_IL_OFFSET && sp->il_offset + 1 == bp->il_offset)
+ seq_point_iterator_init (&it, seq_points);
+ while (seq_point_iterator_next (&it)) {
+ if (it.seq_point.il_offset != METHOD_ENTRY_IL_OFFSET &&
+ it.seq_point.il_offset != METHOD_EXIT_IL_OFFSET &&
+ it.seq_point.il_offset + 1 == bp->il_offset) {
+ it_has_sp = TRUE;
break;
+ }
}
}
- if (i == seq_points->len) {
- char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset, seq_points->len);
+ if (!it_has_sp) {
+ char *s = g_strdup_printf ("Unable to insert breakpoint at %s:%d", mono_method_full_name (jinfo_get_method (ji), TRUE), bp->il_offset);
- for (i = 0; i < seq_points->len; ++i)
- DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
+ seq_point_iterator_init (&it, seq_points);
+ while (seq_point_iterator_next (&it))
+ DEBUG (1, fprintf (log_file, "%d\n", it.seq_point.il_offset));
if (error) {
mono_error_set_error (error, MONO_ERROR_GENERIC, "%s", s);
}
inst = g_new0 (BreakpointInstance, 1);
- inst->sp = sp;
- inst->native_offset = sp->native_offset;
- inst->ip = (guint8*)ji->code_start + sp->native_offset;
+ inst->il_offset = it.seq_point.il_offset;
+ inst->native_offset = it.seq_point.native_offset;
+ inst->ip = (guint8*)ji->code_start + it.seq_point.native_offset;
inst->ji = ji;
inst->domain = domain;
g_ptr_array_add (bp->children, inst);
+ mono_loader_unlock ();
+
+ dbg_lock ();
count = GPOINTER_TO_INT (g_hash_table_lookup (bp_locs, inst->ip));
g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
- mono_loader_unlock ();
+ dbg_unlock ();
- if (sp->native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
+ if (it.seq_point.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
#endif
}
- DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)sp->il_offset, inst->ip, count));
+ DEBUG(1, fprintf (log_file, "[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));
}
static void
MonoJitInfo *ji = inst->ji;
guint8 *ip = inst->ip;
- mono_loader_lock ();
+ dbg_lock ();
count = GPOINTER_TO_INT (g_hash_table_lookup (bp_locs, ip));
g_hash_table_insert (bp_locs, ip, GINT_TO_POINTER (count - 1));
- mono_loader_unlock ();
+ dbg_unlock ();
g_assert (count > 0);
MonoContext *ctx = &tls->restore_ctx;
MonoMethod *method;
MonoSeqPointInfo *info;
- SeqPoint *sp;
+ SeqPoint sp;
+ gboolean found_sp;
// FIXME: Speed this up
* The ip points to the instruction causing the breakpoint event, which is after
* 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 (), method, native_offset, &info);
- if (!sp)
+ found_sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info, &sp);
+
+ if (!found_sp)
no_seq_points_found (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 (), method->name, ip, native_offset, sp ? sp->il_offset : -1));
+ g_assert (found_sp);
+
+ DEBUG(1, fprintf (log_file, "[%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));
bp = NULL;
for (i = 0; i < breakpoints->len; ++i) {
for (j = 0; j < bp->children->len; ++j) {
inst = g_ptr_array_index (bp->children, j);
- if (inst->ji == ji && inst->sp == sp) {
+ if (inst->ji == ji && inst->il_offset == sp.il_offset && inst->native_offset == sp.native_offset) {
if (bp->req->event_kind == EVENT_KIND_STEP) {
g_ptr_array_add (ss_reqs_orig, bp->req);
} else {
}
if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
/* Maybe a method entry/exit event */
- if (sp->il_offset == METHOD_ENTRY_IL_OFFSET)
+ if (sp.il_offset == METHOD_ENTRY_IL_OFFSET)
kind = EVENT_KIND_METHOD_ENTRY;
- else if (sp->il_offset == METHOD_EXIT_IL_OFFSET)
+ else if (sp.il_offset == METHOD_EXIT_IL_OFFSET)
kind = EVENT_KIND_METHOD_EXIT;
}
if (mono_thread_internal_current () != ss_req->thread)
continue;
- hit = ss_update (ss_req, ji, sp, tls, ctx);
+ hit = ss_update (ss_req, ji, &sp, tls, ctx);
if (hit)
g_ptr_array_add (ss_reqs, req);
/* Start single stepping again from the current sequence point */
- ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+ ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
}
if (ss_reqs->len > 0)
// clobbered by a single step/breakpoint event. If this turns out to be a problem,
// clob:c could be added to op_seq_point.
- mono_arch_sigctx_to_monoctx (sigctx, &ctx);
+ mono_sigctx_to_monoctx (sigctx, &ctx);
memcpy (&tls->handler_ctx, &ctx, sizeof (MonoContext));
#ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
mono_arch_setup_resume_sighandler_ctx (&ctx, func);
#else
MONO_CONTEXT_SET_IP (&ctx, func);
#endif
- mono_arch_monoctx_to_sigctx (&ctx, sigctx);
+ mono_monoctx_to_sigctx (&ctx, sigctx);
#ifdef PPC_USES_FUNCTION_DESCRIPTOR
mono_ppc_set_func_into_sigctx (sigctx, func);
GSList *events;
MonoContext *ctx = &tls->restore_ctx;
MonoMethod *method;
- SeqPoint *sp;
+ SeqPoint sp;
MonoSeqPointInfo *info;
ip = MONO_CONTEXT_GET_IP (ctx);
* The ip points to the instruction causing the single step event, which is before
* the offset recorded in the seq point map, so find the next seq point after ip.
*/
- sp = find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info);
- if (!sp)
+ if (!find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
return;
- il_offset = sp->il_offset;
- if (!ss_update (ss_req, ji, sp, tls, ctx))
+ il_offset = sp.il_offset;
+
+ if (!ss_update (ss_req, ji, &sp, tls, ctx))
return;
/* Start single stepping again from the current sequence point */
- ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
+ ss_start (ss_req, method, &sp, info, ctx, tls, FALSE);
if ((ss_req->filter & STEP_FILTER_STATIC_CTOR) &&
(method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
*/
MonoContext ctx;
- mono_arch_sigctx_to_monoctx (sigctx, &ctx);
+ mono_sigctx_to_monoctx (sigctx, &ctx);
mono_arch_skip_single_step (&ctx);
- mono_arch_monoctx_to_sigctx (&ctx, sigctx);
+ mono_monoctx_to_sigctx (&ctx, sigctx);
return;
}
* belong to the same thread as CTX.
*/
static void
-ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint* sp, MonoSeqPointInfo *info, MonoContext *ctx, DebuggerTlsData *tls, gboolean step_to_catch)
{
int i, j, frame_index;
SeqPoint *next_sp;
+ SeqPoint local_sp;
+ gboolean found_sp;
MonoBreakpoint *bp;
gboolean enable_global = FALSE;
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);
+ found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+ sp = (found_sp)? &local_sp : NULL;
frame_index ++;
if (sp && sp->next_len != 0)
break;
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);
+ found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+ sp = (found_sp)? &local_sp : NULL;
if (sp && sp->next_len != 0)
break;
sp = NULL;
}
if (sp && sp->next_len > 0) {
- for (i = 0; i < sp->next_len; ++i) {
- next_sp = &info->seq_points [sp->next [i]];
+ SeqPoint* next = g_new(SeqPoint, sp->next_len);
+
+ seq_point_init_next (info, *sp, next);
+ for (i = 0; i < sp->next_len; i++) {
+ next_sp = &next[i];
bp = set_breakpoint (method, next_sp->il_offset, ss_req->req, NULL);
ss_req->bps = g_slist_append (ss_req->bps, bp);
}
+ g_free (next);
}
if (ss_req->depth == STEP_DEPTH_OVER) {
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);
+ found_sp = find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL, &local_sp);
+ sp = (found_sp)? &local_sp : 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);
DebuggerTlsData *tls;
MonoSeqPointInfo *info = NULL;
SeqPoint *sp = NULL;
+ SeqPoint local_sp;
+ gboolean found_sp;
MonoMethod *method = NULL;
MonoDebugMethodInfo *minfo;
gboolean step_to_catch = FALSE;
* Find the seq point corresponding to the landing site ip, which is the first seq
* point after ip.
*/
- sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info);
+ found_sp = find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &local_sp);
+ sp = (found_sp)? &local_sp : NULL;
if (!sp)
no_seq_points_found (frame.method);
g_assert (sp);
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);
+ found_sp = find_prev_seq_point_for_native_offset (frame->domain, frame->method, frame->native_offset, &info, &local_sp);
+ sp = (found_sp)? &local_sp : NULL;
if (!sp)
no_seq_points_found (frame->method);
g_assert (sp);
return ERR_INVALID_ARGUMENT;
}
m = mono_object_get_virtual_method (this, m);
+ } else if (invoke->flags & INVOKE_FLAG_VIRTUAL) {
+ if (!this) {
+ DEBUG (1, fprintf (log_file, "[%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);
}
DEBUG (1, fprintf (log_file, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "<null>"));
err = decode_value (sig->params [i], domain, (guint8*)&args [i], p, &p, end);
if (err)
break;
-
if (args [i] && ((MonoObject*)args [i])->vtable->domain != domain)
NOT_IMPLEMENTED;
+
+ if (sig->params [i]->byref) {
+ arg_buf [i] = g_alloca (sizeof (mgreg_t));
+ *(gpointer*)arg_buf [i] = args [i];
+ args [i] = arg_buf [i];
+ }
} else {
arg_buf [i] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig->params [i])));
err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end);
/*
* 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_SOFT_DEBUG_SUPPORTED
if (invoke->has_ctx) {
MonoLMF **lmf_addr;
buffer_add_byte (buf, 0);
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &exc, domain);
} else {
- buffer_add_byte (buf, 1);
+ gboolean out_this = FALSE;
+ gboolean out_args = FALSE;
+
+ if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_THIS) && CHECK_PROTOCOL_VERSION (2, 35))
+ out_this = TRUE;
+ if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_ARGS) && CHECK_PROTOCOL_VERSION (2, 35))
+ 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 {
NOT_IMPLEMENTED;
}
+ if (out_this)
+ /* Return the new value of the receiver after the call */
+ buffer_add_value (buf, &m->klass->byval_arg, this_buf, domain);
+ if (out_args) {
+ buffer_add_int (buf, nargs);
+ for (i = 0; i < nargs; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (sig->params [i]))
+ buffer_add_value (buf, sig->params [i], &args [i], domain);
+ else if (sig->params [i]->byref)
+ /* add_value () does an indirection */
+ buffer_add_value (buf, sig->params [i], &arg_buf [i], domain);
+ else
+ buffer_add_value (buf, sig->params [i], arg_buf [i], domain);
+ }
+ }
}
tls->disable_breakpoints = FALSE;
buffer_add_value (buf, t, mono_object_unbox (val), domain);
}
-static void
+static int
buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass *attr_klass, MonoCustomAttrInfo *cinfo)
{
int i, j;
if (!cinfo) {
buffer_add_int (buf, 0);
- return;
+ return ERR_NONE;
}
for (i = 0; i < cinfo->num_attrs; ++i) {
MonoError error;
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));
+ if (!mono_error_ok (&error)) {
+ DEBUG(2, fprintf (log_file, "[dbg] mono_reflection_create_custom_attr_data_args () failed with: '%s'\n", mono_error_get_message (&error)));
+ mono_error_cleanup (&error);
+ return ERR_LOADER_ERROR;
+ }
buffer_add_methodid (buf, domain, attr->ctor);
g_free (arginfo);
}
}
+
+ return ERR_NONE;
}
/* FIXME: Code duplication with icall.c */
cinfo = mono_custom_attrs_from_class (klass);
- buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ err = buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ if (err)
+ return err;
break;
}
case CMD_TYPE_GET_FIELD_CATTRS: {
cinfo = mono_custom_attrs_from_field (klass, field);
- buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ err = buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ if (err)
+ return err;
break;
}
case CMD_TYPE_GET_PROPERTY_CATTRS: {
cinfo = mono_custom_attrs_from_property (klass, prop);
- buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ err = buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
+ if (err)
+ return err;
break;
}
case CMD_TYPE_GET_VALUES:
cinfo = mono_custom_attrs_from_method (method);
- buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo);
+ err = buffer_add_cattrs (buf, domain, method->klass->image, attr_klass, cinfo);
+ if (err)
+ return err;
break;
}
case CMD_METHOD_MAKE_GENERIC_METHOD: {
MonoMethod *method;
MonoDomain *domain;
MonoSeqPointInfo *seq_points;
- SeqPoint *sp = NULL;
+ SeqPoint sp;
+ gboolean found_sp;
gint64 il_offset;
- int i;
method = decode_methodid (p, &p, end, &domain, &err);
if (err)
if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
return ERR_INVALID_ARGUMENT;
- seq_points = get_seq_points (domain, method);
- g_assert (seq_points);
+ found_sp = find_seq_point (domain, method, il_offset, &seq_points, &sp);
- for (i = 0; i < seq_points->len; ++i) {
- sp = &seq_points->seq_points [i];
+ g_assert (seq_points);
- if (sp->il_offset == il_offset)
- break;
- }
- if (i == seq_points->len)
+ if (!found_sp)
return ERR_INVALID_ARGUMENT;
// FIXME: Check that the ip change is safe
- DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp->il_offset, (int)sp->native_offset));
- MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp->native_offset);
+ DEBUG (1, fprintf (log_file, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset));
+ MONO_CONTEXT_SET_IP (&tls->restore_ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
break;
}
default:
mono_metadata_free_mh (header);
break;
}
+ case CMD_STACK_FRAME_GET_DOMAIN: {
+ if (CHECK_PROTOCOL_VERSION (2, 38))
+ buffer_add_domainid (buf, frame->domain);
+ break;
+ }
default:
return ERR_NOT_IMPLEMENTED;
}
static const char* stack_frame_cmds_str[] = {
"GET_VALUES",
"GET_THIS",
- "SET_VALUES"
+ "SET_VALUES",
+ "GET_DOMAIN",
};
static const char* array_cmds_str[] = {
return FALSE;
}
-#endif
+void
+mono_debugger_agent_unhandled_exception (MonoException *exc)
+{
+ g_assert_not_reached ();
+}
+#endif