Ejemplo n.º 1
0
        internal uint GetBlobIndex(ImmutableArray <byte> blob)
        {
            uint result = 0;

            if (blob.Length == 0 || _blobIndex.TryGetValue(blob, out result))
            {
                return(result);
            }

            Debug.Assert(!_streamsAreComplete);
            result = _blobWriter.BaseStream.Position + (uint)_blobIndexStartOffset;
            _blobIndex.Add(blob, result);
            _blobWriter.WriteCompressedUInt((uint)blob.Length);
            _blobWriter.WriteBytes(blob);
            return(result);
        }
Ejemplo n.º 2
0
        public uint AllocateGuid(Guid guid)
        {
            Debug.Assert(!_streamsAreComplete);

            // The only GUIDs that are serialized are MVID, EncId, and EncBaseId in the
            // Module table. Each of those GUID offsets are relative to the local heap,
            // even for deltas, so there's no need for a GetGuidStreamPosition() method
            // to offset the positions by the size of the original heap in delta metadata.
            // Unlike #Blob, #String and #US streams delta #GUID stream is padded to the
            // size of the previous generation #GUID stream before new GUIDs are added.

            // Metadata Spec:
            // The Guid heap is an array of GUIDs, each 16 bytes wide.
            // Its first element is numbered 1, its second 2, and so on.
            uint result = (_guidWriter.BaseStream.Length >> 4) + 1;

            _guidIndex.Add(guid, result);
            _guidWriter.WriteBytes(guid.ToByteArray());

            return(result);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Fills in stringIndexMap with data from stringIndex and write to stringWriter.
        /// Releases stringIndex as the stringTable is sealed after this point.
        /// </summary>
        private void SerializeStringHeap()
        {
            // Sort by suffix and remove stringIndex
            var sorted = new List <KeyValuePair <string, StringIdx> >(_stringIndex);

            sorted.Sort(new SuffixSort());
            _stringIndex = null;

            // Create VirtIdx to Idx map and add entry for empty string
            _stringIndexMap    = new uint[sorted.Count + 1];
            _stringIndexMap[0] = 0;

            // Find strings that can be folded
            string prev = String.Empty;

            foreach (KeyValuePair <string, StringIdx> cur in sorted)
            {
                uint position = _stringWriter.BaseStream.Position + (uint)_stringIndexStartOffset;

                // It is important to use ordinal comparison otherwise we'll use the current culture!
                if (prev.EndsWith(cur.Key, StringComparison.Ordinal))
                {
                    // Map over the tail of prev string. Watch for null-terminator of prev string.
                    _stringIndexMap[cur.Value.VirtIdx] = position - (uint)(s_utf8Encoding.GetByteCount(cur.Key) + 1);
                }
                else
                {
                    _stringIndexMap[cur.Value.VirtIdx] = position;

                    // TODO (tomat): consider reusing the buffer instead of allocating a new one for each string
                    _stringWriter.WriteBytes(s_utf8Encoding.GetBytes(cur.Key));

                    _stringWriter.WriteByte(0);
                }

                prev = cur.Key;
            }
        }
Ejemplo n.º 4
0
        private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo)
        {
            if (!methodBody.HasDynamicLocalVariables)
            {
                return; //There are no dynamic locals
            }

            var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance();

            foreach (ILocalDefinition local in methodBody.LocalVariables)
            {
                if (local.IsDynamic)
                {
                    dynamicLocals.Add(local);
                }
            }

            int dynamicVariableCount = dynamicLocals.Count;

            foreach (var currentScope in methodBody.LocalScopes)
            {
                foreach (var localConstant in currentScope.Constants)
                {
                    if (localConstant.IsDynamic)
                    {
                        dynamicLocals.Add(localConstant);
                    }
                }
            }

            Debug.Assert(dynamicLocals.Any()); // There must be atleast one dynamic local if this point is reached

            const int    blobSize       = 200; //DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128
            MemoryStream customMetadata = new MemoryStream();
            BinaryWriter cmw            = new BinaryWriter(customMetadata, true);

            cmw.WriteByte(CDI.CdiVersion);
            cmw.WriteByte(CDI.CdiKindDynamicLocals);
            cmw.Align(4);
            // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob))
            cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block
            cmw.WriteUint((uint)dynamicLocals.Count);

            int localIndex = 0;

            foreach (ILocalDefinition local in dynamicLocals)
            {
                if (local.Name.Length > 63)//Ignore and push empty information
                {
                    cmw.WriteBytes(0, blobSize);
                    continue;
                }

                var dynamicTransformFlags = local.DynamicTransformFlags;
                if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64)
                {
                    byte[] flag = new byte[64];
                    for (int k = 0; k < dynamicTransformFlags.Length; k++)
                    {
                        if ((bool)dynamicTransformFlags[k].Value)
                        {
                            flag[k] = (byte)1;
                        }
                    }
                    cmw.WriteBytes(flag);                              //Written Flag
                    cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length
                }
                else
                {
                    cmw.WriteBytes(0, 68); //Empty flag array and size.
                }

                if (localIndex < dynamicVariableCount)
                {
                    // Dynamic variable
                    cmw.WriteUint((uint)local.SlotIndex);
                }
                else
                {
                    // Dynamic constant
                    cmw.WriteUint(0);
                }

                char[] localName = new char[64];
                local.Name.CopyTo(0, localName, 0, local.Name.Length);
                cmw.WriteChars(localName);

                localIndex++;
            }

            dynamicLocals.Free();
            customDebugInfo.Add(customMetadata);
        }
