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

Update #5 #3

Merged
merged 51 commits into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5c2fe5e
workaround icon file check by extracting it to disk
campersau Dec 25, 2019
325be69
Fix licenseUrl path
Jan 6, 2020
5546113
Bump Nerdbank.GitVersioning from 3.0.28 to 3.0.48
dependabot-preview[bot] Jan 13, 2020
9967014
Merge pull request #891 from NuGetPackageExplorer/dependabot/nuget/Ne…
dependabot-preview[bot] Jan 13, 2020
3582cd5
Merge pull request #886 from NuGetPackageExplorer/save_package_with_icon
Jan 14, 2020
36019e4
Bump Nerdbank.GitVersioning from 3.0.48 to 3.0.50
dependabot-preview[bot] Jan 15, 2020
5a2569b
Merge pull request #892 from NuGetPackageExplorer/dependabot/nuget/Ne…
dependabot-preview[bot] Jan 15, 2020
2e01675
Merge pull request #1 from NuGetPackageExplorer/master
rtigithub Jan 22, 2020
8262ef5
Access Windows.Storage by using Nuget package Microsoft.Windows.SDK.C…
rtigithub Jan 22, 2020
60bfd8c
Merge pull request #894 from rtigithub/master
Feb 5, 2020
9851549
Bump Nerdbank.GitVersioning from 3.0.50 to 3.1.68
dependabot-preview[bot] Mar 10, 2020
e811bd4
Merge pull request #897 from NuGetPackageExplorer/dependabot/nuget/Ne…
dependabot-preview[bot] Mar 10, 2020
23fa60b
Bump Nerdbank.GitVersioning from 3.1.68 to 3.1.71
dependabot-preview[bot] Mar 16, 2020
7efa665
Merge pull request #898 from NuGetPackageExplorer/dependabot/nuget/Ne…
dependabot-preview[bot] Mar 16, 2020
f16dc48
Update NuGet to latest dev
clairernovotny Mar 19, 2020
f6dd486
Clean up nullability warnings
clairernovotny Mar 19, 2020
f1e4cdf
Merge pull request #899 from NuGetPackageExplorer/latest-nuget
clairernovotny Mar 19, 2020
5f068ec
Update TFM to netcoreapp5.0
clairernovotny Mar 19, 2020
77d9e30
Update cn names
clairernovotny Mar 19, 2020
8e29646
Update README.md
clairernovotny Mar 19, 2020
43587a2
Update README.md
clairernovotny Mar 19, 2020
5b894d5
Update README.md
clairernovotny Mar 19, 2020
60480a8
Add global json so vs will find preview version
clairernovotny Mar 19, 2020
d5b7cdc
Update tfm paths
clairernovotny Mar 19, 2020
9b255a2
Merge pull request #900 from NuGetPackageExplorer/net5p1
clairernovotny Mar 19, 2020
372140d
Update version to match nuget libs
clairernovotny Mar 19, 2020
d470469
Fix nullability warnings
clairernovotny Mar 19, 2020
236ad96
Merge pull request #902 from NuGetPackageExplorer/fix-warnings
clairernovotny Mar 19, 2020
4d13bd9
Bump System.Memory from 4.5.3 to 4.5.4
dependabot-preview[bot] Mar 25, 2020
8ee6378
Merge pull request #905 from NuGetPackageExplorer/dependabot/nuget/Sy…
dependabot-preview[bot] Mar 25, 2020
6443633
Bump System.Runtime.CompilerServices.Unsafe from 4.7.0 to 4.7.1
dependabot-preview[bot] Mar 25, 2020
4b05c8c
Merge pull request #906 from NuGetPackageExplorer/dependabot/nuget/Sy…
dependabot-preview[bot] Mar 25, 2020
a46b587
Add .NET 5 TFM's and clean up/sort menu
clairernovotny Mar 25, 2020
0babea5
Merge pull request #907 from NuGetPackageExplorer/add-net5
clairernovotny Mar 25, 2020
91c0d5b
Refactor associated files into separate method
clairernovotny Mar 25, 2020
56218a1
Simple check for has sourcelink
clairernovotny Mar 25, 2020
d76cb70
Add validation logic for source link when package contains symbols
clairernovotny Mar 25, 2020
7c301cc
Detect symbols and source link separately
clairernovotny Mar 26, 2020
f3b1e6b
Check for snupkg on NuGet.org
clairernovotny Mar 26, 2020
13bec98
Minor code cleanup
clairernovotny Mar 26, 2020
b1d99f3
Merge pull request #908 from NuGetPackageExplorer/validate-sourcelink
clairernovotny Mar 26, 2020
2d0a1c0
Skip satellite assemblies
clairernovotny Mar 26, 2020
04ab2f2
Update source link validation
clairernovotny Mar 26, 2020
f2a51ee
Merge pull request #909 from NuGetPackageExplorer/sourcelink-validation
clairernovotny Mar 26, 2020
0e31bcc
Clean up some code
clairernovotny Mar 27, 2020
249a69f
Ensure temp files are flushed
clairernovotny Mar 27, 2020
45511c4
Check Microsoft files against MSDL symbol server
clairernovotny Mar 27, 2020
faaa75e
Code cleanup
clairernovotny Mar 27, 2020
96d3498
Merge pull request #911 from NuGetPackageExplorer/ms-symbols
clairernovotny Mar 27, 2020
c27f217
Don't display embedded pdb unless present
clairernovotny Mar 27, 2020
a5e5448
Dispose of the PE reader we created
clairernovotny Mar 27, 2020
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
18 changes: 14 additions & 4 deletions Core/AssemblyMetadata/AssemblyDebugData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,23 @@ namespace NuGetPe.AssemblyMetadata
{
public class AssemblyDebugData
{
#pragma warning disable CS8618 // Non-nullable field is uninitialized.
public PdbType PdbType { get; internal set; }
public AssemblyDebugData()
{
SourceLinkErrors = new List<string>();
Sources = new List<AssemblyDebugSourceDocument>();
SymbolKeys = new List<SymbolKey>();
}

public IReadOnlyList<SourceLinkMap> SourceLink { get; internal set; }
public PdbType PdbType { get; internal set; }

public IReadOnlyList<AssemblyDebugSourceDocument> Sources { get; internal set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized.
public IReadOnlyList<string> SourceLinkErrors { get; internal set; }
public IReadOnlyList<SymbolKey> SymbolKeys { get; internal set; }
public bool HasSourceLink => Sources.All(doc => doc.HasSourceLink);


public bool HasDebugInfo { get; internal set; }

}

public enum PdbType
Expand Down
221 changes: 149 additions & 72 deletions Core/AssemblyMetadata/AssemblyDebugParser.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Text;
using Microsoft.DiaSymReader.Tools;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.SourceLink.Tools;

namespace NuGetPe.AssemblyMetadata
{
Expand All @@ -23,6 +25,7 @@ public AssemblyDebugParser(Stream? peStream, Stream pdbStream)
_temporaryPdbStream = new MemoryStream();
PdbConverter.Default.ConvertWindowsToPortable(peStream, pdbStream, _temporaryPdbStream);
_temporaryPdbStream.Position = 0;
peStream.Position = 0;
inputStream = _temporaryPdbStream;
_pdbType = PdbType.Full;
}
Expand All @@ -34,13 +37,16 @@ public AssemblyDebugParser(Stream? peStream, Stream pdbStream)

_readerProvider = MetadataReaderProvider.FromPortablePdbStream(inputStream);
_reader = _readerProvider.GetMetadataReader();

_peReader = new PEReader(peStream!);
_ownPeReader = true;
}

public AssemblyDebugParser(MetadataReaderProvider readerProvider, PdbType pdbType)
public AssemblyDebugParser(PEReader peReader, MetadataReaderProvider readerProvider, PdbType pdbType)
{
_readerProvider = readerProvider;
_pdbType = pdbType;
_peReader = peReader;
_ownPeReader = false;

// Possible BadImageFormatException if a full PDB is passed
// in. We'll let the throw bubble up to something that can handle it
Expand All @@ -51,124 +57,195 @@ public AssemblyDebugParser(MetadataReaderProvider readerProvider, PdbType pdbTyp
private bool _disposedValue = false;
private readonly MetadataReaderProvider _readerProvider;
private readonly MetadataReader _reader;
private readonly PEReader _peReader;
private readonly bool _ownPeReader;
private readonly Stream? _temporaryPdbStream;

private static readonly Guid SourceLinkGuid = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A");
private static readonly Guid SourceLinkId = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A");

private static readonly Guid EmbeddedSourceId = new Guid("0E8A571B-6926-466E-B4AD-8AB04611F5FE");
private const ushort PortableCodeViewVersionMagic = 0x504d;


public AssemblyDebugData GetDebugData()
{

var (documents, errors) = GetDocumentsWithUrls();


var debugData = new AssemblyDebugData
{
PdbType = _pdbType,
Sources = GetSourceDocuments(),
SourceLink = GetSourceLinkInformation()
Sources = documents,
SourceLinkErrors = errors,
SymbolKeys = GetSymbolKeys(_peReader),
HasDebugInfo = true
};

return debugData;
}

private IReadOnlyList<SourceLinkMap> GetSourceLinkInformation()

private byte[]? GetSourceLinkBytes()
{
var sl = (from cdi in _reader.CustomDebugInformation
let cd = _reader.GetCustomDebugInformation(cdi)
let kind = _reader.GetGuid(cd.Kind)
where kind == SourceLinkGuid
let bl = _reader.GetBlobBytes(cd.Value)
select Encoding.UTF8.GetString(bl))
.FirstOrDefault();

if (sl != null)
if (_reader == null) return null;
var blobh = default(BlobHandle);
foreach (var cdih in _reader.GetCustomDebugInformation(EntityHandle.ModuleDefinition))
{
try
{
/* Some tools, like GitLink generate incorrectly escaped JSON:
var cdi = _reader.GetCustomDebugInformation(cdih);
if (_reader.GetGuid(cdi.Kind) == SourceLinkId)
blobh = cdi.Value;
}
if (blobh.IsNil) return Array.Empty<byte>();
return _reader.GetBlobBytes(blobh);
}

{
"documents": {
"C:\projects\cefsharp\*": "https://raw.github.com/CefSharp/CefSharp/4f88ad11416e93dde4b52216800efd42ba3b9c8a/*"
}
}

Catch the exception and try to fix the key
*/
JObject? jobj = null;
try
{
jobj = JObject.Parse(sl);
}
catch (JsonReaderException e) when (e.Path == "documents")
{
sl = sl.Replace(@"\", @"\\", StringComparison.Ordinal);
jobj = JObject.Parse(sl);
}
private bool IsEmbedded(DocumentHandle dh)
{
foreach (var cdih in _reader.GetCustomDebugInformation(dh))
{
var cdi = _reader.GetCustomDebugInformation(cdih);
if (_reader.GetGuid(cdi.Kind) == EmbeddedSourceId)
return true;
}
return false;
}

var docs = (JObject)jobj["documents"];
public static IReadOnlyList<SymbolKey> GetSymbolKeys(PEReader peReader)
{
var result = new List<SymbolKey>();
var checksums = new List<string>();

var slis = (from prop in docs.Properties()
select new SourceLinkMap
{
Base = prop.Name.Replace(@"\", @"/", StringComparison.Ordinal), // use forward slashes for the url,
Location = prop.Value.Value<string>()
})
.ToList();
foreach (var entry in peReader.ReadDebugDirectory())
{
if (entry.Type != DebugDirectoryEntryType.PdbChecksum) continue;

return slis;
}
catch (JsonReaderException jse)
{
throw new InvalidDataException("SourceLink data could not be parsed", jse);
}
var data = peReader.ReadPdbChecksumDebugDirectoryData(entry);
var algorithm = data.AlgorithmName;
var checksum = data.Checksum.Select(b => b.ToString("x2", CultureInfo.InvariantCulture));

checksums.Add($"{algorithm}:{checksum}");
}

foreach (var entry in peReader.ReadDebugDirectory())
{
if (entry.Type != DebugDirectoryEntryType.CodeView) continue;

var data = peReader.ReadCodeViewDebugDirectoryData(entry);
var isPortable = entry.MinorVersion == PortableCodeViewVersionMagic;

var signature = data.Guid;
var age = data.Age;
#pragma warning disable CA1308 // Normalize strings to uppercase
var file = Uri.EscapeDataString(Path.GetFileName(data.Path.Replace("\\", "/", StringComparison.OrdinalIgnoreCase)).ToLowerInvariant());
#pragma warning restore CA1308 // Normalize strings to uppercase

// Portable PDBs, see: https://github.com/dotnet/symstore/blob/83032682c049a2b879790c615c27fbc785b254eb/src/Microsoft.SymbolStore/KeyGenerators/PortablePDBFileKeyGenerator.cs#L84
// Windows PDBs, see: https://github.com/dotnet/symstore/blob/83032682c049a2b879790c615c27fbc785b254eb/src/Microsoft.SymbolStore/KeyGenerators/PDBFileKeyGenerator.cs#L52
var symbolId = isPortable
? signature.ToString("N", CultureInfo.InvariantCulture) + "FFFFFFFF"
: string.Format(CultureInfo.InvariantCulture, "{0}{1:x}", signature.ToString("N", CultureInfo.InvariantCulture), age);

result.Add(new SymbolKey
{
IsPortablePdb = isPortable,
Checksums = checksums,
Key = $"{file}/{symbolId}/{file}",
});
}

return Array.Empty<SourceLinkMap>();
return result;
}


private IReadOnlyList<AssemblyDebugSourceDocument> GetSourceDocuments()
private IEnumerable<AssemblyDebugSourceDocument> GetSourceDocuments()
{
var list = new List<AssemblyDebugSourceDocument>();

foreach (var docHandle in _reader.Documents)
foreach (var dh in _reader.Documents)
{
var document = _reader.GetDocument(docHandle);
if (dh.IsNil) continue;
var d = _reader.GetDocument(dh);
if (d.Name.IsNil || d.Language.IsNil || d.HashAlgorithm.IsNil || d.Hash.IsNil) continue;

var name = _reader.GetString(d.Name);
var language = _reader.GetGuid(d.Language);
var hashAlgorithm = _reader.GetGuid(d.HashAlgorithm);
var hash = _reader.GetBlobBytes(d.Hash);
var isEmbedded = IsEmbedded(dh);

var langGuid = _reader.GetGuid(document.Language);
var hashGuid = _reader.GetGuid(document.HashAlgorithm);
var docName = _reader.GetString(document.Name).Replace(@"\", @"/", StringComparison.Ordinal); // use forward slashes for the url

var doc = new AssemblyDebugSourceDocument
(
docName,
_reader.GetBlobBytes(document.Hash),
langGuid,
hashGuid
name,
hash,
language,
hashAlgorithm,
isEmbedded
);
list.Add(doc);


if (doc.Language == SymbolLanguage.Unknown)
{
DiagnosticsClient.TrackEvent("Unknown language Guid", new Dictionary<string, string>
{
{ "LanguageGuid", langGuid.ToString() },
{ "HashGuid", hashGuid.ToString() },
{ "DocExtension", Path.GetExtension(docName)! }
{ "LanguageGuid", language.ToString() },
{ "HashGuid", hashAlgorithm.ToString() },
{ "DocExtension", Path.GetExtension(name)! }
});
}
}

yield return doc;
}
}


private (IReadOnlyList<AssemblyDebugSourceDocument> documents, IReadOnlyList<string> errors) GetDocumentsWithUrls()
{
var bytes = GetSourceLinkBytes();
SourceLinkMap? map = null;

var errors = new List<string>();
if (bytes != null && bytes.Length > 0)
{
var text = Encoding.UTF8.GetString(bytes);
map = SourceLinkMap.Parse(text, errors.Add);
}
return list;

var list = new List<AssemblyDebugSourceDocument>();

foreach (var doc in GetSourceDocuments())
{
if (!doc.IsEmbedded)
doc.Url = map?.GetUri(doc.Name);
list.Add(doc);
}

return (list, errors);
}




public void Dispose()
{
if (!_disposedValue)
{
_readerProvider.Dispose();
_temporaryPdbStream?.Dispose();

if(_ownPeReader)
_peReader.Dispose();

_disposedValue = true;
}
}
}

[DebuggerDisplay("{Key}, IsPortable={IsPortablePdb}")]
public class SymbolKey
{
public bool IsPortablePdb { get; set; }
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
public IReadOnlyList<string> Checksums { get; set; }
public string Key { get; set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
}
}
6 changes: 5 additions & 1 deletion Core/AssemblyMetadata/AssemblyDebugSourceDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ public class AssemblyDebugSourceDocument
private static readonly Guid Sha1 = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460");
private static readonly Guid Sha256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");

internal AssemblyDebugSourceDocument(string name, byte[] hash, Guid language, Guid hashAlgorithm)
internal AssemblyDebugSourceDocument(string name, byte[] hash, Guid language, Guid hashAlgorithm, bool isEmbedded)
{
Name = name;
Hash = hash;
Language = LanguageFromGuid(language);
HashAlgorithm = HashAlgorithmNameFromGuid(hashAlgorithm);
IsEmbedded = isEmbedded;
}

public string Name { get; }
Expand All @@ -30,6 +31,9 @@ internal AssemblyDebugSourceDocument(string name, byte[] hash, Guid language, Gu
#pragma warning restore CA1819 // Properties should not return arrays
public SymbolLanguage Language { get; }
public HashAlgorithmName? HashAlgorithm { get; }
public bool IsEmbedded { get; }
public bool HasSourceLink => IsEmbedded || !string.IsNullOrWhiteSpace(Url);
public string? Url { get; internal set; }

private SymbolLanguage LanguageFromGuid(Guid guid)
{
Expand Down
2 changes: 1 addition & 1 deletion Core/AssemblyMetadata/AssemblyMetaDataInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class AssemblyMetaDataInfo
private string FullName { get; set; }
private string StrongName { get; set; }
private IEnumerable<AssemblyName> ReferencedAsseblies { get; set; } = Enumerable.Empty<AssemblyName>();
public AssemblyDebugData? DebugData { get; internal set; }

#pragma warning disable CS8618 // Non-nullable field is uninitialized.
public AssemblyDebugData DebugData { get; internal set; }
public AssemblyMetaDataInfo(AssemblyName assemblyName)
#pragma warning restore CS8618 // Non-nullable field is uninitialized.
{
Expand Down
12 changes: 9 additions & 3 deletions Core/AssemblyMetadata/AssemblyMetadataParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,21 @@ public AssemblyMetadataParser(string fileName)
_metadataReader = _peReader.GetMetadataReader();
}

public AssemblyDebugData? GetDebugData()
public AssemblyDebugData GetDebugData()
{
var entry = _peReader.ReadDebugDirectory().Where(de => de.Type == DebugDirectoryEntryType.EmbeddedPortablePdb).ToList();
if (entry.Count == 0) // no embedded ppdb
{
return null;

return new AssemblyDebugData
{
HasDebugInfo = false,
SymbolKeys = AssemblyDebugParser.GetSymbolKeys(_peReader)
};

}

using var reader = new AssemblyDebugParser(_peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry[0]), PdbType.Embedded);
using var reader = new AssemblyDebugParser(_peReader, _peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry[0]), PdbType.Embedded);
return reader.GetDebugData();
}

Expand Down
Loading