[debugger] Invoke method with fixed size array as an attribute of this (mono/mono...
authorThays Grazia <thaystg@gmail.com>
Fri, 2 Aug 2019 13:47:25 +0000 (10:47 -0300)
committerAlexander Köplinger <alex.koeplinger@outlook.com>
Fri, 2 Aug 2019 13:47:25 +0000 (15:47 +0200)
Implement debugger invoke when the this has an attribute that is a fixed size array.

Fixes mono/mono#15556

Commit migrated from https://github.com/mono/mono/commit/3a9df67a64c129fa3c5c32334c231739965f1efb

src/mono/mono/mini/debugger-agent.c

index 3816711..018d92b 100644 (file)
@@ -85,6 +85,7 @@
 #include "interp/interp.h"
 #include "debugger-engine.h"
 #include "mono/metadata/debug-mono-ppdb.h"
+#include "mono/metadata/custom-attrs-internals.h"
 
 /*
  * On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -282,7 +283,7 @@ typedef struct {
 #define HEADER_LENGTH 11
 
 #define MAJOR_VERSION 2
-#define MINOR_VERSION 52
+#define MINOR_VERSION 53
 
 typedef enum {
        CMD_SET_VM = 1,
@@ -335,7 +336,8 @@ typedef enum {
 typedef enum {
        VALUE_TYPE_ID_NULL = 0xf0,
        VALUE_TYPE_ID_TYPE = 0xf1,
-       VALUE_TYPE_ID_PARENT_VTYPE = 0xf2
+       VALUE_TYPE_ID_PARENT_VTYPE = 0xf2,
+       VALUE_TYPE_ID_FIXED_ARRAY = 0xf3
 } ValueTypeId;
 
 typedef enum {
@@ -726,6 +728,8 @@ static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoCont
 static int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args);
 static void ss_args_destroy (SingleStepArgs *ss_args);
 
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute")
+
 #ifndef DISABLE_SOCKET_TRANSPORT
 static void
 register_socket_transport (void);
@@ -3196,6 +3200,45 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        return FALSE;
 }
 
+static gint32 isFixedSizeArray (MonoClassField *f)
+{
+       ERROR_DECL (error);
+       if (!CHECK_PROTOCOL_VERSION (2, 53) || f->type->type != MONO_TYPE_VALUETYPE) {
+               return 1;
+       }
+       MonoCustomAttrInfo *cinfo;
+       MonoCustomAttrEntry *attr;
+       int aindex;
+       gint32 ret = 1;
+       cinfo = mono_custom_attrs_from_field_checked (f->parent, f, error);
+       if (!is_ok (error))
+               return ret;
+       attr = NULL;
+       if (cinfo) {
+               for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) {
+                       MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass;
+                       MonoClass *fixed_size_class = mono_class_try_get_fixed_buffer_class ();
+                       if (fixed_size_class != NULL && mono_class_has_parent (ctor_class, fixed_size_class)) {
+                               attr = &cinfo->attrs [aindex];
+                               gpointer *typed_args, *named_args;
+                               CattrNamedArg *arginfo;
+                               int num_named_args;
+
+                               mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size,
+                                                                                                                                       &typed_args, &named_args, &num_named_args, &arginfo, error);
+                               if (!is_ok (error))
+                                       return FALSE;
+                               ret = *(gint32*)typed_args [1];
+                               g_free (typed_args);
+                               g_free (named_args);
+                               g_free (arginfo);
+                               return ret;
+                       }
+               }
+       }
+       return ret;
+}
+
 static gboolean
 process_filter_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
 {
@@ -5215,6 +5258,47 @@ debugger_agent_end_exception_filter (MonoException *exc, MonoContext *ctx, MonoC
        tls->filter_state.valid = FALSE;
 }
 
+static void 
+buffer_add_fixed_array (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
+                                          gboolean as_vtype, GHashTable *parent_vtypes, gint32 len_fixed_array)
+{
+       buffer_add_byte (buf, VALUE_TYPE_ID_FIXED_ARRAY);
+       buffer_add_byte (buf, t->type);
+       buffer_add_int (buf, len_fixed_array );
+       for (int i = 0; i < len_fixed_array; i++) {
+               switch (t->type) {
+                       case MONO_TYPE_BOOLEAN:
+                       case MONO_TYPE_I1:
+                       case MONO_TYPE_U1:
+                               buffer_add_int (buf, ((gint8*)addr)[i]);
+                               break;
+                       case MONO_TYPE_CHAR:
+                       case MONO_TYPE_I2:
+                       case MONO_TYPE_U2:
+                               buffer_add_int (buf, ((gint16*)addr)[i]);
+                               break;
+                       case MONO_TYPE_I4:
+                       case MONO_TYPE_U4:
+                       case MONO_TYPE_R4:
+                               buffer_add_int (buf, ((gint32*)addr)[i]);
+                               break;
+                       case MONO_TYPE_I8:
+                       case MONO_TYPE_U8:
+                       case MONO_TYPE_R8:
+                               buffer_add_long (buf, ((gint64*)addr)[i]);
+                               break;
+                       case MONO_TYPE_PTR: {
+                               gssize val = *(gssize*)addr;
+                               
+                               buffer_add_byte (buf, t->type);
+                               buffer_add_long (buf, val);
+                               if (CHECK_PROTOCOL_VERSION(2, 46))
+                                       buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t));
+                               break;
+                       }
+               }
+       }
+}
 /*
  * buffer_add_value_full:
  *
@@ -5224,7 +5308,7 @@ debugger_agent_end_exception_filter (MonoException *exc, MonoContext *ctx, MonoC
  */
 static void
 buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
-                                          gboolean as_vtype, GHashTable *parent_vtypes)
+                                          gboolean as_vtype, GHashTable *parent_vtypes, gint32 len_fixed_array)
 {
        MonoObject *obj;
        gboolean boxed_vtype = FALSE;
@@ -5263,7 +5347,12 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
                        break;
                }
        }
