Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Compiler record to PDB files in Crossgen2 #59686

Merged
merged 1 commit into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 129 additions & 1 deletion src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Runtime.InteropServices;
using System.Text;

using Internal.TypeSystem;
using Microsoft.DiaSymReader;

namespace ILCompiler.Diagnostics
Expand Down Expand Up @@ -78,6 +79,7 @@ public class PdbWriter

string _pdbPath;
PDBExtraData _pdbExtraData;
readonly TargetDetails _target;

string _pdbFilePath;
string _tempSourceDllName;
Expand Down Expand Up @@ -116,7 +118,7 @@ private extern static void CreateNGenPdbWriter(
[MarshalAs(UnmanagedType.LPWStr)] string pdbPath,
[MarshalAs(UnmanagedType.Interface)] out ISymNGenWriter2 ngenPdbWriter);

public PdbWriter(string pdbPath, PDBExtraData pdbExtraData)
public PdbWriter(string pdbPath, PDBExtraData pdbExtraData, TargetDetails target)
{
SymDocument unknownDocument = new SymDocument();
unknownDocument.Name = "unknown";
Expand All @@ -126,6 +128,7 @@ public PdbWriter(string pdbPath, PDBExtraData pdbExtraData)
_symDocuments.Add(unknownDocument);
_pdbPath = pdbPath;
_pdbExtraData = pdbExtraData;
_target = target;
}

public void WritePDBData(string dllPath, IEnumerable<MethodInfo> methods)
Expand Down Expand Up @@ -227,6 +230,7 @@ private void WritePDBDataHelper(string dllPath, IEnumerable<MethodInfo> methods)

_ngenWriter.OpenModW(originalDllPath, Path.GetFileName(originalDllPath), out _pdbMod);

WriteCompilerVersion();
WriteStringTable();
WriteFileChecksums();

Expand Down Expand Up @@ -301,6 +305,24 @@ private enum DEBUG_S_SUBSECTION_TYPE {
DEBUG_S_COFF_SYMBOL_RVA,
}

private enum SYM_ENUM : ushort
{
S_COMPILE3 = 0x113c, // Replacement for S_COMPILE2
}

private enum CV_CPU_TYPE
{
CV_CFL_PENTIUMIII = 0x07,
CV_CFL_X64 = 0xD0,
CV_CFL_ARMNT = 0xF4,
CV_CFL_ARM64 = 0xF6,
}

private enum CV_CFL_LANG
{
CV_CFL_MSIL = 0x0F, // Unknown MSIL (LTCG of .NETMODULE)
}

private void WriteStringTable()
{
_stringTableToOffsetMapping = new Dictionary<string,int>();
Expand Down Expand Up @@ -384,5 +406,111 @@ private void WriteFileChecksums()
byte[] checksumTableArray = checksumStream.ToArray();
_ngenWriter.ModAddSymbols(_pdbMod, checksumTableArray, checksumTableArray.Length);
}

private void WriteCompilerVersion()
{
// The only symbol we write into the DEBUG_S_SYMBOLS stream is the compiler version.
// Other symbols are represented as "public" symbols which are something else entirely.

MemoryStream symbolStream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(symbolStream, Encoding.UTF8);
writer.Write(CV_SIGNATURE_C13);
writer.Write((uint)DEBUG_S_SUBSECTION_TYPE.DEBUG_S_SYMBOLS);
long startOfSymbolTablePosition = writer.BaseStream.Position;
writer.Write((uint)0); // Size of actual symbol table. To be filled in later
long startOfSymbolTableOffset = writer.BaseStream.Position;

{
long startOfCompile3RecordLength = writer.BaseStream.Position;
writer.Write((ushort)0); // Write record length. Fill in later
long startOfCompile3Record = writer.BaseStream.Position;
writer.Write((ushort)SYM_ENUM.S_COMPILE3);
byte iLanguage = (byte)CV_CFL_LANG.CV_CFL_MSIL;
writer.Write(iLanguage);
// Write rest of flags
writer.Write((byte)0);
writer.Write((byte)0);
writer.Write((byte)0);

switch (_target.Architecture)
{
case TargetArchitecture.ARM:
writer.Write((ushort)CV_CPU_TYPE.CV_CFL_ARMNT);
break;
case TargetArchitecture.ARM64:
writer.Write((ushort)CV_CPU_TYPE.CV_CFL_ARM64);
break;
case TargetArchitecture.X64:
writer.Write((ushort)CV_CPU_TYPE.CV_CFL_X64);
break;
case TargetArchitecture.X86:
writer.Write((ushort)CV_CPU_TYPE.CV_CFL_PENTIUMIII);
break;
default:
throw new Exception("Unknown target architecture");
}

writer.Write((ushort)0); // Front end Major Version
writer.Write((ushort)0); // Front end Minor Version
writer.Write((ushort)0); // Front end Build Version
writer.Write((ushort)0); // Front end QFE Version

Version compilerVersion = null;
foreach (AssemblyFileVersionAttribute versionAttribute in typeof(PdbWriter).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true))
{
string versionString = versionAttribute.Version;
compilerVersion = new Version(versionString);
}
if (compilerVersion == null)
{
throw new Exception("No AssemblyFileVersionAttribute present");
}

writer.Write((ushort)compilerVersion.Major); // Front end Major Version
writer.Write((ushort)compilerVersion.Minor); // Front end Minor Version
writer.Write((ushort)compilerVersion.Build); // Front end Build Version
writer.Write((ushort)compilerVersion.Revision); // Front end QFE Version

// compiler version string
string informationalVersion = null;
foreach (AssemblyInformationalVersionAttribute versionAttribute in typeof(PdbWriter).Assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), true))
{
informationalVersion = versionAttribute.InformationalVersion;
}

