private static void SerializeStateMachineLocalScopes(IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } uint numberOfScopes = (uint)scopes.Length; MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindStateMachineHoistedLocalScopes); cmw.Align(4); cmw.WriteUint(12 + numberOfScopes * 8); cmw.WriteUint(numberOfScopes); foreach (var scope in scopes) { cmw.WriteUint(scope.StartOffset); cmw.WriteUint(scope.EndOffset); } customDebugInfo.Add(customMetadata); }
private static void SerializeIteratorLocalScopes(IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo) { ImmutableArray <LocalScope> scopes = methodBody.IteratorScopes; uint numberOfScopes = (uint)scopes.Length; if (numberOfScopes == 0) { return; } MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(4); // version cmw.WriteByte(3); // kind: IteratorLocals cmw.Align(4); cmw.WriteUint(12 + numberOfScopes * 8); cmw.WriteUint(numberOfScopes); foreach (var scope in scopes) { cmw.WriteUint(scope.Offset); cmw.WriteUint(scope.Offset + scope.Length); } customDebugInfo.Add(customMetadata); }
private void SerializeReferenceToMethodWithModuleInfo(ArrayBuilder <MemoryStream> customDebugInfo) { MemoryStream customMetadata = new MemoryStream(12); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(4); // version cmw.WriteByte(2); // kind: ForwardToModuleInfo cmw.Align(4); cmw.WriteUint(12); cmw.WriteUint(this.methodTokenWithModuleInfo); customDebugInfo.Add(customMetadata); }
private void SerializeReferenceToPreviousMethodWithUsingInfo(ArrayBuilder <MemoryStream> customDebugInfo) { MemoryStream customMetadata = new MemoryStream(12); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardInfo); cmw.Align(4); cmw.WriteUint(12); cmw.WriteUint(_previousMethodTokenWithUsingInfo); customDebugInfo.Add(customMetadata); }
private void SerializeNamespaceScopeMetadata(IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo) { if (methodBody.NamespaceScopeEncoding == NamespaceScopeEncoding.Forwarding) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } MemoryStream customMetadata = new MemoryStream(); List <ushort> usingCounts = new List <ushort>(); BinaryWriter cmw = new BinaryWriter(customMetadata); foreach (NamespaceScope namespaceScope in methodBody.NamespaceScopes) { usingCounts.Add((ushort)namespaceScope.UsedNamespaces.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 = 0; cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindUsingInfo); cmw.Align(4); cmw.WriteUint(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUshort((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUshort(uc); } cmw.Align(4); Debug.Assert(streamLength == customMetadata.Length); customDebugInfo.Add(customMetadata); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } MemoryStream customMetadata = new MemoryStream(); List <ushort> usingCounts = new List <ushort>(); BinaryWriter cmw = new BinaryWriter(customMetadata); 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.WriteUint(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUshort((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUshort(uc); } cmw.Align(4); Debug.Assert(streamLength == customMetadata.Length); customDebugInfo.Add(customMetadata); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
private static MemoryStream SerializeRecord(byte kind, Action <BinaryWriter> data) { MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size (will be patched) uint alignmentSizeAndLengthPosition = cmw.BaseStream.Position; cmw.WriteByte(0); // length (will be patched) cmw.WriteUint(0); data(cmw); uint length = customMetadata.Position; uint alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); for (int i = 0; i < alignmentSize; i++) { cmw.WriteByte(0); } cmw.BaseStream.Position = alignmentSizeAndLengthPosition; cmw.WriteByte(alignmentSize); cmw.WriteUint(alignedLength); cmw.BaseStream.Position = length; return(customMetadata); }
private static byte[] SerializeCustomDebugMetadata(ArrayBuilder <MemoryStream> customDebugInfo) { if (customDebugInfo.Count == 0) { return(null); } MemoryStream customMetadata = MemoryStream.GetInstance(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte((byte)customDebugInfo.Count); // count cmw.Align(4); foreach (MemoryStream ms in customDebugInfo) { ms.WriteTo(customMetadata); } var result = customMetadata.ToArray(); customMetadata.Free(); return(result); }
private static MemoryStream SerializeRecord(byte kind, Action <BinaryWriter> data) { MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.Align(4); // length (will be patched) uint lengthPosition = cmw.BaseStream.Position; cmw.WriteUint(0); data(cmw); uint length = customMetadata.Position; cmw.BaseStream.Position = lengthPosition; cmw.WriteUint(length); cmw.BaseStream.Position = length; return(customMetadata); }
public MetadataHeapsBuilder( int userStringIndexStartOffset = 0, int stringIndexStartOffset = 0, int blobIndexStartOffset = 0, int guidIndexStartOffset = 0) { // Add zero-th entry to heaps. // Full metadata represent empty blob/string at heap index 0. // Delta metadata requires these to avoid nil generation-relative handles, // which are technically viable but confusing. _blobWriter.WriteByte(0); _stringWriter.WriteByte(0); _userStringWriter.WriteByte(0); // When EnC delta is applied #US, #String and #Blob heaps are appended. // Thus indices of strings and blobs added to this generation are offset // by the sum of respective heap sizes of all previous generations. _userStringIndexStartOffset = userStringIndexStartOffset; _stringIndexStartOffset = stringIndexStartOffset; _blobIndexStartOffset = blobIndexStartOffset; // Unlike other heaps, #Guid heap in EnC delta is zero-padded. _guidWriter.Pad(guidIndexStartOffset); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder <MemoryStream> customDebugInfo) { if (iteratorClassName == null) { return; } MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata, true); 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.WriteUint(length); cmw.WriteString(iteratorClassName, true); cmw.Align(4); Debug.Assert(customMetadata.Position == length); customDebugInfo.Add(customMetadata); }
private void WriteDebugTable(Stream peStream, ContentId pdbContentId, MetadataSizes metadataSizes) { if (!EmitPdb) { return; } MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); // characteristics: writer.WriteUint(0); // PDB stamp writer.WriteBytes(pdbContentId.Stamp); // version writer.WriteUint(0); // type: const int ImageDebugTypeCodeView = 2; writer.WriteUint(ImageDebugTypeCodeView); // size of data: writer.WriteUint((uint)ComputeSizeOfDebugDirectoryData()); uint dataOffset = (uint)ComputeOffsetToDebugTable(metadataSizes) + ImageDebugDirectoryBaseSize; // PointerToRawData (RVA of the data): writer.WriteUint(_textSection.RelativeVirtualAddress + dataOffset); // AddressOfRawData (position of the data in the PE stream): writer.WriteUint(_textSection.PointerToRawData + dataOffset); writer.WriteByte((byte)'R'); writer.WriteByte((byte)'S'); writer.WriteByte((byte)'D'); writer.WriteByte((byte)'S'); // PDB id: writer.WriteBytes(pdbContentId.Guid); // age writer.WriteUint(PdbWriter.Age); // UTF-8 encoded zero-terminated path to PDB writer.WriteString(_pdbPathOpt, emitNullTerminator: true); writer.BaseStream.WriteTo(peStream); stream.Free(); }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder <MemoryStream> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder <ILocalDefinition> .GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { if (local.IsDynamic) { dynamicLocals.Add(local); } } int dynamicVariableCount = dynamicLocals.Count; foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be atleast one dynamic local if this point is reached const int blobSize = 200; //DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128 MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata, true); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUint((uint)dynamicLocals.Count); int localIndex = 0; foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length > 63)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64) { byte[] flag = new byte[64]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = (byte)1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUint((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUint(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteChars(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(customMetadata); }
private void WriteHeaders(Stream peStream, out long timestampOffset) { IModule module = _module; NtHeader ntHeader = _ntHeader; BinaryWriter writer = new BinaryWriter(_headerStream); // MS-DOS stub (128 bytes) writer.WriteBytes(s_dosHeader); // TODO: provide an option to suppress the second half of the DOS header? // PE Signature (4 bytes) writer.WriteUint(0x00004550); /* "PE\0\0" */ // COFF Header 20 bytes writer.WriteUshort((ushort)module.Machine); writer.WriteUshort((ushort)ntHeader.NumberOfSections); timestampOffset = (uint)(writer.BaseStream.Position + peStream.Position); writer.WriteUint(ntHeader.TimeDateStamp); writer.WriteUint(ntHeader.PointerToSymbolTable); writer.WriteUint(0); // NumberOfSymbols writer.WriteUshort((ushort)(!module.Requires64bits ? 224 : 240)); // SizeOfOptionalHeader // ushort characteristics = 0x0002|0x0004|0x0008; // executable | no COFF line nums | no COFF symbols (as required by the standard) ushort characteristics = 0x0002; // executable (as required by the Linker team). if (module.Kind == ModuleKind.DynamicallyLinkedLibrary || module.Kind == ModuleKind.WindowsRuntimeMetadata) { characteristics |= 0x2000; } if (module.Requires32bits) { characteristics |= 0x0100; // 32 bit machine (The standard says to always set this, the linker team says otherwise) //The loader team says that this is not used for anything in the OS. } else { characteristics |= 0x0020; // large address aware (the standard says never to set this, the linker team says otherwise). //The loader team says that this is not overridden for managed binaries and will be respected if set. } writer.WriteUshort(characteristics); // PE Header (224 bytes if 32 bits, 240 bytes if 64 bit) if (!module.Requires64bits) { writer.WriteUshort(0x10B); // Magic = PE32 // 2 } else { writer.WriteUshort(0x20B); // Magic = PE32+ // 2 } writer.WriteByte(module.LinkerMajorVersion); // 3 writer.WriteByte(module.LinkerMinorVersion); // 4 writer.WriteUint(ntHeader.SizeOfCode); // 8 writer.WriteUint(ntHeader.SizeOfInitializedData); // 12 writer.WriteUint(ntHeader.SizeOfUninitializedData); // 16 writer.WriteUint(ntHeader.AddressOfEntryPoint); // 20 writer.WriteUint(ntHeader.BaseOfCode); // 24 if (!module.Requires64bits) { writer.WriteUint(ntHeader.BaseOfData); // 28 writer.WriteUint((uint)module.BaseAddress); // 32 } else { writer.WriteUlong(module.BaseAddress); // 32 } writer.WriteUint(0x2000); // SectionAlignment 36 writer.WriteUint(module.FileAlignment); // 40 writer.WriteUshort(4); // MajorOperatingSystemVersion 42 writer.WriteUshort(0); // MinorOperatingSystemVersion 44 writer.WriteUshort(0); // MajorImageVersion 46 writer.WriteUshort(0); // MinorImageVersion 48 writer.WriteUshort(module.MajorSubsystemVersion); // MajorSubsystemVersion 50 writer.WriteUshort(module.MinorSubsystemVersion); // MinorSubsystemVersion 52 writer.WriteUint(0); // Win32VersionValue 56 writer.WriteUint(ntHeader.SizeOfImage); // 60 writer.WriteUint(ntHeader.SizeOfHeaders); // 64 writer.WriteUint(0); // CheckSum 68 switch (module.Kind) { case ModuleKind.ConsoleApplication: case ModuleKind.DynamicallyLinkedLibrary: case ModuleKind.WindowsRuntimeMetadata: writer.WriteUshort(3); // 70 break; case ModuleKind.WindowsApplication: writer.WriteUshort(2); // 70 break; default: writer.WriteUshort(0); // break; } writer.WriteUshort(module.DllCharacteristics); if (!module.Requires64bits) { writer.WriteUint((uint)module.SizeOfStackReserve); // 76 writer.WriteUint((uint)module.SizeOfStackCommit); // 80 writer.WriteUint((uint)module.SizeOfHeapReserve); // 84 writer.WriteUint((uint)module.SizeOfHeapCommit); // 88 } else { writer.WriteUlong(module.SizeOfStackReserve); // 80 writer.WriteUlong(module.SizeOfStackCommit); // 88 writer.WriteUlong(module.SizeOfHeapReserve); // 96 writer.WriteUlong(module.SizeOfHeapCommit); // 104 } writer.WriteUint(0); // LoaderFlags 92|108 writer.WriteUint(16); // numberOfDataDirectories 96|112 writer.WriteUint(ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 writer.WriteUint(ntHeader.ExportTable.Size); // 104|120 writer.WriteUint(ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 writer.WriteUint(ntHeader.ImportTable.Size); // 112|128 writer.WriteUint(ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 writer.WriteUint(ntHeader.ResourceTable.Size); // 120|136 writer.WriteUint(ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 writer.WriteUint(ntHeader.ExceptionTable.Size); // 128|144 writer.WriteUint(ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 writer.WriteUint(ntHeader.CertificateTable.Size); // 136|152 writer.WriteUint(ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 writer.WriteUint(ntHeader.BaseRelocationTable.Size); // 144|160 writer.WriteUint(ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 writer.WriteUint(ntHeader.DebugTable.Size); // 152|168 writer.WriteUint(ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 writer.WriteUint(ntHeader.CopyrightTable.Size); // 160|176 writer.WriteUint(ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 writer.WriteUint(ntHeader.GlobalPointerTable.Size); // 168|184 writer.WriteUint(ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 writer.WriteUint(ntHeader.ThreadLocalStorageTable.Size); // 176|192 writer.WriteUint(ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 writer.WriteUint(ntHeader.LoadConfigTable.Size); // 184|200 writer.WriteUint(ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 writer.WriteUint(ntHeader.BoundImportTable.Size); // 192|208 writer.WriteUint(ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 writer.WriteUint(ntHeader.ImportAddressTable.Size); // 200|216 writer.WriteUint(ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 writer.WriteUint(ntHeader.DelayImportTable.Size); // 208|224 writer.WriteUint(ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 writer.WriteUint(ntHeader.CliHeaderTable.Size); // 216|232 writer.WriteUlong(0); // 224|240 // Section Headers WriteSectionHeader(_textSection, writer); WriteSectionHeader(_rdataSection, writer); WriteSectionHeader(_sdataSection, writer); WriteSectionHeader(_coverSection, writer); WriteSectionHeader(_resourceSection, writer); WriteSectionHeader(_relocSection, writer); WriteSectionHeader(_tlsSection, writer); writer.BaseStream.WriteTo(peStream); _headerStream = _emptyStream; }
private void WriteImportTable(Stream peStream) { BinaryWriter writer = new BinaryWriter(new MemoryStream(70)); bool use32bitAddresses = !_module.Requires64bits; uint importTableRVA = _ntHeader.ImportTable.RelativeVirtualAddress; uint ilRVA = importTableRVA + 40; uint hintRva = ilRVA + (use32bitAddresses ? 12u : 16u); uint nameRva = hintRva + 12 + 2; // Import table writer.WriteUint(ilRVA); // 4 writer.WriteUint(0); // 8 writer.WriteUint(0); // 12 writer.WriteUint(nameRva); // 16 writer.WriteUint(_ntHeader.ImportAddressTable.RelativeVirtualAddress); // 20 writer.BaseStream.Position += 20; // 40 // Import Lookup table if (use32bitAddresses) { writer.WriteUint(hintRva); // 44 writer.WriteUint(0); // 48 writer.WriteUint(0); // 52 } else { writer.WriteUlong(hintRva); // 48 writer.WriteUlong(0); // 56 } // Hint table writer.WriteUshort(0); // Hint 54|58 string entryPointName = (_module.Kind == ModuleKind.DynamicallyLinkedLibrary || _module.Kind == ModuleKind.WindowsRuntimeMetadata) ? "_CorDllMain" : "_CorExeMain"; foreach (char ch in entryPointName) { writer.WriteByte((byte)ch); // 65|69 } writer.WriteByte(0); // 66|70 writer.BaseStream.WriteTo(peStream); }
private static void WriteSectionHeader(SectionHeader sectionHeader, BinaryWriter 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.WriteUint(sectionHeader.VirtualSize); writer.WriteUint(sectionHeader.RelativeVirtualAddress); writer.WriteUint(sectionHeader.SizeOfRawData); writer.WriteUint(sectionHeader.PointerToRawData); writer.WriteUint(sectionHeader.PointerToRelocations); writer.WriteUint(sectionHeader.PointerToLinenumbers); writer.WriteUshort(sectionHeader.NumberOfRelocations); writer.WriteUshort(sectionHeader.NumberOfLinenumbers); writer.WriteUint(sectionHeader.Characteristics); }
private void SerializeNamespaceScopeMetadata(EmitContext context, IMethodBody methodBody, ArrayBuilder<MemoryStream> customDebugInfo) { if (context.Module.GenerateVisualBasicStylePdb) { return; } if (ShouldForwardToPreviousMethodWithUsingInfo(context, methodBody)) { Debug.Assert(!ReferenceEquals(_previousMethodBodyWithUsingInfo, methodBody)); SerializeReferenceToPreviousMethodWithUsingInfo(customDebugInfo); return; } MemoryStream customMetadata = new MemoryStream(); List<ushort> usingCounts = new List<ushort>(); BinaryWriter cmw = new BinaryWriter(customMetadata); for (IImportScope scope = methodBody.ImportScope; scope != null; scope = scope.Parent) { usingCounts.Add((ushort)scope.GetUsedNamespaces(context).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 = 0; cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindUsingInfo); cmw.Align(4); cmw.WriteUint(streamLength = BitArithmeticUtilities.Align((uint)usingCounts.Count * 2 + 10, 4)); cmw.WriteUshort((ushort)usingCounts.Count); foreach (ushort uc in usingCounts) { cmw.WriteUshort(uc); } cmw.Align(4); Debug.Assert(streamLength == customMetadata.Length); customDebugInfo.Add(customMetadata); } if (_methodBodyWithModuleInfo != null && !ReferenceEquals(_methodBodyWithModuleInfo, methodBody)) { SerializeReferenceToMethodWithModuleInfo(customDebugInfo); } }
private void WriteDirectory(Directory directory, BinaryWriter writer, uint offset, uint level, uint sizeOfDirectoryTree, uint virtualAddressBase, BinaryWriter dataWriter) { writer.WriteUint(0); // Characteristics writer.WriteUint(0); // Timestamp writer.WriteUint(0); // Version writer.WriteUshort(directory.NumberOfNamedEntries); writer.WriteUshort(directory.NumberOfIdEntries); uint n = (uint)directory.Entries.Count; uint k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { int id = int.MinValue; string name = null; uint nameOffset = dataWriter.BaseStream.Position + sizeOfDirectoryTree; uint directoryOffset = k; Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { id = subDir.ID; name = subDir.Name; if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } else { //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed //immediately by the data that it refers to. This results //in a layout different than that produced by pulling the resources //from an OBJ. In that case all of the data bits of a resource are //contiguous in .rsrc$02. After processing these will end up at //the end of .rsrc following all of the directory //info and IMAGE_RESOURCE_DATA_ENTRYs IWin32Resource r = (IWin32Resource)directory.Entries[i]; id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; dataWriter.WriteUint(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.BaseStream.Position); byte[] data = new List<byte>(r.Data).ToArray(); dataWriter.WriteUint((uint)data.Length); dataWriter.WriteUint(r.CodePage); dataWriter.WriteUint(0); dataWriter.WriteBytes(data); while ((dataWriter.BaseStream.Length % 4) != 0) { dataWriter.WriteByte(0); } } if (id >= 0) { writer.WriteInt(id); } else { if (name == null) { name = string.Empty; } writer.WriteUint(nameOffset | 0x80000000); dataWriter.WriteUshort((ushort)name.Length); dataWriter.WriteChars(name.ToCharArray()); // REVIEW: what happens if the name contains chars that do not fit into a single utf8 code point? } if (subDir != null) { writer.WriteUint(directoryOffset | 0x80000000); } else { writer.WriteUint(nameOffset); } } k = offset + 16 + n * 8; for (int i = 0; i < n; i++) { Directory subDir = directory.Entries[i] as Directory; if (subDir != null) { this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); if (level == 0) { k += SizeOfDirectory(subDir); } else { k += 16 + 8 * (uint)subDir.Entries.Count; } } } }
private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuilder<MemoryStream> customDebugInfo) { if (!methodBody.HasDynamicLocalVariables) { return; //There are no dynamic locals } var dynamicLocals = ArrayBuilder<ILocalDefinition>.GetInstance(); foreach (ILocalDefinition local in methodBody.LocalVariables) { if (local.IsDynamic) { dynamicLocals.Add(local); } } int dynamicVariableCount = dynamicLocals.Count; foreach (var currentScope in methodBody.LocalScopes) { foreach (var localConstant in currentScope.Constants) { if (localConstant.IsDynamic) { dynamicLocals.Add(localConstant); } } } Debug.Assert(dynamicLocals.Any()); // There must be atleast one dynamic local if this point is reached const int blobSize = 200;//DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128 MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata, true); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.Align(4); // size = Version,Kind + size + cBuckets + (dynamicCount * sizeOf(Local Blob)) cmw.WriteUint(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUint((uint)dynamicLocals.Count); int localIndex = 0; foreach (ILocalDefinition local in dynamicLocals) { if (local.Name.Length > 63)//Ignore and push empty information { cmw.WriteBytes(0, blobSize); continue; } var dynamicTransformFlags = local.DynamicTransformFlags; if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64) { byte[] flag = new byte[64]; for (int k = 0; k < dynamicTransformFlags.Length; k++) { if ((bool)dynamicTransformFlags[k].Value) { flag[k] = (byte)1; } } cmw.WriteBytes(flag); //Written Flag cmw.WriteUint((uint)dynamicTransformFlags.Length); //Written Length } else { cmw.WriteBytes(0, 68); //Empty flag array and size. } if (localIndex < dynamicVariableCount) { // Dynamic variable cmw.WriteUint((uint)local.SlotIndex); } else { // Dynamic constant cmw.WriteUint(0); } char[] localName = new char[64]; local.Name.CopyTo(0, localName, 0, local.Name.Length); cmw.WriteChars(localName); localIndex++; } dynamicLocals.Free(); customDebugInfo.Add(customMetadata); }
private static byte[] SerializeCustomDebugMetadata(ArrayBuilder<MemoryStream> customDebugInfo) { if (customDebugInfo.Count == 0) { return null; } MemoryStream customMetadata = MemoryStream.GetInstance(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte((byte)customDebugInfo.Count); // count cmw.Align(4); foreach (MemoryStream ms in customDebugInfo) { ms.WriteTo(customMetadata); } var result = customMetadata.ToArray(); customMetadata.Free(); return result; }
private static void SerializeStateMachineLocalScopes(IMethodBody methodBody, ArrayBuilder<MemoryStream> customDebugInfo) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) { return; } uint numberOfScopes = (uint)scopes.Length; MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindStateMachineHoistedLocalScopes); cmw.Align(4); cmw.WriteUint(12 + numberOfScopes * 8); cmw.WriteUint(numberOfScopes); foreach (var scope in scopes) { if (scope.IsDefault) { cmw.WriteUint(0); cmw.WriteUint(0); } else { // Dev12 C# emits end-inclusive range cmw.WriteUint((uint)scope.StartOffset); cmw.WriteUint((uint)scope.EndOffset - 1); } } customDebugInfo.Add(customMetadata); }
private void WriteNameTable(Stream peStream) { BinaryWriter writer = new BinaryWriter(new MemoryStream(14)); foreach (char ch in "mscoree.dll") { writer.WriteByte((byte)ch); // 11 } writer.WriteByte(0); // 12 writer.WriteUshort(0); // 14 writer.BaseStream.WriteTo(peStream); }
private static MemoryStream SerializeRecord(byte kind, Action<BinaryWriter> data) { MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.Align(4); // length (will be patched) uint lengthPosition = cmw.BaseStream.Position; cmw.WriteUint(0); data(cmw); uint length = customMetadata.Position; cmw.BaseStream.Position = lengthPosition; cmw.WriteUint(length); cmw.BaseStream.Position = length; return customMetadata; }
private static MemoryStream SerializeRecord(byte kind, Action<BinaryWriter> data) { MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(kind); cmw.WriteByte(0); // alignment size (will be patched) uint alignmentSizeAndLengthPosition = cmw.BaseStream.Position; cmw.WriteByte(0); // length (will be patched) cmw.WriteUint(0); data(cmw); uint length = customMetadata.Position; uint alignedLength = 4 * ((length + 3) / 4); byte alignmentSize = (byte)(alignedLength - length); for (int i = 0; i < alignmentSize; i++) { cmw.WriteByte(0); } cmw.BaseStream.Position = alignmentSizeAndLengthPosition; cmw.WriteByte(alignmentSize); cmw.WriteUint(alignedLength); cmw.BaseStream.Position = length; return customMetadata; }
private void SerializeReferenceToPreviousMethodWithUsingInfo(ArrayBuilder<MemoryStream> customDebugInfo) { MemoryStream customMetadata = new MemoryStream(12); BinaryWriter cmw = new BinaryWriter(customMetadata); cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiKindForwardInfo); cmw.Align(4); cmw.WriteUint(12); cmw.WriteUint(_previousMethodTokenWithUsingInfo); customDebugInfo.Add(customMetadata); }
private static void SerializeReferenceToIteratorClass(string iteratorClassName, ArrayBuilder<MemoryStream> customDebugInfo) { if (iteratorClassName == null) return; MemoryStream customMetadata = new MemoryStream(); BinaryWriter cmw = new BinaryWriter(customMetadata, true); 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.WriteUint(length); cmw.WriteString(iteratorClassName, true); cmw.Align(4); Debug.Assert(customMetadata.Position == length); customDebugInfo.Add(customMetadata); }
private void WriteRuntimeStartupStub(Stream peStream) { BinaryWriter writer = new BinaryWriter(new MemoryStream(16)); // entry point code, consisting of a jump indirect to _CorXXXMain if (!_module.Requires64bits) { //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.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //4 writer.WriteUint(_ntHeader.ImportAddressTable.RelativeVirtualAddress + (uint)_module.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.WriteUint(0); writer.WriteUshort(0); writer.WriteByte(0xff); writer.WriteByte(0x25); //8 writer.WriteUlong(_ntHeader.ImportAddressTable.RelativeVirtualAddress + _module.BaseAddress); //16 } writer.BaseStream.WriteTo(peStream); }