Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThays Grazia <thaystg@gmail.com>2019-08-02 16:47:25 +0300
committerAlexander Köplinger <alex.koeplinger@outlook.com>2019-08-02 16:47:25 +0300
commit3a9df67a64c129fa3c5c32334c231739965f1efb (patch)
tree6f232b35edbe12b9052b2b89adc8d83d37536c74 /mcs/class/Mono.Debugger.Soft
parent4883b56c10a077e4c82feff604172d6994994e1a (diff)
[debugger] Invoke method with fixed size array as an attribute of this (#15766)
Implement debugger invoke when the this has an attribute that is a fixed size array. Fixes #15556
Diffstat (limited to 'mcs/class/Mono.Debugger.Soft')
-rw-r--r--mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs155
-rw-r--r--mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs24
-rw-r--r--mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs38
-rw-r--r--mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs85
-rw-r--r--mcs/class/Mono.Debugger.Soft/Test/dtest.cs42
5 files changed, 338 insertions, 6 deletions
diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
index bbe59a9c899..febf383b2a2 100644
--- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
+++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
@@ -151,7 +151,8 @@ namespace Mono.Debugger.Soft
enum ValueTypeId {
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
}
[Flags]
@@ -215,6 +216,7 @@ namespace Mono.Debugger.Soft
public bool IsEnum; // For ElementType.ValueType
public long Id; /* For VALUE_TYPE_ID_TYPE */
public int Index; /* For VALUE_TYPE_PARENT_VTYPE */
+ public int FixedSize;
}
class ModuleInfo {
@@ -427,7 +429,7 @@ namespace Mono.Debugger.Soft
* with newer runtimes, and vice versa.
*/
internal const int MAJOR_VERSION = 2;
- internal const int MINOR_VERSION = 52;
+ internal const int MINOR_VERSION = 53;
enum WPSuspendPolicy {
NONE = 0,
@@ -855,7 +857,6 @@ namespace Mono.Debugger.Soft
public ValueImpl ReadValue () {
ElementType etype = (ElementType)ReadByte ();
-
switch (etype) {
case ElementType.Void:
return new ValueImpl { Type = etype };
@@ -916,11 +917,94 @@ namespace Mono.Debugger.Soft
return new ValueImpl () { Type = etype, Id = ReadId () };
case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE:
return new ValueImpl () { Type = etype, Index = ReadInt () };
+ case (ElementType)ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY:
+ return ReadValueFixedSize ();
default:
throw new NotImplementedException ("Unable to handle type " + etype);
}
}
+ ValueImpl ReadValueFixedSize () {
+ var lenFixedSize = 1;
+ ElementType etype = (ElementType)ReadByte ();
+ lenFixedSize = ReadInt ();
+ switch (etype) {
+ case ElementType.I1: {
+ var val = new sbyte[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (sbyte)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.U1: {
+ var val = new byte[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (byte)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.Boolean: {
+ var val = new bool[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (ReadInt () != 0);
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.I2: {
+ var val = new short[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (short)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.U2: {
+ var val = new ushort[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (ushort)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.Char: {
+ var val = new char[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (char)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.I4: {
+ var val = new int[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.U4: {
+ var val = new uint[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (uint)ReadInt ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.I8: {
+ var val = new long[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = ReadLong ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.U8: {
+ var val = new ulong[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = (ulong) ReadLong ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.R4: {
+ var val = new float[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = ReadFloat ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ case ElementType.R8: {
+ var val = new double[lenFixedSize];
+ for (int i = 0; i < lenFixedSize; i++)
+ val[i] = ReadDouble ();
+ return new ValueImpl { Type = etype, Value = val };
+ }
+ }
+ throw new NotImplementedException ("Unable to handle type " + etype);
+ }
+
public long[] ReadIds (int n) {
long[] res = new long [n];
for (int i = 0; i < n; ++i)
@@ -1046,9 +1130,13 @@ namespace Mono.Debugger.Soft
ElementType t;
if (v.Value != null)
- t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()));
+ t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()), v.Value.GetType ());
else
t = v.Type;
+ if (v.FixedSize > 1 && t != ElementType.ValueType) {
+ WriteFixedSizeValue (v);
+ return this;
+ }
WriteByte ((byte)t);
switch (t) {
case ElementType.Boolean:
@@ -1113,6 +1201,61 @@ namespace Mono.Debugger.Soft
return this;
}
+ PacketWriter WriteFixedSizeValue (ValueImpl v) {
+ ElementType t;
+
+ if (v.Value != null)
+ t = TypeCodeToElementType (Type.GetTypeCode (v.Value.GetType ()), v.Value.GetType ());
+ else
+ t = v.Type;
+ WriteByte ((byte) ValueTypeId.VALUE_TYPE_ID_FIXED_ARRAY);
+ WriteByte ((byte)t);
+ WriteInt (v.FixedSize);
+ for (int j = 0 ; j < v.FixedSize; j++) {
+ switch (t) {
+ case ElementType.Boolean:
+ WriteInt (((bool[])v.Value)[j]? 1 : 0);
+ break;
+ case ElementType.Char:
+ WriteInt ((int)((char[])v.Value)[j]);
+ break;
+ case ElementType.I1:
+ WriteInt ((int)((sbyte[])v.Value)[j]);
+ break;
+ case ElementType.U1:
+ WriteInt ((int)((byte[])v.Value)[j]);
+ break;
+ case ElementType.I2:
+ WriteInt ((int)((short[])v.Value)[j]);
+ break;
+ case ElementType.U2:
+ WriteInt ((int)((ushort[])v.Value)[j]);
+ break;
+ case ElementType.I4:
+ WriteInt ((int)((int[])v.Value)[j]);
+ break;
+ case ElementType.U4:
+ WriteInt ((int)((uint[])v.Value)[j]);
+ break;
+ case ElementType.I8:
+ WriteLong ((long)((long[])v.Value)[j]);
+ break;
+ case ElementType.U8:
+ WriteLong ((long)((ulong[])v.Value)[j]);
+ break;
+ case ElementType.R4:
+ WriteFloat (((float[])v.Value)[j]);
+ break;
+ case ElementType.R8:
+ WriteDouble (((double[])v.Value)[j]);
+ break;
+ default:
+ throw new NotImplementedException ();
+ }
+ }
+ return this;
+ }
+
public PacketWriter WriteValues (ValueImpl[] values) {
for (int i = 0; i < values.Length; ++i)
WriteValue (values [i]);
@@ -1695,7 +1838,7 @@ namespace Mono.Debugger.Soft
return res;
}
- static ElementType TypeCodeToElementType (TypeCode c) {
+ static ElementType TypeCodeToElementType (TypeCode c, Type t) {
switch (c) {
case TypeCode.Boolean:
return ElementType.Boolean;
@@ -1721,6 +1864,8 @@ namespace Mono.Debugger.Soft
return ElementType.R4;
case TypeCode.Double:
return ElementType.R8;
+ case TypeCode.Object:
+ return TypeCodeToElementType(Type.GetTypeCode (t.GetElementType()), t.GetElementType());
default:
throw new NotImplementedException ();
}
diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs
index 38decd106e8..1998be6f279 100644
--- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs
+++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/FieldInfoMirror.cs
@@ -17,6 +17,7 @@ namespace Mono.Debugger.Soft
FieldAttributes attrs;
CustomAttributeDataMirror[] cattrs;
bool inited;
+ int len_fixed_size_array;
#if ENABLE_CECIL
C.FieldDefinition meta;
@@ -27,6 +28,7 @@ namespace Mono.Debugger.Soft
this.name = name;
this.type = type;
this.attrs = attrs;
+ this.len_fixed_size_array = -1;
inited = true;
}
@@ -162,6 +164,28 @@ namespace Mono.Debugger.Soft
}
}
+ public int FixedSize
+ {
+ get
+ {
+ if (len_fixed_size_array == -1) {
+ if (!vm.Version.AtLeast (2, 53) || !type.IsValueType) {
+ len_fixed_size_array = 0;
+ }
+ else {
+ var fbas = this.GetCustomAttributes (true);
+ for (int j = 0 ; j < fbas.Length; ++j) {
+ if (fbas [j].Constructor.DeclaringType.FullName.Equals("System.Runtime.CompilerServices.FixedBufferAttribute")){
+ len_fixed_size_array = (int) fbas [j].ConstructorArguments[1].Value;
+ break;
+ }
+ }
+ }
+ }
+ return len_fixed_size_array;
+ }
+ }
+
public CustomAttributeDataMirror[] GetCustomAttributes (bool inherit) {
return GetCAttrs (null, inherit);
}
diff --git a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
index 0bd77256a17..8cbe54a697c 100644
--- a/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
+++ b/mcs/class/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
@@ -724,7 +724,32 @@ namespace Mono.Debugger.Soft
return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
duplicates.Add (v);
- return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields, duplicates) };
+ return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeFieldValues ((v as StructMirror).Fields, (v as StructMirror).Type.GetFields (), duplicates, 1) };
+ } else if (v is PointerValue) {
+ PointerValue val = (PointerValue)v;
+ return new ValueImpl { Type = ElementType.Ptr, Klass = val.Type.Id, Value = val.Address };
+ } else {
+ throw new NotSupportedException ("Value of type " + v.GetType());
+ }
+ }
+
+ internal ValueImpl EncodeValueFixedSize (Value v, List<Value> duplicates, int len_fixed_size) {
+ if (v is PrimitiveValue) {
+ object val = (v as PrimitiveValue).Value;
+ if (val == null)
+ return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
+ else
+ return new ValueImpl { Value = val , FixedSize = len_fixed_size};
+ } else if (v is ObjectMirror) {
+ return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
+ } else if (v is StructMirror) {
+ if (duplicates == null)
+ duplicates = new List<Value> ();
+ if (duplicates.Contains (v))
+ return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
+ duplicates.Add (v);
+
+ return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeFieldValues ((v as StructMirror).Fields, (v as StructMirror).Type.GetFields (), duplicates, len_fixed_size) };
} else if (v is PointerValue) {
PointerValue val = (PointerValue)v;
return new ValueImpl { Type = ElementType.Ptr, Klass = val.Type.Id, Value = val.Address };
@@ -740,6 +765,17 @@ namespace Mono.Debugger.Soft
return res;
}
+ internal ValueImpl[] EncodeFieldValues (IList<Value> values, FieldInfoMirror[] field_info, List<Value> duplicates, int fixedSize) {
+ ValueImpl[] res = new ValueImpl [values.Count];
+ for (int i = 0; i < values.Count; ++i) {
+ if (fixedSize > 1 || field_info [i].FixedSize > 1)
+ res [i] = EncodeValueFixedSize (values [i], duplicates, fixedSize > 1 ? fixedSize : field_info [i].FixedSize);
+ else
+ res [i] = EncodeValue (values [i], duplicates);
+ }
+ return res;
+ }
+
internal void CheckProtocolVersion (int major, int minor) {
if (!conn.Version.AtLeast (major, minor))
throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
index bf560421bd2..360d114a4a7 100644
--- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
+++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
@@ -174,6 +174,83 @@ public struct AStruct : ITest2 {
}
}
+public struct int4
+{
+ public int w, x, y, z;
+
+ public int4(int w, int x, int y, int z)
+ {
+ this.w = w;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+}
+
+
+public struct char4
+{
+ public int w, x, y, z;
+
+ public char4(char w, char x, char y, char z)
+ {
+ this.w = w;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+}
+
+public unsafe struct NodeTestFixedArray
+{
+ private fixed short buffer[4];
+ private fixed char buffer2[4];
+
+ public int4 Buffer
+ {
+ set
+ {
+ this.buffer[0] = (short)value.w;
+ this.buffer[1] = (short)value.x;
+ this.buffer[2] = (short)value.y;
+ this.buffer[3] = (short)value.z;
+ }
+ }
+ public char4 Buffer2
+ {
+ set
+ {
+ this.buffer2[0] = (char)value.w;
+ this.buffer2[1] = (char)value.x;
+ this.buffer2[2] = (char)value.y;
+ this.buffer2[3] = (char)value.z;
+ }
+ }
+ public String getBuffer0() {
+ return Convert.ToString(this.buffer[0]);
+ }
+ public String getBuffer1() {
+ return Convert.ToString(this.buffer[1]);
+ }
+ public String getBuffer2() {
+ return Convert.ToString(this.buffer[2]);
+ }
+ public String getBuffer3() {
+ return Convert.ToString(this.buffer[3]);
+ }
+ public String getBuffer2_0() {
+ return Char.ToString(this.buffer2[0]);
+ }
+ public String getBuffer2_1() {
+ return Char.ToString(this.buffer2[1]);
+ }
+ public String getBuffer2_2() {
+ return Char.ToString(this.buffer2[2]);
+ }
+ public String getBuffer2_3() {
+ return Char.ToString(this.buffer2[3]);
+ }
+}
public struct BlittableStruct {
public int i;
@@ -494,6 +571,7 @@ public class Tests : TestsBase, ITest2
field_with_unsafe_cast_value();
inspect_enumerator_in_generic_struct();
if_property_stepping();
+ fixed_size_array();
return 3;
}
@@ -731,6 +809,13 @@ public class Tests : TestsBase, ITest2
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void fixed_size_array () {
+ var n = new NodeTestFixedArray();
+ n.Buffer = new int4(1, 2, 3, 4);
+ n.Buffer2 = new char4('a', 'b', 'c', 'd');
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void inspect_enumerator_in_generic_struct() {
TestEnumeratorInsideGenericStruct<String, String> generic_struct = new TestEnumeratorInsideGenericStruct<String, String>(new KeyValuePair<string, string>("0", "f1"));
}
diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs
index aa5fd2fe58e..75967555e6b 100644
--- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs
+++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs
@@ -5044,6 +5044,48 @@ public class DebuggerTests
ShouldNotSendUnexpectedTypeLoadEventsAndInvalidSuspendPolicyAfterAttach (port);
}
+
+ [Test]
+ public void InvokeMethodFixedArray () {
+ Event e = run_until ("fixed_size_array");
+ var req = create_step (e);
+ req.Enable ();
+ step_once ();
+ step_over ();
+ step_over ();
+ var bp = step_over ();
+ var thread = bp.Thread;
+ var frame = thread.GetFrames()[0];
+
+ var local = frame.GetVisibleVariableByName("n");
+ var n = (StructMirror)frame.GetValue(local);
+ var get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer0");
+ var min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("1", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer1");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("2", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer2");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("3", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer3");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("4", min.Value);
+
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer2_0");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("a", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer2_1");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("b", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer2_2");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("c", min.Value);
+ get_Min = n.Type.GetMethods().First(m => m.Name == "getBuffer2_3");
+ min = (StringMirror) n.InvokeMethod(thread, get_Min, Array.Empty<Value>());
+ Assert.AreEqual("d", min.Value);
+ }
+
#endif
} // class DebuggerTests
} // namespace