diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs index 27b3e38c0caf64..a79dc376d7506c 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs @@ -418,32 +418,28 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, EndLocation = new SourceLocation(this, end); DebuggerAttrInfo = new DebuggerAttributesInfo(); - foreach (var cattr in methodDef.GetCustomAttributes()) + foreach (CustomAttributeHandle cattr in methodDef.GetCustomAttributes()) { - var ctorHandle = asmMetadataReader.GetCustomAttribute(cattr).Constructor; - if (ctorHandle.Kind == HandleKind.MemberReference) - { - var container = asmMetadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent; - var name = assembly.EnCGetString(asmMetadataReader.GetTypeReference((TypeReferenceHandle)container).Name); - switch (name) - { - case "DebuggerHiddenAttribute": - DebuggerAttrInfo.HasDebuggerHidden = true; - break; - case "DebuggerStepThroughAttribute": - DebuggerAttrInfo.HasStepThrough = true; - break; - case "DebuggerNonUserCodeAttribute": - DebuggerAttrInfo.HasNonUserCode = true; - break; - case "DebuggerStepperBoundaryAttribute": - DebuggerAttrInfo.HasStepperBoundary = true; - break; - case nameof(CompilerGeneratedAttribute): - IsCompilerGenerated = true; - break; - } + if (!assembly.TryGetCustomAttributeName(cattr, asmMetadataReader, out string name)) + continue; + switch (name) + { + case "DebuggerHiddenAttribute": + DebuggerAttrInfo.HasDebuggerHidden = true; + break; + case "DebuggerStepThroughAttribute": + DebuggerAttrInfo.HasStepThrough = true; + break; + case "DebuggerNonUserCodeAttribute": + DebuggerAttrInfo.HasNonUserCode = true; + break; + case "DebuggerStepperBoundaryAttribute": + DebuggerAttrInfo.HasStepperBoundary = true; + break; + case nameof(CompilerGeneratedAttribute): + IsCompilerGenerated = true; + break; } } DebuggerAttrInfo.ClearInsignificantAttrFlags(); @@ -795,13 +791,10 @@ internal TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDe } } - foreach (var cattr in type.GetCustomAttributes()) + foreach (CustomAttributeHandle cattr in type.GetCustomAttributes()) { - var ctorHandle = metadataReader.GetCustomAttribute(cattr).Constructor; - if (ctorHandle.Kind != HandleKind.MemberReference) + if (!assembly.TryGetCustomAttributeName(cattr, metadataReader, out string attributeName)) continue; - var container = metadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent; - var attributeName = assembly.EnCGetString(metadataReader.GetTypeReference((TypeReferenceHandle)container).Name); switch (attributeName) { case nameof(CompilerGeneratedAttribute): @@ -921,6 +914,33 @@ public unsafe AssemblyInfo(MonoProxy monoProxy, SessionId sessionId, string url, Populate(); } + public bool TryGetCustomAttributeName(CustomAttributeHandle customAttribute, MetadataReader metadataReader, out string name) + { + name = ""; + EntityHandle ctorHandle = metadataReader.GetCustomAttribute(customAttribute).Constructor; + if (ctorHandle.Kind != HandleKind.MemberReference) + return false; + EntityHandle? container = ctorHandle.Kind switch + { + HandleKind.MethodDefinition => metadataReader.GetMethodDefinition((MethodDefinitionHandle)ctorHandle).GetDeclaringType(), + HandleKind.MemberReference => metadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent, + _ => null, + }; + if (container == null) + return false; + StringHandle? attributeTypeNameHandle = container.Value.Kind switch + { + HandleKind.TypeDefinition => metadataReader.GetTypeDefinition((TypeDefinitionHandle)container.Value).Name, + HandleKind.TypeReference => metadataReader.GetTypeReference((TypeReferenceHandle)container.Value).Name, + HandleKind.TypeSpecification => null, // custom generic attributes, TypeSpecification does not keep the attribute name for them + _ => null, + }; + if (attributeTypeNameHandle == null) + return false; + name = EnCGetString(attributeTypeNameHandle.Value); + return true; + } + public async Task GetDebugId(MonoSDBHelper sdbAgent, CancellationToken token) { if (debugId > 0) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index ee626ee4c9f6fa..0c94c171d1d858 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -1042,13 +1042,19 @@ await EvaluateAndCheck( ); } - [Theory] + [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("ClassInheritsFromClassWithoutDebugSymbols", 1287, true)] [InlineData("ClassInheritsFromClassWithoutDebugSymbols", 1287, false)] [InlineData("ClassInheritsFromNonUserCodeClass", 1335, true)] [InlineData("ClassInheritsFromNonUserCodeClass", 1335, false)] [InlineData("ClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1352, true)] [InlineData("ClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1352, false)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols", 1390, true)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols", 1390, false)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass", 1407, true)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass", 1407, false)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1425, true)] + [InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1425, false)] public async Task InspectThisThatInheritsFromClassNonUserCode(string class_name, int line, bool jmc) { await SetJustMyCode(jmc); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 5e30c999b3304d..cf7be308718a32 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -1371,4 +1371,60 @@ public static void CheckArguments(ReadOnlySpan parameters) { System.Diagnostics.Debugger.Break(); } +} +[AttributeUsage(AttributeTargets.Class)] +public sealed class CustomAttribute : Attribute +{ +} + +[Custom] +public class GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols : DebuggerTests.ClassWithoutDebugSymbolsToInherit +{ + public static void Run() + { + var myVar = new GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols(); + myVar.CallMethod(); + } + + public void CallMethod() + { + System.Diagnostics.Debugger.Break(); + } + public int myField2; + public int myField; +} + +[Custom] +public class GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass : ClassNonUserCodeToInherit +{ + public static void Run() + { + var myVar = new GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass(); + myVar.CallMethod(); + } + + public void CallMethod() + { + System.Diagnostics.Debugger.Break(); + } + + public int myField2; + public int myField; +} + +[Custom] +public class GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass : DebuggerTests.ClassNonUserCodeToInheritThatInheritsFromNormalClass +{ + public static void Run() + { + var myVar = new GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass(); + myVar.CallMethod(); + } + + public void CallMethod() + { + System.Diagnostics.Debugger.Break(); + } + + public int myField; } \ No newline at end of file