-
+       
+       if (len_fixed_array > 1 && t->type != MONO_TYPE_VALUETYPE && CHECK_PROTOCOL_VERSION (2, 53))
+       {
+               buffer_add_fixed_array(buf, t, addr, domain, as_vtype, parent_vtypes, len_fixed_array);
+               return;
+       }
        switch (t->type) {
        case MONO_TYPE_VOID:
                buffer_add_byte (buf, t->type);
@@ -5342,8 +5431,8 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
 
                if (boxed_vtype) {
                        /*
-                        * Handle boxed vtypes recursively referencing themselves using fields.
-                        */
+                       * Handle boxed vtypes recursively referencing themselves using fields.
+                       */
                        if (!parent_vtypes)
                                parent_vtypes = g_hash_table_new (NULL, NULL);
                        vtype_index = GPOINTER_TO_INT (g_hash_table_lookup (parent_vtypes, addr));
@@ -5382,7 +5471,7 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
                                continue;
                        if (mono_field_is_deleted (f))
                                continue;
-                       buffer_add_value_full (buf, f->type, mono_vtype_get_field_addr (addr, f), domain, FALSE, parent_vtypes);
+                       buffer_add_value_full (buf, f->type, mono_vtype_get_field_addr (addr, f), domain, FALSE, parent_vtypes, len_fixed_array != 1 ? len_fixed_array : isFixedSizeArray(f));
                }
 
                if (boxed_vtype) {
@@ -5409,7 +5498,7 @@ buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
 static void
 buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
 {
-       buffer_add_value_full (buf, t, addr, domain, FALSE, NULL);
+       buffer_add_value_full (buf, t, addr, domain, FALSE, NULL, 1);
 }
 
 static gboolean
@@ -5478,14 +5567,66 @@ decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void
 
        return ERR_NONE;
 }
-
+static ErrorCode decode_fixed_size_array_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
+{
+       ErrorCode err = ERR_NONE;
+       int fixedSizeLen = 1;
+       int newType = MONO_TYPE_END;
+       if (CHECK_PROTOCOL_VERSION (2, 53)) {
+               newType = decode_byte (buf, &buf, limit);
+               fixedSizeLen = decode_int (buf, &buf, limit);
+               //t->type = newType;
+       }
+       for (int i = 0 ; i < fixedSizeLen; i++) {
+               switch (newType) {
+               case MONO_TYPE_BOOLEAN:
+                       ((guint8*)addr)[i] = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_CHAR:
+                       ((gunichar2*)addr)[i] = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_I1:
+                       ((gint8*)addr)[i] = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_U1:
+                       ((guint8*)addr)[i] = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_I2:
+                       ((gint16*)addr)[i] = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_U2:
+                       ((guint16*)addr)[i]  = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_I4:
+                       ((gint32*)addr)[i]  = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_U4:
+                       ((guint32*)addr)[i]  = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_I8:
+                       ((gint64*)addr)[i]  = decode_long (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_U8:
+                       ((guint64*)addr)[i]  = decode_long (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_R4:
+                       ((guint32*)addr)[i]  = decode_int (buf, &buf, limit);
+                       break;
+               case MONO_TYPE_R8:
+                       ((guint64*)addr)[i]  = decode_long (buf, &buf, limit);
+                       break;
+               }
+       }
+       *endbuf = buf;
+       return err;
+}
 static ErrorCode
 decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
 {
        ErrorCode err;
-
        if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) &&
                !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
+               !(type == VALUE_TYPE_ID_FIXED_ARRAY) &&
                !(t->type == MONO_TYPE_U && type == MONO_TYPE_VALUETYPE) &&
                !(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8) &&
                !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) &&
@@ -5495,6 +5636,10 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                g_free (name);
                return ERR_INVALID_ARGUMENT;
        }
+       if (type == VALUE_TYPE_ID_FIXED_ARRAY && t->type != MONO_TYPE_VALUETYPE) {
+               decode_fixed_size_array_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype);
+               return ERR_NONE;
+       }
 
        switch (t->type) {
        case MONO_TYPE_BOOLEAN:
@@ -5612,9 +5757,9 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
 
                                /* This can happen when round-tripping boxed vtypes */
                                /*
-                                * Obtain vtype class.
-                                * Same as the beginning of the handle_vtype case above.
-                                */
+                               * Obtain vtype class.
+                               * Same as the beginning of the handle_vtype case above.
+                               */
                                buf2 = buf;
                                is_enum = decode_byte (buf, &buf, limit);
                                if (is_enum)
@@ -5655,6 +5800,7 @@ decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr,
                break;
        }
 
