提交 25474a25 编写于 作者: T Tomáš Matoušek

Merge pull request #2193 from tmat/DeterministicPDB

Use Microsoft.DiaSymReader.Native to make PDB id and stamp deterministic
......@@ -46,7 +46,7 @@ private ImmutableArray<byte> EmitDeterministic(string source, Platform platform,
return compilation.EmitToArray();
}
[Fact(Skip = "900646"), WorkItem(900646)]
[Fact, WorkItem(372, "https://github.com/dotnet/roslyn/issues/372")]
public void Simple()
{
var source =
......@@ -80,7 +80,7 @@ public void CompareAllBytesEmitted_Release()
AssertEx.Equal(result3, result4);
}
[Fact(Skip="https://github.com/dotnet/roslyn/issues/926"), WorkItem(926)]
[Fact, WorkItem(926)]
public void CompareAllBytesEmitted_Debug()
{
var source =
......
......@@ -333,8 +333,9 @@
<Compile Include="MetadataReference\PortableExecutableReference.cs" />
<Compile Include="MetadataReference\ReferenceDirective.cs" />
<Compile Include="MetadataReference\UnresolvedMetadataReference.cs" />
<Compile Include="PEWriter\ComMemoryStream.cs" />
<Compile Include="PEWriter\IUnsafeComStream.cs" />
<Compile Include="NativePdbWriter\ComMemoryStream.cs" />
<Compile Include="NativePdbWriter\IUnsafeComStream.cs" />
<Compile Include="PEWriter\ContentId.cs" />
<Compile Include="PEWriter\MetadataHeapsBuilder.cs" />
<Compile Include="PEWriter\ITypeReferenceExtensions.cs" />
<Compile Include="PEWriter\NoPiaReferenceIndexer.cs" />
......@@ -362,8 +363,8 @@
<Compile Include="PEWriter\IFileReference.cs" />
<Compile Include="PEWriter\InheritedTypeParameter.cs" />
<Compile Include="PEWriter\InstructionOperandTypes.cs" />
<Compile Include="PEWriter\ISymbolWriter.cs" />
<Compile Include="PEWriter\ISymUnmanagedAsyncMethodPropertiesWriter.cs" />
<Compile Include="NativePdbWriter\ISymUnmanagedWriter.cs" />
<Compile Include="NativePdbWriter\ISymUnmanagedAsyncMethodPropertiesWriter.cs" />
<Compile Include="PEWriter\LocalScope.cs" />
<Compile Include="PEWriter\ManagedResource.cs" />
<Compile Include="PEWriter\MemberRefComparer.cs" />
......@@ -376,8 +377,8 @@
<Compile Include="PEWriter\ModifiedTypeReference.cs" />
<Compile Include="PEWriter\IImportScope.cs" />
<Compile Include="PEWriter\NtHeader.cs" />
<Compile Include="PEWriter\PdbMetadataWrapper.cs" />
<Compile Include="PEWriter\PdbWriter.cs" />
<Compile Include="NativePdbWriter\PdbMetadataWrapper.cs" />
<Compile Include="NativePdbWriter\PdbWriter.cs" />
<Compile Include="PEWriter\PeWriter.cs" />
<Compile Include="PEWriter\ReferenceIndexer.cs" />
<Compile Include="PEWriter\ReturnValueParameter.cs" />
......@@ -664,6 +665,14 @@
<HintPath>..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="..\..\..\..\packages\Microsoft.DiaSymReader.Native.1.0.0-rc2\lib\any~windows\x86\Microsoft.DiaSymReader.Native.x86.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\..\..\..\packages\Microsoft.DiaSymReader.Native.1.0.0-rc2\lib\any~windows\amd64\Microsoft.DiaSymReader.Native.amd64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="..\AnalyzerDriver\AnalyzerDriver.projitems" Label="Shared" />
<Import Project="..\SharedCollections\SharedCollections.projitems" Label="Shared" />
<ImportGroup Label="Targets">
......
......@@ -917,6 +917,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to SymWriter doesn&apos;t support deterministic compilation.
/// </summary>
internal static string SymWriterNotDeterministic {
get {
return ResourceManager.GetString("SymWriterNotDeterministic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to type must be a subclass of SyntaxAnnotation..
/// </summary>
......
......@@ -433,4 +433,7 @@
<data name="InvalidDataAtOffset" xml:space="preserve">
<value>Invalid data at offset {0}: {1}{2}*{3}{4}</value>
</data>
<data name="SymWriterNotDeterministic" xml:space="preserve">
<value>SymWriter doesn't support deterministic compilation</value>
</data>
</root>
\ No newline at end of file
......@@ -1639,7 +1639,7 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
// The calls ISymUnmanagedWriter2.GetDebugInfo require a file name in order to succeed. This is
// frequently used during PDB writing. Ensure a name is provided here in the case we were given
// only a Stream value.
nativePdbWriter = new Cci.PdbWriter(pdbPath, testSymWriterFactory);
nativePdbWriter = new Cci.PdbWriter(pdbPath, testSymWriterFactory, deterministic);
}
Func<Stream> getPeStream = () =>
......@@ -1779,7 +1779,8 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
{
using (var pdbWriter = new Cci.PdbWriter(
moduleBeingBuilt.EmitOptions.PdbFilePath ?? FileNameUtilities.ChangeExtension(SourceModule.Name, "pdb"),
testSymWriterFactory))
testSymWriterFactory,
deterministic: false))
{
var context = new EmitContext((Cci.IModule)moduleBeingBuilt, null, diagnostics);
var encId = Guid.NewGuid();
......
......@@ -133,7 +133,7 @@ internal struct VariantPadding
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("DCF7780D-BDE9-45DF-ACFE-21731A32000C"), SuppressUnmanagedCodeSecurity]
internal interface ISymUnmanagedWriter5
internal interface ISymUnmanagedWriter5 : ISymUnmanagedWriter2
{
// ISymUnmanagedWriter, ISymUnmanagedWriter2, ISymUnmanagedWriter3, ISymUnmanagedWriter4
void _VtblGap1_30();
......@@ -144,6 +144,17 @@ internal interface ISymUnmanagedWriter5
void MapTokenToSourceSpan(uint token, ISymUnmanagedDocumentWriter document, uint startLine, uint startColumn, uint endLine, uint endColumn);
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("CA6C2ED9-103D-46A9-B03B-05446485848B"), SuppressUnmanagedCodeSecurity]
internal interface ISymUnmanagedWriter6 : ISymUnmanagedWriter5
{
// ISymUnmanagedWriter, ISymUnmanagedWriter2, ISymUnmanagedWriter3, ISymUnmanagedWriter4, ISymUnmanagedWriter5
void _VtblGap1_33();
// ISymUnmanagedWriter6
void InitializeDeterministic([MarshalAs(UnmanagedType.IUnknown)] object emitter, [MarshalAs(UnmanagedType.IUnknown)] object stream);
void SetSignature(uint sig, Guid sig70);
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct ImageDebugDirectory
{
......
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
......@@ -34,9 +35,11 @@ internal sealed class PdbWriter : IDisposable
{
internal const uint HiddenLocalAttributesValue = 1u;
internal const uint DefaultLocalAttributesValue = 0u;
internal const uint Age = 1;
private static Type s_lazyCorSymWriterSxSType;
private readonly bool _deterministic;
private readonly string _fileName;
private readonly Func<object> _symWriterFactory;
private ComMemoryStream _pdbStream;
......@@ -55,10 +58,12 @@ internal sealed class PdbWriter : IDisposable
private uint[] _sequencePointEndLines;
private uint[] _sequencePointEndColumns;
public PdbWriter(string fileName, Func<object> symWriterFactory = null)
public PdbWriter(string fileName, Func<object> symWriterFactory, bool deterministic)
{
_fileName = fileName;
_symWriterFactory = symWriterFactory;
_deterministic = deterministic;
CreateSequencePointBuffers(capacity: 64);
}
......@@ -544,31 +549,89 @@ private void DefineScopeLocals(LocalScope currentScope, uint localSignatureToken
#region SymWriter calls
const string SymWriterClsid = "0AE2DEB0-F901-478b-BB9F-881EE8066788";
private static bool s_MicrosoftDiaSymReaderNativeLoadFailed;
[DllImport("Microsoft.DiaSymReader.Native.x86.dll", EntryPoint = "CreateSymWriter")]
private extern static void CreateSymWriter32(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)]out object symWriter);
[DllImport("Microsoft.DiaSymReader.Native.amd64.dll", EntryPoint = "CreateSymWriter")]
private extern static void CreateSymWriter64(ref Guid id, [MarshalAs(UnmanagedType.IUnknown)]out object symWriter);
private static Type GetCorSymWriterSxSType()
{
if (s_lazyCorSymWriterSxSType == null)
{
// If an exception is thrown we propagate it - we want to report it every time.
s_lazyCorSymWriterSxSType = Marshal.GetTypeFromCLSID(new Guid("0AE2DEB0-F901-478b-BB9F-881EE8066788"));
s_lazyCorSymWriterSxSType = Marshal.GetTypeFromCLSID(new Guid(SymWriterClsid));
}
return s_lazyCorSymWriterSxSType;
}
private static object CreateSymWriterWorker()
{
object symWriter = null;
// First try to load an implementation from Microsoft.DiaSymReader.Native, which supports determinism.
if (!s_MicrosoftDiaSymReaderNativeLoadFailed)
{
try
{
var guid = new Guid(SymWriterClsid);
if (IntPtr.Size == 4)
{
CreateSymWriter32(ref guid, out symWriter);
}
else
{
CreateSymWriter64(ref guid, out symWriter);
}
}
catch (Exception)
{
s_MicrosoftDiaSymReaderNativeLoadFailed = true;
symWriter = null;
}
}
if (symWriter == null)
{
// Try to find a registered CLR implementation
symWriter = Activator.CreateInstance(GetCorSymWriterSxSType());
}
return symWriter;
}
public void SetMetadataEmitter(MetadataWriter metadataWriter)
{
try
{
var instance = (ISymUnmanagedWriter2)(_symWriterFactory != null ? _symWriterFactory() : Activator.CreateInstance(GetCorSymWriterSxSType()));
var symWriter = (ISymUnmanagedWriter2)(_symWriterFactory != null ? _symWriterFactory() : CreateSymWriterWorker());
// Correctness: If the stream is not specified or if it is non-empty the SymWriter appends data to it (provided it contains valid PDB)
// and the resulting PDB has Age = existing_age + 1.
_pdbStream = new ComMemoryStream();
instance.Initialize(new PdbMetadataWrapper(metadataWriter), _fileName, _pdbStream, fullBuild: true);
if (_deterministic)
{
var deterministicSymWriter = symWriter as ISymUnmanagedWriter6;
if (symWriter == null)
{
throw new NotSupportedException(CodeAnalysisResources.SymWriterNotDeterministic);
}
deterministicSymWriter.InitializeDeterministic(new PdbMetadataWrapper(metadataWriter), _pdbStream);
}
else
{
symWriter.Initialize(new PdbMetadataWrapper(metadataWriter), _fileName, _pdbStream, fullBuild: true);
}
_metadataWriter = metadataWriter;
_symWriter = instance;
_symWriter = symWriter;
}
catch (Exception ex)
{
......@@ -576,8 +639,31 @@ public void SetMetadataEmitter(MetadataWriter metadataWriter)
}
}
public unsafe void GetDebugDirectoryGuidAndStampAndAge(out Guid guid, out uint stamp, out uint age)
public unsafe ContentId GetContentId()
{
if (_deterministic)
{
// Call to GetDebugInfo fails for SymWriter initialized using InitializeDeterministic.
// We already have all the info we need though.
// TODO (https://github.com/dotnet/roslyn/issues/926): calculate sha1 hash
var id = new ContentId(
new byte[] { 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, },
new byte[] { 0x12, 0x12, 0x12, 0x12 });
try
{
Debug.Assert(BitConverter.IsLittleEndian);
((ISymUnmanagedWriter6)_symWriter).SetSignature(BitConverter.ToUInt32(id.Stamp, 0), new Guid(id.Guid));
}
catch (Exception ex)
{
throw new PdbWritingException(ex);
}
return id;
}
// See symwrite.cpp - the data byte[] doesn't depend on the content of metadata tables or IL.
// The writer only sets two values of the ImageDebugDirectory struct.
//
......@@ -625,12 +711,16 @@ public unsafe void GetDebugDirectoryGuidAndStampAndAge(out Guid guid, out uint s
byte[] guidBytes = new byte[GuidSize];
Buffer.BlockCopy(data, 4, guidBytes, 0, guidBytes.Length);
guid = new Guid(guidBytes);
// Retrieve the timestamp the PDB writer generates when creating a new PDB stream.
// Note that ImageDebugDirectory.TimeDateStamp is not set by GetDebugInfo,
// we need to go thru IPdbWriter interface to get it.
uint stamp;
uint age;
((IPdbWriter)_symWriter).GetSignatureAge(out stamp, out age);
Debug.Assert(age == Age);
Debug.Assert(BitConverter.IsLittleEndian);
return new ContentId(guidBytes, BitConverter.GetBytes(stamp));
}
public void SetEntryPoint(uint entryMethodToken)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.Cci
{
internal struct ContentId
{
public readonly byte[] Guid;
public readonly byte[] Stamp;
public ContentId(byte[] guid, byte[] stamp)
{
Debug.Assert(guid.Length == 16 && stamp.Length == 4);
Guid = guid;
Stamp = stamp;
}
internal static ContentId FromSha1(ImmutableArray<byte> sha1)
{
var guid = new byte[16];
for (var i = 0; i < guid.Length; i++)
{
guid[i] = sha1[i];
}
// modify the guid data so it decodes to the form of a "random" guid ala rfc4122
var t = guid[7];
t = (byte)((t & 0xf) | (4 << 4));
guid[7] = t;
t = guid[8];
t = (byte)((t & 0x3f) | (2 << 6));
guid[8] = t;
// compute a random-looking stamp from the remaining bits, but with the upper bit set
var stamp = new byte[4];
stamp[0] = sha1[16];
stamp[1] = sha1[17];
stamp[2] = sha1[18];
stamp[3] = (byte)(sha1[19] | 0x80);
return new ContentId(guid, stamp);
}
}
}
......@@ -22,7 +22,6 @@ internal sealed class PeWriter
private readonly bool _deterministic;
private readonly IModule _module;
private readonly PdbWriter _nativePdbWriterOpt;
private readonly string _pdbPathOpt;
private readonly bool _emitRuntimeStartupStub;
private readonly int _sizeOfImportAddressTable;
......@@ -47,11 +46,10 @@ internal sealed class PeWriter
private SectionHeader _textSection;
private SectionHeader _tlsSection;
private PeWriter(IModule module, PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool deterministic)
private PeWriter(IModule module, string pdbPathOpt, bool deterministic)
{
_module = module;
_emitRuntimeStartupStub = module.RequiresStartupStub;
_nativePdbWriterOpt = nativePdbWriterOpt;
_pdbPathOpt = pdbPathOpt;
_deterministic = deterministic;
_sizeOfImportAddressTable = _emitRuntimeStartupStub ? (!_module.Requires64bits ? 8 : 16) : 0;
......@@ -72,38 +70,13 @@ private PeWriter(IModule module, PdbWriter nativePdbWriterOpt, string pdbPathOpt
// If PDB writer is given, we have to have PDB path.
Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null);
var peWriter = new PeWriter(context.Module, nativePdbWriterOpt, pdbPathOpt, deterministic);
var peWriter = new PeWriter(context.Module, pdbPathOpt, deterministic);
var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, deterministic, cancellationToken);
nativePdbWriterOpt?.SetMetadataEmitter(mdWriter);
uint entryPointToken;
if (!peWriter.WritePeToStream(mdWriter, getPeStream, nativePdbWriterOpt, out entryPointToken))
{
return false;
}
if (nativePdbWriterOpt != null)
{
if (entryPointToken != 0)
{
nativePdbWriterOpt.SetEntryPoint(entryPointToken);
}
var assembly = context.Module.AsAssembly;
if (assembly != null && assembly.Kind == ModuleKind.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(context.Module.GetSymbolToLocationMap());
}
}
return true;
return peWriter.WritePeToStream(mdWriter, getPeStream, nativePdbWriterOpt);
}
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, PdbWriter nativePdbWriterOpt, out uint entryPointToken)
private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream, PdbWriter nativePdbWriterOpt)
{
// TODO: we can precalculate the exact size of IL stream
var ilBuffer = new MemoryStream(32 * 1024);
......@@ -115,6 +88,8 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
var managedResourceBuffer = new MemoryStream(1024);
var managedResourceWriter = new BinaryWriter(managedResourceBuffer);
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.
......@@ -128,6 +103,7 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
});
MetadataSizes metadataSizes;
uint entryPointToken;
mdWriter.SerializeMetadataAndIL(
nativePdbWriterOpt,
metadataWriter,
......@@ -140,6 +116,32 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
out entryPointToken,
out metadataSizes);
ContentId pdbContentId;
if (nativePdbWriterOpt != null)
{
if (entryPointToken != 0)
{
nativePdbWriterOpt.SetEntryPoint(entryPointToken);
}
var assembly = _module.AsAssembly;
if (assembly != null && assembly.Kind == ModuleKind.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(_module.GetSymbolToLocationMap());
}
pdbContentId = nativePdbWriterOpt.GetContentId();
// the writer shall not be used after this point for writing:
nativePdbWriterOpt = null;
}
else
{
pdbContentId = default(ContentId);
}
FillInSectionHeaders();
// fill in header fields.
......@@ -147,18 +149,17 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
var corHeader = CreateCorHeader(metadataSizes, entryPointToken);
// write to pe stream.
long positionOfHeaderTimestamp;
Stream peStream = getPeStream();
if (peStream == null)
{
return false;
}
WriteHeaders(peStream, out positionOfHeaderTimestamp);
long startOfMetadataStream;
long positionOfDebugTableTimestamp;
long ntHeaderTimestampPosition;
long metadataPosition;
WriteHeaders(peStream, out ntHeaderTimestampPosition);
WriteTextSection(
peStream,
corHeader,
......@@ -167,8 +168,8 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
mappedFieldDataBuffer,
managedResourceBuffer,
metadataSizes,
out startOfMetadataStream,
out positionOfDebugTableTimestamp);
pdbContentId,
out metadataPosition);
WriteRdataSection(peStream);
WriteSdataSection(peStream);
......@@ -179,8 +180,8 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func<Stream> getPeStream,
if (_deterministic)
{
var positionOfModuleVersionId = startOfMetadataStream + moduleVersionIdOffsetInMetadataStream;
WriteDeterministicGuidAndTimestamps(peStream, positionOfModuleVersionId, positionOfHeaderTimestamp, positionOfDebugTableTimestamp);
var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream;
WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition);
}
return true;
......@@ -198,37 +199,34 @@ private int CalculateMappedFieldDataStreamRva(MetadataSizes metadataSizes)
/// Compute a deterministic Guid and timestamp based on the contents of the stream, and replace
/// the 16 zero bytes at the given position and one or two 4-byte values with that computed Guid and timestamp.
/// </summary>
/// <param name="stream">Stream of data</param>
/// <param name="positionOfModuleVersionId">Position in the stream of 16 zero bytes to be replaced by a Guid</param>
/// <param name="positionOfHeaderTimestamp">Position in the stream of four zero bytes to be replaced by a timestamp</param>
/// <param name="positionOfDebugTableTimestamp">Position in the stream of four zero bytes to be replaced by a timestamp, or 0 if there is no second timestamp to be replaced</param>
private static void WriteDeterministicGuidAndTimestamps(Stream stream, long positionOfModuleVersionId, long positionOfHeaderTimestamp, long positionOfDebugTableTimestamp)
/// <param name="peStream">PE stream.</param>
/// <param name="mvidPosition">Position in the stream of 16 zero bytes to be replaced by a Guid</param>
/// <param name="ntHeaderTimestampPosition">Position in the stream of four zero bytes to be replaced by a timestamp</param>
private static void WriteDeterministicGuidAndTimestamps(
Stream peStream,
long mvidPosition,
long ntHeaderTimestampPosition)
{
var previousPosition = stream.Position;
// The existing Guid in the data should be empty, as we are about to compute it.
// Check to be sure.
CheckZeroDataInStream(stream, positionOfModuleVersionId, 16);
Debug.Assert(mvidPosition != 0);
Debug.Assert(ntHeaderTimestampPosition != 0);
var previousPosition = peStream.Position;
// Compute and write deterministic guid data over the relevant portion of the stream
byte[] timestamp;
var guidData = ComputeSerializedGuidFromData(stream, out timestamp);
stream.Position = positionOfModuleVersionId;
stream.Write(guidData, 0, 16);
// Write a deterministic timestamp over the relevant portion(s) of the stream
Debug.Assert(positionOfHeaderTimestamp != 0);
CheckZeroDataInStream(stream, positionOfHeaderTimestamp, 4);
stream.Position = positionOfHeaderTimestamp;
stream.Write(timestamp, 0, 4);
if (positionOfDebugTableTimestamp != 0)
{
CheckZeroDataInStream(stream, positionOfDebugTableTimestamp, 4);
stream.Position = positionOfDebugTableTimestamp;
stream.Write(timestamp, 0, 4);
}
peStream.Position = 0;
var contentId = ContentId.FromSha1(CryptographicHashProvider.ComputeSha1(peStream));
// The existing Guid should be zero.
CheckZeroDataInStream(peStream, mvidPosition, contentId.Guid.Length);
peStream.Position = mvidPosition;
peStream.Write(contentId.Guid, 0, contentId.Guid.Length);
stream.Position = previousPosition;
// The existing timestamp should be zero.
CheckZeroDataInStream(peStream, ntHeaderTimestampPosition, contentId.Stamp.Length);
peStream.Position = ntHeaderTimestampPosition;
peStream.Write(contentId.Stamp, 0, contentId.Stamp.Length);
peStream.Position = previousPosition;
}
[Conditional("DEBUG")]
......@@ -242,38 +240,6 @@ private static void CheckZeroDataInStream(Stream stream, long position, int byte
}
}
/// <summary>
/// Compute a random-looking but deterministic Guid from a hash of the stream's data, and produce a "timestamp" from the remaining bits.
/// </summary>
private static byte[] ComputeSerializedGuidFromData(Stream stream, out byte[] timestamp)
{
stream.Position = 0; // rewind the stream
var hashData = CryptographicHashProvider.ComputeSha1(stream);
var guidData = new byte[16];
for (var i = 0; i < guidData.Length; i++)
{
guidData[i] = hashData[i];
}
// modify the guid data so it decodes to the form of a "random" guid ala rfc4122
var t = guidData[7];
t = (byte)((t & 0xf) | (4 << 4));
guidData[7] = t;
t = guidData[8];
t = (byte)((t & 0x3f) | (2 << 6));
guidData[8] = t;
// compute a random-looking timestamp from the remaining bits, but with the upper bit set
timestamp = new byte[4];
timestamp[0] = hashData[16];
timestamp[1] = hashData[17];
timestamp[2] = hashData[18];
timestamp[3] = (byte)(hashData[19] | 0x80);
return guidData;
}
private int ComputeStrongNameSignatureSize()
{
IAssembly assembly = _module.AsAssembly;
......@@ -1054,7 +1020,7 @@ private void SerializeWin32Resources(ResourceSection resourceSections, uint reso
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
private void WriteHeaders(Stream peStream, out long timestampOffset)
private void WriteHeaders(Stream peStream, out long ntHeaderTimestampPosition)
{
IModule module = _module;
NtHeader ntHeader = _ntHeader;
......@@ -1069,7 +1035,7 @@ private void WriteHeaders(Stream peStream, out long timestampOffset)
// COFF Header 20 bytes
writer.WriteUshort((ushort)module.Machine);
writer.WriteUshort(ntHeader.NumberOfSections);
timestampOffset = (uint)(writer.BaseStream.Position + peStream.Position);
ntHeaderTimestampPosition = writer.BaseStream.Position + peStream.Position;
writer.WriteUint(ntHeader.TimeDateStamp);
writer.WriteUint(ntHeader.PointerToSymbolTable);
writer.WriteUint(0); // NumberOfSymbols
......@@ -1251,8 +1217,8 @@ private static void WriteSectionHeader(SectionHeader sectionHeader, BinaryWriter
MemoryStream mappedFieldDataStream,
MemoryStream managedResourceStream,
MetadataSizes metadataSizes,
out long startOfMetadata,
out long positionOfTimestamp)
ContentId pdbContentId,
out long metadataPosition)
{
peStream.Position = _textSection.PointerToRawData;
if (_emitRuntimeStartupStub)
......@@ -1263,12 +1229,12 @@ private static void WriteSectionHeader(SectionHeader sectionHeader, BinaryWriter
WriteCorHeader(peStream, corHeader);
WriteIL(peStream, ilStream);
startOfMetadata = peStream.Position;
metadataPosition = peStream.Position;
WriteMetadata(peStream, metadataStream);
WriteManagedResources(peStream, managedResourceStream);
WriteSpaceForHash(peStream, (int)corHeader.StrongNameSignature.Size);
WriteDebugTable(peStream, metadataSizes, out positionOfTimestamp);
WriteDebugTable(peStream, pdbContentId, metadataSizes);
if (_emitRuntimeStartupStub)
{
......@@ -1431,37 +1397,21 @@ private static void WriteManagedResources(Stream peStream, MemoryStream managedR
}
}
private void WriteDebugTable(Stream peStream, MetadataSizes metadataSizes, out long timestampOffset)
private void WriteDebugTable(Stream peStream, ContentId pdbContentId, MetadataSizes metadataSizes)
{
if (!EmitPdb)
{
timestampOffset = 0;
return;
}
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
Guid pdbId;
uint pdbStamp;
uint age;
if (_nativePdbWriterOpt != null)
{
_nativePdbWriterOpt.GetDebugDirectoryGuidAndStampAndAge(out pdbId, out pdbStamp, out age);
}
else
{
pdbId = Guid.NewGuid();
pdbStamp = 0;
age = 1;
}
// characteristics:
writer.WriteUint(0);
// PDB stamp
timestampOffset = writer.BaseStream.Position + peStream.Position;
writer.WriteUint(pdbStamp);
writer.WriteBytes(pdbContentId.Stamp);
// version
writer.WriteUint(0);
......@@ -1487,10 +1437,10 @@ private void WriteDebugTable(Stream peStream, MetadataSizes metadataSizes, out l
writer.WriteByte((byte)'S');
// PDB id:
writer.WriteBytes(pdbId.ToByteArray());
writer.WriteBytes(pdbContentId.Guid);
// age
writer.WriteUint(age);
writer.WriteUint(PdbWriter.Age);
// UTF-8 encoded zero-terminated path to PDB
writer.WriteString(_pdbPathOpt, emitNullTerminator: true);
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.DiaSymReader.Native" version="1.0.0-rc2" />
</packages>
......@@ -42,7 +42,7 @@ End Class"
AssertEx.Equal(result3, result4)
End Sub
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/926"), WorkItem(926)>
<Fact, WorkItem(926)>
Public Sub CompareAllBytesEmitted_Debug()
Dim source =
"Class Program
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册