#include <mono/metadata/gc-internals.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/threads-types.h>
-#include <mono/metadata/threadpool-ms.h>
+#include <mono/metadata/threadpool.h>
#include <mono/metadata/socket-io.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/runtime.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/networking.h>
+#include <mono/utils/mono-proclib.h>
#include "debugger-agent.h"
#include "mini.h"
#include "seq-points.h"
+#include <mono/io-layer/io-layer.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 42
+#define MINOR_VERSION 44
typedef enum {
CMD_SET_VM = 1,
CMD_STACK_FRAME_GET_THIS = 2,
CMD_STACK_FRAME_SET_VALUES = 3,
CMD_STACK_FRAME_GET_DOMAIN = 4,
+ CMD_STACK_FRAME_SET_THIS = 5,
} CmdStackFrame;
typedef enum {
GSList *bps;
/* The number of frames at the start of a step-over */
int nframes;
+ /* If set, don't stop in methods that are not part of user assemblies */
+ MonoAssembly** user_assemblies;
} SingleStepReq;
/*
static MonoNativeThreadId debugger_thread_id;
-static HANDLE debugger_thread_handle;
+static MonoThreadHandle *debugger_thread_handle;
static int log_level;
/* Waiting for deferred attachment */
agent_config.defer = TRUE;
if (agent_config.address == NULL) {
- agent_config.address = g_strdup_printf ("0.0.0.0:%u", 56000 + (getpid () % 1000));
+ agent_config.address = g_strdup_printf ("0.0.0.0:%u", 56000 + (mono_process_current_pid () % 1000));
}
}
static void
start_debugger_thread (void)
{
- MonoThreadParm tp;
-
- tp.priority = MONO_THREAD_PRIORITY_NORMAL;
- tp.stack_size = 0;
- tp.creation_flags = 0;
- debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, &tp, NULL);
+ debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, NULL, NULL);
g_assert (debugger_thread_handle);
}
res = (Id *)g_ptr_array_index (ids [type], GPOINTER_TO_INT (id - 1));
dbg_unlock ();
- if (res->domain == NULL) {
+ if (res->domain == NULL || res->domain->state == MONO_APPDOMAIN_UNLOADED) {
DEBUG_PRINTF (1, "ERR_UNLOADED, id=%d, type=%d.\n", id, type);
*err = ERR_UNLOADED;
return NULL;
/*
* Suspend creation of new threadpool threads, since they cannot run
*/
- mono_threadpool_ms_suspend ();
+ mono_threadpool_suspend ();
mono_loader_unlock ();
}
//g_assert (err == 0);
if (suspend_count == 0)
- mono_threadpool_ms_resume ();
+ mono_threadpool_resume ();
mono_loader_unlock ();
}
if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
return;
+ /*
+ * This could be in ss_update method, but mono_find_next_seq_point_for_native_offset is pretty expensive method,
+ * hence we prefer this check here.
+ */
+ if (ss_req->user_assemblies) {
+ gboolean found = FALSE;
+ for (int k = 0; ss_req->user_assemblies[k]; k++)
+ if (ss_req->user_assemblies[k] == method->klass->image->assembly) {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ 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.
ss_req->filter = filter;
req->info = ss_req;
+ for (int i = 0; i < req->nmodifiers; i++) {
+ if (req->modifiers[i].kind == MOD_KIND_ASSEMBLY_ONLY) {
+ ss_req->user_assemblies = req->modifiers[i].data.assemblies;
+ break;
+ }
+ }
+
mono_loader_lock ();
tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
mono_loader_unlock ();
g_assert (tls);
- g_assert (tls->context.valid);
+ if (!tls->context.valid) {
+ DEBUG_PRINTF (1, "Received a single step request on a thread with no managed frames.");
+ return ERR_INVALID_ARGUMENT;
+ }
if (tls->restore_state.valid && MONO_CONTEXT_GET_IP (&tls->context.ctx) != MONO_CONTEXT_GET_IP (&tls->restore_state.ctx)) {
/*
}
if (match_count) {
- newassemblies = g_new0 (MonoAssembly*, count - match_count);
+ // +1 because we don't know length and we use last element to check for end
+ newassemblies = g_new0 (MonoAssembly*, count - match_count + 1);
pos = 0;
for (i = 0; i < count; ++i)
if (!m->klass->valuetype && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this_arg) {
if (!strcmp (m->name, ".ctor")) {
- if (m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT)
+ if (mono_class_is_abstract (m->klass))
return ERR_INVALID_ARGUMENT;
else {
MonoError error;
int n = decode_int (p, &p, end);
int j;
- req->modifiers [i].data.assemblies = g_new0 (MonoAssembly*, n);
+ // +1 because we don't know length and we use last element to check for end
+ req->modifiers [i].data.assemblies = g_new0 (MonoAssembly*, n + 1);
for (j = 0; j < n; ++j) {
req->modifiers [i].data.assemblies [j] = decode_assemblyid (p, &p, end, &domain, &err);
if (err != ERR_NONE) {
return ERR_NONE;
}
+static ErrorCode
+get_assembly_object_command (MonoDomain *domain, MonoAssembly *ass, Buffer *buf, MonoError *error)
+{
+ HANDLE_FUNCTION_ENTER();
+ ErrorCode err = ERR_NONE;
+ mono_error_init (error);
+ MonoReflectionAssemblyHandle o = mono_assembly_get_object_handle (domain, ass, error);
+ if (MONO_HANDLE_IS_NULL (o)) {
+ err = ERR_INVALID_OBJECT;
+ goto leave;
+ }
+ buffer_add_objid (buf, MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, o)));
+leave:
+ HANDLE_FUNCTION_RETURN_VAL (err);
+}
+
+
static ErrorCode
assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
{
}
case CMD_ASSEMBLY_GET_OBJECT: {
MonoError error;
- MonoObject *o = (MonoObject*)mono_assembly_get_object_checked (domain, ass, &error);
- if (!o) {
- mono_error_cleanup (&error); /* FIXME don't swallow the error */
- return ERR_INVALID_OBJECT;
- }
- buffer_add_objid (buf, o);
- break;
+ err = get_assembly_object_command (domain, ass, buf, &error);
+ mono_error_cleanup (&error);
+ return err;
}
case CMD_ASSEMBLY_GET_TYPE: {
MonoError error;
buffer_add_id (buf, 0);
buffer_add_int (buf, klass->type_token);
buffer_add_byte (buf, klass->rank);
- buffer_add_int (buf, klass->flags);
+ buffer_add_int (buf, mono_class_get_flags (klass));
b = 0;
type = &klass->byval_arg;
// FIXME: Can't decide whenever a class represents a byref type
b |= (1 << 3);
if (klass->enumtype)
b |= (1 << 4);
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass))
b |= (1 << 5);
- if (klass->generic_container || klass->generic_class)
+ if (mono_class_is_gtd (klass) || mono_class_is_ginst (klass))
b |= (1 << 6);
buffer_add_byte (buf, b);
nnested = 0;
while ((nested = mono_class_get_nested_types (klass, &iter)))
buffer_add_typeid (buf, domain, nested);
if (CHECK_PROTOCOL_VERSION (2, 12)) {
- if (klass->generic_container)
+ if (mono_class_is_gtd (klass))
buffer_add_typeid (buf, domain, klass);
- else if (klass->generic_class)
- buffer_add_typeid (buf, domain, klass->generic_class->container_class);
+ else if (mono_class_is_ginst (klass))
+ buffer_add_typeid (buf, domain, mono_class_get_generic_class (klass)->container_class);
else
buffer_add_id (buf, 0);
}
if (CHECK_PROTOCOL_VERSION (2, 15)) {
int count, i;
- if (klass->generic_class) {
- MonoGenericInst *inst = klass->generic_class->context.class_inst;
+ if (mono_class_is_ginst (klass)) {
+ MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
count = inst->type_argc;
buffer_add_int (buf, count);
for (i = 0; i < count; i++)
buffer_add_typeid (buf, domain, mono_class_from_mono_type (inst->type_argv [i]));
- } else if (klass->generic_container) {
- MonoGenericContainer *container = klass->generic_container;
+ } else if (mono_class_is_gtd (klass)) {
+ MonoGenericContainer *container = mono_class_get_generic_container (klass);
MonoClass *pklass;
count = container->type_argc;
locals = mono_debug_lookup_locals (method);
if (!locals) {
+ if (CHECK_PROTOCOL_VERSION (2, 43)) {
+ /* Scopes */
+ buffer_add_int (buf, 1);
+ buffer_add_int (buf, 0);
+ buffer_add_int (buf, header->code_size);
+ }
buffer_add_int (buf, header->num_locals);
/* Types */
for (i = 0; i < header->num_locals; ++i) {
buffer_add_int (buf, header->code_size);
}
} else {
+ if (CHECK_PROTOCOL_VERSION (2, 43)) {
+ /* Scopes */
+ buffer_add_int (buf, locals->num_blocks);
+ int last_start = 0;
+ for (i = 0; i < locals->num_blocks; ++i) {
+ buffer_add_int (buf, locals->code_blocks [i].start_offset - last_start);
+ buffer_add_int (buf, locals->code_blocks [i].end_offset - locals->code_blocks [i].start_offset);
+ last_start = locals->code_blocks [i].start_offset;
+ }
+ }
+
num_locals = locals->num_locals;
buffer_add_int (buf, num_locals);
}
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.class_inst = mono_class_is_ginst (method->klass) ? mono_class_get_generic_class (method->klass)->context.class_inst : NULL;
tmp_context.method_inst = ginst;
inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, &error);
buffer_add_domainid (buf, frame->domain);
break;
}
+ case CMD_STACK_FRAME_SET_THIS: {
+ guint8 *val_buf;
+ MonoType *t;
+ MonoDebugVarInfo *var;
+
+ t = &frame->actual_method->klass->byval_arg;
+ /* Checked by the sender */
+ g_assert (MONO_TYPE_ISSTRUCT (t));
+ var = jit->this_var;
+ g_assert (var);
+
+ val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (t)));
+ err = decode_value (t, frame->domain, val_buf, p, &p, end);
+ if (err != ERR_NONE)
+ return err;
+
+ set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+ break;
+ }
default:
return ERR_NOT_IMPLEMENTED;
}
"GET_THIS",
"SET_VALUES",
"GET_DOMAIN",
+ "SET_THIS"
};
static const char* array_cmds_str[] = {