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)
}
}
- 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):
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)
}
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;
[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);
}
}
+[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;
+}