From 71ad38f74918b71b2793469f28c6129c268ae577 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:59:36 -0800 Subject: [PATCH 1/3] Change AttributeAttribute Name field to a Type field --- .../Contexts/ReferencedTypeAnalysisContext.cs | 3 +- .../Model/Contexts/SystemTypesContext.cs | 50 ++++++++++++++++++- .../Model/Contexts/TypeAnalysisContext.cs | 20 ++++++++ .../CustomAttributeTypeParameter.cs | 37 +++++++++----- .../InjectedCustomAttributeTypeParameter.cs | 19 ------- .../AttributeInjectorProcessingLayer.cs | 10 ++-- Cpp2IL.Core/Utils/AttributeInjectionUtils.cs | 4 +- LibCpp2IL/LibCpp2IlUtils.cs | 47 ++++++++--------- 8 files changed, 126 insertions(+), 64 deletions(-) delete mode 100644 Cpp2IL.Core/Model/CustomAttributes/InjectedCustomAttributeTypeParameter.cs diff --git a/Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs index b7fc8758..d0a8a946 100644 --- a/Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs @@ -1,3 +1,4 @@ +using System; using LibCpp2IL.BinaryStructures; namespace Cpp2IL.Core.Model.Contexts; @@ -8,7 +9,7 @@ namespace Cpp2IL.Core.Model.Contexts; public abstract class ReferencedTypeAnalysisContext(AssemblyAnalysisContext referencedFrom) : TypeAnalysisContext(null, referencedFrom) { - public abstract Il2CppTypeEnum Type { get; } //Must be set by derived classes + public override Il2CppTypeEnum Type => throw new NotImplementedException("Type must be set by derived classes"); protected override int CustomAttributeIndex => -1; diff --git a/Cpp2IL.Core/Model/Contexts/SystemTypesContext.cs b/Cpp2IL.Core/Model/Contexts/SystemTypesContext.cs index c5745b9c..11653999 100644 --- a/Cpp2IL.Core/Model/Contexts/SystemTypesContext.cs +++ b/Cpp2IL.Core/Model/Contexts/SystemTypesContext.cs @@ -1,4 +1,6 @@ -namespace Cpp2IL.Core.Model.Contexts; +using LibCpp2IL.BinaryStructures; + +namespace Cpp2IL.Core.Model.Contexts; public class SystemTypesContext { @@ -84,4 +86,50 @@ public bool IsPrimitive(TypeAnalysisContext context) context == SystemIntPtrType || context == SystemUIntPtrType; } + + public bool TryGetIl2CppTypeEnum(TypeAnalysisContext context, out Il2CppTypeEnum value) + { + if (context == SystemBooleanType) + value = Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN; + else if (context == SystemCharType) + value = Il2CppTypeEnum.IL2CPP_TYPE_CHAR; + else if (context == SystemSByteType) + value = Il2CppTypeEnum.IL2CPP_TYPE_I1; + else if (context == SystemByteType) + value = Il2CppTypeEnum.IL2CPP_TYPE_U1; + else if (context == SystemInt16Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_I2; + else if (context == SystemUInt16Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_U2; + else if (context == SystemInt32Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_I4; + else if (context == SystemUInt32Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_U4; + else if (context == SystemInt64Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_I8; + else if (context == SystemUInt64Type) + value = Il2CppTypeEnum.IL2CPP_TYPE_U8; + else if (context == SystemSingleType) + value = Il2CppTypeEnum.IL2CPP_TYPE_R4; + else if (context == SystemDoubleType) + value = Il2CppTypeEnum.IL2CPP_TYPE_R8; + else if (context == SystemIntPtrType) + value = Il2CppTypeEnum.IL2CPP_TYPE_I; + else if (context == SystemUIntPtrType) + value = Il2CppTypeEnum.IL2CPP_TYPE_U; + else if (context == SystemStringType) + value = Il2CppTypeEnum.IL2CPP_TYPE_STRING; + else if (context == SystemTypedReferenceType) + value = Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF; + else if (context == SystemObjectType) + value = Il2CppTypeEnum.IL2CPP_TYPE_OBJECT; + else if (context == SystemVoidType) + value = Il2CppTypeEnum.IL2CPP_TYPE_VOID; + else + { + value = default; + return false; + } + return true; + } } diff --git a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs index a4e2ed81..124ee483 100644 --- a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs @@ -92,6 +92,26 @@ public bool IsPrimitive } } + public virtual Il2CppTypeEnum Type + { + get + { + if (Definition is { RawBaseType: not null }) + return Definition.RawBaseType.Type; + + if (AppContext.SystemTypes.TryGetIl2CppTypeEnum(this, out var value)) + return value; + + if (IsEnumType) + return Il2CppTypeEnum.IL2CPP_TYPE_ENUM; + + if (IsValueType) + return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE; + + return Il2CppTypeEnum.IL2CPP_TYPE_CLASS; + } + } + public string FullName { get diff --git a/Cpp2IL.Core/Model/CustomAttributes/CustomAttributeTypeParameter.cs b/Cpp2IL.Core/Model/CustomAttributes/CustomAttributeTypeParameter.cs index 0794037a..fe94110f 100644 --- a/Cpp2IL.Core/Model/CustomAttributes/CustomAttributeTypeParameter.cs +++ b/Cpp2IL.Core/Model/CustomAttributes/CustomAttributeTypeParameter.cs @@ -12,13 +12,25 @@ namespace Cpp2IL.Core.Model.CustomAttributes; /// public class CustomAttributeTypeParameter : BaseCustomAttributeTypeParameter { - public Il2CppType? Type; + private Il2CppType? _type; + private TypeAnalysisContext? _typeContext; - public override TypeAnalysisContext? TypeContext => Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type); + public override TypeAnalysisContext? TypeContext + { + get + { + return _typeContext ??= Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(_type); + } + } public CustomAttributeTypeParameter(Il2CppType? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) { - Type = type; + _type = type; + } + + public CustomAttributeTypeParameter(TypeAnalysisContext? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) + { + _typeContext = type; } public CustomAttributeTypeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index) @@ -29,29 +41,28 @@ public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisCon { var typeIndex = reader.BaseStream.ReadUnityCompressedInt(); if (typeIndex == -1) - Type = null; + _type = null; else { - Type = context.Binary.GetType(typeIndex); + _type = context.Binary.GetType(typeIndex); } + _typeContext = null; } public override string ToString() { - if (Type == null) + if (TypeContext == null) return "(Type) null"; - if (Type.Type.IsIl2CppPrimitive()) - return $"typeof({LibCpp2ILUtils.GetTypeName(Owner.Constructor.AppContext.Metadata, Owner.Constructor.AppContext.Binary, Type)}"; + if (TypeContext.IsPrimitive) + return $"typeof({LibCpp2ILUtils.GetTypeName(TypeContext.Type)}"; - if (Type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE) + if (TypeContext is ReferencedTypeAnalysisContext) { - //Some sort of wrapper type, like a generic parameter or a generic instance. - var typeContext = Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type); - return $"typeof({typeContext.GetCSharpSourceString()})"; + return $"typeof({TypeContext.GetCSharpSourceString()})"; } //Basic class/struct - return $"typeof({Type.AsClass().Name})"; + return $"typeof({TypeContext.Name})"; } } diff --git a/Cpp2IL.Core/Model/CustomAttributes/InjectedCustomAttributeTypeParameter.cs b/Cpp2IL.Core/Model/CustomAttributes/InjectedCustomAttributeTypeParameter.cs deleted file mode 100644 index 826b647e..00000000 --- a/Cpp2IL.Core/Model/CustomAttributes/InjectedCustomAttributeTypeParameter.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.IO; -using Cpp2IL.Core.Model.Contexts; - -namespace Cpp2IL.Core.Model.CustomAttributes; - -/// -/// Represents an injected for a . -/// -public class InjectedCustomAttributeTypeParameter( - TypeAnalysisContext? type, - AnalyzedCustomAttribute owner, - CustomAttributeParameterKind kind, - int index) - : BaseCustomAttributeTypeParameter(owner, kind, index) -{ - public override TypeAnalysisContext? TypeContext { get; } = type; - - public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisContext context) => throw new System.NotSupportedException(); -} diff --git a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs index c5c7d455..89a75fe1 100644 --- a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs @@ -154,7 +154,7 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte var attributeAttributes = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "AttributeAttribute", appContext.SystemTypes.SystemAttributeType); - var attributeNameFields = attributeAttributes.InjectFieldToAllAssemblies("Name", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); + var attributeTypeFields = attributeAttributes.InjectFieldToAllAssemblies("Type", appContext.SystemTypes.SystemTypeType, FieldAttributes.Public); var attributeRvaFields = attributeAttributes.InjectFieldToAllAssemblies("RVA", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); var attributeOffsetFields = attributeAttributes.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); @@ -162,7 +162,7 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte foreach (var assemblyAnalysisContext in appContext.Assemblies) { - var nameField = attributeNameFields[assemblyAnalysisContext]; + var typeField = attributeTypeFields[assemblyAnalysisContext]; var rvaField = attributeRvaFields[assemblyAnalysisContext]; var offsetField = attributeOffsetFields[assemblyAnalysisContext]; @@ -176,11 +176,11 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte .Append(ctx)) .Append(assemblyAnalysisContext); - MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, nameField, rvaField, offsetField, attributeConstructor)); + MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, typeField, rvaField, offsetField, attributeConstructor)); } } - private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext nameField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor) + private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext typeField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor) { if (_useEzDiffMode) context.CustomAttributes = []; @@ -210,7 +210,7 @@ private static void ProcessCustomAttributesForContext(HasCustomAttributes contex offsetInBinary = 0; //Add the 3 fields to the replacement attribute - replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 0))); + replacementAttribute.Fields.Add(new(typeField, new CustomAttributeTypeParameter(attribute.Constructor.DeclaringType, replacementAttribute, CustomAttributeParameterKind.Field, 0))); replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 1))); replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2))); diff --git a/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs b/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs index 6efc642e..511c6098 100644 --- a/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs +++ b/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs @@ -181,8 +181,8 @@ private static BaseCustomAttributeParameter MakeCustomAttributeParameter(object? return value switch { Il2CppType type => new CustomAttributeTypeParameter(type, owner, parameterKind, index), - TypeAnalysisContext type => new InjectedCustomAttributeTypeParameter(type, owner, parameterKind, index), - TypeAnalysisContext?[] types => new CustomAttributeArrayParameter(owner, parameterKind, index) { ArrType = Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX, ArrayElements = types.Select(t => (BaseCustomAttributeParameter)new InjectedCustomAttributeTypeParameter(t, owner, CustomAttributeParameterKind.ArrayElement, index)).ToList() }, + TypeAnalysisContext type => new CustomAttributeTypeParameter(type, owner, parameterKind, index), + TypeAnalysisContext?[] types => new CustomAttributeArrayParameter(owner, parameterKind, index) { ArrType = Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX, ArrayElements = types.Select(t => (BaseCustomAttributeParameter)new CustomAttributeTypeParameter(t, owner, CustomAttributeParameterKind.ArrayElement, index)).ToList() }, object?[] objects => new CustomAttributeArrayParameter(owner, parameterKind, index) { ArrType = Il2CppTypeEnum.IL2CPP_TYPE_OBJECT, diff --git a/LibCpp2IL/LibCpp2IlUtils.cs b/LibCpp2IL/LibCpp2IlUtils.cs index 42edd915..b5e6e9d6 100644 --- a/LibCpp2IL/LibCpp2IlUtils.cs +++ b/LibCpp2IL/LibCpp2IlUtils.cs @@ -11,28 +11,6 @@ namespace LibCpp2IL; public static class LibCpp2ILUtils { - private static readonly Dictionary TypeString = new Dictionary - { - { 1, "void" }, - { 2, "bool" }, - { 3, "char" }, - { 4, "sbyte" }, - { 5, "byte" }, - { 6, "short" }, - { 7, "ushort" }, - { 8, "int" }, - { 9, "uint" }, - { 10, "long" }, - { 11, "ulong" }, - { 12, "float" }, - { 13, "double" }, - { 14, "string" }, - { 22, "TypedReference" }, - { 24, "IntPtr" }, - { 25, "UIntPtr" }, - { 28, "object" } - }; - private static readonly Dictionary PrimitiveSizes = new() { { "Byte", 1 }, @@ -51,6 +29,29 @@ public static class LibCpp2ILUtils { "UIntPtr", 8 }, }; + public static string GetTypeName(Il2CppTypeEnum type) => (int)type switch + { + 1 => "void", + 2 => "bool", + 3 => "char", + 4 => "sbyte", + 5 => "byte", + 6 => "short", + 7 => "ushort", + 8 => "int", + 9 => "uint", + 10 => "long", + 11 => "ulong", + 12 => "float", + 13 => "double", + 14 => "string", + 22 => "TypedReference", + 24 => "IntPtr", + 25 => "UIntPtr", + 28 => "object", + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; + internal static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssembly, Il2CppTypeDefinition typeDef, bool fullName = false) { var ret = string.Empty; @@ -159,7 +160,7 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb break; } default: - ret = TypeString[(int)type.Type]; + ret = GetTypeName(type.Type); break; } From 7ef7558b258aa3bfce9f9005585d457159c3f432 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:58:35 -0800 Subject: [PATCH 2/3] Revert removal of Name field --- .../AttributeInjectorProcessingLayer.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs index 89a75fe1..e4d1f51e 100644 --- a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs @@ -155,6 +155,7 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte var attributeAttributes = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "AttributeAttribute", appContext.SystemTypes.SystemAttributeType); var attributeTypeFields = attributeAttributes.InjectFieldToAllAssemblies("Type", appContext.SystemTypes.SystemTypeType, FieldAttributes.Public); + var attributeNameFields = attributeAttributes.InjectFieldToAllAssemblies("Name", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); var attributeRvaFields = attributeAttributes.InjectFieldToAllAssemblies("RVA", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); var attributeOffsetFields = attributeAttributes.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public); @@ -162,7 +163,10 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte foreach (var assemblyAnalysisContext in appContext.Assemblies) { + // Todo: Remove nameField because typeField makes it redundant. It only remains for backwards compatibility with Il2CppInterop. + // https://github.com/BepInEx/Il2CppInterop/blob/9d4599dc78d69ede49a2ee96a1ccf41eec02db5b/Il2CppInterop.Generator/Passes/Pass70GenerateProperties.cs#L46 var typeField = attributeTypeFields[assemblyAnalysisContext]; + var nameField = attributeNameFields[assemblyAnalysisContext]; var rvaField = attributeRvaFields[assemblyAnalysisContext]; var offsetField = attributeOffsetFields[assemblyAnalysisContext]; @@ -176,11 +180,11 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte .Append(ctx)) .Append(assemblyAnalysisContext); - MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, typeField, rvaField, offsetField, attributeConstructor)); + MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, typeField, nameField, rvaField, offsetField, attributeConstructor)); } } - private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext typeField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor) + private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext typeField, FieldAnalysisContext nameField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor) { if (_useEzDiffMode) context.CustomAttributes = []; @@ -211,8 +215,9 @@ private static void ProcessCustomAttributesForContext(HasCustomAttributes contex //Add the 3 fields to the replacement attribute replacementAttribute.Fields.Add(new(typeField, new CustomAttributeTypeParameter(attribute.Constructor.DeclaringType, replacementAttribute, CustomAttributeParameterKind.Field, 0))); - replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 1))); - replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2))); + replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 1))); + replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2))); + replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 3))); //Replace the original attribute with the replacement attribute context.CustomAttributes[index] = replacementAttribute; From b9caa35d083d36492fcfcfb33b804d09781e1597 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:07:04 -0800 Subject: [PATCH 3/3] Make the name field last --- .../ProcessingLayers/AttributeInjectorProcessingLayer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs index e4d1f51e..7a67dbf8 100644 --- a/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs @@ -215,9 +215,9 @@ private static void ProcessCustomAttributesForContext(HasCustomAttributes contex //Add the 3 fields to the replacement attribute replacementAttribute.Fields.Add(new(typeField, new CustomAttributeTypeParameter(attribute.Constructor.DeclaringType, replacementAttribute, CustomAttributeParameterKind.Field, 0))); - replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 1))); - replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2))); - replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 3))); + replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 1))); + replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2))); + replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 3))); //Replace the original attribute with the replacement attribute context.CustomAttributes[index] = replacementAttribute;