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

[SymbolStore] Add support to index .NET Framework Runtime debugging modules #4616

Merged
182 changes: 102 additions & 80 deletions src/Microsoft.SymbolStore/KeyGenerators/PEFileKeyGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ namespace Microsoft.SymbolStore.KeyGenerators
public class PEFileKeyGenerator : KeyGenerator
{
private const string CoreClrFileName = "coreclr.dll";
private const string ClrFileName = "clr.dll";
mdh1418 marked this conversation as resolved.
Show resolved Hide resolved

private static readonly HashSet<string> s_longNameBinaryPrefixes = new(new string[] { "mscordaccore_", "sos_" });
private static readonly HashSet<string> s_daclongNameBinaryPrefixes = new(new string[] { "mscordaccore_" });

private static readonly string[] s_specialFiles = new string[] { "mscordaccore.dll", "mscordbi.dll" };
private static readonly string[] s_sosSpecialFiles = new string[] { "sos.dll", "SOS.NETCore.dll" };

private static readonly HashSet<string> s_coreClrSpecialFiles = new(s_specialFiles.Concat(s_sosSpecialFiles));
private static readonly HashSet<string> s_dacdbiSpecialFiles = new(s_specialFiles);
private const string SosFileName = "SOS.dll";
private const string CoreClrDACFileName = "mscordaccore.dll";
private const string ClrDACFileName = "mscordacwks.dll";
private const string DbiFileName = "mscordbi.dll";
private static readonly string[] s_knownFilesWithLongNameVariant = new string[] { SosFileName, CoreClrDACFileName, ClrDACFileName };
private static readonly string[] s_knownRuntimeSpecialFiles = new string[] { CoreClrDACFileName, ClrDACFileName, DbiFileName };

private readonly PEFile _peFile;
private readonly string _path;
Expand Down Expand Up @@ -51,7 +50,7 @@ public override IEnumerable<SymbolStoreKey> GetKeys(KeyTypeFlags flags)
{
yield return GetKey(_path, _peFile.Timestamp, _peFile.SizeOfImage);
}
if ((flags & KeyTypeFlags.RuntimeKeys) != 0 && GetFileName(_path) == CoreClrFileName)
if ((flags & KeyTypeFlags.RuntimeKeys) != 0 && (GetFileName(_path) == CoreClrFileName || GetFileName(_path) == ClrFileName))
{
yield return GetKey(_path, _peFile.Timestamp, _peFile.SizeOfImage);
}
Expand Down Expand Up @@ -93,22 +92,31 @@ public override IEnumerable<SymbolStoreKey> GetKeys(KeyTypeFlags flags)
}
}

// Return keys for SOS modules for a given runtime module
if ((flags & (KeyTypeFlags.ClrKeys)) != 0)
{
string coreclrId = BuildId(_peFile.Timestamp, _peFile.SizeOfImage);
foreach (string specialFileName in GetSOSFiles(GetFileName(_path)))
{
yield return BuildKey(specialFileName, coreclrId);
}
}

// Return keys for DAC and DBI modules for a given runtime module
if ((flags & (KeyTypeFlags.ClrKeys | KeyTypeFlags.DacDbiKeys)) != 0)
{
if (GetFileName(_path) == CoreClrFileName)
string coreclrId = BuildId(_peFile.Timestamp, _peFile.SizeOfImage);
foreach (string specialFileName in GetDACFiles(GetFileName(_path)))
{
string coreclrId = string.Format("{0:X8}{1:x}", _peFile.Timestamp, _peFile.SizeOfImage);
foreach (string specialFileName in GetSpecialFiles(flags))
{
yield return BuildKey(specialFileName, coreclrId);
}
yield return BuildKey(specialFileName, coreclrId);
}
}

if ((flags & KeyTypeFlags.HostKeys) != 0)
{
if ((_peFile.FileHeader.Characteristics & (ushort)ImageFile.Dll) == 0 && !_peFile.IsILImage)
{
string id = string.Format("{0:X8}{1:x}", _peFile.Timestamp, _peFile.SizeOfImage);
string id = BuildId(_peFile.Timestamp, _peFile.SizeOfImage);

// The host program as itself (usually dotnet.exe)
yield return BuildKey(_path, id);
Expand All @@ -120,79 +128,88 @@ public override IEnumerable<SymbolStoreKey> GetKeys(KeyTypeFlags flags)
}
}

private IEnumerable<string> GetSpecialFiles(KeyTypeFlags flags)
private IEnumerable<string> GetSOSFiles(string runtimeFileName)
{
List<string> specialFiles = new((flags & KeyTypeFlags.ClrKeys) != 0 ? s_coreClrSpecialFiles : s_dacdbiSpecialFiles);

VsFixedFileInfo fileVersion = _peFile.VersionInfo;
if (fileVersion != null)
if (runtimeFileName == ClrFileName)
{
ushort major = fileVersion.ProductVersionMajor;
ushort minor = fileVersion.ProductVersionMinor;
ushort build = fileVersion.ProductVersionBuild;
ushort revision = fileVersion.ProductVersionRevision;
return GetFilesLongNameVariants(SosFileName);
}

List<string> hostArchitectures = new();
string targetArchitecture = null;
return Enumerable.Empty<string>();
}

ImageFileMachine machine = (ImageFileMachine)_peFile.FileHeader.Machine;
switch (machine)
{
case ImageFileMachine.Amd64:
targetArchitecture = "amd64";
break;

case ImageFileMachine.I386:
targetArchitecture = "x86";
break;

case ImageFileMachine.ArmNT:
targetArchitecture = "arm";
hostArchitectures.Add("x86");
break;

case ImageFileMachine.Arm64:
targetArchitecture = "arm64";
hostArchitectures.Add("amd64");
break;
}
private IEnumerable<string> GetDACFiles(string runtimeFileName)
{
if (runtimeFileName == CoreClrFileName)
{
string[] coreClrDACFiles = new string[] { CoreClrDACFileName, DbiFileName };
IEnumerable<string> longNameDACFiles = GetFilesLongNameVariants(CoreClrDACFileName);
return coreClrDACFiles.Concat(longNameDACFiles);
}

if (targetArchitecture != null)
{
hostArchitectures.Add(targetArchitecture);
if (runtimeFileName == ClrFileName)
{
string[] clrDACFiles = new string[] { ClrDACFileName, DbiFileName };
IEnumerable<string> longNameDACFiles = GetFilesLongNameVariants(ClrDACFileName);
return clrDACFiles.Concat(longNameDACFiles);
}

foreach (string hostArchitecture in hostArchitectures)
{
string buildFlavor = "";
return Enumerable.Empty<string>();
}

if ((fileVersion.FileFlags & FileInfoFlags.Debug) != 0)
{
if ((fileVersion.FileFlags & FileInfoFlags.SpecialBuild) != 0)
{
buildFlavor = ".dbg";
}
else
{
buildFlavor = ".chk";
}
}
private IEnumerable<string> GetFilesLongNameVariants(string fileWithLongNameVariant)
{
if (!s_knownFilesWithLongNameVariant.Contains(fileWithLongNameVariant))
{
Tracer.Warning("{0} is not a recognized file with a long name variant", fileWithLongNameVariant);
return Enumerable.Empty<string>();
}

foreach (string name in (flags & KeyTypeFlags.ClrKeys) != 0 ? s_longNameBinaryPrefixes : s_daclongNameBinaryPrefixes)
{
// The name prefixes include the trailing "_".
string longName = string.Format("{0}{1}_{2}_{3}.{4}.{5}.{6:00}{7}.dll",
name, hostArchitecture, targetArchitecture, major, minor, build, revision, buildFlavor);
specialFiles.Add(longName);
}
}
}
VsFixedFileInfo fileVersionInfo = _peFile.VersionInfo;
if (fileVersionInfo == null)
{
Tracer.Warning("{0} has no version resource, long name file keys could not be generated", _path);
return Enumerable.Empty<string>();
}
else

string targetArchitecture;
List<string> hostArchitectures = new();
ImageFileMachine machine = (ImageFileMachine)_peFile.FileHeader.Machine;
switch (machine)
{
case ImageFileMachine.Amd64:
targetArchitecture = "amd64";
break;
case ImageFileMachine.I386:
targetArchitecture = "x86";
break;
case ImageFileMachine.ArmNT:
targetArchitecture = "arm";
hostArchitectures.Add("x86");
break;
case ImageFileMachine.Arm64:
targetArchitecture = "arm64";
hostArchitectures.Add("amd64");
break;
default:
Tracer.Warning("{0} has an architecture not used to generate long name file keys", _peFile);
return Enumerable.Empty<string>();
}
hostArchitectures.Add(targetArchitecture);

string fileVersion = $"{fileVersionInfo.FileVersionMajor}.{fileVersionInfo.FileVersionMinor}.{fileVersionInfo.FileVersionBuild}.{fileVersionInfo.FileVersionRevision:00}";

string buildFlavor = (fileVersionInfo.FileFlags & FileInfoFlags.Debug) == 0 ? "" :
(fileVersionInfo.FileFlags & FileInfoFlags.SpecialBuild) != 0 ? ".dbg" : ".chk";

List<string> longNameFileVariants = new();
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileWithLongNameVariant);
foreach (string hostArchitecture in hostArchitectures)
{
Tracer.Warning("{0} has no version resource", _path);
longNameFileVariants.Add($"{fileNameWithoutExtension}_{hostArchitecture}_{targetArchitecture}_{fileVersion}{buildFlavor}.dll");
}

