Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 50 additions & 29 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,31 +389,28 @@ public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle,
this.IsEnCMethod = false;
this.TypeInfo = type;
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)
if (!assembly.TryGetCustomAttributeName(cattr, asmMetadataReader, out string name))
continue;

switch (name)
{
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;
}
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 (!hasDebugInformation)
Expand Down Expand Up @@ -788,13 +785,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):
Expand Down Expand Up @@ -945,6 +939,33 @@ private unsafe AssemblyInfo(IDisposable owningReader, string name, MetadataReade
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<int> GetDebugId(MonoSDBHelper sdbAgent, CancellationToken token)
{
if (debugId > 0)
Expand Down Expand Up @@ -1602,7 +1623,7 @@ public async IAsyncEnumerable<SourceFile> Load(SessionId id, string[] loaded_fil
}
catch (Exception e)
{
logger.LogError($"Failed to load {step.Url} ({e.Message})");
logger.LogError($"Failed to load {step.Url} ({e.Message}) (stack={e.StackTrace})");
}
if (assembly == null)
continue;
Expand Down
6 changes: 6 additions & 0 deletions src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,12 @@ await EvaluateAndCheck(
[InlineData("ClassInheritsFromNonUserCodeClass", 1335, false)]
[InlineData("ClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1352, true)]
[InlineData("ClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1352, false)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols", 1618, true)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols", 1618, false)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass", 1635, true)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass", 1635, false)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1653, true)]
[InlineData("GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass", 1653, false)]
public async Task InspectThisThatInheritsFromClassNonUserCode(string class_name, int line, bool jmc)
{
await SetJustMyCode(jmc);
Expand Down
56 changes: 56 additions & 0 deletions src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1600,3 +1600,59 @@ static void Write(string input)
}
}

[AttributeUsage(AttributeTargets.Class)]
public sealed class CustomAttribute<TInterface> : Attribute
{
}

[Custom<GenericCustomAttributeDecoratedClassInheritsFromClassWithoutDebugSymbols>]
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<GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClass>]
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<GenericCustomAttributeDecoratedClassInheritsFromNonUserCodeClassThatInheritsFromNormalClass>]
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;
}