Ejemplo n.º 5
0
        private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder<MemoryStream> customDebugInfo)
        {
            if (!methodBody.HasDynamicLocalVariables)
            {
                return; //There are no dynamic locals
            }

            var dynamicLocals = ArrayBuilder<ILocalDefinition>.GetInstance();

            foreach (ILocalDefinition local in methodBody.LocalVariables)
            {
                if (local.IsDynamic)
                {
                    dynamicLocals.Add(local);
                }
            }

            int dynamicVariableCount = dynamicLocals.Count;

            foreach (var currentScope in methodBody.LocalScopes)
            {
                foreach (var localConstant in currentScope.Constants)
                {
                    if (localConstant.IsDynamic)
                    {
                        dynamicLocals.Add(localConstant);
                    }
                }
            }

            Debug.Assert(dynamicLocals.Any()); // There must be atleast one dynamic local if this point is reached

            const int blobSize = 200;//DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128
            MemoryStream customMetadata = new MemoryStream();
            BinaryWriter cmw = new BinaryWriter(customMetadata, true);
            cmw.WriteByte(CDI.CdiVersion);
            cmw.WriteByte(CDI.CdiKindDynamicLocals);
            cmw.Align(4);
            // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob))
            cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block
            cmw.WriteUint((uint)dynamicLocals.Count);

            int localIndex = 0;
            foreach (ILocalDefinition local in dynamicLocals)
            {
                if (local.Name.Length > 63)//Ignore and push empty information
                {
                    cmw.WriteBytes(0, blobSize);
                    continue;
                }

                var dynamicTransformFlags = local.DynamicTransformFlags;
                if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64)
                {
                    byte[] flag = new byte[64];
                    for (int k = 0; k < dynamicTransformFlags.Length; k++)
                    {
                        if ((bool)dynamicTransformFlags[k].Value)
                        {
                            flag[k] = (byte)1;
                        }
                    }
                    cmw.WriteBytes(flag); //Written Flag
                    cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length
                }
                else
                {
                    cmw.WriteBytes(0, 68); //Empty flag array and size.
                }

                if (localIndex < dynamicVariableCount)
                {
                    // Dynamic variable
                    cmw.WriteUint((uint)local.SlotIndex);
                }
                else
                {
                    // Dynamic constant
                    cmw.WriteUint(0);
                }

                char[] localName = new char[64];
                local.Name.CopyTo(0, localName, 0, local.Name.Length);
                cmw.WriteChars(localName);

                localIndex++;
            }

            dynamicLocals.Free();
            customDebugInfo.Add(customMetadata);
        }