return specialFiles;
return longNameFileVariants;
}

/// <summary>
Expand All @@ -209,11 +226,16 @@ public static SymbolStoreKey GetKey(string path, uint timestamp, uint sizeOfImag
// The clr special file flag can not be based on the GetSpecialFiles() list because
// that is only valid when "path" is the coreclr.dll.
string fileName = GetFileName(path);
bool clrSpecialFile = s_coreClrSpecialFiles.Contains(fileName) ||
(s_longNameBinaryPrefixes.Any((prefix) => fileName.StartsWith(prefix)) && Path.GetExtension(fileName) == ".dll");
bool clrSpecialFile = s_knownRuntimeSpecialFiles.Contains(fileName) ||
(s_knownFilesWithLongNameVariant.Any((file) => fileName.StartsWith(Path.GetFileNameWithoutExtension(file).ToLowerInvariant() + "_")) && Path.GetExtension(fileName) == ".dll");

string id = string.Format("{0:X8}{1:x}", timestamp, sizeOfImage);
string id = BuildId(timestamp, sizeOfImage);
return BuildKey(path, id, clrSpecialFile);
}

private static string BuildId(uint timestamp, uint sizeOfImage)
{
return string.Format("{0:X8}{1:x}", timestamp, sizeOfImage);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -456,16 +456,16 @@ private void PEFileKeyGeneratorInternal(bool fileGenerator)
Assert.True(symbolKey.First().Index == "coreclr.pdb/3f3d5a3258e64ae8b86b31ff776949351/coreclr.pdb");

Dictionary<string, SymbolStoreKey> clrKeys = generator.GetKeys(KeyTypeFlags.ClrKeys).ToDictionary((key) => key.Index);
Assert.True(clrKeys.Count() == 3);
Assert.True(clrKeys.ContainsKey("mscordaccore.dll/595EBCD5538000/mscordaccore.dll"));
Assert.True(clrKeys.ContainsKey("mscordaccore_amd64_amd64_4.6.25505.00.dll/595EBCD5538000/mscordaccore_amd64_amd64_4.6.25505.00.dll"));
Assert.True(clrKeys.ContainsKey("mscordbi.dll/595EBCD5538000/mscordbi.dll"));
Assert.True(clrKeys.ContainsKey("sos.dll/595EBCD5538000/sos.dll"));
Assert.True(clrKeys.ContainsKey("sos.netcore.dll/595EBCD5538000/sos.netcore.dll"));

Dictionary<string, SymbolStoreKey> dacdbiKeys = generator.GetKeys(KeyTypeFlags.DacDbiKeys).ToDictionary((key) => key.Index);
Assert.True(dacdbiKeys.Count() == 3);
Assert.True(dacdbiKeys.ContainsKey("mscordaccore.dll/595EBCD5538000/mscordaccore.dll"));
Assert.True(dacdbiKeys.ContainsKey("mscordaccore_amd64_amd64_4.6.25505.00.dll/595EBCD5538000/mscordaccore_amd64_amd64_4.6.25505.00.dll"));
Assert.True(dacdbiKeys.ContainsKey("mscordbi.dll/595EBCD5538000/mscordbi.dll"));
Assert.False(dacdbiKeys.ContainsKey("sos.dll/595EBCD5538000/sos.dll"));
Assert.False(dacdbiKeys.ContainsKey("sos.netcore.dll/595EBCD5538000/sos.netcore.dll"));

IEnumerable<SymbolStoreKey> perfMapKey = generator.GetKeys(KeyTypeFlags.PerfMapKeys);
Assert.True(perfMapKey.Count() == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\coreclr.dll.gz">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mockclr_amd64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mockclr_arm64.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mockclr_i386.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mockdac.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mockdbi.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\mocksos.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)TestBinaries\libSystem.Security.Cryptography.Native.Apple.dylib.gz">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
Loading
Loading