obfuz/Plugins/dnlib/DotNet/Pdb/Portable/SymbolReaderFactory.cs

92 lines
3.2 KiB
C#
Raw Normal View History

2025-04-08 20:31:44 +08:00
// 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;
}
}
}