Ejemplo n.º 1
0
 public int GetHashCode(RawTypeDefRow obj) =>
 (int)obj.Flags +
 rol(obj.Name, 3) +
 rol(obj.Namespace, 7) +
 rol(obj.Extends, 11) +
 rol(obj.FieldList, 15) +
 rol(obj.MethodList, 19);
Ejemplo n.º 2
0
 public bool Equals(RawTypeDefRow x, RawTypeDefRow y) =>
 x.Flags == y.Flags &&
 x.Name == y.Name &&
 x.Namespace == y.Namespace &&
 x.Extends == y.Extends &&
 x.FieldList == y.FieldList &&
 x.MethodList == y.MethodList;
Ejemplo n.º 3
0
        void DeleteTypeDef(MetadataEditor mdEditor, TypeDef nonNestedTypeDef)
        {
            Debug.Assert(nonNestedTypeDef.DeclaringType == null);

            var dict = new Dictionary <TypeDef, (TypeDef Type, uint TypeRefRid, RawTypeRefRow TypeRefRow)>();

            foreach (var type in MDPatcherUtils.GetMetadataTypes(nonNestedTypeDef))
            {
                var typeRefRid = mdEditor.TablesHeap.TypeRefTable.Create();
                remappedTypeTokens.Add(type.MDToken.Raw, new MDToken(Table.TypeRef, typeRefRid).Raw);

                // Remove the type by renaming it and making it private/internal
                var tdRow = mdEditor.TablesHeap.TypeDefTable.Get(type.Rid);
                var flags = tdRow.Flags;
                if ((flags & 7) <= 1)
                {
                    flags = flags & ~7U;                                // NotPublic
                }
                else
                {
                    flags = (flags & ~7U) | 3;                      // NestedPrivate
                }
                var deletedType = (Type : type, TypeRefRid : typeRefRid, TypeRefRow : new RawTypeRefRow(0, tdRow.Name, tdRow.Namespace));
                tdRow = new RawTypeDefRow(flags, mdEditor.StringsHeap.Create(Guid.NewGuid().ToString()), mdEditor.StringsHeap.Create(string.Empty), tdRow.Extends, tdRow.FieldList, tdRow.MethodList);
                mdEditor.TablesHeap.TypeDefTable.Set(type.Rid, ref tdRow);
                dict.Add(type, deletedType);
            }
            remappedTypeTokens.SetReadOnly();

            foreach (var kv in dict)
            {
                var  deletedType = kv.Value;
                uint resolutionScope;
                if (deletedType.Type.DeclaringType != null)
                {
                    var declType = dict[deletedType.Type.DeclaringType];
                    resolutionScope = CodedToken.ResolutionScope.Encode(new MDToken(Table.TypeRef, declType.TypeRefRid));
                }
                else
                {
                    resolutionScope = CodedToken.ResolutionScope.Encode(new MDToken(Table.AssemblyRef, GetOrCreateTempAssemblyRid()));
                }
                deletedType.TypeRefRow = new RawTypeRefRow(resolutionScope, deletedType.TypeRefRow.Name, deletedType.TypeRefRow.Namespace);
                mdEditor.TablesHeap.TypeRefTable.Set(deletedType.TypeRefRid, ref deletedType.TypeRefRow);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Reads a raw <c>TypeDef</c> row or returns false if the row doesn't exist
        /// </summary>
        /// <param name="rid">Row ID</param>
        /// <param name="row">Row data</param>
        /// <returns></returns>
        public bool TryReadTypeDefRow(uint rid, out RawTypeDefRow row)
        {
            var table = TypeDefTable;

            if (table.IsInvalidRID(rid))
            {
                row = default;
                return(false);
            }
            var reader = table.DataReader;

            reader.Position = (rid - 1) * (uint)table.TableInfo.RowSize;
            row             = new RawTypeDefRow(
                reader.Unsafe_ReadUInt32(),
                table.Column1.Unsafe_Read24(ref reader),
                table.Column2.Unsafe_Read24(ref reader),
                table.Column3.Unsafe_Read24(ref reader),
                table.Column4.Unsafe_Read24(ref reader),
                table.Column5.Unsafe_Read24(ref reader));
            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Patches all columns and blob signatures that reference a moved TypeDef so they reference the new TypeRef
        /// </summary>
        void PatchTypeTokenReferences(TypeDef nonNestedEditedType)
        {
            if (remappedTypeTokens.Count == 0)
            {
                return;
            }

            // NOTE: We don't patch the following:
            //	- Method bodies
            //	- All MemberRefs referenced by method bodies
            //	- StandAloneSig.Signature. It's only used by method bodies
            //	- MethodSpec.Instantiation. It's only used by method bodies
            //	- Custom attribute blobs. Could reference the edited type but not likely to cause a problem.
            //	- Marshal blobs. Could reference the edited type but not likely to cause a problem.
            //	  The MD writer doesn't write the FieldMarshal table.

            var tablesHeap = mdEditor.TablesHeap;

            var typeSigDict     = new Dictionary <uint, uint>();
            var callConvSigDict = new Dictionary <uint, uint>();

            MDTable    table;
            byte *     p;
            int        rowSize;
            ColumnInfo column, column2;
            uint       i, codedToken, newToken, sig, newSig, rid;
            MDToken    token;

            // Patch the TypeDef table
            {
                table   = mdEditor.RealMetadata.TablesStream.TypeDefTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[3];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                    {
                        var row = tablesHeap.TypeDefTable.Get(i + 1);
                        row = new RawTypeDefRow(row.Flags, row.Name, row.Namespace, CodedToken.TypeDefOrRef.Encode(newToken), row.FieldList, row.MethodList);
                        tablesHeap.TypeDefTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the Field table
            {
                table   = mdEditor.RealMetadata.TablesStream.FieldTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[2];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    sig    = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    newSig = PatchCallingConventionSignature(callConvSigDict, sig);
                    if (newSig != sig)
                    {
                        var row = tablesHeap.FieldTable.Get(i + 1);
                        row = new RawFieldRow(row.Flags, row.Name, newSig);
                        tablesHeap.FieldTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the Method table
            {
                table   = mdEditor.RealMetadata.TablesStream.MethodTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[4];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    sig    = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    newSig = PatchCallingConventionSignature(callConvSigDict, sig);
                    if (newSig != sig)
                    {
                        var row = tablesHeap.MethodTable.Get(i + 1);
                        row = new RawMethodRow(row.RVA, row.ImplFlags, row.Flags, row.Name, newSig, row.ParamList);
                        tablesHeap.MethodTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the InterfaceImpl table
            {
                table   = mdEditor.RealMetadata.TablesStream.InterfaceImplTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[1];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                    {
                        var row = tablesHeap.InterfaceImplTable.Get(i + 1);
                        row = new RawInterfaceImplRow(row.Class, CodedToken.TypeDefOrRef.Encode(newToken));
                        tablesHeap.InterfaceImplTable.Set(i + 1, ref row);
                    }
                }
            }

            //TODO: PERF: If needed, this table could mostly be skipped. We only need to update refs from:
            //			CustomAttribute.Type, MethodImpl.MethodBody, MethodImpl.MethodDeclaration
            //		CustomAttribute.Type almost never references the edited type, and if it does, the
            //		edited type, or any of its nested types, is an attribute. Quick test: this block
            //		took ~25% of the total time (patch file, write new MD, test file was dnSpy.exe = 3.3MB).
            // Patch the MemberRef table
            {
                table   = mdEditor.RealMetadata.TablesStream.MemberRefTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[0];
                column2 = table.Columns[2];
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.MemberRefParent.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    rid = i + 1;
                    RawMemberRefRow row;
                    switch (token.Table)
                    {
                    case Table.TypeRef:
                    case Table.TypeDef:
                    case Table.TypeSpec:
                        if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                        {
                            row = tablesHeap.MemberRefTable.Get(rid);
                            row = new RawMemberRefRow(CodedToken.MemberRefParent.Encode(newToken), row.Name, row.Signature);
                            tablesHeap.MemberRefTable.Set(rid, ref row);
                        }
                        break;

                    case Table.ModuleRef:
                        if (nonNestedEditedType.IsGlobalModuleType && CheckResolutionScopeIsSameModule(token, nonNestedEditedType.Module))
                        {
                            if (remappedTypeTokens.TryGetValue(nonNestedEditedType.MDToken.Raw, out newToken))
                            {
                                row = tablesHeap.MemberRefTable.Get(rid);
                                row = new RawMemberRefRow(CodedToken.MemberRefParent.Encode(newToken), row.Name, row.Signature);
                                tablesHeap.MemberRefTable.Set(rid, ref row);
                            }
                        }
                        break;

                    case Table.Method:
                        break;

                    default:
                        Debug.Fail("Impossible");
                        break;
                    }

                    sig    = column2.Size == 2 ? *(ushort *)(p + column2.Offset) : *(uint *)(p + column2.Offset);
                    newSig = PatchCallingConventionSignature(callConvSigDict, sig);
                    if (sig != newSig)
                    {
                        row = tablesHeap.MemberRefTable.Get(rid);
                        row = new RawMemberRefRow(row.Class, row.Name, newSig);
                        tablesHeap.MemberRefTable.Set(rid, ref row);
                    }
                }
            }

            // Patch the Event table
            {
                table   = mdEditor.RealMetadata.TablesStream.EventTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[2];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                    {
                        var row = tablesHeap.EventTable.Get(i + 1);
                        row = new RawEventRow(row.EventFlags, row.Name, CodedToken.TypeDefOrRef.Encode(newToken));
                        tablesHeap.EventTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the Property table
            {
                table   = mdEditor.RealMetadata.TablesStream.PropertyTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[2];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    sig    = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    newSig = PatchCallingConventionSignature(callConvSigDict, sig);
                    if (newSig != sig)
                    {
                        var row = tablesHeap.PropertyTable.Get(i + 1);
                        row = new RawPropertyRow(row.PropFlags, row.Name, newSig);
                        tablesHeap.PropertyTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the TypeSpec table
            {
                table   = mdEditor.RealMetadata.TablesStream.TypeSpecTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[0];
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    sig    = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    newSig = PatchTypeSignature(typeSigDict, sig);
                    if (newSig != sig)
                    {
                        var row = new RawTypeSpecRow(newSig);
                        tablesHeap.TypeSpecTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the GenericParam table
            if (mdEditor.RealMetadata.TablesStream.GenericParamTable.Columns.Count == 5)
            {
                table   = mdEditor.RealMetadata.TablesStream.GenericParamTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[4];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                    {
                        var row = tablesHeap.GenericParamTable.Get(i + 1);
                        row = new RawGenericParamRow(row.Number, row.Flags, row.Owner, row.Name, CodedToken.TypeDefOrRef.Encode(newToken));
                        tablesHeap.GenericParamTable.Set(i + 1, ref row);
                    }
                }
            }

            // Patch the GenericParamConstraint table
            {
                table   = mdEditor.RealMetadata.TablesStream.GenericParamConstraintTable;
                p       = peFile + (int)table.StartOffset;
                rowSize = (int)table.RowSize;
                column  = table.Columns[1];
                p      += column.Offset;
                for (i = 0; i < table.Rows; i++, p += rowSize)
                {
                    codedToken = column.Size == 2 ? *(ushort *)p : *(uint *)p;
                    if (!CodedToken.TypeDefOrRef.Decode(codedToken, out token))
                    {
                        continue;
                    }
                    if (remappedTypeTokens.TryGetValue(token.Raw, out newToken))
                    {
                        var row = tablesHeap.GenericParamConstraintTable.Get(i + 1);
                        row = new RawGenericParamConstraintRow(row.Owner, CodedToken.TypeDefOrRef.Encode(newToken));
                        tablesHeap.GenericParamConstraintTable.Set(i + 1, ref row);
                    }
                }
            }
        }
Ejemplo n.º 6
0
 static uint ReadTypeDefColumnMethod(ref RawTypeDefRow row, int index) => row[index];
        /// <inheritdoc/>
        protected override void AllocateMemberDefRids()
        {
            int       numTypes        = allTypeDefs.Length;
            int       typeNum         = 0;
            int       notifyNum       = 0;
            const int numNotifyEvents = 5;
            int       notifyAfter     = numTypes / numNotifyEvents;

            uint fieldListRid = 1, methodListRid = 1;
            uint eventListRid = 1, propertyListRid = 1;
            uint paramListRid = 1;
            int  count;

            foreach (var type in allTypeDefs)
            {
                if (typeNum++ == notifyAfter && notifyNum < numNotifyEvents)
                {
                    RaiseProgress(Writer.MetadataEvent.AllocateMemberDefRids, (double)typeNum / numTypes);
                    notifyNum++;
                    notifyAfter = (int)((double)numTypes / numNotifyEvents * (notifyNum + 1));
                }

                if (type == null)
                {
                    continue;
                }
                uint typeRid = GetRid(type);
                var  typeRow = tablesHeap.TypeDefTable[typeRid];
                typeRow = new RawTypeDefRow(typeRow.Flags, typeRow.Name, typeRow.Namespace, typeRow.Extends, fieldListRid, methodListRid);
                tablesHeap.TypeDefTable[typeRid] = typeRow;

                var fields = type.Fields;
                count = fields.Count;
                for (int i = 0; i < count; i++)
                {
                    var field = fields[i];
                    if (field == null)
                    {
                        continue;
                    }
                    uint rid = fieldListRid++;
                    if (rid != tablesHeap.FieldTable.Create(new RawFieldRow()))
                    {
                        throw new ModuleWriterException("Invalid field rid");
                    }
                    fieldDefInfos.Add(field, rid);
                }

                var methods = type.Methods;
                count = methods.Count;
                for (int i = 0; i < count; i++)
                {
                    var method = methods[i];
                    if (method == null)
                    {
                        continue;
                    }
                    uint rid = methodListRid++;
                    var  row = new RawMethodRow(0, 0, 0, 0, 0, paramListRid);
                    if (rid != tablesHeap.MethodTable.Create(row))
                    {
                        throw new ModuleWriterException("Invalid method rid");
                    }
                    methodDefInfos.Add(method, rid);
                    foreach (var pd in Sort(method.ParamDefs))
                    {
                        if (pd == null)
                        {
                            continue;
                        }
                        uint pdRid = paramListRid++;
                        if (pdRid != tablesHeap.ParamTable.Create(new RawParamRow()))
                        {
                            throw new ModuleWriterException("Invalid param rid");
                        }
                        paramDefInfos.Add(pd, pdRid);
                    }
                }

                if (!IsEmpty(type.Events))
                {
                    uint eventMapRid = tablesHeap.EventMapTable.Create(new RawEventMapRow(typeRid, eventListRid));
                    eventMapInfos.Add(type, eventMapRid);
                    var events = type.Events;
                    count = events.Count;
                    for (int i = 0; i < count; i++)
                    {
                        var evt = events[i];
                        if (evt == null)
                        {
                            continue;
                        }
                        uint rid = eventListRid++;
                        if (rid != tablesHeap.EventTable.Create(new RawEventRow()))
                        {
                            throw new ModuleWriterException("Invalid event rid");
                        }
                        eventDefInfos.Add(evt, rid);
                    }
                }

                if (!IsEmpty(type.Properties))
                {
                    uint propertyMapRid = tablesHeap.PropertyMapTable.Create(new RawPropertyMapRow(typeRid, propertyListRid));
                    propertyMapInfos.Add(type, propertyMapRid);
                    var properties = type.Properties;
                    count = properties.Count;
                    for (int i = 0; i < count; i++)
                    {
                        var prop = properties[i];
                        if (prop == null)
                        {
                            continue;
                        }
                        uint rid = propertyListRid++;
                        if (rid != tablesHeap.PropertyTable.Create(new RawPropertyRow()))
                        {
                            throw new ModuleWriterException("Invalid property rid");
                        }
                        propertyDefInfos.Add(prop, rid);
                    }
                }
            }
        }