Ejemplo n.º 6
0
        private void WriteDirectory(Directory directory, BinaryWriter writer, uint offset, uint level, uint sizeOfDirectoryTree, uint virtualAddressBase, BinaryWriter dataWriter)
        {
            writer.WriteUint(0); // Characteristics
            writer.WriteUint(0); // Timestamp
            writer.WriteUint(0); // Version
            writer.WriteUshort(directory.NumberOfNamedEntries);
            writer.WriteUshort(directory.NumberOfIdEntries);
            uint n = (uint)directory.Entries.Count;
            uint k = offset + 16 + n * 8;
            for (int i = 0; i < n; i++)
            {
                int id = int.MinValue;
                string name = null;
                uint nameOffset = dataWriter.BaseStream.Position + sizeOfDirectoryTree;
                uint directoryOffset = k;
                Directory subDir = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    id = subDir.ID;
                    name = subDir.Name;
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
                else
                {
                    //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed
                    //immediately by the data that it refers to. This results
                    //in a layout different than that produced by pulling the resources
                    //from an OBJ. In that case all of the data bits of a resource are
                    //contiguous in .rsrc$02. After processing these will end up at
                    //the end of .rsrc following all of the directory
                    //info and IMAGE_RESOURCE_DATA_ENTRYs
                    IWin32Resource r = (IWin32Resource)directory.Entries[i];
                    id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId;
                    name = level == 0 ? r.TypeName : level == 1 ? r.Name : null;
                    dataWriter.WriteUint(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.BaseStream.Position);
                    byte[] data = new List<byte>(r.Data).ToArray();
                    dataWriter.WriteUint((uint)data.Length);
                    dataWriter.WriteUint(r.CodePage);
                    dataWriter.WriteUint(0);
                    dataWriter.WriteBytes(data);
                    while ((dataWriter.BaseStream.Length % 4) != 0)
                    {
                        dataWriter.WriteByte(0);
                    }
                }

                if (id >= 0)
                {
                    writer.WriteInt(id);
                }
                else
                {
                    if (name == null)
                    {
                        name = string.Empty;
                    }

                    writer.WriteUint(nameOffset | 0x80000000);
                    dataWriter.WriteUshort((ushort)name.Length);
                    dataWriter.WriteChars(name.ToCharArray());  // REVIEW: what happens if the name contains chars that do not fit into a single utf8 code point?
                }

                if (subDir != null)
                {
                    writer.WriteUint(directoryOffset | 0x80000000);
                }
                else
                {
                    writer.WriteUint(nameOffset);
                }
            }

            k = offset + 16 + n * 8;
            for (int i = 0; i < n; i++)
            {
                Directory subDir = directory.Entries[i] as Directory;
                if (subDir != null)
                {
                    this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter);
                    if (level == 0)
                    {
                        k += SizeOfDirectory(subDir);
                    }
                    else
                    {
                        k += 16 + 8 * (uint)subDir.Entries.Count;
                    }
                }
            }
        }
Ejemplo n.º 7
0
        private void WriteDebugTable(Stream peStream, out long timestampOffset)
        {
            timestampOffset = 0;
            PeDebugDirectory debugDirectory = _debugDirectory;
            if (debugDirectory == null)
            {
                return;
            }

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);
            writer.WriteUint(debugDirectory.Characteristics);
            timestampOffset = writer.BaseStream.Position + peStream.Position;
            writer.WriteUint(debugDirectory.TimeDateStamp);
            writer.WriteUshort(debugDirectory.MajorVersion);
            writer.WriteUshort(debugDirectory.MinorVersion);
            writer.WriteUint(debugDirectory.Type);
            writer.WriteUint(debugDirectory.SizeOfData);
            debugDirectory.AddressOfRawData = debugDirectory.PointerToRawData + _textSection.RelativeVirtualAddress;
            debugDirectory.PointerToRawData += _textSection.PointerToRawData;
            writer.WriteUint(debugDirectory.AddressOfRawData);
            writer.WriteUint(debugDirectory.PointerToRawData);
            writer.WriteBytes(debugDirectory.Data);
            writer.BaseStream.WriteTo(peStream);
            stream.Free();
        }