+
        *endbuf = buf;
 
        return ERR_NONE;
@@ -5725,7 +5871,7 @@ add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo
        case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
                reg_val = mono_arch_context_get_int_reg (ctx, reg);
 
-               buffer_add_value_full (buf, t, &reg_val, domain, as_vtype, NULL);
+               buffer_add_value_full (buf, t, &reg_val, domain, as_vtype, NULL, 1);
                break;
        case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
                addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
@@ -5733,7 +5879,7 @@ add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo
 
                //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
 
-               buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL);
+               buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL, 1);
                break;
        case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
                NOT_IMPLEMENTED;
@@ -5746,7 +5892,7 @@ add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo
 
                gaddr = (guint8 *)*(gpointer*)addr;
                g_assert (gaddr);
-               buffer_add_value_full (buf, t, gaddr, domain, as_vtype, NULL);
+               buffer_add_value_full (buf, t, gaddr, domain, as_vtype, NULL, 1);
                break;
        case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: {
                MonoDebugVarInfo *info_var = jit->gsharedvt_info_var;
@@ -5788,7 +5934,7 @@ add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo
 
                addr = locals + GPOINTER_TO_INT (info->entries [idx]);
 
-               buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL);
+               buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL, 1);
                break;
        }
 
@@ -8883,7 +9029,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                        addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos);
 
-                                       buffer_add_value_full (buf, sig->params [pos], addr, frame->de.domain, FALSE, NULL);
+                                       buffer_add_value_full (buf, sig->params [pos], addr, frame->de.domain, FALSE, NULL, 1);
                                } else {
                                        g_assert (pos >= 0 && pos < jit->num_params);
 
@@ -8906,7 +9052,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                        addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos);
 
-                                       buffer_add_value_full (buf, header->locals [pos], addr, frame->de.domain, FALSE, NULL);
+                                       buffer_add_value_full (buf, header->locals [pos], addr, frame->de.domain, FALSE, NULL, 1);
                                } else {
                                        g_assert (pos >= 0 && pos < jit->num_locals);
 
@@ -8930,7 +9076,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                        addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
 
-                                       buffer_add_value_full (buf, m_class_get_this_arg (frame->actual_method->klass), addr, frame->de.domain, FALSE, NULL);
+                                       buffer_add_value_full (buf, m_class_get_this_arg (frame->actual_method->klass), addr, frame->de.domain, FALSE, NULL, 1);
                                } else {
                                        add_var (buf, jit, m_class_get_this_arg (frame->actual_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
                                }
@@ -8945,7 +9091,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                        addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
 
-                                       buffer_add_value_full (buf, m_class_get_byval_arg (frame->api_method->klass), addr, frame->de.domain, FALSE, NULL);
+                                       buffer_add_value_full (buf, m_class_get_byval_arg (frame->api_method->klass), addr, frame->de.domain, FALSE, NULL, 1);
                                } else {
                                        add_var (buf, jit, m_class_get_byval_arg (frame->api_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
                                }