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()); }
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()); }
public void WriteContentToBlobBuilder() { var builder1 = new BlobBuilder(16); for (int i = 0; i < 20; i++) { builder1.WriteByte((byte)i); } var builder2 = new BlobBuilder(256); builder1.WriteContentTo(builder2); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 }, builder2.ToArray()); builder1.WriteByte(0xff); builder1.WriteContentTo(builder2); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xff, }, builder2.ToArray()); }
public void WriteContentToStream_Errors() { var builder = new BlobBuilder(16); builder.WriteByte(1); Assert.Throws<ArgumentNullException>(() => builder.WriteContentTo((Stream)null)); Assert.Throws<NotSupportedException>(() => builder.WriteContentTo(new MemoryStream(new byte[] { 1 }, writable: false))); }
public void ToImmutableArray_Errors() { var builder = new BlobBuilder(16); builder.WriteByte(1); Assert.Throws<ArgumentOutOfRangeException>(() => builder.ToImmutableArray(-1, 0)); Assert.Throws<ArgumentOutOfRangeException>(() => builder.ToImmutableArray(0, -1)); Assert.Throws<ArgumentOutOfRangeException>(() => builder.ToImmutableArray(0, 2)); Assert.Throws<ArgumentOutOfRangeException>(() => builder.ToImmutableArray(1, 1)); }
public void ToArray2() { var builder = new BlobBuilder(16); AssertEx.Equal(new byte[] { }, builder.ToArray(0, 0)); for (int i = 0; i < 34; i++) { builder.WriteByte((byte)i); } AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 }, builder.ToArray()); AssertEx.Equal(new byte[] { 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 }, builder.ToArray(0x0e, 20)); AssertEx.Equal(new byte[] { 0x0E }, builder.ToArray(0x0e, 1)); AssertEx.Equal(new byte[] { 0x0E, 0x0F }, builder.ToArray(0x0e, 2)); AssertEx.Equal(new byte[] { 0x0E, 0x0F, 0x10 }, builder.ToArray(0x0e, 3)); AssertEx.Equal(new byte[] { 0x0E, 0x0F, 0x10, 0x11 }, builder.ToArray(0x0e, 4)); AssertEx.Equal(new byte[] { 0x1E }, builder.ToArray(0x1e, 1)); AssertEx.Equal(new byte[] { 0x1E, 0x1F }, builder.ToArray(0x1e, 2)); AssertEx.Equal(new byte[] { 0x1E, 0x1F, 0x20 }, builder.ToArray(0x1e, 3)); AssertEx.Equal(new byte[] { 0x1E, 0x1F, 0x20, 0x21 }, builder.ToArray(0x1e, 4)); }
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 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); }
private void SerializeReferenceToPreviousMethodWithUsingInfo(ArrayBuilder<BlobBuilder> customDebugInfo) { BlobBuilder cmw = new BlobBuilder(12); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardInfo); cmw.Align(4); cmw.WriteUInt32(12); cmw.WriteUInt32((uint)_previousMethodTokenWithUsingInfo); customDebugInfo.Add(cmw); }
private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody methodBody, ArrayBuilder<BlobBuilder> customDebugInfo) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } List<ushort> usingCounts = new List<ushort>(); var cmw = new BlobBuilder(); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { usingCounts.Add((ushort)scope.GetUsedNamespaces().Length); } // ACASEY: This originally wrote (uint)12, (ushort)1, (ushort)0 in the // case where usingCounts was empty, but I'm not sure why. if (usingCounts.Count > 0) { uint streamLength; cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindUsingInfo); cmw.Align(4); cmw.WriteUInt32(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUInt16((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUInt16(uc); } cmw.Align(4); Debug.Assert(streamLength == cmw.Length); customDebugInfo.Add(cmw); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
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) { 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 at least one dynamic local if this point is reached const int blobSize = 200;//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); 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] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUInt32((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUInt32(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(cmw); }
private static void SerializeStateMachineLocalScopes(IMethodBody methodBody, ArrayBuilder<BlobBuilder> customDebugInfo) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } uint numberOfScopes = (uint)scopes.Length; var cmw = new BlobBuilder(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindStateMachineHoistedLocalScopes); cmw.Align(4); cmw.WriteUInt32(12 + numberOfScopes * 8); cmw.WriteUInt32(numberOfScopes); foreach (var scope in scopes) { if (scope.IsDefault) { cmw.WriteUInt32(0); cmw.WriteUInt32(0); } else { // Dev12 C# emits end-inclusive range cmw.WriteUInt32((uint)scope.StartOffset); cmw.WriteUInt32((uint)scope.EndOffset - 1); } } customDebugInfo.Add(cmw); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder<BlobBuilder> customDebugInfo) { if (iteratorClassName == null) return; var cmw = new BlobBuilder(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardIterator); cmw.Align(4); uint length = 10 + (uint)iteratorClassName.Length * 2; if ((length & 3) != 0) length += 4 - (length & 3); cmw.WriteUInt32(length); cmw.WriteUTF16(iteratorClassName); cmw.WriteInt16(0); cmw.Align(4); Debug.Assert(cmw.Position == length); customDebugInfo.Add(cmw); }
private static BlobBuilder SerializeRecord(byte kind, Action<BlobBuilder> data) { var cmw = new BlobBuilder(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size (will be patched) int alignmentSizeAndLengthPosition = cmw.Position; cmw.WriteByte(0); // length (will be patched) cmw.WriteUInt32(0); data(cmw); int length = cmw.Position; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); for (int i = 0; i < alignmentSize; i++) { cmw.WriteByte(0); } cmw.SetPosition(alignmentSizeAndLengthPosition); cmw.WriteByte(alignmentSize); cmw.WriteUInt32((uint)alignedLength); cmw.SetPosition(length); return cmw; }
public void Link() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); var builder2 = new BlobBuilder(16); builder2.WriteByte(2); var builder3 = new BlobBuilder(16); builder3.WriteByte(3); var builder4 = new BlobBuilder(16); builder4.WriteByte(4); var builder5 = new BlobBuilder(16); builder5.WriteByte(5); builder2.LinkPrefix(builder1); AssertEx.Equal(new byte[] { 1, 2 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder1.ToArray()); Assert.Throws<InvalidOperationException>(() => builder2.LinkPrefix(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteByte(0xff)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(1, 10)); Assert.Throws<InvalidOperationException>(() => builder1.WriteBytes(new byte[] { 1 })); Assert.Throws<InvalidOperationException>(() => builder1.ReserveBytes(1)); Assert.Throws<InvalidOperationException>(() => builder1.GetBlobs()); Assert.Throws<InvalidOperationException>(() => builder1.ContentEquals(builder1)); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF16("str")); Assert.Throws<InvalidOperationException>(() => builder1.WriteUTF8("str", allowUnpairedSurrogates: false)); builder2.LinkSuffix(builder3); AssertEx.Equal(new byte[] { 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder3.LinkPrefix(builder5)); builder2.LinkPrefix(builder4); AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder2.ToArray()); Assert.Throws<InvalidOperationException>(() => builder4.LinkPrefix(builder5)); builder2.LinkSuffix(builder5); AssertEx.Equal(new byte[] { 4, 1, 2, 3, 5 }, builder2.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(); }
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 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); }
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 static BlobBuilder SerializeRecord(byte kind, Action<BlobBuilder> data) { var cmw = new BlobBuilder(); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size and length (will be patched) var alignmentSizeAndLengthWriter = cmw.ReserveBytes(sizeof(byte) + sizeof(uint)); data(cmw); int length = cmw.Position; int alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); cmw.WriteBytes(0, alignmentSize); // fill in alignment size and length: alignmentSizeAndLengthWriter.WriteByte(alignmentSize); alignmentSizeAndLengthWriter.WriteUInt32((uint)alignedLength); return cmw; }
private void EmbedCompilationOptions(CommonPEModuleBuilder module) { var builder = new BlobBuilder(); var compilerVersion = typeof(Compilation).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion; WriteValue(CompilationOptionNames.CompilationOptionsVersion, CompilationOptionsSchemaVersion.ToString()); WriteValue(CompilationOptionNames.CompilerVersion, compilerVersion); WriteValue(CompilationOptionNames.Language, module.CommonCompilation.Options.Language); WriteValue(CompilationOptionNames.SourceFileCount, module.CommonCompilation.SyntaxTrees.Count().ToString()); if (module.EmitOptions.FallbackSourceFileEncoding != null) { WriteValue(CompilationOptionNames.FallbackEncoding, module.EmitOptions.FallbackSourceFileEncoding.WebName); } if (module.EmitOptions.DefaultSourceFileEncoding != null) { WriteValue(CompilationOptionNames.DefaultEncoding, module.EmitOptions.DefaultSourceFileEncoding.WebName); } int portabilityPolicy = 0; if (module.CommonCompilation.Options.AssemblyIdentityComparer is DesktopAssemblyIdentityComparer identityComparer) { portabilityPolicy |= identityComparer.PortabilityPolicy.SuppressSilverlightLibraryAssembliesPortability ? 0b1 : 0; portabilityPolicy |= identityComparer.PortabilityPolicy.SuppressSilverlightPlatformAssembliesPortability ? 0b10 : 0; } if (portabilityPolicy != 0) { WriteValue(CompilationOptionNames.PortabilityPolicy, portabilityPolicy.ToString()); } var optimizationLevel = module.CommonCompilation.Options.OptimizationLevel; var debugPlusMode = module.CommonCompilation.Options.DebugPlusMode; if (optimizationLevel != OptimizationLevel.Debug || debugPlusMode) { WriteValue(CompilationOptionNames.Optimization, optimizationLevel.ToPdbSerializedString(debugPlusMode)); } var runtimeVersion = typeof(object).Assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion; WriteValue(CompilationOptionNames.RuntimeVersion, runtimeVersion); module.CommonCompilation.SerializePdbEmbeddedCompilationOptions(builder); _debugMetadataOpt.AddCustomDebugInformation( parent: EntityHandle.ModuleDefinition, kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.CompilationOptions), value: _debugMetadataOpt.GetOrAddBlob(builder)); void WriteValue(string key, string value) { builder.WriteUTF8(key); builder.WriteByte(0); builder.WriteUTF8(value); builder.WriteByte(0); } }
public void GetBlobs() { var builder = new BlobBuilder(16); builder.WriteBytes(1, 100); var blobs = builder.GetBlobs().ToArray(); Assert.Equal(2, blobs.Length); Assert.Equal(16, blobs[0].Length); Assert.Equal(100 - 16, blobs[1].Length); builder.WriteByte(1); blobs = builder.GetBlobs().ToArray(); Assert.Equal(3, blobs.Length); Assert.Equal(16, blobs[0].Length); Assert.Equal(16, blobs[0].GetUnderlyingBuffer().Array.Length); Assert.Equal(100 - 16, blobs[1].Length); Assert.Equal(100 - 16, blobs[1].GetUnderlyingBuffer().Array.Length); Assert.Equal(1, blobs[2].Length); Assert.Equal(100 - 16, blobs[2].GetUnderlyingBuffer().Array.Length); builder.Clear(); blobs = builder.GetBlobs().ToArray(); Assert.Equal(1, blobs.Length); Assert.Equal(0, blobs[0].Length); // Clear uses the first buffer: Assert.Equal(16, blobs[0].GetUnderlyingBuffer().Array.Length); }
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.CompilationMetadataReferences), value: _debugMetadataOpt.GetOrAddBlob(builder));
public void ToImmutableArray() { var builder = new BlobBuilder(16); AssertEx.Equal(new byte[] { }, builder.ToArray(0, 0)); for (int i = 0; i < 13; i++) { builder.WriteByte((byte)i); } builder.WriteUInt32(0xaabbccdd); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xDD, 0xCC, 0xBB, 0xAA }, builder.ToImmutableArray()); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(0, 0)); AssertEx.Equal(new byte[] { 0 }, builder.ToImmutableArray(0, 1)); AssertEx.Equal(new byte[] { 1 }, builder.ToImmutableArray(1, 1)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(14, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(15, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(16, 0)); AssertEx.Equal(new byte[] { }, builder.ToImmutableArray(17, 0)); AssertEx.Equal(new byte[] { 0xdd }, builder.ToImmutableArray(13, 1)); AssertEx.Equal(new byte[] { 0xcc }, builder.ToImmutableArray(14, 1)); AssertEx.Equal(new byte[] { 0xbb }, builder.ToImmutableArray(15, 1)); AssertEx.Equal(new byte[] { 0xaa }, builder.ToImmutableArray(16, 1)); AssertEx.Equal(new byte[] { 0xdd, 0xcc }, builder.ToImmutableArray(13, 2)); AssertEx.Equal(new byte[] { 0xcc, 0xbb }, builder.ToImmutableArray(14, 2)); AssertEx.Equal(new byte[] { 0xbb, 0xaa }, builder.ToImmutableArray(15, 2)); AssertEx.Equal(new byte[] { 0xdd, 0xcc, 0xbb }, builder.ToImmutableArray(13, 3)); AssertEx.Equal(new byte[] { 0xcc, 0xbb, 0xaa }, builder.ToImmutableArray(14, 3)); AssertEx.Equal(new byte[] { 0xdd, 0xcc, 0xbb, 0xaa }, builder.ToImmutableArray(13, 4)); }
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)); }
public void WriteContentToStream() { var builder = new BlobBuilder(16); for (int i = 0; i < 20; i++) { builder.WriteByte((byte)i); } var stream = new MemoryStream(); builder.WriteContentTo(stream); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 }, stream.ToArray()); builder.WriteByte(0xff); builder.WriteContentTo(stream); AssertEx.Equal(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xff, }, stream.ToArray()); }
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> /// Write string as UTF8 with null terminator. /// </summary> private static void WriteUtf8String(BlobBuilder builder, string str) { builder.WriteUTF8(str); builder.WriteByte(0); }
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); }
public void LinkPrefix1() { var builder1 = new BlobBuilder(16); builder1.WriteByte(1); builder1.WriteByte(2); builder1.WriteByte(3); var builder2 = new BlobBuilder(16); builder2.WriteByte(4); builder1.LinkPrefix(builder2); AssertEx.Equal(new byte[] { 4, 1, 2, 3 }, builder1.ToArray()); }
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; } } } }
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()); }
/// <summary> /// Write string as UTF8 with null terminator. /// </summary> private static void WriteUtf8String(BlobBuilder cmw, string str) { cmw.WriteUTF8(str); cmw.WriteByte(0); }
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 void SerializeTablesHeader(BlobBuilder writer, MetadataSizes metadataSizes) { int startPosition = writer.Position; HeapSizeFlag heapSizes = 0; if (metadataSizes.StringIndexSize > 2) { heapSizes |= HeapSizeFlag.StringHeapLarge; } if (metadataSizes.GuidIndexSize > 2) { heapSizes |= HeapSizeFlag.GuidHeapLarge; } if (metadataSizes.BlobIndexSize > 2) { heapSizes |= HeapSizeFlag.BlobHeapLarge; } if (metadataSizes.IsMinimalDelta) { heapSizes |= (HeapSizeFlag.EnCDeltas | HeapSizeFlag.DeletedMarks); } ulong sortedDebugTables = metadataSizes.PresentTablesMask & MetadataSizes.SortedDebugTables; // Consider filtering out type system tables that are not present: ulong sortedTables = sortedDebugTables | (metadataSizes.IsStandaloneDebugMetadata ? 0UL : 0x16003301fa00); writer.WriteUInt32(0); // reserved writer.WriteByte(MetadataFormatMajorVersion); writer.WriteByte(MetadataFormatMinorVersion); writer.WriteByte((byte)heapSizes); writer.WriteByte(1); // reserved writer.WriteUInt64(metadataSizes.PresentTablesMask); writer.WriteUInt64(sortedTables); SerializeRowCounts(writer, metadataSizes.RowCounts, metadataSizes.PresentTablesMask); int endPosition = writer.Position; Debug.Assert(metadataSizes.CalculateTableStreamHeaderSize() == endPosition - startPosition); }
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 void SerializeConstantTable(BlobBuilder writer, MetadataSizes metadataSizes) { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). var ordered = _constantTableNeedsSorting ? _constantTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _constantTable; foreach (ConstantRow constant in ordered) { writer.WriteByte(constant.Type); writer.WriteByte(0); writer.WriteReference(constant.Parent, metadataSizes.HasConstantCodedIndexSize); writer.WriteReference((uint)_heaps.ResolveBlobIndex(constant.Value), metadataSizes.BlobIndexSize); } }
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 void SerializeMetadataTables( BlobBuilder writer, MetadataSizes metadataSizes, int methodBodyStreamRva, int mappedFieldDataStreamRva) { int startPosition = writer.Position; this.SerializeTablesHeader(writer, metadataSizes); if (metadataSizes.IsPresent(TableIndex.Module)) { SerializeModuleTable(writer, metadataSizes, _heaps); } if (metadataSizes.IsPresent(TableIndex.TypeRef)) { this.SerializeTypeRefTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.TypeDef)) { this.SerializeTypeDefTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.Field)) { this.SerializeFieldTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MethodDef)) { this.SerializeMethodDefTable(writer, metadataSizes, methodBodyStreamRva); } if (metadataSizes.IsPresent(TableIndex.Param)) { this.SerializeParamTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.InterfaceImpl)) { this.SerializeInterfaceImplTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MemberRef)) { this.SerializeMemberRefTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.Constant)) { this.SerializeConstantTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.CustomAttribute)) { this.SerializeCustomAttributeTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.FieldMarshal)) { this.SerializeFieldMarshalTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.DeclSecurity)) { this.SerializeDeclSecurityTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ClassLayout)) { this.SerializeClassLayoutTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.FieldLayout)) { this.SerializeFieldLayoutTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.StandAloneSig)) { this.SerializeStandAloneSigTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.EventMap)) { this.SerializeEventMapTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.Event)) { this.SerializeEventTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.PropertyMap)) { this.SerializePropertyMapTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.Property)) { this.SerializePropertyTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MethodSemantics)) { this.SerializeMethodSemanticsTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MethodImpl)) { this.SerializeMethodImplTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ModuleRef)) { this.SerializeModuleRefTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.TypeSpec)) { this.SerializeTypeSpecTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ImplMap)) { this.SerializeImplMapTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.FieldRva)) { this.SerializeFieldRvaTable(writer, metadataSizes, mappedFieldDataStreamRva); } if (metadataSizes.IsPresent(TableIndex.EncLog)) { this.SerializeEncLogTable(writer); } if (metadataSizes.IsPresent(TableIndex.EncMap)) { this.SerializeEncMapTable(writer); } if (metadataSizes.IsPresent(TableIndex.Assembly)) { this.SerializeAssemblyTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.AssemblyRef)) { this.SerializeAssemblyRefTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.File)) { this.SerializeFileTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ExportedType)) { this.SerializeExportedTypeTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ManifestResource)) { this.SerializeManifestResourceTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.NestedClass)) { this.SerializeNestedClassTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.GenericParam)) { this.SerializeGenericParamTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MethodSpec)) { this.SerializeMethodSpecTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.GenericParamConstraint)) { this.SerializeGenericParamConstraintTable(writer, metadataSizes); } // debug tables if (metadataSizes.IsPresent(TableIndex.Document)) { this.SerializeDocumentTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.MethodDebugInformation)) { this.SerializeMethodDebugInformationTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.LocalScope)) { this.SerializeLocalScopeTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.LocalVariable)) { this.SerializeLocalVariableTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.LocalConstant)) { this.SerializeLocalConstantTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.ImportScope)) { this.SerializeImportScopeTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.StateMachineMethod)) { this.SerializeStateMachineMethodTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.CustomDebugInformation)) { this.SerializeCustomDebugInformationTable(writer, metadataSizes); } writer.WriteByte(0); writer.Align(4); int endPosition = writer.Position; Debug.Assert(metadataSizes.MetadataTableStreamSize == endPosition - startPosition); }
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; } } } }
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) { 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 at least one dynamic local if this point is reached const int blobSize = 200; //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); 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] = 1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUInt32((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUInt32((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUInt32(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteUTF16(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(cmw); }