Ejemplo n.º 8
0
        private void WriteHeaders(Stream peStream, out long timestampOffset)
        {
            IModule module = _module;
            NtHeader ntHeader = _ntHeader;
            BinaryWriter writer = new BinaryWriter(_headerStream);

            // MS-DOS stub (128 bytes)
            writer.WriteBytes(s_dosHeader); // TODO: provide an option to suppress the second half of the DOS header?

            // PE Signature (4 bytes)
            writer.WriteUint(0x00004550); /* "PE\0\0" */

            // COFF Header 20 bytes
            writer.WriteUshort((ushort)module.Machine);
            writer.WriteUshort((ushort)ntHeader.NumberOfSections);
            timestampOffset = (uint)(writer.BaseStream.Position + peStream.Position);
            writer.WriteUint(ntHeader.TimeDateStamp);
            writer.WriteUint(ntHeader.PointerToSymbolTable);
            writer.WriteUint(0); // NumberOfSymbols
            writer.WriteUshort((ushort)(!module.Requires64bits ? 224 : 240)); // SizeOfOptionalHeader
            // ushort characteristics = 0x0002|0x0004|0x0008; // executable | no COFF line nums | no COFF symbols (as required by the standard)
            ushort characteristics = 0x0002; // executable (as required by the Linker team).
            if (module.Kind == ModuleKind.DynamicallyLinkedLibrary || module.Kind == ModuleKind.WindowsRuntimeMetadata)
            {
                characteristics |= 0x2000;
            }

            if (module.Requires32bits)
            {
                characteristics |= 0x0100; // 32 bit machine (The standard says to always set this, the linker team says otherwise)
                                           //The loader team says that this is not used for anything in the OS. 
            }
            else
            {
                characteristics |= 0x0020; // large address aware (the standard says never to set this, the linker team says otherwise).
                                           //The loader team says that this is not overridden for managed binaries and will be respected if set.
            }

            writer.WriteUshort(characteristics);

            // PE Header (224 bytes if 32 bits, 240 bytes if 64 bit)
            if (!module.Requires64bits)
            {
                writer.WriteUshort(0x10B); // Magic = PE32  // 2
            }
            else
            {
                writer.WriteUshort(0x20B); // Magic = PE32+ // 2
            }

            writer.WriteByte(module.LinkerMajorVersion); // 3
            writer.WriteByte(module.LinkerMinorVersion); // 4
            writer.WriteUint(ntHeader.SizeOfCode); // 8
            writer.WriteUint(ntHeader.SizeOfInitializedData); // 12
            writer.WriteUint(ntHeader.SizeOfUninitializedData); // 16
            writer.WriteUint(ntHeader.AddressOfEntryPoint); // 20
            writer.WriteUint(ntHeader.BaseOfCode); // 24
            if (!module.Requires64bits)
            {
                writer.WriteUint(ntHeader.BaseOfData); // 28
                writer.WriteUint((uint)module.BaseAddress); // 32
            }
            else
            {
                writer.WriteUlong(module.BaseAddress); // 32
            }

            writer.WriteUint(0x2000); // SectionAlignment 36
            writer.WriteUint(module.FileAlignment); // 40
            writer.WriteUshort(4); // MajorOperatingSystemVersion 42
            writer.WriteUshort(0); // MinorOperatingSystemVersion 44
            writer.WriteUshort(0); // MajorImageVersion 46
            writer.WriteUshort(0); // MinorImageVersion 48
            writer.WriteUshort(module.MajorSubsystemVersion); // MajorSubsystemVersion 50
            writer.WriteUshort(module.MinorSubsystemVersion); // MinorSubsystemVersion 52
            writer.WriteUint(0); // Win32VersionValue 56
            writer.WriteUint(ntHeader.SizeOfImage); // 60
            writer.WriteUint(ntHeader.SizeOfHeaders); // 64
            writer.WriteUint(0); // CheckSum 68
            switch (module.Kind)
            {
                case ModuleKind.ConsoleApplication:
                case ModuleKind.DynamicallyLinkedLibrary:
                case ModuleKind.WindowsRuntimeMetadata:
                    writer.WriteUshort(3); // 70
                    break;
                case ModuleKind.WindowsApplication:
                    writer.WriteUshort(2); // 70
                    break;
                default:
                    writer.WriteUshort(0); //
                    break;
            }

            writer.WriteUshort(module.DllCharacteristics);

            if (!module.Requires64bits)
            {
                writer.WriteUint((uint)module.SizeOfStackReserve); // 76
                writer.WriteUint((uint)module.SizeOfStackCommit); // 80
                writer.WriteUint((uint)module.SizeOfHeapReserve); // 84
                writer.WriteUint((uint)module.SizeOfHeapCommit); // 88
            }
            else
            {
                writer.WriteUlong(module.SizeOfStackReserve); // 80
                writer.WriteUlong(module.SizeOfStackCommit); // 88
                writer.WriteUlong(module.SizeOfHeapReserve); // 96
                writer.WriteUlong(module.SizeOfHeapCommit); // 104
            }

            writer.WriteUint(0); // LoaderFlags 92|108
            writer.WriteUint(16); // numberOfDataDirectories 96|112

            writer.WriteUint(ntHeader.ExportTable.RelativeVirtualAddress); // 100|116
            writer.WriteUint(ntHeader.ExportTable.Size); // 104|120
            writer.WriteUint(ntHeader.ImportTable.RelativeVirtualAddress); // 108|124
            writer.WriteUint(ntHeader.ImportTable.Size); // 112|128
            writer.WriteUint(ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132
            writer.WriteUint(ntHeader.ResourceTable.Size); // 120|136
            writer.WriteUint(ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140
            writer.WriteUint(ntHeader.ExceptionTable.Size); // 128|144
            writer.WriteUint(ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148
            writer.WriteUint(ntHeader.CertificateTable.Size); // 136|152
            writer.WriteUint(ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156
            writer.WriteUint(ntHeader.BaseRelocationTable.Size); // 144|160
            writer.WriteUint(ntHeader.DebugTable.RelativeVirtualAddress); // 148|164
            writer.WriteUint(ntHeader.DebugTable.Size); // 152|168
            writer.WriteUint(ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172
            writer.WriteUint(ntHeader.CopyrightTable.Size); // 160|176
            writer.WriteUint(ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180
            writer.WriteUint(ntHeader.GlobalPointerTable.Size); // 168|184
            writer.WriteUint(ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188
            writer.WriteUint(ntHeader.ThreadLocalStorageTable.Size); // 176|192
            writer.WriteUint(ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196
            writer.WriteUint(ntHeader.LoadConfigTable.Size); // 184|200
            writer.WriteUint(ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204
            writer.WriteUint(ntHeader.BoundImportTable.Size); // 192|208
            writer.WriteUint(ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212
            writer.WriteUint(ntHeader.ImportAddressTable.Size); // 200|216
            writer.WriteUint(ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220
            writer.WriteUint(ntHeader.DelayImportTable.Size); // 208|224
            writer.WriteUint(ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228
            writer.WriteUint(ntHeader.CliHeaderTable.Size); // 216|232
            writer.WriteUlong(0); // 224|240

            // Section Headers
            WriteSectionHeader(_textSection, writer);
            WriteSectionHeader(_rdataSection, writer);
            WriteSectionHeader(_sdataSection, writer);
            WriteSectionHeader(_coverSection, writer);
            WriteSectionHeader(_resourceSection, writer);
            WriteSectionHeader(_relocSection, writer);
            WriteSectionHeader(_tlsSection, writer);

            writer.BaseStream.WriteTo(peStream);
            _headerStream = _emptyStream;
        }
Ejemplo n.º 9
0
        private void WriteDebugTable(Stream peStream, ContentId pdbContentId, MetadataSizes metadataSizes)
        {
            if (!EmitPdb)
            {
                return;
            }

            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);

            // characteristics:
            writer.WriteUint(0);

            // PDB stamp
            writer.WriteBytes(pdbContentId.Stamp);

            // version
            writer.WriteUint(0);

            // type: 
            const int ImageDebugTypeCodeView = 2;
            writer.WriteUint(ImageDebugTypeCodeView);

            // size of data:
            writer.WriteUint((uint)ComputeSizeOfDebugDirectoryData());

            uint dataOffset = (uint)ComputeOffsetToDebugTable(metadataSizes) + ImageDebugDirectoryBaseSize;

            // PointerToRawData (RVA of the data):
            writer.WriteUint(_textSection.RelativeVirtualAddress + dataOffset);

            // AddressOfRawData (position of the data in the PE stream):
            writer.WriteUint(_textSection.PointerToRawData + dataOffset);

            writer.WriteByte((byte)'R');
            writer.WriteByte((byte)'S');
            writer.WriteByte((byte)'D');
            writer.WriteByte((byte)'S');

            // PDB id:
            writer.WriteBytes(pdbContentId.Guid);

            // age
            writer.WriteUint(PdbWriter.Age);

            // UTF-8 encoded zero-terminated path to PDB
            writer.WriteString(_pdbPathOpt, emitNullTerminator: true);

            writer.BaseStream.WriteTo(peStream);
            stream.Free();
        }