diff options
author | Thays Grazia <thaystg@gmail.com> | 2019-08-02 16:47:25 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-08-02 16:47:25 +0300 |
commit | 3a9df67a64c129fa3c5c32334c231739965f1efb (patch) | |
tree | 6f232b35edbe12b9052b2b89adc8d83d37536c74 /mcs/class/Mono.Debugger.Soft | |
parent | 4883b56c10a077e4c82feff604172d6994994e1a (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')
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 |