#include <mono/metadata/mono-debug-debugger.h>
#include <mono/metadata/debug-mono-symfile.h>
#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/environment.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/socket-io.h>
#include <mono/metadata/assembly.h>
gboolean embedding;
gboolean defer;
int keepalive;
+ gboolean setpgid;
} AgentConfig;
typedef struct
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 24
+#define MINOR_VERSION 27
typedef enum {
CMD_SET_VM = 1,
typedef enum {
STEP_FILTER_NONE = 0,
STEP_FILTER_STATIC_CTOR = 1,
- STEP_FILTER_DEBUGGER_HIDDEN = 2
+ STEP_FILTER_DEBUGGER_HIDDEN = 2,
+ STEP_FILTER_DEBUGGER_STEP_THROUGH = 4
} StepFilter;
typedef enum {
GHashTable *type_names; /* For kind == MONO_KIND_TYPE_NAME_ONLY */
StepFilter filter; /* For kind == MOD_KIND_STEP */
} data;
- gboolean caught, uncaught; /* For kind == MOD_KIND_EXCEPTION_ONLY */
+ gboolean caught, uncaught, subclasses; /* For kind == MOD_KIND_EXCEPTION_ONLY */
} Modifier;
typedef struct{
gboolean global;
/* The list of breakpoints used to implement step-over */
GSList *bps;
+ /* The number of frames at the start of a step-over */
+ int nframes;
} SingleStepReq;
/*
fprintf (stderr, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
fprintf (stderr, " server=y/n\t\t\tWhether to listen for a client connection.\n");
fprintf (stderr, " keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
+ fprintf (stderr, " setpgid=y/n\t\t\tWhether to call setpid(0, 0) after startup.\n");
fprintf (stderr, " help\t\t\t\tPrint this help.\n");
}
char **args, **ptr;
char *host;
int port;
- char *extra;
+ const char *extra;
#ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
fprintf (stderr, "--debugger-agent is not supported on this platform.\n");
agent_config.embedding = atoi (arg + 10) == 1;
} else if (strncmp (arg, "keepalive=", 10) == 0) {
agent_config.keepalive = atoi (arg + 10);
+ } else if (strncmp (arg, "setpgid=", 8) == 0) {
+ agent_config.setpgid = parse_flag ("setpgid", arg + 8);
} else {
print_usage ();
exit (1);
*/
mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE;
+#ifdef HAVE_SETPGID
+ if (agent_config.setpgid)
+ setpgid (0, 0);
+#endif
+
if (!agent_config.onuncaught && !agent_config.onthrow)
finish_agent_init (TRUE);
}
static void
start_debugger_thread (void)
{
- gsize tid;
-
- debugger_thread_handle = mono_create_thread (NULL, 0, debugger_thread, NULL, 0, &tid);
+ debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, 0, 0, NULL);
g_assert (debugger_thread_handle);
}
if (ji) {
/* Running managed code, will be suspended by the single step code */
- DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, ji->method->name, ip));
+ DEBUG (1, fprintf (log_file, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip));
return TRUE;
} else {
/*
/* Already terminated */
return TRUE;
- tls->context.valid = FALSE;
-
/*
* We are in a difficult position: we want to be able to provide stack
* traces for this thread, but we can't use the current ctx+lmf, since
tls->async_state.unwind_data [MONO_UNWIND_DATA_LMF] = data.lmf;
tls->async_state.unwind_data [MONO_UNWIND_DATA_JIT_TLS] = tls->thread->jit_data;
} else {
- /* No managed frames */
tls->async_state.valid = FALSE;
}
+
mono_memory_barrier ();
tls->suspended = TRUE;
{
guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
MonoJitInfo *ji;
+ MonoMethod *method;
if (mono_loader_lock_is_owned_by_self ()) {
/*
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
/* Can't suspend in these methods */
- if (ji->method->klass == mono_defaults.string_class && (!strcmp (ji->method->name, "memset") || strstr (ji->method->name, "memcpy")))
+ method = jinfo_get_method (ji);
+ if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
return;
save_thread_context (ctx);
}
if (info->ji)
- method = info->ji->method;
+ method = jinfo_get_method (info->ji);
else
method = info->method;
actual_method = info->actual_method;
if (mod->data.thread != mono_thread_internal_current ())
filtered = TRUE;
} else if (mod->kind == MOD_KIND_EXCEPTION_ONLY && ei) {
- if (mod->data.exc_class && !mono_class_is_assignable_from (mod->data.exc_class, ei->exc->vtable->klass))
+ if (mod->data.exc_class && mod->subclasses && !mono_class_is_assignable_from (mod->data.exc_class, ei->exc->vtable->klass))
+ filtered = TRUE;
+ if (mod->data.exc_class && !mod->subclasses && mod->data.exc_class != ei->exc->vtable->klass)
filtered = TRUE;
if (ei->caught && !mod->caught)
filtered = TRUE;
if (assemblies) {
for (k = 0; assemblies [k]; ++k)
- if (assemblies [k] == ji->method->klass->image->assembly)
+ if (assemblies [k] == jinfo_get_method (ji)->klass->image->assembly)
found = TRUE;
}
if (!found)
g_free (s);
} else if (mod->kind == MOD_KIND_STEP) {
if ((mod->data.filter & STEP_FILTER_STATIC_CTOR) && ji &&
- (ji->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
- !strcmp (ji->method->name, ".cctor"))
+ (jinfo_get_method (ji)->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
+ !strcmp (jinfo_get_method (ji)->name, ".cctor"))
filtered = TRUE;
if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) {
MonoCustomAttrInfo *ainfo;
g_assert (klass);
}
if (!ji->dbg_hidden_inited) {
- ainfo = mono_custom_attrs_from_method (ji->method);
+ ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
if (ainfo) {
if (mono_custom_attrs_has_attr (ainfo, klass))
ji->dbg_hidden = TRUE;
if (ji->dbg_hidden)
filtered = TRUE;
}
+ if ((mod->data.filter & STEP_FILTER_DEBUGGER_STEP_THROUGH) && ji) {
+ MonoCustomAttrInfo *ainfo;
+ static MonoClass *klass;
+
+ if (!klass) {
+ klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerStepThroughAttribute");
+ g_assert (klass);
+ }
+ if (!ji->dbg_step_through_inited) {
+ ainfo = mono_custom_attrs_from_method (jinfo_get_method (ji));
+ if (ainfo) {
+ if (mono_custom_attrs_has_attr (ainfo, klass))
+ ji->dbg_step_through = TRUE;
+ mono_custom_attrs_free (ainfo);
+ }
+ ainfo = mono_custom_attrs_from_class (jinfo_get_method (ji)->klass);
+ if (ainfo) {
+ if (mono_custom_attrs_has_attr (ainfo, klass))
+ ji->dbg_step_through = TRUE;
+ mono_custom_attrs_free (ainfo);
+ }
+ ji->dbg_step_through_inited = TRUE;
+ }
+ if (ji->dbg_step_through)
+ filtered = TRUE;
+ }
}
}
buffer_add_domainid (&buf, mono_get_root_domain ());
break;
case EVENT_KIND_VM_DEATH:
+ if (CHECK_PROTOCOL_VERSION (2, 27))
+ buffer_add_int (&buf, mono_environment_exitcode_get ());
break;
case EVENT_KIND_EXCEPTION: {
EventInfo *ei = arg;
}
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 (ji->method, TRUE), bp->il_offset, 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);
for (i = 0; i < seq_points->len; ++i)
DEBUG (1, fprintf (log_file, "%d\n", seq_points->seq_points [i].il_offset));
#endif
}
- DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji->method, TRUE), (int)sp->il_offset));
+ DEBUG(1, fprintf (log_file, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)sp->il_offset));
}
static void
int i, j;
MonoSeqPointInfo *seq_points;
MonoDomain *domain;
+ MonoMethod *jmethod;
if (!breakpoints)
return;
}
if (!found) {
+ jmethod = jinfo_get_method (ji);
mono_domain_lock (domain);
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, ji->method);
- if (!seq_points && ji->method->is_inflated)
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (ji->method));
+ 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));
mono_domain_unlock (domain);
if (!seq_points)
/* Could be AOT code */
/*
* ss_update:
*
- * Return FALSE if single stepping needs to continue because we are at the same line.
+ * Return FALSE if single stepping needs to continue.
*/
static gboolean
-ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp)
+ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *tls, MonoContext *ctx)
{
MonoDebugMethodInfo *minfo;
MonoDebugSourceLocation *loc = NULL;
gboolean hit = TRUE;
+ MonoMethod *method;
+
+ if (req->depth == STEP_DEPTH_OVER && (sp->flags & MONO_SEQ_POINT_FLAG_NONEMPTY_STACK)) {
+ /*
+ * These seq points are inserted by the JIT after calls, step over needs to skip them.
+ */
+ DEBUG (1, fprintf (log_file, "[%p] Seq point at nonempty stack %x while stepping over, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset));
+ return FALSE;
+ }
+
+ if (req->depth == STEP_DEPTH_OVER && hit) {
+ if (!tls->context.valid)
+ mono_thread_state_init_from_monoctx (&tls->context, ctx);
+ compute_frame_info (tls->thread, tls);
+ if (req->nframes && tls->frame_count && tls->frame_count > req->nframes) {
+ /* Hit the breakpoint in a recursive call */
+ DEBUG (1, fprintf (log_file, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer)GetCurrentThreadId ()));
+ return FALSE;
+ }
+ }
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);
+ method = jinfo_get_method (ji);
+ minfo = mono_debug_lookup_method (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)) {
+ if (!loc || (loc && method == ss_req->last_method && loc->row == ss_req->last_line)) {
/* Have to continue single stepping */
if (!loc)
DEBUG(1, fprintf (log_file, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer)GetCurrentThreadId (), sp->il_offset));
}
if (loc) {
- ss_req->last_method = ji->method;
+ ss_req->last_method = method;
ss_req->last_line = loc->row;
mono_debug_free_source_location (loc);
}
GSList *bp_events = NULL, *ss_events = NULL, *enter_leave_events = NULL;
EventKind kind = EVENT_KIND_BREAKPOINT;
MonoContext *ctx = &tls->restore_ctx;
+ MonoMethod *method;
MonoSeqPointInfo *info;
SeqPoint *sp;
ip = MONO_CONTEXT_GET_IP (ctx);
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
g_assert (ji);
- g_assert (ji->method);
+ method = jinfo_get_method (ji);
/* Compute the native offset of the breakpoint from the ip */
native_offset = ip - (guint8*)ji->code_start;
*/
mono_arch_skip_breakpoint (ctx, ji);
- if (ji->method->wrapper_type || tls->disable_breakpoints)
+ if (method->wrapper_type || tls->disable_breakpoints)
return;
bp_reqs = g_ptr_array_new ();
* 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 (), ji->method, native_offset, &info);
+ sp = find_prev_seq_point_for_native_offset (mono_domain_get (), method, native_offset, &info);
if (!sp)
- no_seq_points_found (ji->method);
+ 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 (), ji->method->name, ip, native_offset, sp ? sp->il_offset : -1));
+ 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));
bp = NULL;
for (i = 0; i < breakpoints->len; ++i) {
SingleStepReq *ss_req = req->info;
gboolean hit;
- hit = ss_update (ss_req, ji, sp);
+ if (mono_thread_internal_current () != ss_req->thread)
+ continue;
+
+ 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, ji->method, sp, info, ctx, tls, FALSE);
+ ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
}
if (ss_reqs->len > 0)
* resume.
*/
if (ss_events)
- process_event (EVENT_KIND_STEP, ji->method, 0, ctx, ss_events, suspend_policy);
+ process_event (EVENT_KIND_STEP, method, 0, ctx, ss_events, suspend_policy);
if (bp_events)
- process_event (kind, ji->method, 0, ctx, bp_events, suspend_policy);
+ process_event (kind, method, 0, ctx, bp_events, suspend_policy);
if (enter_leave_events)
- process_event (kind, ji->method, 0, ctx, enter_leave_events, suspend_policy);
+ process_event (kind, method, 0, ctx, enter_leave_events, suspend_policy);
}
/* Process a breakpoint/single step event after resuming from a signal handler */
{
DebuggerTlsData *tls;
MonoContext orig_restore_ctx, ctx;
- static void (*restore_context) (void *);
-
- if (!restore_context)
- restore_context = mono_get_restore_context ();
tls = mono_native_tls_get_value (debugger_tls_id);
/* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
/* This is called when resuming from a signal handler, so it shouldn't return */
memcpy (&ctx, &tls->restore_ctx, sizeof (MonoContext));
memcpy (&tls->restore_ctx, &orig_restore_ctx, sizeof (MonoContext));
- restore_context (&ctx);
+ mono_restore_context (&ctx);
g_assert_not_reached ();
}
MonoDomain *domain;
GSList *events;
MonoContext *ctx = &tls->restore_ctx;
+ MonoMethod *method;
SeqPoint *sp;
MonoSeqPointInfo *info;
if (log_level > 0) {
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
- DEBUG (1, fprintf (log_file, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer)GetCurrentThreadId (), ss_depth_to_string (ss_req->depth), mono_method_full_name (ji->method, TRUE), MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp));
+ DEBUG (1, fprintf (log_file, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer)GetCurrentThreadId (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp));
}
ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
g_assert (ji);
- g_assert (ji->method);
+ method = jinfo_get_method (ji);
+ g_assert (method);
- if (ji->method->wrapper_type && ji->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
+ if (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
return;
/*
- * FIXME:
+ * FIXME:
* Stopping in memset makes half-initialized vtypes visible.
* Stopping in memcpy makes half-copied vtypes visible.
*/
- if (ji->method->klass == mono_defaults.string_class && (!strcmp (ji->method->name, "memset") || strstr (ji->method->name, "memcpy")))
+ if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
return;
/*
* 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, ji->method, (guint8*)ip - (guint8*)ji->code_start, &info);
+ sp = find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info);
if (!sp)
return;
il_offset = sp->il_offset;
- if (!ss_update (ss_req, ji, sp))
+ if (!ss_update (ss_req, ji, sp, tls, ctx))
return;
/* Start single stepping again from the current sequence point */
- ss_start (ss_req, ji->method, sp, info, ctx, tls, FALSE);
+ ss_start (ss_req, method, sp, info, ctx, tls, FALSE);
if ((ss_req->filter & STEP_FILTER_STATIC_CTOR) &&
- (ji->method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
- !strcmp (ji->method->name, ".cctor"))
+ (method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
+ !strcmp (method->name, ".cctor"))
return;
// FIXME: Has to lock earlier
mono_loader_unlock ();
- process_event (EVENT_KIND_STEP, ji->method, il_offset, ctx, events, suspend_policy);
+ process_event (EVENT_KIND_STEP, jinfo_get_method (ji), il_offset, ctx, events, suspend_policy);
}
static void
}
if (ss_req->depth == STEP_DEPTH_OVER) {
+ if (ss_req->nframes == 0)
+ ss_req->nframes = tls->frame_count;
/* Need to stop in catch clauses as well */
for (i = 0; i < tls->frame_count; ++i) {
StackFrame *frame = tls->frames [i];
if (assemblies) {
for (k = 0; assemblies [k]; ++k)
- if (assemblies [k] == catch_ji->method->klass->image->assembly)
+ if (assemblies [k] == jinfo_get_method (catch_ji)->klass->image->assembly)
found = TRUE;
}
if (!found)
nfields --;
}
g_assert (nfields == 0);
+
+ *endbuf = buf;
+
return 0;
}
NOT_IMPLEMENTED;
break;
case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
+ case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR:
/* Same as regoffset, but with an indirection */
addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
addr += (gint32)var->offset;
mgreg_t v;
gboolean is_signed = FALSE;
+ if (t->byref) {
+ addr = (gpointer)mono_arch_context_get_int_reg (ctx, reg);
+
+ if (addr) {
+ // FIXME: Write barriers
+ mono_gc_memmove (addr, val, size);
+ }
+ break;
+ }
+
if (!t->byref && (t->type == MONO_TYPE_I1 || t->type == MONO_TYPE_I2 || t->type == MONO_TYPE_I4 || t->type == MONO_TYPE_I8))
is_signed = TRUE;
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 */
else
this = NULL;
+ if (MONO_CLASS_IS_INTERFACE (m->klass)) {
+ if (!this) {
+ DEBUG (1, fprintf (log_file, "[%p] Error: Interface method invoked 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>"));
if (this && this->vtable->domain != domain)
/* Setup our lmf */
memset (&ext, 0, sizeof (ext));
-#ifdef TARGET_AMD64
- ext.lmf.previous_lmf = *(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.rsp = (gssize)&ext;
-#elif defined(TARGET_X86)
- ext.lmf.previous_lmf = (gsize)*(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gsize)(gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.ebp = (gssize)&ext;
-#elif defined(TARGET_ARM)
- ext.lmf.previous_lmf = *(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.sp = (gssize)&ext;
-#elif defined(TARGET_POWERPC)
- ext.lmf.previous_lmf = *(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.ebp = (gssize)&ext;
-#elif defined(TARGET_S390X)
- ext.lmf.previous_lmf = *(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.ebp = (gssize)&ext;
-#elif defined(TARGET_MIPS)
- ext.lmf.previous_lmf = *(lmf_addr);
- /* Mark that this is a MonoLMFExt */
- ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
- ext.lmf.iregs [mips_sp] = (gssize)&ext;
-#else
- g_assert_not_reached ();
-#endif
+ mono_arch_init_lmf_ext (&ext, *lmf_addr);
ext.debugger_invoke = TRUE;
memcpy (&ext.ctx, &invoke->ctx, sizeof (MonoContext));
int id;
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 ();
-
tls = mono_native_tls_get_value (debugger_tls_id);
g_assert (tls);
if (!mono_runtime_try_shutdown ())
break;
+ mono_environment_exitcode_set (exit_code);
+
/* Suspend all managed threads since the runtime is going away */
DEBUG(1, fprintf (log_file, "Suspending all threads...\n"));
mono_thread_suspend_all_other_threads ();
if (CHECK_PROTOCOL_VERSION (2, 16))
filter = decode_int (p, &p, end);
req->modifiers [i].data.filter = filter;
+ if (!CHECK_PROTOCOL_VERSION (2, 26) && (req->modifiers [i].data.filter & STEP_FILTER_DEBUGGER_HIDDEN))
+ /* Treat STEP_THOUGH the same as HIDDEN */
+ req->modifiers [i].data.filter |= STEP_FILTER_DEBUGGER_STEP_THROUGH;
} else if (mod == MOD_KIND_THREAD_ONLY) {
int id = decode_id (p, &p, end);
return err;
req->modifiers [i].caught = decode_byte (p, &p, end);
req->modifiers [i].uncaught = decode_byte (p, &p, end);
- DEBUG(1, fprintf (log_file, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s).\n", exc_class ? exc_class->name : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : ""));
+ if (CHECK_PROTOCOL_VERSION (2, 25))
+ req->modifiers [i].subclasses = decode_byte (p, &p, end);
+ else
+ req->modifiers [i].subclasses = TRUE;
+ DEBUG(1, fprintf (log_file, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class ? exc_class->name : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : ""));
if (exc_class) {
req->modifiers [i].data.exc_class = exc_class;