public void WriteData(BlobBuilder resourceWriter) { if (_fileReference == null) { try { using (Stream stream = _streamProvider()) { if (stream == null) { throw new InvalidOperationException(CodeAnalysisResources.ResourceStreamProviderShouldReturnNonNullStream); } var count = (int)(stream.Length - stream.Position); resourceWriter.WriteInt32(count); int bytesWritten = resourceWriter.TryWriteBytes(stream, count); if (bytesWritten != count) { throw new EndOfStreamException( string.Format(CultureInfo.CurrentUICulture, CodeAnalysisResources.ResourceStreamEndedUnexpectedly, bytesWritten, count)); } resourceWriter.Align(8); } } catch (Exception e) { throw new ResourceException(_name, e); } } }
public void WriteData(BlobBuilder resourceWriter) { if (_fileReference == null) { try { using (Stream stream = _streamProvider()) { if (stream == null) { throw new InvalidOperationException(CodeAnalysisResources.ResourceStreamProviderShouldReturnNonNullStream); } var count = (int)(stream.Length - stream.Position); resourceWriter.WriteInt32(count); resourceWriter.Write(stream, count); resourceWriter.Align(8); } } catch (Exception e) { throw new ResourceException(_name, e); } } }
public void Ctor() { var builder = new BlobBuilder(); Assert.Equal(BlobBuilder.DefaultChunkSize, builder.BufferSize); builder = new BlobBuilder(0); Assert.Equal(BlobBuilder.MinChunkSize, builder.BufferSize); builder = new BlobBuilder(10001); Assert.Equal(10001, builder.BufferSize); }
private void TestContentEquals(byte[] left, byte[] right) { var builder1 = new BlobBuilder(0); builder1.WriteBytes(left); var builder2 = new BlobBuilder(0); builder2.WriteBytes(right); bool expected = ByteSequenceComparer.Equals(left, right); Assert.Equal(expected, builder1.ContentEquals(builder2)); }
public void ContentEquals() { var builder = new BlobBuilder(); Assert.True(builder.ContentEquals(builder)); Assert.False(builder.ContentEquals(null)); TestContentEquals(new byte[] { }, new byte[] { }); TestContentEquals(new byte[] { 1 }, new byte[] { }); TestContentEquals(new byte[] { }, new byte[] { 1 }); TestContentEquals(new byte[] { 1 }, new byte[] { 1 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }); TestContentEquals( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }); }
internal PdbLogger(bool logging) { _logging = logging; if (logging) { _logData = BlobBuilder.GetInstance(); _hashAlgorithm = new SHA1CryptoServiceProvider(); Debug.Assert(_hashAlgorithm.SupportsTransform); } else { _logData = null; _hashAlgorithm = null; } }
public BlobBuilder(int size = DefaultChunkSize) { if (size < 0) { throw new ArgumentOutOfRangeException(nameof(size)); } // the writer assumes little-endian architecture: if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(); } _nextOrPrevious = this; _buffer = new byte[Math.Max(MinChunkSize, size)]; }
public void CountClear() { var builder = new BlobBuilder(); Assert.Equal(0, builder.Count); builder.WriteByte(1); Assert.Equal(1, builder.Count); builder.WriteInt32(4); Assert.Equal(5, builder.Count); builder.Clear(); Assert.Equal(0, builder.Count); builder.WriteInt64(1); Assert.Equal(8, builder.Count); AssertEx.Equal(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, builder.ToArray()); }
internal PdbLogger(bool logging) { _logging = logging; if (logging) { // do not get this from pool // we need a fairly large buffer here (where the pool typically contains small ones) // and we need just one per compile session // pooling will be couter-productive in such scenario _logData = new BlobBuilder(bufferFlushLimit); _hashAlgorithm = new SHA1CryptoServiceProvider(); Debug.Assert(_hashAlgorithm.SupportsTransform); } else { _logData = null; _hashAlgorithm = null; } }
public void WritePrimitive() { var writer = new BlobBuilder(4); writer.WriteUInt32(0x11223344); writer.WriteUInt16(0x5566); writer.WriteByte(0x77); writer.WriteUInt64(0x8899aabbccddeeff); writer.WriteInt32(-1); writer.WriteInt16(-2); writer.WriteSByte(-3); writer.WriteBoolean(true); writer.WriteBoolean(false); writer.WriteInt64(unchecked((long)0xfedcba0987654321)); writer.WriteDateTime(new DateTime(0x1112223334445556)); writer.WriteDecimal(102030405060.70m); writer.WriteDouble(double.NaN); writer.WriteSingle(float.NegativeInfinity); AssertEx.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x77, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfd, 0x01, 0x00, 0x21, 0x43, 0x65, 0x87, 0x09, 0xBA, 0xDC, 0xFE, 0x56, 0x55, 0x44, 0x34, 0x33, 0x22, 0x12, 0x11, 0x02, 0xD6, 0xE0, 0x9A, 0x94, 0x47, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x80, 0xFF }, writer.ToArray()); }
private static void WriteSectionHeader(SectionHeader sectionHeader, BlobBuilder writer) { if (sectionHeader.VirtualSize == 0) { return; } for (int j = 0, m = sectionHeader.Name.Length; j < 8; j++) { if (j < m) { writer.WriteByte((byte)sectionHeader.Name[j]); } else { writer.WriteByte(0); } } writer.WriteUInt32((uint)sectionHeader.VirtualSize); writer.WriteUInt32((uint)sectionHeader.RelativeVirtualAddress); writer.WriteUInt32((uint)sectionHeader.SizeOfRawData); writer.WriteUInt32((uint)sectionHeader.PointerToRawData); writer.WriteUInt32((uint)sectionHeader.PointerToRelocations); writer.WriteUInt32((uint)sectionHeader.PointerToLinenumbers); writer.WriteUInt16(sectionHeader.NumberOfRelocations); writer.WriteUInt16(sectionHeader.NumberOfLinenumbers); writer.WriteUInt32((uint)sectionHeader.Characteristics); }
public void WriteSerializedString() { var writer = new BlobBuilder(4); writer.WriteSerializedString(""); writer.WriteSerializedString("a"); writer.WriteSerializedString(null); writer.WriteSerializedString(""); writer.WriteSerializedString("\ud800"); // hi surrogate writer.WriteSerializedString("\udc00"); // lo surrogate writer.WriteSerializedString("\ud800\udc00"); // pair writer.WriteSerializedString("\udc00\ud800"); // lo + hi writer.WriteSerializedString("\u1234"); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x61, 0xff, 0x00, 0x03, 0xED, 0xA0, 0x80, 0x03, 0xED, 0xB0, 0x80, 0x04, 0xF0, 0x90, 0x80, 0x80, 0x06, 0xED, 0xB0, 0x80, 0xED, 0xA0, 0x80, 0x03, 0xE1, 0x88, 0xB4 }, writer.ToArray()); }
public void Pooled() { var builder1 = PooledBlobBuilder.GetInstance(); var builder2 = PooledBlobBuilder.GetInstance(); var builder3 = new BlobBuilder(); builder1.WriteByte(1); builder2.WriteByte(2); builder3.WriteByte(3); // mix pooled with non-pooled builder1.LinkPrefix(builder3); builder1.Free(); builder2.Free(); }
public void WriteBytes2() { var writer = new BlobBuilder(4); writer.WriteBytes(0xff, 0); writer.WriteBytes(1, 4); writer.WriteBytes(0xff, 0); writer.WriteBytes(2, 10); writer.WriteBytes(0xff, 0); writer.WriteBytes(3, 1); AssertEx.Equal(new byte[] { 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03 }, writer.ToArray()); }
public void WriteAlignPad() { var writer = new BlobBuilder(4); writer.WriteByte(0x01); writer.PadTo(2); writer.WriteByte(0x02); writer.Align(4); writer.Align(4); writer.WriteByte(0x03); writer.Align(4); writer.WriteByte(0x04); writer.WriteByte(0x05); writer.Align(8); writer.WriteByte(0x06); writer.Align(2); writer.Align(1); AssertEx.Equal(new byte[] { 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00 }, writer.ToArray()); }
private void WriteDebugTable(Stream peStream, SectionHeader textSection, ContentId nativePdbContentId, ContentId portablePdbContentId, MetadataSizes metadataSizes) { Debug.Assert(nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault); var writer = new BlobBuilder(); // characteristics: writer.WriteUInt32(0); // PDB stamp & version if (portablePdbContentId.IsDefault) { writer.WriteBytes(nativePdbContentId.Stamp); writer.WriteUInt32(0); } else { writer.WriteBytes(portablePdbContentId.Stamp); writer.WriteUInt32('P' << 24 | 'M' << 16 | 0x00 << 8 | 0x01); } // type: const int ImageDebugTypeCodeView = 2; writer.WriteUInt32(ImageDebugTypeCodeView); // size of data: writer.WriteUInt32((uint)ComputeSizeOfDebugDirectoryData()); uint dataOffset = (uint)ComputeOffsetToDebugTable(metadataSizes) + ImageDebugDirectoryBaseSize; // PointerToRawData (RVA of the data): writer.WriteUInt32((uint)textSection.RelativeVirtualAddress + dataOffset); // AddressOfRawData (position of the data in the PE stream): writer.WriteUInt32((uint)textSection.PointerToRawData + dataOffset); writer.WriteByte((byte)'R'); writer.WriteByte((byte)'S'); writer.WriteByte((byte)'D'); writer.WriteByte((byte)'S'); // PDB id: writer.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid); // age writer.WriteUInt32(PdbWriter.Age); // UTF-8 encoded zero-terminated path to PDB writer.WriteUTF8(_pdbPathOpt); writer.WriteByte(0); writer.WriteTo(peStream); writer.Free(); }
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, Func<Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) { // TODO: we can precalculate the exact size of IL stream var ilWriter = new BlobBuilder(32 * 1024); var metadataWriter = new BlobBuilder(16 * 1024); var mappedFieldDataWriter = new BlobBuilder(); var managedResourceWriter = new BlobBuilder(1024); var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobBuilder(16 * 1024) : null; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(_properties.PersistentIdentifier == default(Guid)); int sectionCount = 1; if (_properties.RequiresStartupStub) sectionCount++; //.reloc if (!IteratorHelper.EnumerableIsEmpty(_nativeResourcesOpt) || _nativeResourceSectionOpt != null) sectionCount++; //.rsrc; int sizeOfPeHeaders = ComputeSizeOfPeHeaders(sectionCount); int textSectionRva = BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.SectionAlignment); int moduleVersionIdOffsetInMetadataStream; int methodBodyStreamRva = textSectionRva + OffsetToILStream; int entryPointToken; MetadataSizes metadataSizes; mdWriter.SerializeMetadataAndIL( metadataWriter, debugMetadataWriterOpt, nativePdbWriterOpt, ilWriter, mappedFieldDataWriter, managedResourceWriter, methodBodyStreamRva, mdSizes => CalculateMappedFieldDataStreamRva(textSectionRva, mdSizes), out moduleVersionIdOffsetInMetadataStream, out entryPointToken, out metadataSizes); ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { if (entryPointToken != 0) { nativePdbWriterOpt.SetEntryPoint((uint)entryPointToken); } var assembly = mdWriter.Module.AsAssembly; if (assembly != null && assembly.Kind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } nativePdbContentId = nativePdbWriterOpt.GetContentId(); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; } else { nativePdbContentId = default(ContentId); } // write to Portable PDB stream: ContentId portablePdbContentId; Stream portablePdbStream = getPortablePdbStreamOpt?.Invoke(); if (portablePdbStream != null) { debugMetadataWriterOpt.WriteTo(portablePdbStream); if (_deterministic) { portablePdbContentId = ContentId.FromHash(CryptographicHashProvider.ComputeSha1(portablePdbStream)); } else { portablePdbContentId = new ContentId(Guid.NewGuid().ToByteArray(), BitConverter.GetBytes(_timeStamp)); } } else { portablePdbContentId = default(ContentId); } // Only the size of the fixed part of the debug table goes here. DirectoryEntry debugDirectory = default(DirectoryEntry); DirectoryEntry importTable = default(DirectoryEntry); DirectoryEntry importAddressTable = default(DirectoryEntry); int entryPointAddress = 0; if (EmitPdb) { debugDirectory = new DirectoryEntry(textSectionRva + ComputeOffsetToDebugTable(metadataSizes), ImageDebugDirectoryBaseSize); } if (_properties.RequiresStartupStub) { importAddressTable = new DirectoryEntry(textSectionRva, SizeOfImportAddressTable); entryPointAddress = CalculateMappedFieldDataStreamRva(textSectionRva, metadataSizes) - (_is32bit ? 6 : 10); // TODO: constants importTable = new DirectoryEntry(textSectionRva + ComputeOffsetToImportTable(metadataSizes), (_is32bit ? 66 : 70) + 13); // TODO: constants } var corHeaderDirectory = new DirectoryEntry(textSectionRva + SizeOfImportAddressTable, size: CorHeaderSize); long ntHeaderTimestampPosition; long metadataPosition; List<SectionHeader> sectionHeaders = CreateSectionHeaders(metadataSizes, sectionCount); CoffHeader coffHeader; NtHeader ntHeader; FillInNtHeader(sectionHeaders, entryPointAddress, corHeaderDirectory, importTable, importAddressTable, debugDirectory, out coffHeader, out ntHeader); Stream peStream = getPeStream(); if (peStream == null) { return false; } WriteHeaders(peStream, ntHeader, coffHeader, sectionHeaders, out ntHeaderTimestampPosition); WriteTextSection( peStream, sectionHeaders[0], importTable.RelativeVirtualAddress, importAddressTable.RelativeVirtualAddress, entryPointToken, metadataWriter, ilWriter, mappedFieldDataWriter, managedResourceWriter, metadataSizes, nativePdbContentId, portablePdbContentId, out metadataPosition); var resourceSection = sectionHeaders.FirstOrDefault(s => s.Name == ResourceSectionName); if (resourceSection != null) { WriteResourceSection(peStream, resourceSection); } var relocSection = sectionHeaders.FirstOrDefault(s => s.Name == RelocationSectionName); if (relocSection != null) { WriteRelocSection(peStream, relocSection, entryPointAddress); } if (_deterministic) { var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); } return true; }
public static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, Func <Stream> getPeStream, Func <Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool allowMissingMethodBodies, bool isDeterministic, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); MetadataWriter mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken); ModulePropertiesForSerialization properties = context.Module.SerializationProperties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(properties.PersistentIdentifier == default(Guid)); BlobBuilder ilBuilder = new BlobBuilder(32 * 1024); BlobBuilder mappedFieldDataBuilder = new BlobBuilder(); BlobBuilder managedResourceBuilder = new BlobBuilder(1024); mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, out Blob mvidFixup, out Blob mvidStringFixup); mdWriter.GetEntryPoints(out MethodDefinitionHandle entryPointHandle, out MethodDefinitionHandle debugEntryPointHandle); if (!debugEntryPointHandle.IsNil) { nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle)); } if (nativePdbWriterOpt != null) { if (mdWriter.Module.OutputKind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } // embedded text not currently supported for native PDB and we should have validated that Debug.Assert(!mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments.Any()); } Stream peStream = getPeStream(); if (peStream == null) { return(false); } BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(BlobContentId); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; ushort portablePdbVersion = 0; MetadataRootBuilder metadataRootBuilder = mdWriter.GetRootBuilder(); PEHeaderBuilder peHeaderBuilder = new PEHeaderBuilder( machine: properties.Machine, sectionAlignment: properties.SectionAlignment, fileAlignment: properties.FileAlignment, imageBase: properties.BaseAddress, majorLinkerVersion: properties.LinkerMajorVersion, minorLinkerVersion: properties.LinkerMinorVersion, majorOperatingSystemVersion: 4, minorOperatingSystemVersion: 0, majorImageVersion: 0, minorImageVersion: 0, majorSubsystemVersion: properties.MajorSubsystemVersion, minorSubsystemVersion: properties.MinorSubsystemVersion, subsystem: properties.Subsystem, dllCharacteristics: properties.DllCharacteristics, imageCharacteristics: properties.ImageCharacteristics, sizeOfStackReserve: properties.SizeOfStackReserve, sizeOfStackCommit: properties.SizeOfStackCommit, sizeOfHeapReserve: properties.SizeOfHeapReserve, sizeOfHeapCommit: properties.SizeOfHeapCommit); Func <IEnumerable <Blob>, BlobContentId> deterministicIdProvider = isDeterministic ? new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) : null; BlobBuilder portablePdbToEmbed = null; if (mdWriter.EmitStandaloneDebugMetadata) { mdWriter.AddRemainingEmbeddedDocuments(mdWriter.Module.DebugDocumentsBuilder.EmbeddedDocuments); BlobBuilder portablePdbBlob = new BlobBuilder(); PortablePdbBuilder portablePdbBuilder = mdWriter.GetPortablePdbBuilder(metadataRootBuilder.Sizes.RowCounts, debugEntryPointHandle, deterministicIdProvider); pdbContentId = portablePdbBuilder.Serialize(portablePdbBlob); portablePdbVersion = portablePdbBuilder.FormatVersion; if (getPortablePdbStreamOpt == null) { // embed to debug directory: portablePdbToEmbed = portablePdbBlob; } else { // write to Portable PDB stream: Stream portablePdbStream = getPortablePdbStreamOpt(); if (portablePdbStream != null) { portablePdbBlob.WriteContentTo(portablePdbStream); } } } DebugDirectoryBuilder debugDirectoryBuilder; if (pdbPathOpt != null || isDeterministic || portablePdbToEmbed != null) { debugDirectoryBuilder = new DebugDirectoryBuilder(); if (pdbPathOpt != null) { string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt); debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion); } if (isDeterministic) { debugDirectoryBuilder.AddReproducibleEntry(); } if (portablePdbToEmbed != null) { debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbToEmbed, portablePdbVersion); } } else { debugDirectoryBuilder = null; } ManagedPEBuilder peBuilder = new ManagedPEBuilder( peHeaderBuilder, metadataRootBuilder, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, CreateNativeResourceSectionSerializer(context.Module), debugDirectoryBuilder, CalculateStrongNameSignatureSize(context.Module), entryPointHandle, properties.CorFlags, deterministicIdProvider); BlobBuilder peBlob = new BlobBuilder(); BlobContentId peContentId = peBuilder.Serialize(peBlob); PatchModuleVersionIds(mvidFixup, mvidStringFixup, peContentId.Guid); try { peBlob.WriteContentTo(peStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new PeWritingException(e); } return(true); }
protected override void Serialize(BlobBuilder builder, SectionLocation location) { NativeResourceWriter.SerializeWin32Resources(builder, _resources, location.RelativeVirtualAddress); }
private static void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) { writer.WriteUInt32(0); // Characteristics writer.WriteUInt32(0); // Timestamp writer.WriteUInt32(0); // Version writer.WriteUInt16(directory.NumberOfNamedEntries); writer.WriteUInt16(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id; string name; uint nameOffset = (uint)dataWriter.Count + 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.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Count)); byte[] data = new List <byte>(r.Data).ToArray(); dataWriter.WriteUInt32((uint)data.Length); dataWriter.WriteUInt32(r.CodePage); dataWriter.WriteUInt32(0); dataWriter.WriteBytes(data); while ((dataWriter.Count % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt32(id); } else { if (name == null) { name = string.Empty; } writer.WriteUInt32(nameOffset | 0x80000000); dataWriter.WriteUInt16((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUInt32(directoryOffset | 0x80000000); } else { writer.WriteUInt32(nameOffset); } } k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } } }
internal static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, Func <Stream> getPeStream, Func <Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool metadataOnly, bool isDeterministic, bool emitTestCoverageData, RSAParameters?privateKeyOpt, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); var mdWriter = FullMetadataWriter.Create(context, messageProvider, metadataOnly, isDeterministic, emitTestCoverageData, getPortablePdbStreamOpt != null, cancellationToken); var properties = context.Module.SerializationProperties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(properties.PersistentIdentifier == default(Guid)); var ilBuilder = new BlobBuilder(32 * 1024); var mappedFieldDataBuilder = new BlobBuilder(); var managedResourceBuilder = new BlobBuilder(1024); Blob mvidFixup, mvidStringFixup; mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, out mvidFixup, out mvidStringFixup); MethodDefinitionHandle entryPointHandle; MethodDefinitionHandle debugEntryPointHandle; mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle); if (!debugEntryPointHandle.IsNil) { nativePdbWriterOpt?.SetEntryPoint(MetadataTokens.GetToken(debugEntryPointHandle)); } if (nativePdbWriterOpt != null) { if (context.Module.SourceLinkStreamOpt != null) { nativePdbWriterOpt.EmbedSourceLink(context.Module.SourceLinkStreamOpt); } if (mdWriter.Module.OutputKind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in a winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } nativePdbWriterOpt.WriteRemainingDebugDocuments(mdWriter.Module.DebugDocumentsBuilder.DebugDocuments); } Stream peStream = getPeStream(); if (peStream == null) { return(false); } BlobContentId pdbContentId = nativePdbWriterOpt?.GetContentId() ?? default; // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; ushort portablePdbVersion = 0; var metadataRootBuilder = mdWriter.GetRootBuilder(); var peHeaderBuilder = new PEHeaderBuilder( machine: properties.Machine, sectionAlignment: properties.SectionAlignment, fileAlignment: properties.FileAlignment, imageBase: properties.BaseAddress, majorLinkerVersion: properties.LinkerMajorVersion, minorLinkerVersion: properties.LinkerMinorVersion, majorOperatingSystemVersion: 4, minorOperatingSystemVersion: 0, majorImageVersion: 0, minorImageVersion: 0, majorSubsystemVersion: properties.MajorSubsystemVersion, minorSubsystemVersion: properties.MinorSubsystemVersion, subsystem: properties.Subsystem, dllCharacteristics: properties.DllCharacteristics, imageCharacteristics: properties.ImageCharacteristics, sizeOfStackReserve: properties.SizeOfStackReserve, sizeOfStackCommit: properties.SizeOfStackCommit, sizeOfHeapReserve: properties.SizeOfHeapReserve, sizeOfHeapCommit: properties.SizeOfHeapCommit); var peIdProvider = isDeterministic ? new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(CryptographicHashProvider.ComputeSourceHash(content))) : null; // We need to calculate the PDB checksum, so we may as well use the calculated hash for PDB ID regardless of whether deterministic build is requested. var portablePdbContentHash = default(ImmutableArray <byte>); BlobBuilder portablePdbToEmbed = null; if (mdWriter.EmitPortableDebugMetadata) { mdWriter.AddRemainingDebugDocuments(mdWriter.Module.DebugDocumentsBuilder.DebugDocuments); // The algorithm must be specified for deterministic builds (checked earlier). Debug.Assert(!isDeterministic || context.Module.PdbChecksumAlgorithm.Name != null); var portablePdbIdProvider = (context.Module.PdbChecksumAlgorithm.Name != null) ? new Func <IEnumerable <Blob>, BlobContentId>(content => BlobContentId.FromHash(portablePdbContentHash = CryptographicHashProvider.ComputeHash(context.Module.PdbChecksumAlgorithm, content))) : null; var portablePdbBlob = new BlobBuilder(); var portablePdbBuilder = mdWriter.GetPortablePdbBuilder(metadataRootBuilder.Sizes.RowCounts, debugEntryPointHandle, portablePdbIdProvider); pdbContentId = portablePdbBuilder.Serialize(portablePdbBlob); portablePdbVersion = portablePdbBuilder.FormatVersion; if (getPortablePdbStreamOpt == null) { // embed to debug directory: portablePdbToEmbed = portablePdbBlob; } else { // write to Portable PDB stream: Stream portablePdbStream = getPortablePdbStreamOpt(); if (portablePdbStream != null) { try { portablePdbBlob.WriteContentTo(portablePdbStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new SymUnmanagedWriterException(e.Message, e); } } } } DebugDirectoryBuilder debugDirectoryBuilder; if (pdbPathOpt != null || isDeterministic || portablePdbToEmbed != null) { debugDirectoryBuilder = new DebugDirectoryBuilder(); if (pdbPathOpt != null) { string paddedPath = isDeterministic ? pdbPathOpt : PadPdbPath(pdbPathOpt); debugDirectoryBuilder.AddCodeViewEntry(paddedPath, pdbContentId, portablePdbVersion); if (!portablePdbContentHash.IsDefault) { // Emit PDB Checksum entry for Portable and Embedded PDBs. The checksum is not as useful when the PDB is embedded, // however it allows the client to efficiently validate a standalone Portable PDB that // has been extracted from Embedded PDB and placed next to the PE file. debugDirectoryBuilder.AddPdbChecksumEntry(context.Module.PdbChecksumAlgorithm.Name, portablePdbContentHash); } } if (isDeterministic) { debugDirectoryBuilder.AddReproducibleEntry(); } if (portablePdbToEmbed != null) { debugDirectoryBuilder.AddEmbeddedPortablePdbEntry(portablePdbToEmbed, portablePdbVersion); } } else { debugDirectoryBuilder = null; } var strongNameProvider = context.Module.CommonCompilation.Options.StrongNameProvider; var corFlags = properties.CorFlags; var peBuilder = new ExtendedPEBuilder( peHeaderBuilder, metadataRootBuilder, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, CreateNativeResourceSectionSerializer(context.Module), debugDirectoryBuilder, CalculateStrongNameSignatureSize(context.Module, privateKeyOpt), entryPointHandle, corFlags, peIdProvider, metadataOnly && !context.IncludePrivateMembers); var peBlob = new BlobBuilder(); var peContentId = peBuilder.Serialize(peBlob, out Blob mvidSectionFixup); PatchModuleVersionIds(mvidFixup, mvidSectionFixup, mvidStringFixup, peContentId.Guid); if (privateKeyOpt != null && corFlags.HasFlag(CorFlags.StrongNameSigned)) { strongNameProvider.SignBuilder(peBuilder, peBlob, privateKeyOpt.Value); } try { peBlob.WriteContentTo(peStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new PeWritingException(e); } return(true); }
public static void SerializeWin32Resources(BlobBuilder builder, IEnumerable <IWin32Resource> theResources, int resourcesRva) { theResources = SortResources(theResources); Directory typeDirectory = new Directory(string.Empty, 0); Directory nameDirectory = null; Directory languageDirectory = null; int lastTypeID = int.MinValue; string lastTypeName = null; int lastID = int.MinValue; string lastName = null; uint sizeOfDirectoryTree = 16; //EDMAURER note that this list is assumed to be sorted lowest to highest //first by typeId, then by Id. foreach (IWin32Resource r in theResources) { bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; if (typeDifferent) { lastTypeID = r.TypeId; lastTypeName = r.TypeName; if (lastTypeID < 0) { Debug.Assert(typeDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with types encoded as strings precede those encoded as ints"); typeDirectory.NumberOfNamedEntries++; } else { typeDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; typeDirectory.Entries.Add(nameDirectory = new Directory(lastTypeName, lastTypeID)); } if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) { lastID = r.Id; lastName = r.Name; if (lastID < 0) { Debug.Assert(nameDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with names encoded as strings precede those encoded as ints"); nameDirectory.NumberOfNamedEntries++; } else { nameDirectory.NumberOfIdEntries++; } sizeOfDirectoryTree += 24; nameDirectory.Entries.Add(languageDirectory = new Directory(lastName, lastID)); } languageDirectory.NumberOfIdEntries++; sizeOfDirectoryTree += 8; languageDirectory.Entries.Add(r); } var dataWriter = new BlobBuilder(); //'dataWriter' is where opaque resource data goes as well as strings that are used as type or name identifiers WriteDirectory(typeDirectory, builder, 0, 0, sizeOfDirectoryTree, resourcesRva, dataWriter); builder.LinkSuffix(dataWriter); builder.WriteByte(0); builder.Align(4); }
private BlobHandle SerializeSequencePoints( StandaloneSignatureHandle localSignatureHandleOpt, ImmutableArray <SequencePoint> sequencePoints, Dictionary <DebugSourceDocument, DocumentHandle> documentIndex, out DocumentHandle singleDocumentHandle ) { if (sequencePoints.Length == 0) { singleDocumentHandle = default(DocumentHandle); return(default(BlobHandle)); } var writer = new BlobBuilder(); int previousNonHiddenStartLine = -1; int previousNonHiddenStartColumn = -1; // header: writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(localSignatureHandleOpt)); var previousDocument = TryGetSingleDocument(sequencePoints); singleDocumentHandle = (previousDocument != null) ? GetOrAddDocument(previousDocument, documentIndex) : default(DocumentHandle); for (int i = 0; i < sequencePoints.Length; i++) { var currentDocument = sequencePoints[i].Document; if (previousDocument != currentDocument) { var documentHandle = GetOrAddDocument(currentDocument, documentIndex); // optional document in header or document record: if (previousDocument != null) { writer.WriteCompressedInteger(0); } writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(documentHandle)); previousDocument = currentDocument; } // delta IL offset: if (i > 0) { writer.WriteCompressedInteger( sequencePoints[i].Offset - sequencePoints[i - 1].Offset ); } else { writer.WriteCompressedInteger(sequencePoints[i].Offset); } if (sequencePoints[i].IsHidden) { writer.WriteInt16(0); continue; } // Delta Lines & Columns: SerializeDeltaLinesAndColumns(writer, sequencePoints[i]); // delta Start Lines & Columns: if (previousNonHiddenStartLine < 0) { Debug.Assert(previousNonHiddenStartColumn < 0); writer.WriteCompressedInteger(sequencePoints[i].StartLine); writer.WriteCompressedInteger(sequencePoints[i].StartColumn); } else { writer.WriteCompressedSignedInteger( sequencePoints[i].StartLine - previousNonHiddenStartLine ); writer.WriteCompressedSignedInteger( sequencePoints[i].StartColumn - previousNonHiddenStartColumn ); } previousNonHiddenStartLine = sequencePoints[i].StartLine; previousNonHiddenStartColumn = sequencePoints[i].StartColumn; } return(_debugMetadataOpt.GetOrAddBlob(writer)); }
private static void WriteUtf8String(BlobBuilder builder, string str) { builder.WriteUTF8(str); builder.WriteByte(0); }
private void WriteImportAddressTable(Stream peStream, int importTableRva) { var writer = new BlobBuilder(SizeOfImportAddressTable); int ilRVA = importTableRva + 40; int hintRva = ilRVA + (_is32bit ? 12 : 16); // Import Address Table if (_is32bit) { writer.WriteUInt32((uint)hintRva); // 4 writer.WriteUInt32(0); // 8 } else { writer.WriteUInt64((uint)hintRva); // 8 writer.WriteUInt64(0); // 16 } Debug.Assert(writer.Length == SizeOfImportAddressTable); writer.WriteTo(peStream); }
// internal for testing internal void ClearChunk() { _length = 0; _previousLength = 0; _nextOrPrevious = this; }
private static void WriteNameTable(Stream peStream) { var writer = new BlobBuilder(SizeOfNameTable); foreach (char ch in CorEntryPointDll) { writer.WriteByte((byte)ch); } writer.WriteByte(0); writer.WriteUInt16(0); Debug.Assert(writer.Length == SizeOfNameTable); writer.WriteTo(peStream); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception> public bool ContentEquals(BlobBuilder other) { if (!IsHead) { ThrowHeadRequired(); } if (ReferenceEquals(this, other)) { return(true); } if (other == null) { return(false); } if (!other.IsHead) { ThrowHeadRequired(); } if (Count != other.Count) { return(false); } var leftEnumerator = GetChunks(); var rightEnumerator = other.GetChunks(); int leftStart = 0; int rightStart = 0; bool leftContinues = leftEnumerator.MoveNext(); bool rightContinues = rightEnumerator.MoveNext(); while (leftContinues && rightContinues) { Debug.Assert(leftStart == 0 || rightStart == 0); var left = leftEnumerator.Current; var right = rightEnumerator.Current; int minLength = Math.Min(left.Length - leftStart, right.Length - rightStart); if (!ByteSequenceComparer.Equals(left._buffer, leftStart, right._buffer, rightStart, minLength)) { return(false); } leftStart += minLength; rightStart += minLength; // nothing remains in left chunk to compare: if (leftStart == left.Length) { leftContinues = leftEnumerator.MoveNext(); leftStart = 0; } // nothing remains in left chunk to compare: if (rightStart == right.Length) { rightContinues = rightEnumerator.MoveNext(); rightStart = 0; } } return(leftContinues == rightContinues); }
private void WriteRelocSection(Stream peStream, SectionHeader relocSection, int entryPointAddress) { peStream.Position = relocSection.PointerToRawData; var writer = new BlobBuilder(relocSection.SizeOfRawData); writer.WriteUInt32((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); writer.WriteUInt32(_properties.Requires64bits && !_properties.RequiresAmdInstructionSet ? 14u : 12u); uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; uint relocType = _properties.Requires64bits ? 10u : 3u; ushort s = (ushort)((relocType << 12) | offsetWithinPage); writer.WriteUInt16(s); if (_properties.Requires64bits && !_properties.RequiresAmdInstructionSet) { writer.WriteUInt32(relocType << 12); } writer.WriteUInt16(0); // next chunk's RVA writer.PadTo(relocSection.SizeOfRawData); writer.WriteTo(peStream); }
/// <exception cref="ArgumentNullException"><paramref name="suffix"/> is null.</exception> /// <exception cref="InvalidOperationException">Builder is not writable, it has been linked with another one.</exception> public void LinkSuffix(BlobBuilder suffix) { if (suffix == null) { throw new ArgumentNullException(nameof(suffix)); } // TODO: consider copying data from right to left while there is space if (!IsHead || !suffix.IsHead) { ThrowHeadRequired(); } // avoid chaining empty chunks: if (suffix.Count == 0) { return; } // swap buffers of the heads: var suffixBuffer = suffix._buffer; uint suffixLength = suffix._length; suffix._buffer = _buffer; suffix._length = FrozenLength; // suffix is not a head anymore _buffer = suffixBuffer; _length = suffixLength; int suffixPreviousLength = suffix._previousLength; suffix._previousLength = _previousLength; _previousLength = _previousLength + suffix.Length + suffixPreviousLength; // First and last chunks: // // [First]->[]->[Last] <- [this] [SuffixFirst]->[]->[SuffixLast] <- [suffix] // ^___________| ^_________________| // // Degenerate cases: // this == First == Last and/or suffix == SuffixFirst == SuffixLast. var first = FirstChunk; var suffixFirst = suffix.FirstChunk; var last = _nextOrPrevious; var suffixLast = suffix._nextOrPrevious; // Relink like so: // [First]->[]->[Last] -> [suffix] -> [SuffixFirst]->[]->[SuffixLast] <- [this] // ^_______________________________________________________| _nextOrPrevious = suffixLast; suffix._nextOrPrevious = (suffixFirst != suffix) ? suffixFirst : (first != this) ? first : suffix; if (last != this) { last._nextOrPrevious = suffix; } if (suffixLast != suffix) { suffixLast._nextOrPrevious = (first != this) ? first : suffix; } CheckInvariants(); suffix.CheckInvariants(); }
private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) { if (import.TargetXmlNamespaceOpt != null) { Debug.Assert(import.TargetNamespaceOpt == null); Debug.Assert(import.TargetAssemblyOpt == null); Debug.Assert(import.TargetTypeOpt == null); // <import> ::= ImportXmlNamespace <alias> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportXmlNamespace); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.AliasOpt) ) ); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.TargetXmlNamespaceOpt) ) ); } else if (import.TargetTypeOpt != null) { Debug.Assert(import.TargetNamespaceOpt == null); Debug.Assert(import.TargetAssemblyOpt == null); if (import.AliasOpt != null) { // <import> ::= AliasType <alias> <target-type> writer.WriteByte((byte)ImportDefinitionKind.AliasType); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.AliasOpt) ) ); } else { // <import> ::= ImportType <target-type> writer.WriteByte((byte)ImportDefinitionKind.ImportType); } writer.WriteCompressedInteger( CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(import.TargetTypeOpt)) ); // TODO: index in release build } else if (import.TargetNamespaceOpt != null) { if (import.TargetAssemblyOpt != null) { if (import.AliasOpt != null) { // <import> ::= AliasAssemblyNamespace <alias> <target-assembly> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.AliasAssemblyNamespace); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.AliasOpt) ) ); } else { // <import> ::= ImportAssemblyNamespace <target-assembly> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyNamespace); } writer.WriteCompressedInteger( MetadataTokens.GetRowNumber( GetAssemblyReferenceHandle(import.TargetAssemblyOpt) ) ); } else { if (import.AliasOpt != null) { // <import> ::= AliasNamespace <alias> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.AliasNamespace); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.AliasOpt) ) ); } else { // <import> ::= ImportNamespace <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportNamespace); } } // TODO: cache? string namespaceName = TypeNameSerializer.BuildQualifiedNamespaceName( import.TargetNamespaceOpt ); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUTF8(namespaceName)) ); } else { // <import> ::= ImportReferenceAlias <alias> Debug.Assert(import.AliasOpt != null); Debug.Assert(import.TargetAssemblyOpt == null); writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyReferenceAlias); writer.WriteCompressedInteger( MetadataTokens.GetHeapOffset( _debugMetadataOpt.GetOrAddBlobUTF8(import.AliasOpt) ) ); } }
/// <summary> /// Writes information about metadata references to the pdb so the same /// reference can be found on sourcelink to create the compilation again /// </summary> private void EmbedMetadataReferenceInformation(CommonPEModuleBuilder module) { var builder = new BlobBuilder(); // Order of information // File name (null terminated string): A.exe // Extern Alias (null terminated string): a1,a2,a3 // MetadataImageKind (byte) // EmbedInteropTypes (boolean) // COFF header Timestamp field (4 byte int) // COFF header SizeOfImage field (4 byte int) // MVID (Guid, 24 bytes) foreach (var metadataReference in module.CommonCompilation.ExternalReferences) { if (metadataReference is PortableExecutableReference portableReference && portableReference.FilePath is object) { var fileName = PathUtilities.GetFileName(portableReference.FilePath); var reference = module.CommonCompilation.GetAssemblyOrModuleSymbol(portableReference); var peReader = GetReader(reference); // Don't write before checking that we can get a peReader for the metadata reference if (peReader is null) { continue; } // Write file name first builder.WriteUTF8(fileName); // Make sure to add null terminator builder.WriteByte(0); // Extern alias if (portableReference.Properties.Aliases.Any()) { builder.WriteUTF8(string.Join(",", portableReference.Properties.Aliases)); } // Always null terminate the extern alias list builder.WriteByte(0); byte kindAndEmbedInteropTypes = (byte)(portableReference.Properties.EmbedInteropTypes ? 0b10 : 0b0); kindAndEmbedInteropTypes |= portableReference.Properties.Kind switch { MetadataImageKind.Assembly => 1, MetadataImageKind.Module => 0, _ => throw ExceptionUtilities.UnexpectedValue(portableReference.Properties.Kind) }; builder.WriteByte(kindAndEmbedInteropTypes); builder.WriteInt32(peReader.PEHeaders.CoffHeader.TimeDateStamp); builder.WriteInt32(peReader.PEHeaders.PEHeader.SizeOfImage); var metadataReader = peReader.GetMetadataReader(); var moduleDefinition = metadataReader.GetModuleDefinition(); builder.WriteGuid(metadataReader.GetGuid(moduleDefinition.Mvid)); } } _debugMetadataOpt.AddCustomDebugInformation( parent: EntityHandle.ModuleDefinition, kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.MetadataReferenceInfo), value: _debugMetadataOpt.GetOrAddBlob(builder));
/// <summary> /// Write string as UTF8 with null terminator. /// </summary> private static void WriteUtf8String(BlobBuilder cmw, string str) { cmw.WriteUTF8(str); cmw.WriteByte(0); }
public static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, Func <Stream> getPeStream, Func <Stream> getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool allowMissingMethodBodies, bool isDeterministic, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken); var properties = context.Module.Properties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. Debug.Assert(properties.PersistentIdentifier == default(Guid)); var ilBuilder = new BlobBuilder(32 * 1024); var mappedFieldDataBuilder = new BlobBuilder(); var managedResourceBuilder = new BlobBuilder(1024); Blob mvidFixup; mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, out mvidFixup); MethodDefinitionHandle entryPointHandle; MethodDefinitionHandle debugEntryPointHandle; mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle); if (!debugEntryPointHandle.IsNil) { nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle)); } if (nativePdbWriterOpt != null) { var assembly = mdWriter.Module.AsAssembly; if (assembly != null && assembly.Kind == OutputKind.WindowsRuntimeMetadata) { // Dev12: If compiling to winmdobj, we need to add to PDB source spans of // all types and members for better error reporting by WinMDExp. nativePdbWriterOpt.WriteDefinitionLocations(mdWriter.Module.GetSymbolToLocationMap()); } else { #if DEBUG // validate that all definitions are writable // if same scenario would happen in an winmdobj project nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } } Stream peStream = getPeStream(); if (peStream == null) { return(false); } ContentId nativePdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(ContentId); // the writer shall not be used after this point for writing: nativePdbWriterOpt = null; var metadataSerializer = mdWriter.GetTypeSystemMetadataSerializer(); var peBuilder = new PEBuilder( machine: properties.Machine, sectionAlignment: properties.SectionAlignment, fileAlignment: properties.FileAlignment, imageBase: properties.BaseAddress, majorLinkerVersion: properties.LinkerMajorVersion, minorLinkerVersion: properties.LinkerMinorVersion, majorOperatingSystemVersion: 4, minorOperatingSystemVersion: 0, majorImageVersion: 0, minorImageVersion: 0, majorSubsystemVersion: properties.MajorSubsystemVersion, minorSubsystemVersion: properties.MinorSubsystemVersion, subsystem: properties.Subsystem, dllCharacteristics: properties.DllCharacteristics, imageCharacteristics: properties.ImageCharacteristics, sizeOfStackReserve: properties.SizeOfStackReserve, sizeOfStackCommit: properties.SizeOfStackCommit, sizeOfHeapReserve: properties.SizeOfHeapReserve, sizeOfHeapCommit: properties.SizeOfHeapCommit, deterministicIdProvider: isDeterministic ? new Func <BlobBuilder, ContentId>(content => ContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) : null); ContentId portablePdbContentId; if (mdWriter.EmitStandaloneDebugMetadata) { Debug.Assert(getPortablePdbStreamOpt != null); var debugMetadataBuilder = new BlobBuilder(); var debugMetadataSerializer = mdWriter.GetStandaloneDebugMetadataSerializer(metadataSerializer.MetadataSizes, debugEntryPointHandle); debugMetadataSerializer.SerializeMetadata(debugMetadataBuilder, peBuilder.IdProvider, out portablePdbContentId); // write to Portable PDB stream: Stream portablePdbStream = getPortablePdbStreamOpt(); if (portablePdbStream != null) { debugMetadataBuilder.WriteContentTo(portablePdbStream); } } else { portablePdbContentId = default(ContentId); } var peDirectoriesBuilder = new PEDirectoriesBuilder(); peBuilder.AddManagedSections( peDirectoriesBuilder, metadataSerializer, ilBuilder, mappedFieldDataBuilder, managedResourceBuilder, CreateNativeResourceSectionSerializer(context.Module), CalculateStrongNameSignatureSize(context.Module), entryPointHandle, pdbPathOpt, nativePdbContentId, portablePdbContentId, properties.CorFlags); var peBlob = new BlobBuilder(); ContentId peContentId; peBuilder.Serialize(peBlob, peDirectoriesBuilder, out peContentId); // Patch MVID if (!mvidFixup.IsDefault) { var mvidWriter = new BlobWriter(mvidFixup); mvidWriter.WriteBytes(peContentId.Guid); Debug.Assert(mvidWriter.RemainingBytes == 0); } try { peBlob.WriteContentTo(peStream); } catch (Exception e) when(!(e is OperationCanceledException)) { throw new PeWritingException(e); } return(true); }
public void WriteUTF16() { var writer = new BlobBuilder(4); writer.WriteUTF16(""); writer.WriteUTF16("a"); writer.WriteUTF16(""); writer.WriteUTF16(new char[0]); writer.WriteUTF16(new char[] { '\ud800' }); // hi surrogate writer.WriteUTF16("\udc00"); // lo surrogate writer.WriteUTF16("\ud800\udc00"); // pair writer.WriteUTF16(new char[] { '\udc00', '\ud800' }); // lo + hi writer.WriteUTF16("\u1234"); AssertEx.Equal(new byte[] { 0x61, 0x00, 0x00, 0xD8, 0x00, 0xDC, 0x00, 0xD8, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0xD8, 0x34, 0x12 }, writer.ToArray()); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <BlobBuilder> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { Debug.Assert(local.SlotIndex >= 0); if (local.IsDynamic) { dynamicLocals.Add(local); } } foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { Debug.Assert(localConstant.SlotIndex < 0); if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached const int dynamicAttributeSize = 64; const int identifierSize = 64; const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128 var cmw = new BlobBuilder(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32((uint)dynamicLocals.Count); foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length >= identifierSize)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= dynamicAttributeSize) { byte[] flag = new byte[dynamicAttributeSize]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, dynamicAttributeSize + 4); //Empty flag array and size. } var localIndex = local.SlotIndex; cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex); char[] localName = new char[identifierSize]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
public void WriteUTF8_ReplaceUnpairedSurrogates() { var writer = new BlobBuilder(4); writer.WriteUTF8("a", allowUnpairedSurrogates: false); writer.WriteUTF8("", allowUnpairedSurrogates: false); writer.WriteUTF8("bc", allowUnpairedSurrogates: false); writer.WriteUTF8("d", allowUnpairedSurrogates: false); writer.WriteUTF8("", allowUnpairedSurrogates: false); writer.WriteUTF8(Encoding.UTF8.GetString(new byte[] { 0x00, 0xC2, 0x80, 0xE1, 0x88, 0xB4 }), allowUnpairedSurrogates: false); writer.WriteUTF8("\0\ud800", allowUnpairedSurrogates: false); // hi surrogate writer.WriteUTF8("\0\udc00", allowUnpairedSurrogates: false); // lo surrogate writer.WriteUTF8("\0\ud800\udc00", allowUnpairedSurrogates: false); // pair writer.WriteUTF8("\0\udc00\ud800", allowUnpairedSurrogates: false); // lo + hi AssertEx.Equal(new byte[] { (byte)'a', (byte)'b', (byte)'c', (byte)'d', 0x00, 0xC2, 0x80, 0xE1, 0x88, 0xB4, 0x00, 0xEF, 0xBF, 0xBD, 0x00, 0xEF, 0xBF, 0xBD, 0x00, 0xF0, 0x90, 0x80, 0x80, 0x00, 0xEF, 0xBF, 0xBD, 0xEF, 0xBF, 0xBD }, writer.ToArray()); }
private BlobIdx SerializeSequencePoints( int localSignatureRowId, ImmutableArray <SequencePoint> sequencePoints, Dictionary <DebugSourceDocument, int> documentIndex, out int singleDocumentRowId) { if (sequencePoints.Length == 0) { singleDocumentRowId = 0; return(default(BlobIdx)); } var writer = new BlobBuilder(); int previousNonHiddenStartLine = -1; int previousNonHiddenStartColumn = -1; // header: writer.WriteCompressedInteger((uint)localSignatureRowId); var previousDocument = TryGetSingleDocument(sequencePoints); singleDocumentRowId = (previousDocument != null) ? GetOrAddDocument(previousDocument, documentIndex) : 0; for (int i = 0; i < sequencePoints.Length; i++) { var currentDocument = sequencePoints[i].Document; if (previousDocument != currentDocument) { int documentRowId = GetOrAddDocument(currentDocument, documentIndex); // optional document in header or document record: if (previousDocument != null) { writer.WriteCompressedInteger(0); } writer.WriteCompressedInteger((uint)documentRowId); previousDocument = currentDocument; } // delta IL offset: if (i > 0) { writer.WriteCompressedInteger((uint)(sequencePoints[i].Offset - sequencePoints[i - 1].Offset)); } else { writer.WriteCompressedInteger((uint)sequencePoints[i].Offset); } if (sequencePoints[i].IsHidden) { writer.WriteInt16(0); continue; } // Delta Lines & Columns: SerializeDeltaLinesAndColumns(writer, sequencePoints[i]); // delta Start Lines & Columns: if (previousNonHiddenStartLine < 0) { Debug.Assert(previousNonHiddenStartColumn < 0); writer.WriteCompressedInteger((uint)sequencePoints[i].StartLine); writer.WriteCompressedInteger((uint)sequencePoints[i].StartColumn); } else { writer.WriteCompressedSignedInteger(sequencePoints[i].StartLine - previousNonHiddenStartLine); writer.WriteCompressedSignedInteger(sequencePoints[i].StartColumn - previousNonHiddenStartColumn); } previousNonHiddenStartLine = sequencePoints[i].StartLine; previousNonHiddenStartColumn = sequencePoints[i].StartColumn; } return(_debugHeapsOpt.GetBlobIndex(writer)); }
private void WriteHeaders(Stream peStream, NtHeader ntHeader, CoffHeader coffHeader, List<SectionHeader> sectionHeaders, out long ntHeaderTimestampPosition) { var writer = new BlobBuilder(1024); // MS-DOS stub (128 bytes) writer.WriteBytes(s_dosHeader); // PE Signature "PE\0\0" writer.WriteUInt32(0x00004550); // COFF Header (20 bytes) writer.WriteUInt16((ushort)coffHeader.Machine); writer.WriteUInt16((ushort)coffHeader.NumberOfSections); ntHeaderTimestampPosition = writer.Position + peStream.Position; writer.WriteUInt32((uint)coffHeader.TimeDateStamp); writer.WriteUInt32((uint)coffHeader.PointerToSymbolTable); writer.WriteUInt32((uint)coffHeader.NumberOfSymbols); writer.WriteUInt16((ushort)(_is32bit ? 224 : 240)); // SizeOfOptionalHeader writer.WriteUInt16((ushort)coffHeader.Characteristics); // PE Headers: writer.WriteUInt16((ushort)(_is32bit ? PEMagic.PE32 : PEMagic.PE32Plus)); // 2 writer.WriteByte(ntHeader.MajorLinkerVersion); // 3 writer.WriteByte(ntHeader.MinorLinkerVersion); // 4 writer.WriteUInt32((uint)ntHeader.SizeOfCode); // 8 writer.WriteUInt32((uint)ntHeader.SizeOfInitializedData); // 12 writer.WriteUInt32((uint)ntHeader.SizeOfUninitializedData); // 16 writer.WriteUInt32((uint)ntHeader.AddressOfEntryPoint); // 20 writer.WriteUInt32((uint)ntHeader.BaseOfCode); // 24 if (_is32bit) { writer.WriteUInt32((uint)ntHeader.BaseOfData); // 28 writer.WriteUInt32((uint)ntHeader.ImageBase); // 32 } else { writer.WriteUInt64(ntHeader.ImageBase); // 32 } // NT additional fields: writer.WriteUInt32((uint)ntHeader.SectionAlignment); // 36 writer.WriteUInt32((uint)ntHeader.FileAlignment); // 40 writer.WriteUInt16(ntHeader.MajorOperatingSystemVersion); // 42 writer.WriteUInt16(ntHeader.MinorOperatingSystemVersion); // 44 writer.WriteUInt16(ntHeader.MajorImageVersion); // 46 writer.WriteUInt16(ntHeader.MinorImageVersion); // 48 writer.WriteUInt16(ntHeader.MajorSubsystemVersion); // MajorSubsystemVersion 50 writer.WriteUInt16(ntHeader.MinorSubsystemVersion); // MinorSubsystemVersion 52 // Win32VersionValue (reserved, should be 0) writer.WriteUInt32(0); // 56 writer.WriteUInt32((uint)ntHeader.SizeOfImage); // 60 writer.WriteUInt32((uint)ntHeader.SizeOfHeaders); // 64 writer.WriteUInt32(ntHeader.Checksum); // 68 writer.WriteUInt16((ushort)ntHeader.Subsystem); // 70 writer.WriteUInt16((ushort)ntHeader.DllCharacteristics); if (_is32bit) { writer.WriteUInt32((uint)ntHeader.SizeOfStackReserve); // 76 writer.WriteUInt32((uint)ntHeader.SizeOfStackCommit); // 80 writer.WriteUInt32((uint)ntHeader.SizeOfHeapReserve); // 84 writer.WriteUInt32((uint)ntHeader.SizeOfHeapCommit); // 88 } else { writer.WriteUInt64(ntHeader.SizeOfStackReserve); // 80 writer.WriteUInt64(ntHeader.SizeOfStackCommit); // 88 writer.WriteUInt64(ntHeader.SizeOfHeapReserve); // 96 writer.WriteUInt64(ntHeader.SizeOfHeapCommit); // 104 } // LoaderFlags writer.WriteUInt32(0); // 92|108 // The number of data-directory entries in the remainder of the header. writer.WriteUInt32(16); // 96|112 // directory entries: writer.WriteUInt32((uint)ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 writer.WriteUInt32((uint)ntHeader.ExportTable.Size); // 104|120 writer.WriteUInt32((uint)ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 writer.WriteUInt32((uint)ntHeader.ImportTable.Size); // 112|128 writer.WriteUInt32((uint)ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 writer.WriteUInt32((uint)ntHeader.ResourceTable.Size); // 120|136 writer.WriteUInt32((uint)ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 writer.WriteUInt32((uint)ntHeader.ExceptionTable.Size); // 128|144 writer.WriteUInt32((uint)ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 writer.WriteUInt32((uint)ntHeader.CertificateTable.Size); // 136|152 writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.Size); // 144|160 writer.WriteUInt32((uint)ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 writer.WriteUInt32((uint)ntHeader.DebugTable.Size); // 152|168 writer.WriteUInt32((uint)ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 writer.WriteUInt32((uint)ntHeader.CopyrightTable.Size); // 160|176 writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.Size); // 168|184 writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.Size); // 176|192 writer.WriteUInt32((uint)ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 writer.WriteUInt32((uint)ntHeader.LoadConfigTable.Size); // 184|200 writer.WriteUInt32((uint)ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 writer.WriteUInt32((uint)ntHeader.BoundImportTable.Size); // 192|208 writer.WriteUInt32((uint)ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 writer.WriteUInt32((uint)ntHeader.ImportAddressTable.Size); // 200|216 writer.WriteUInt32((uint)ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 writer.WriteUInt32((uint)ntHeader.DelayImportTable.Size); // 208|224 writer.WriteUInt32((uint)ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 writer.WriteUInt32((uint)ntHeader.CliHeaderTable.Size); // 216|232 writer.WriteUInt64(0); // 224|240 // Section Headers foreach (var sectionHeader in sectionHeaders) { WriteSectionHeader(sectionHeader, writer); } writer.WriteTo(peStream); }
private static void SerializeTupleElementNames(ArrayBuilder <LocalAndScope> locals, BlobBuilder cmw) { cmw.WriteInt32(locals.Count); foreach (var localAndScope in locals) { var local = localAndScope.Local; var scope = localAndScope.Scope; var tupleElementNames = local.TupleElementNames; cmw.WriteInt32(tupleElementNames.Length); foreach (var tupleElementName in tupleElementNames) { WriteUtf8String(cmw, (string)tupleElementName.Value ?? string.Empty); } cmw.WriteInt32(local.SlotIndex); cmw.WriteInt32(scope.StartOffset); cmw.WriteInt32(scope.EndOffset); WriteUtf8String(cmw, local.Name); } }
private void WriteTextSection( Stream peStream, SectionHeader textSection, int importTableRva, int importAddressTableRva, int entryPointToken, BlobBuilder metadataWriter, BlobBuilder ilWriter, BlobBuilder mappedFieldDataWriter, BlobBuilder managedResourceWriter, MetadataSizes metadataSizes, ContentId nativePdbContentId, ContentId portablePdbContentId, out long metadataPosition) { // TODO: zero out all bytes: peStream.Position = textSection.PointerToRawData; if (_properties.RequiresStartupStub) { WriteImportAddressTable(peStream, importTableRva); } var corHeader = CreateCorHeader(metadataSizes, textSection.RelativeVirtualAddress, entryPointToken); WriteCorHeader(peStream, corHeader); // IL: ilWriter.Align(4); ilWriter.WriteTo(peStream); // metadata: metadataPosition = peStream.Position; Debug.Assert(metadataWriter.Length % 4 == 0); metadataWriter.WriteTo(peStream); // managed resources: Debug.Assert(managedResourceWriter.Length % 4 == 0); managedResourceWriter.WriteTo(peStream); // strong name signature: WriteSpaceForHash(peStream, metadataSizes.StrongNameSignatureSize); if (EmitPdb) { WriteDebugTable(peStream, textSection, nativePdbContentId, portablePdbContentId, metadataSizes); } if (_properties.RequiresStartupStub) { WriteImportTable(peStream, importTableRva, importAddressTableRva); WriteNameTable(peStream); WriteRuntimeStartupStub(peStream, importAddressTableRva); } // mapped field data: mappedFieldDataWriter.WriteTo(peStream); // TODO: zero out all bytes: int alignedPosition = textSection.PointerToRawData + textSection.SizeOfRawData; if (peStream.Position != alignedPosition) { peStream.Position = alignedPosition - 1; peStream.WriteByte(0); } }
private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) { if (import.TargetXmlNamespaceOpt != null) { Debug.Assert(import.TargetNamespaceOpt == null); Debug.Assert(import.TargetAssemblyOpt == null); Debug.Assert(import.TargetTypeOpt == null); // <import> ::= ImportXmlNamespace <alias> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportXmlNamespace); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.TargetXmlNamespaceOpt))); } else if (import.TargetTypeOpt != null) { Debug.Assert(import.TargetNamespaceOpt == null); Debug.Assert(import.TargetAssemblyOpt == null); if (import.AliasOpt != null) { // <import> ::= AliasType <alias> <target-type> writer.WriteByte((byte)ImportDefinitionKind.AliasType); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); } else { // <import> ::= ImportType <target-type> writer.WriteByte((byte)ImportDefinitionKind.ImportType); } writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(import.TargetTypeOpt, treatRefAsPotentialTypeSpec: true)); // TODO: index in release build } else if (import.TargetNamespaceOpt != null) { if (import.TargetAssemblyOpt != null) { if (import.AliasOpt != null) { // <import> ::= AliasAssemblyNamespace <alias> <target-assembly> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.AliasAssemblyNamespace); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); } else { // <import> ::= ImportAssemblyNamespace <target-assembly> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyNamespace); } writer.WriteCompressedInteger((uint)GetAssemblyRefIndex(import.TargetAssemblyOpt)); } else { if (import.AliasOpt != null) { // <import> ::= AliasNamespace <alias> <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.AliasNamespace); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); } else { // <import> ::= ImportNamespace <target-namespace> writer.WriteByte((byte)ImportDefinitionKind.ImportNamespace); } } // TODO: cache? string namespaceName = TypeNameSerializer.BuildQualifiedNamespaceName(import.TargetNamespaceOpt); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(namespaceName))); } else { // <import> ::= ImportReferenceAlias <alias> Debug.Assert(import.AliasOpt != null); Debug.Assert(import.TargetAssemblyOpt == null); writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyReferenceAlias); writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); } }
private void WriteImportTable(Stream peStream, int importTableRva, int importAddressTableRva) { var writer = new BlobBuilder(SizeOfImportTable); int ilRVA = importTableRva + 40; int hintRva = ilRVA + (_is32bit ? 12 : 16); int nameRva = hintRva + 12 + 2; // Import table writer.WriteUInt32((uint)ilRVA); // 4 writer.WriteUInt32(0); // 8 writer.WriteUInt32(0); // 12 writer.WriteUInt32((uint)nameRva); // 16 writer.WriteUInt32((uint)importAddressTableRva); // 20 writer.WriteBytes(0, 20); // 40 // Import Lookup table if (_is32bit) { writer.WriteUInt32((uint)hintRva); // 44 writer.WriteUInt32(0); // 48 writer.WriteUInt32(0); // 52 } else { writer.WriteUInt64((uint)hintRva); // 48 writer.WriteUInt64(0); // 56 } // Hint table writer.WriteUInt16(0); // Hint 54|58 foreach (char ch in CorEntryPointName) { writer.WriteByte((byte)ch); // 65|69 } writer.WriteByte(0); // 66|70 Debug.Assert(writer.Length == SizeOfImportTable); writer.WriteTo(peStream); }
private BlobIdx SerializeLocalConstantSignature(ILocalDefinition localConstant) { var writer = new BlobBuilder(); // CustomMod* SerializeCustomModifiers(localConstant.CustomModifiers, writer); var type = localConstant.Type; var typeCode = type.TypeCode(Context); object value = localConstant.CompileTimeValue.Value; // PrimitiveConstant or EnumConstant if (value is decimal) { writer.WriteByte(0x11); writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); writer.WriteDecimal((decimal)value); } else if (value is DateTime) { writer.WriteByte(0x11); writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); writer.WriteDateTime((DateTime)value); } else if (typeCode == PrimitiveTypeCode.String) { writer.WriteByte((byte)ConstantTypeCode.String); if (value == null) { writer.WriteByte(0xff); } else { writer.WriteUTF16((string)value); } } else if (value != null) { // TypeCode writer.WriteByte((byte)GetConstantTypeCode(value)); // Value writer.WriteConstant(value); // EnumType if (type.IsEnum) { writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); } } else if (this.module.IsPlatformType(type, PlatformType.SystemObject)) { writer.WriteByte(0x1c); } else { writer.WriteByte((byte)(type.IsValueType ? 0x11 : 0x12)); writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); } return(_debugHeapsOpt.GetBlobIndex(writer)); }
private static void WriteCorHeader(Stream peStream, CorHeader corHeader) { var writer = new BlobBuilder(CorHeaderSize); writer.WriteUInt32(CorHeaderSize); writer.WriteUInt16(corHeader.MajorRuntimeVersion); writer.WriteUInt16(corHeader.MinorRuntimeVersion); writer.WriteUInt32((uint)corHeader.MetadataDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.MetadataDirectory.Size); writer.WriteUInt32((uint)corHeader.Flags); writer.WriteUInt32((uint)corHeader.EntryPointTokenOrRelativeVirtualAddress); writer.WriteUInt32((uint)(corHeader.ResourcesDirectory.Size == 0 ? 0 : corHeader.ResourcesDirectory.RelativeVirtualAddress)); // 28 writer.WriteUInt32((uint)corHeader.ResourcesDirectory.Size); writer.WriteUInt32((uint)(corHeader.StrongNameSignatureDirectory.Size == 0 ? 0 : corHeader.StrongNameSignatureDirectory.RelativeVirtualAddress)); // 36 writer.WriteUInt32((uint)corHeader.StrongNameSignatureDirectory.Size); writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.Size); writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.Size); writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.RelativeVirtualAddress); writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.Size); writer.WriteUInt64(0); Debug.Assert(writer.Length == CorHeaderSize); Debug.Assert(writer.Length % 4 == 0); writer.WriteTo(peStream); }
/// <summary> /// Write string as UTF16 with null terminator. /// </summary> private static void WriteUtf16String(BlobBuilder cmw, string str) { cmw.WriteUTF16(str); cmw.WriteUInt16(0); }
private void WriteRuntimeStartupStub(Stream peStream, int importAddressTableRva) { var writer = new BlobBuilder(16); // entry point code, consisting of a jump indirect to _CorXXXMain if (_is32bit) { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUInt16(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 writer.WriteUInt32((uint)importAddressTableRva + (uint)_properties.BaseAddress); //8 } else { //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) { writer.WriteByte(0); } writer.WriteUInt32(0); writer.WriteUInt16(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //8 writer.WriteUInt64((ulong)importAddressTableRva + _properties.BaseAddress); //16 } writer.WriteTo(peStream); }
private static void TestCompressedSignedInteger(byte[] expected, int value) { var writer = new BlobWriter(4); writer.WriteCompressedSignedInteger(value); AssertEx.Equal(expected, writer.ToArray()); var builder = new BlobBuilder(); builder.WriteCompressedSignedInteger(value); AssertEx.Equal(expected, builder.ToArray()); }
private void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) { writer.WriteUInt32(0); // Characteristics writer.WriteUInt32(0); // Timestamp writer.WriteUInt32(0); // Version writer.WriteUInt16(directory.NumberOfNamedEntries); writer.WriteUInt16(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id; string name; uint nameOffset = (uint)dataWriter.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.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position)); byte[] data = new List<byte>(r.Data).ToArray(); dataWriter.WriteUInt32((uint)data.Length); dataWriter.WriteUInt32(r.CodePage); dataWriter.WriteUInt32(0); dataWriter.WriteBytes(data); while ((dataWriter.Length % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt32(id); } else { if (name == null) { name = string.Empty; } writer.WriteUInt32(nameOffset | 0x80000000); dataWriter.WriteUInt16((ushort)name.Length); dataWriter.WriteUTF16(name); } if (subDir != null) { writer.WriteUInt32(directoryOffset | 0x80000000); } else { writer.WriteUInt32(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; } } } }
public void WriteBytes1() { var writer = new BlobBuilder(4); writer.WriteBytes(new byte[] { 1, 2, 3, 4 }); writer.WriteBytes(new byte[] { }); writer.WriteBytes(new byte[] { }, 0, 0); writer.WriteBytes(new byte[] { 5, 6, 7, 8 }); writer.WriteBytes(new byte[] { 9 }); writer.WriteBytes(new byte[] { 0x0a }, 0, 0); writer.WriteBytes(new byte[] { 0x0b }, 0, 1); writer.WriteBytes(new byte[] { 0x0c }, 1, 0); writer.WriteBytes(new byte[] { 0x0d, 0x0e }, 1, 1); AssertEx.Equal(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0b, 0x0e }, writer.ToArray()); }
private BlobHandle GetOrAddBlob(BlobBuilder builder) { // TODO: avoid making a copy if the blob exists in the index return(GetOrAddBlob(builder.ToImmutableArray())); }
private BlobHandle SerializeLocalConstantSignature(ILocalDefinition localConstant) { var builder = new BlobBuilder(); // TODO: BlobEncoder.LocalConstantSignature // CustomMod* var encoder = new CustomModifiersEncoder(builder); SerializeCustomModifiers(encoder, localConstant.CustomModifiers); var type = localConstant.Type; var typeCode = type.TypeCode; object value = localConstant.CompileTimeValue.Value; // PrimitiveConstant or EnumConstant if (value is decimal) { builder.WriteByte((byte)SignatureTypeKind.ValueType); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); builder.WriteDecimal((decimal)value); } else if (value is DateTime) { builder.WriteByte((byte)SignatureTypeKind.ValueType); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); builder.WriteDateTime((DateTime)value); } else if (typeCode == PrimitiveTypeCode.String) { builder.WriteByte((byte)ConstantTypeCode.String); if (value == null) { builder.WriteByte(0xff); } else { builder.WriteUTF16((string)value); } } else if (value != null) { // TypeCode builder.WriteByte((byte)GetConstantTypeCode(value)); // Value builder.WriteConstant(value); // EnumType if (type.IsEnum) { builder.WriteCompressedInteger( CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type)) ); } } else if (this.module.IsPlatformType(type, PlatformType.SystemObject)) { builder.WriteByte((byte)SignatureTypeCode.Object); } else { builder.WriteByte( (byte)(type.IsValueType ? SignatureTypeKind.ValueType : SignatureTypeKind.Class) ); builder.WriteCompressedInteger(CodedIndex.TypeDefOrRefOrSpec(GetTypeHandle(type))); } return(_debugMetadataOpt.GetOrAddBlob(builder)); }