if (informationalVersion == null)
{
throw new Exception("No AssemblyInformationalVersionAttribute present");
}

string CompilerVersionString = $"Crossgen2 - {informationalVersion}";
writer.Write(CompilerVersionString.AsSpan());
writer.Write((byte)0); // Null terminate all strings

// Must align to the next 4-byte boundary
while ((writer.BaseStream.Position % 4) != 0)
{
writer.Write((byte)0);
}

// Update Compile3 record size
long currentPosition = writer.BaseStream.Position;
long compile3RecordSize = writer.BaseStream.Position - startOfCompile3Record;
writer.BaseStream.Position = startOfCompile3RecordLength;
writer.Write(checked((ushort)compile3RecordSize));
writer.Flush();
writer.BaseStream.Position = currentPosition;
}

// Update symbol table size
long symbolTableSize = writer.BaseStream.Position - startOfSymbolTableOffset;
writer.BaseStream.Position = startOfSymbolTablePosition;
writer.Write(checked((uint)symbolTableSize));
writer.Flush();

// Write symbol table into pdb file
byte[] symbolTableArray = symbolStream.ToArray();
_ngenWriter.ModAddSymbols(_pdbMod, symbolTableArray, symbolTableArray.Length);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public ReadyToRunObjectWriter(

if (generateSymbols)
{
_symbolFileBuilder = new SymbolFileBuilder(_outputInfoBuilder);
_symbolFileBuilder = new SymbolFileBuilder(_outputInfoBuilder, _nodeFactory.Target);
}

if (generateProfileFile)
Expand Down Expand Up @@ -400,7 +400,7 @@ public void EmitPortableExecutable()
{
path = Path.GetDirectoryName(_objectFilePath);
}
_symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath, _nodeFactory.Target);
_symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath);
}

if (_profileFileBuilder != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@ namespace ILCompiler.PEWriter
public class SymbolFileBuilder
{
private readonly OutputInfoBuilder _outputInfoBuilder;
private readonly TargetDetails _details;

public SymbolFileBuilder(OutputInfoBuilder outputInfoBuilder)
public SymbolFileBuilder(OutputInfoBuilder outputInfoBuilder, TargetDetails details)
{
_outputInfoBuilder = outputInfoBuilder;
_details = details;
}

public void SavePdb(string pdbPath, string dllFileName)
{
Console.WriteLine("Emitting PDB file: {0}", Path.Combine(pdbPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.pdb"));

new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods());
new PdbWriter(pdbPath, PDBExtraData.None, _details).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods());
}

public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName, TargetDetails details)
public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName)
{
string perfMapExtension;
if (perfMapFormatVersion == PerfMapWriter.LegacyCrossgen1FormatVersion)
Expand All @@ -56,7 +58,7 @@ public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dll

string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + perfMapExtension);
Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName);
PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), details);
PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), _details);
}
}
}
3 changes: 2 additions & 1 deletion src/coreclr/tools/r2rdump/R2RDump.cs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ public void Dump(ReadyToRunReader r2r)
{
pdbPath = Path.GetDirectoryName(r2r.Filename);
}
var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None);
TargetDetails details = new TargetDetails(r2r.TargetArchitecture, r2r.TargetOperatingSystem, TargetAbi.CoreRT);
var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None, details);
pdbWriter.WritePDBData(r2r.Filename, ProduceDebugInfoMethods(r2r));
}

Expand Down