提交 8da79efb 编写于 作者: T Tomáš Matoušek

Merge pull request #4785 from tmat/PdbPadding

PDB path padding
......@@ -6232,7 +6232,7 @@ class Program3
using (var peFile = File.OpenRead(exe.Path))
{
PdbValidation.ValidateDebugDirectory(peFile, pdb.Path, isPortable: false);
PdbValidation.ValidateDebugDirectory(peFile, pdb.Path, isPortable: false, isDeterministic: false);
}
Assert.True(new FileInfo(exe.Path).Length < oldSize);
......@@ -6243,7 +6243,7 @@ class Program3
using (var peFile = File.OpenRead(exe.Path))
{
PdbValidation.ValidateDebugDirectory(peFile, pdb.Path, isPortable: false);
PdbValidation.ValidateDebugDirectory(peFile, pdb.Path, isPortable: false, isDeterministic: false);
}
}
......
......@@ -1805,6 +1805,8 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
return new EmitResult(success, diagnostics.ToReadOnlyAndFree());
}
internal bool IsEmitDeterministic => this.Feature("deterministic")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
internal bool SerializeToPeStream(
CommonPEModuleBuilder moduleBeingBuilt,
EmitStreamProvider peStreamProvider,
......@@ -1825,7 +1827,7 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
Stream portablePdbTempStream = null;
Stream peTempStream = null;
bool deterministic = this.Feature("deterministic")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
bool deterministic = IsEmitDeterministic;
bool emitPortablePdb = moduleBeingBuilt.EmitOptions.DebugInformationFormat == DebugInformationFormat.PortablePdb;
string pdbPath = (pdbStreamProvider != null) ? (moduleBeingBuilt.EmitOptions.PdbFilePath ?? FileNameUtilities.ChangeExtension(SourceModule.Name, "pdb")) : null;
......
......@@ -27,6 +27,13 @@ internal sealed class PeWriter
private const string ResourceSectionName = ".rsrc";
private const string RelocationSectionName = ".reloc";
/// <summary>
/// Minimal size of PDB path in Debug Directory. We pad the path to this minimal size to
/// allow some tools to patch the path without the need to rewrite the entire image.
/// This is a workaround put in place until these tools are retired.
/// </summary>
private readonly int _minPdbPath;
/// <summary>
/// True if we should attempt to generate a deterministic output (no timestamps or random data).
/// </summary>
......@@ -53,6 +60,8 @@ internal sealed class PeWriter
_pdbPathOpt = pdbPathOpt;
_deterministic = deterministic;
// The PDB padding workaround is only needed for legacy tools that don't use deterministic build.
_minPdbPath = deterministic ? 0 : 260;
_nativeResourcesOpt = nativeResourcesOpt;
_nativeResourceSectionOpt = nativeResourceSectionOpt;
_is32bit = !_properties.Requires64bits;
......@@ -457,8 +466,7 @@ private int ComputeSizeOfDebugDirectoryData()
4 + // 4B signature "RSDS"
16 + // GUID
sizeof(uint) + // Age
Encoding.UTF8.GetByteCount(_pdbPathOpt) +
1; // Null terminator
Math.Max(BlobUtilities.GetUTF8ByteCount(_pdbPathOpt) + 1, _minPdbPath);
}
private int ComputeSizeOfDebugDirectory()
......@@ -1380,9 +1388,13 @@ private void WriteDebugTable(Stream peStream, SectionHeader textSection, Content
writer.WriteUInt32(PdbWriter.Age);
// UTF-8 encoded zero-terminated path to PDB
int pathStart = writer.Position;
writer.WriteUTF8(_pdbPathOpt, allowUnpairedSurrogates: true);
writer.WriteByte(0);
// padding:
writer.WriteBytes(0, Math.Max(0, _minPdbPath - (writer.Position - pathStart)));
writer.WriteContentTo(peStream);
writer.Free();
}
......
......@@ -226,13 +226,13 @@ private static void RemoveNonPortablePdb(XElement expectedNativePdb)
actual = PdbToXmlConverter.ToXml(pdbbits, exebits, options, methodName: qualifiedMethodName);
}
ValidateDebugDirectory(exebits, compilation.AssemblyName + ".pdb", portable);
ValidateDebugDirectory(exebits, compilation.AssemblyName + ".pdb", portable, compilation.IsEmitDeterministic);
}
return actual;
}
public static void ValidateDebugDirectory(Stream peStream, string pdbPath, bool isPortable)
public static void ValidateDebugDirectory(Stream peStream, string pdbPath, bool isPortable, bool isDeterministic)
{
peStream.Seek(0, SeekOrigin.Begin);
PEReader peReader = new PEReader(peStream);
......@@ -281,11 +281,28 @@ public static void ValidateDebugDirectory(Stream peStream, string pdbPath, bool
Assert.Equal(1u, reader.ReadUInt32());
byte[] pathBlob = new byte[sizeOfData - 24 - 1];
byte[] pathBlob = new byte[sizeOfData - 24];
reader.Read(pathBlob, 0, pathBlob.Length);
var actualPath = Encoding.UTF8.GetString(pathBlob);
int terminator = Array.IndexOf(pathBlob, (byte)0);
Assert.True(terminator >= 0, "Path should be NUL terminated");
for (int i = terminator + 1; i < pathBlob.Length; i++)
{
Assert.Equal(0, pathBlob[i]);
}
if (isDeterministic)
{
Assert.Equal(pathBlob.Length - 1, terminator);
}
else
{
Assert.True(pathBlob.Length >= 260, "Path should be at least MAX_PATH long");
}
var actualPath = Encoding.UTF8.GetString(pathBlob, 0, terminator);
Assert.Equal(pdbPath, actualPath);
Assert.Equal(0, reader.ReadByte());
}
public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册