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

150 lines
4.9 KiB
C#

// dnlib: See LICENSE.txt for more info
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb.Symbols;
using dnlib.IO;
namespace dnlib.DotNet.Pdb {
static class SymbolReaderFactory {
public static SymbolReader CreateFromAssemblyFile(PdbReaderOptions options, Metadata metadata, string assemblyFileName) {
var pdbContext = new PdbReaderContext(metadata.PEImage, options);
if (!pdbContext.HasDebugInfo)
return null;
if (!pdbContext.TryGetCodeViewData(out var guid, out uint age, out var pdbWindowsFilename))
return null;
string pdbFilename;
int index = pdbWindowsFilename.LastIndexOfAny(windowsPathSepChars);
if (index >= 0)
pdbFilename = pdbWindowsFilename.Substring(index + 1);
else
pdbFilename = pdbWindowsFilename;
string fileToCheck;
try {
fileToCheck = assemblyFileName == string.Empty ? pdbFilename : Path.Combine(Path.GetDirectoryName(assemblyFileName), pdbFilename);
if (!File.Exists(fileToCheck)) {
var ext = Path.GetExtension(pdbFilename);
if (string.IsNullOrEmpty(ext))
ext = "pdb";
fileToCheck = Path.ChangeExtension(assemblyFileName, ext);
}
}
catch (ArgumentException) {
return null;// Invalid filename
}
return Create(options, metadata, fileToCheck);
}
static readonly char[] windowsPathSepChars = new char[] { '\\', '/' };
public static SymbolReader Create(PdbReaderOptions options, Metadata metadata, string pdbFileName) {
var pdbContext = new PdbReaderContext(metadata.PEImage, options);
if (!pdbContext.HasDebugInfo)
return null;
return CreateCore(pdbContext, metadata, DataReaderFactoryUtils.TryCreateDataReaderFactory(pdbFileName));
}
public static SymbolReader Create(PdbReaderOptions options, Metadata metadata, byte[] pdbData) {
var pdbContext = new PdbReaderContext(metadata.PEImage, options);
if (!pdbContext.HasDebugInfo)
return null;
return CreateCore(pdbContext, metadata, ByteArrayDataReaderFactory.Create(pdbData, filename: null));
}
public static SymbolReader Create(PdbReaderOptions options, Metadata metadata, DataReaderFactory pdbStream) {
var pdbContext = new PdbReaderContext(metadata.PEImage, options);
return CreateCore(pdbContext, metadata, pdbStream);
}
static SymbolReader CreateCore(PdbReaderContext pdbContext, Metadata metadata, DataReaderFactory pdbStream) {
SymbolReader symReader = null;
bool error = true;
try {
if (!pdbContext.HasDebugInfo)
return null;
#if NETSTANDARD || NETCOREAPP
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#else
var isWindows = true;
#endif
if ((pdbContext.Options & PdbReaderOptions.MicrosoftComReader) != 0 && isWindows && pdbStream is not null && IsWindowsPdb(pdbStream.CreateReader()))
symReader = Dss.SymbolReaderWriterFactory.Create(pdbContext, metadata, pdbStream);
else
symReader = CreateManaged(pdbContext, metadata, pdbStream);
if (symReader is not null) {
error = false;
return symReader;
}
}
catch (IOException) {
}
finally {
if (error) {
pdbStream?.Dispose();
symReader?.Dispose();
}
}
return null;
}
static bool IsWindowsPdb(DataReader reader) {
const string SIG = "Microsoft C/C++ MSF 7.00\r\n\u001ADS\0";
if (!reader.CanRead(SIG.Length))
return false;
return reader.ReadString(SIG.Length, Encoding.ASCII) == SIG;
}
public static SymbolReader TryCreateEmbeddedPdbReader(PdbReaderOptions options, Metadata metadata) {
var pdbContext = new PdbReaderContext(metadata.PEImage, options);
if (!pdbContext.HasDebugInfo)
return null;
return TryCreateEmbeddedPortablePdbReader(pdbContext, metadata);
}
static SymbolReader CreateManaged(PdbReaderContext pdbContext, Metadata metadata, DataReaderFactory pdbStream) {
try {
// Embedded PDBs have priority
var embeddedReader = TryCreateEmbeddedPortablePdbReader(pdbContext, metadata);
if (embeddedReader is not null) {
pdbStream?.Dispose();
return embeddedReader;
}
return CreateManagedCore(pdbContext, pdbStream);
}
catch {
pdbStream?.Dispose();
throw;
}
}
static SymbolReader CreateManagedCore(PdbReaderContext pdbContext, DataReaderFactory pdbStream) {
if (pdbStream is null)
return null;
try {
var reader = pdbStream.CreateReader();
if (reader.Length >= 4) {
uint sig = reader.ReadUInt32();
if (sig == 0x424A5342)
return Portable.SymbolReaderFactory.TryCreate(pdbContext, pdbStream, isEmbeddedPortablePdb: false);
return Managed.SymbolReaderFactory.Create(pdbContext, pdbStream);
}
}
catch (IOException) {
}
pdbStream?.Dispose();
return null;
}
static SymbolReader TryCreateEmbeddedPortablePdbReader(PdbReaderContext pdbContext, Metadata metadata) =>
Portable.SymbolReaderFactory.TryCreateEmbeddedPortablePdbReader(pdbContext, metadata);
}
}