minor refactoring in new symbol code
This commit is contained in:
parent
e3b38a70f8
commit
0b29eb3bc3
|
@ -35,8 +35,11 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
/// <summary>A minimal assembly definition resolver which resolves references to known loaded assemblies.</summary>
|
||||
private readonly AssemblyDefinitionResolver AssemblyDefinitionResolver;
|
||||
|
||||
private readonly SymbolReaderProvider SymbolReaderProvider;
|
||||
private readonly SymbolWriterProvider SymbolWriterProvider;
|
||||
/// <summary>Provides assembly symbol readers for Mono.Cecil.</summary>
|
||||
private readonly SymbolReaderProvider SymbolReaderProvider = new SymbolReaderProvider();
|
||||
|
||||
/// <summary>Provides assembly symbol writers for Mono.Cecil.</summary>
|
||||
private readonly SymbolWriterProvider SymbolWriterProvider = new SymbolWriterProvider();
|
||||
|
||||
/// <summary>The objects to dispose as part of this instance.</summary>
|
||||
private readonly HashSet<IDisposable> Disposables = new HashSet<IDisposable>();
|
||||
|
@ -65,9 +68,6 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
this.AssemblyDefinitionResolver = this.TrackForDisposal(new AssemblyDefinitionResolver());
|
||||
Constants.ConfigureAssemblyResolver(this.AssemblyDefinitionResolver);
|
||||
|
||||
this.SymbolReaderProvider = new SymbolReaderProvider();
|
||||
this.SymbolWriterProvider = new SymbolWriterProvider();
|
||||
|
||||
// generate type => assembly lookup for types which should be rewritten
|
||||
this.TypeAssemblies = new Dictionary<string, Assembly>();
|
||||
foreach (Assembly assembly in this.AssemblyMap.Targets)
|
||||
|
@ -121,7 +121,7 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
|
||||
// rewrite assembly
|
||||
bool changed = this.RewriteAssembly(mod, assembly.Definition, loggedMessages, logPrefix: " ");
|
||||
|
||||
|
||||
// detect broken assembly reference
|
||||
foreach (AssemblyNameReference reference in assembly.Definition.MainModule.AssemblyReferences)
|
||||
{
|
||||
|
@ -142,10 +142,10 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
this.Monitor.Log($" Loading {assembly.File.Name} (rewritten)...", LogLevel.Trace);
|
||||
|
||||
// load assembly
|
||||
using MemoryStream outStream = new MemoryStream();
|
||||
using MemoryStream outAssemblyStream = new MemoryStream();
|
||||
using MemoryStream outSymbolStream = new MemoryStream();
|
||||
assembly.Definition.Write(outStream, new WriterParameters() { WriteSymbols = true, SymbolStream = outSymbolStream, SymbolWriterProvider = this.SymbolWriterProvider } );
|
||||
byte[] bytes = outStream.ToArray();
|
||||
assembly.Definition.Write(outAssemblyStream, new WriterParameters { WriteSymbols = true, SymbolStream = outSymbolStream, SymbolWriterProvider = this.SymbolWriterProvider });
|
||||
byte[] bytes = outAssemblyStream.ToArray();
|
||||
lastAssembly = Assembly.Load(bytes, outSymbolStream.ToArray());
|
||||
}
|
||||
else
|
||||
|
@ -233,13 +233,13 @@ namespace StardewModdingAPI.Framework.ModLoading
|
|||
if (!file.Exists)
|
||||
yield break; // not a local assembly
|
||||
|
||||
// read assembly and PDB (if present)
|
||||
// read assembly and symbols
|
||||
byte[] assemblyBytes = File.ReadAllBytes(file.FullName);
|
||||
Stream readStream = this.TrackForDisposal(new MemoryStream(assemblyBytes));
|
||||
{
|
||||
string symbolsPath = Path.Combine(Path.GetDirectoryName(file.FullName), Path.GetFileNameWithoutExtension(file.FullName)) + ".pdb";
|
||||
if ( File.Exists( symbolsPath ) )
|
||||
this.SymbolReaderProvider.AddSymbolMapping( Path.GetFileName( file.FullName ), this.TrackForDisposal( new MemoryStream( File.ReadAllBytes( symbolsPath ) ) ) );
|
||||
FileInfo symbolsFile = new FileInfo(Path.Combine(Path.GetDirectoryName(file.FullName)!, Path.GetFileNameWithoutExtension(file.FullName)) + ".pdb");
|
||||
if (symbolsFile.Exists)
|
||||
this.SymbolReaderProvider.TryAddSymbolData(file.Name, this.TrackForDisposal(symbolsFile.OpenRead()));
|
||||
}
|
||||
AssemblyDefinition assembly = this.TrackForDisposal(AssemblyDefinition.ReadAssembly(readStream, new ReaderParameters(ReadingMode.Immediate) { AssemblyResolver = assemblyResolver, InMemory = true, ReadSymbols = true, SymbolReaderProvider = this.SymbolReaderProvider }));
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
|
@ -6,46 +5,68 @@ using Mono.Cecil.Pdb;
|
|||
|
||||
namespace StardewModdingAPI.Framework.ModLoading.Symbols
|
||||
{
|
||||
/// <summary>Reads symbol data for an assembly.</summary>
|
||||
internal class SymbolReader : ISymbolReader
|
||||
{
|
||||
private ModuleDefinition Module;
|
||||
private Stream Stream;
|
||||
private ISymbolReader Using;
|
||||
/*********
|
||||
** Fields
|
||||
*********/
|
||||
/// <summary>The module for which to read symbols.</summary>
|
||||
private readonly ModuleDefinition Module;
|
||||
|
||||
public SymbolReader( ModuleDefinition module, Stream stream )
|
||||
/// <summary>The symbol file stream.</summary>
|
||||
private readonly Stream Stream;
|
||||
|
||||
/// <summary>The underlying symbol reader.</summary>
|
||||
private ISymbolReader Reader;
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Construct an instance.</summary>
|
||||
/// <param name="module">The module for which to read symbols.</param>
|
||||
/// <param name="stream">The symbol file stream.</param>
|
||||
public SymbolReader(ModuleDefinition module, Stream stream)
|
||||
{
|
||||
this.Module = module;
|
||||
this.Stream = stream;
|
||||
this.Using = new NativePdbReaderProvider().GetSymbolReader( module, stream );
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Using.Dispose();
|
||||
this.Reader = new NativePdbReaderProvider().GetSymbolReader(module, stream);
|
||||
}
|
||||
|
||||
/// <summary>Get the symbol writer provider for the assembly.</summary>
|
||||
public ISymbolWriterProvider GetWriterProvider()
|
||||
{
|
||||
return new PortablePdbWriterProvider();
|
||||
}
|
||||
|
||||
public bool ProcessDebugHeader( ImageDebugHeader header )
|
||||
/// <summary>Process a debug header in the symbol file.</summary>
|
||||
/// <param name="header">The debug header.</param>
|
||||
public bool ProcessDebugHeader(ImageDebugHeader header)
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.Using.ProcessDebugHeader( header );
|
||||
return this.Reader.ProcessDebugHeader(header);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch
|
||||
{
|
||||
this.Using.Dispose();
|
||||
this.Using = new PortablePdbReaderProvider().GetSymbolReader( this.Module, this.Stream );
|
||||
return this.Using.ProcessDebugHeader( header );
|
||||
this.Reader.Dispose();
|
||||
this.Reader = new PortablePdbReaderProvider().GetSymbolReader(this.Module, this.Stream);
|
||||
return this.Reader.ProcessDebugHeader(header);
|
||||
}
|
||||
}
|
||||
|
||||
public MethodDebugInformation Read( MethodDefinition method )
|
||||
/// <summary>Read the method debug information for a method in the assembly.</summary>
|
||||
/// <param name="method">The method definition.</param>
|
||||
public MethodDebugInformation Read(MethodDefinition method)
|
||||
{
|
||||
return this.Using.Read( method );
|
||||
return this.Reader.Read(method);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
this.Reader.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Mono.Cecil;
|
||||
|
@ -5,31 +6,48 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.Framework.ModLoading.Symbols
|
||||
{
|
||||
/// <summary>Provides assembly symbol readers for Mono.Cecil.</summary>
|
||||
internal class SymbolReaderProvider : ISymbolReaderProvider
|
||||
{
|
||||
/*********
|
||||
** Fields
|
||||
*********/
|
||||
/// <summary>The underlying symbol reader provider.</summary>
|
||||
private readonly ISymbolReaderProvider BaseProvider = new DefaultSymbolReaderProvider();
|
||||
|
||||
private readonly Dictionary<string, Stream> SymbolMapping = new Dictionary<string, Stream>();
|
||||
/// <summary>The symbol data loaded by absolute assembly path.</summary>
|
||||
private readonly Dictionary<string, Stream> SymbolsByAssemblyPath = new Dictionary<string, Stream>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void AddSymbolMapping( string dllName, Stream symbolStream )
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Add the symbol file for a given assembly name, if it's not already registered.</summary>
|
||||
/// <param name="fileName">The assembly file name.</param>
|
||||
/// <param name="symbolStream">The raw file stream for the symbols.</param>
|
||||
public void AddSymbolData(string fileName, Stream symbolStream)
|
||||
{
|
||||
this.SymbolMapping.Add( dllName, symbolStream );
|
||||
this.SymbolsByAssemblyPath.Add(fileName, symbolStream);
|
||||
}
|
||||
|
||||
public ISymbolReader GetSymbolReader( ModuleDefinition module, string fileName )
|
||||
/// <summary>Get a symbol reader for a given module and assembly name.</summary>
|
||||
/// <param name="module">The loaded assembly module.</param>
|
||||
/// <param name="fileName">The assembly file name.</param>
|
||||
public ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName)
|
||||
{
|
||||
if ( this.SymbolMapping.ContainsKey( module.Name ) )
|
||||
return new SymbolReader( module, this.SymbolMapping[ module.Name ] );
|
||||
|
||||
return this.BaseProvider.GetSymbolReader( module, fileName );
|
||||
return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream symbolData)
|
||||
? new SymbolReader(module, symbolData)
|
||||
: this.BaseProvider.GetSymbolReader(module, fileName);
|
||||
}
|
||||
|
||||
public ISymbolReader GetSymbolReader( ModuleDefinition module, Stream symbolStream )
|
||||
/// <summary>Get a symbol reader for a given module and symbol stream.</summary>
|
||||
/// <param name="module">The loaded assembly module.</param>
|
||||
/// <param name="symbolStream">The loaded symbol file stream.</param>
|
||||
public ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream)
|
||||
{
|
||||
if ( this.SymbolMapping.ContainsKey( module.Name ) )
|
||||
return new SymbolReader( module, this.SymbolMapping[ module.Name ] );
|
||||
|
||||
return this.BaseProvider.GetSymbolReader( module, symbolStream );
|
||||
return this.SymbolsByAssemblyPath.TryGetValue(module.Name, out Stream symbolData)
|
||||
? new SymbolReader(module, symbolData)
|
||||
: this.BaseProvider.GetSymbolReader(module, symbolStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,37 @@ using Mono.Cecil.Cil;
|
|||
|
||||
namespace StardewModdingAPI.Framework.ModLoading.Symbols
|
||||
{
|
||||
/// <summary>Provides assembly symbol writers for Mono.Cecil.</summary>
|
||||
internal class SymbolWriterProvider : ISymbolWriterProvider
|
||||
{
|
||||
private readonly ISymbolWriterProvider BaseProvider = new DefaultSymbolWriterProvider();
|
||||
/*********
|
||||
** Fields
|
||||
*********/
|
||||
/// <summary>The default symbol writer provider.</summary>
|
||||
private readonly ISymbolWriterProvider DefaultProvider = new DefaultSymbolWriterProvider();
|
||||
|
||||
public ISymbolWriter GetSymbolWriter( ModuleDefinition module, string fileName )
|
||||
/// <summary>The symbol writer provider for the portable PDB format.</summary>
|
||||
private readonly ISymbolWriterProvider PortablePdbProvider = new PortablePdbWriterProvider();
|
||||
|
||||
|
||||
/*********
|
||||
** Public methods
|
||||
*********/
|
||||
/// <summary>Get a symbol writer for a given module and assembly path.</summary>
|
||||
/// <param name="module">The loaded assembly module.</param>
|
||||
/// <param name="fileName">The assembly name.</param>
|
||||
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName)
|
||||
{
|
||||
return this.BaseProvider.GetSymbolWriter( module, fileName );
|
||||
return this.DefaultProvider.GetSymbolWriter(module, fileName);
|
||||
}
|
||||
|
||||
public ISymbolWriter GetSymbolWriter( ModuleDefinition module, Stream symbolStream )
|
||||
/// <summary>Get a symbol writer for a given module and symbol stream.</summary>
|
||||
/// <param name="module">The loaded assembly module.</param>
|
||||
/// <param name="symbolStream">The loaded symbol file stream.</param>
|
||||
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream)
|
||||
{
|
||||
// Not implemented in default native pdb writer, so fallback to portable
|
||||
return new PortablePdbWriterProvider().GetSymbolWriter( module, symbolStream );
|
||||
return this.PortablePdbProvider.GetSymbolWriter(module, symbolStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue