[io-layer] Extract socket (#4241)
[mono.git] / mono / mini / debugger-agent.c
index 7aa562c591db78c8118002b5f80503112154414c..ce2656126b6d1750e130ee034779a0be7664e87b 100644 (file)
 #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/socket-io.h>
+#include <mono/metadata/threadpool.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/runtime.h>
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/w32socket.h>
 #include <mono/utils/mono-coop-mutex.h>
 #include <mono/utils/mono-coop-semaphore.h>
 #include <mono/utils/mono-error-internals.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
@@ -271,7 +273,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 43
+#define MINOR_VERSION 44
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -499,6 +501,7 @@ typedef enum {
        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 {
@@ -566,6 +569,8 @@ typedef struct {
        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;
 
 /*
@@ -667,7 +672,7 @@ static MonoGHashTable *tid_to_thread_obj;
 
 static MonoNativeThreadId debugger_thread_id;
 
-static HANDLE debugger_thread_handle;
+static MonoThreadHandle *debugger_thread_handle;
 
 static int log_level;
 
@@ -931,7 +936,7 @@ mono_debugger_agent_parse_options (char *options)
                /* 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));
                }
        }
 
@@ -1627,7 +1632,7 @@ stop_debugger_thread (void)
 static void
 start_debugger_thread (void)
 {
-       debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, 0, NULL);
+       debugger_thread_handle = mono_threads_create_thread (debugger_thread, NULL, NULL, NULL);
        g_assert (debugger_thread_handle);
 }
 
@@ -2307,7 +2312,7 @@ decode_ptr_id (guint8 *buf, guint8 **endbuf, guint8 *limit, IdType type, MonoDom
        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;
@@ -2771,7 +2776,7 @@ suspend_vm (void)
                /*
                 * Suspend creation of new threadpool threads, since they cannot run
                 */
-               mono_threadpool_ms_suspend ();
+               mono_threadpool_suspend ();
 
        mono_loader_unlock ();
 }
@@ -2809,7 +2814,7 @@ resume_vm (void)
        //g_assert (err == 0);
 
        if (suspend_count == 0)
-               mono_threadpool_ms_resume ();
+               mono_threadpool_resume ();
 
        mono_loader_unlock ();
 }
@@ -4907,6 +4912,22 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        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.
@@ -5215,6 +5236,21 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint* sp, MonoSeqPointI
                        nframes = tls->frame_count;
                }
 
+               /* Need to stop in catch clauses as well */
+               for (i = ss_req->depth == STEP_DEPTH_OUT ? 1 : 0; i < nframes; ++i) {
+                       StackFrame *frame = frames [i];
+
+                       if (frame->ji) {
+                               MonoJitInfo *jinfo = frame->ji;
+                               for (j = 0; j < jinfo->num_clauses; ++j) {
+                                       MonoJitExceptionInfo *ei = &jinfo->clauses [j];
+
+                                       if (mono_find_next_seq_point_for_native_offset (frame->domain, frame->method, (char*)ei->handler_start - (char*)jinfo->code_start, NULL, &local_sp))
+                                               ss_bp_add_one (ss_req, &ss_req_bp_count, &ss_req_bp_cache, frame->method, local_sp.il_offset);
+                               }
+                       }
+               }
+
                /*
                 * Find the first sequence point in the current or in a previous frame which
                 * is not the last in its method.
@@ -5301,26 +5337,6 @@ ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint* sp, MonoSeqPointI
                        ss_req->depth = STEP_DEPTH_INTO;
                }
 
-               if (ss_req->depth == STEP_DEPTH_OVER) {
-                       /* Need to stop in catch clauses as well */
-                       for (i = 0; i < nframes; ++i) {
-                               StackFrame *frame = frames [i];
-
-                               if (frame->ji) {
-                                       MonoJitInfo *jinfo = frame->ji;
-                                       for (j = 0; j < jinfo->num_clauses; ++j) {
-                                               MonoJitExceptionInfo *ei = &jinfo->clauses [j];
-
-                                               found_sp = mono_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 (found_sp)
-                                                       ss_bp_add_one (ss_req, &ss_req_bp_count, &ss_req_bp_cache, frame->method, sp->il_offset);
-                                       }
-                               }
-                       }
-               }
-
                if (ss_req->depth == STEP_DEPTH_INTO) {
                        /* Enable global stepping so we stop at method entry too */
                        enable_global = TRUE;
@@ -5389,11 +5405,21 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilte
        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)) {
                /*
@@ -6478,7 +6504,8 @@ clear_assembly_from_modifier (EventRequest *req, Modifier *m, MonoAssembly *asse
                }
 
                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)
@@ -6681,7 +6708,7 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8
 
        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;
@@ -7488,7 +7515,8 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                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) {
@@ -7736,6 +7764,23 @@ domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
        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)
 {
@@ -7778,13 +7823,9 @@ 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;
@@ -8034,7 +8075,7 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
                        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
@@ -8048,9 +8089,9 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
                        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;
@@ -8062,25 +8103,25 @@ type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint
                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;
@@ -8909,7 +8950,7 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g
                }
                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);
@@ -9269,6 +9310,25 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                        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;
        }
@@ -9688,6 +9748,7 @@ static const char* stack_frame_cmds_str[] = {
        "GET_THIS",
        "SET_VALUES",
        "GET_DOMAIN",
+       "SET_THIS"
 };
 
 static const char* array_cmds_str[] = {