92 lines
3.2 KiB
C#
92 lines
3.2 KiB
C#
|
// dnlib: See LICENSE.txt for more info
|
||
|
|
||
|
using System.Diagnostics;
|
||
|
using System.IO;
|
||
|
using System.IO.Compression;
|
||
|
using dnlib.DotNet.MD;
|
||
|
using dnlib.DotNet.Pdb.Symbols;
|
||
|
using dnlib.IO;
|
||
|
using dnlib.PE;
|
||
|
|
||
|
namespace dnlib.DotNet.Pdb.Portable {
|
||
|
static class SymbolReaderFactory {
|
||
|
public static SymbolReader TryCreate(PdbReaderContext pdbContext, DataReaderFactory pdbStream, bool isEmbeddedPortablePdb) {
|
||
|
bool disposePdbStream = true;
|
||
|
try {
|
||
|
if (!pdbContext.HasDebugInfo)
|
||
|
return null;
|
||
|
if (pdbStream is null)
|
||
|
return null;
|
||
|
if (pdbStream.Length < 4)
|
||
|
return null;
|
||
|
if (pdbStream.CreateReader().ReadUInt32() != 0x424A5342)
|
||
|
return null;
|
||
|
|
||
|
var debugDir = pdbContext.CodeViewDebugDirectory;
|
||
|
if (debugDir is null)
|
||
|
return null;
|
||
|
// Don't check that debugDir.MinorVersion == PortablePdbConstants.PortableCodeViewVersionMagic
|
||
|
// and debugDir.MajorVersion == PortablePdbConstants.FormatVersion since it could be a converted
|
||
|
// WindowsPDB file: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#codeview-debug-directory-entry-type-2
|
||
|
if (!pdbContext.TryGetCodeViewData(out var pdbGuid, out uint age))
|
||
|
return null;
|
||
|
|
||
|
var reader = new PortablePdbReader(pdbStream, isEmbeddedPortablePdb ? PdbFileKind.EmbeddedPortablePDB : PdbFileKind.PortablePDB);
|
||
|
if (!reader.MatchesModule(pdbGuid, debugDir.TimeDateStamp, age))
|
||
|
return null;
|
||
|
disposePdbStream = false;
|
||
|
return reader;
|
||
|
}
|
||
|
catch (IOException) {
|
||
|
}
|
||
|
finally {
|
||
|
if (disposePdbStream)
|
||
|
pdbStream?.Dispose();
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public static SymbolReader TryCreateEmbeddedPortablePdbReader(PdbReaderContext pdbContext, Metadata metadata) {
|
||
|
if (metadata is null)
|
||
|
return null;
|
||
|
try {
|
||
|
if (!pdbContext.HasDebugInfo)
|
||
|
return null;
|
||
|
var embeddedDir = pdbContext.TryGetDebugDirectoryEntry(ImageDebugType.EmbeddedPortablePdb);
|
||
|
if (embeddedDir is null)
|
||
|
return null;
|
||
|
var reader = pdbContext.CreateReader(embeddedDir.AddressOfRawData, embeddedDir.SizeOfData);
|
||
|
if (reader.Length < 8)
|
||
|
return null;
|
||
|
// "MPDB" = 0x4244504D
|
||
|
if (reader.ReadUInt32() != 0x4244504D)
|
||
|
return null;
|
||
|
uint uncompressedSize = reader.ReadUInt32();
|
||
|
// If this fails, see the (hopefully) updated spec:
|
||
|
// https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#embedded-portable-pdb-debug-directory-entry-type-17
|
||
|
bool newVersion = (uncompressedSize & 0x80000000) != 0;
|
||
|
Debug.Assert(!newVersion);
|
||
|
if (newVersion)
|
||
|
return null;
|
||
|
var decompressedBytes = new byte[uncompressedSize];
|
||
|
using (var deflateStream = new DeflateStream(reader.AsStream(), CompressionMode.Decompress)) {
|
||
|
int pos = 0;
|
||
|
while (pos < decompressedBytes.Length) {
|
||
|
int read = deflateStream.Read(decompressedBytes, pos, decompressedBytes.Length - pos);
|
||
|
if (read == 0)
|
||
|
break;
|
||
|
pos += read;
|
||
|
}
|
||
|
if (pos != decompressedBytes.Length)
|
||
|
return null;
|
||
|
var stream = ByteArrayDataReaderFactory.Create(decompressedBytes, filename: null);
|
||
|
return TryCreate(pdbContext, stream, isEmbeddedPortablePdb: true);
|
||
|
}
|
||
|
}
|
||
|
catch (IOException) {
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|