diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
index 72cfd119..5180f072 100644
--- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
+++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs
@@ -35,8 +35,11 @@ namespace StardewModdingAPI.Framework.ModLoading
/// A minimal assembly definition resolver which resolves references to known loaded assemblies.
private readonly AssemblyDefinitionResolver AssemblyDefinitionResolver;
- private readonly SymbolReaderProvider SymbolReaderProvider;
- private readonly SymbolWriterProvider SymbolWriterProvider;
+ /// Provides assembly symbol readers for Mono.Cecil.
+ private readonly SymbolReaderProvider SymbolReaderProvider = new SymbolReaderProvider();
+
+ /// Provides assembly symbol writers for Mono.Cecil.
+ private readonly SymbolWriterProvider SymbolWriterProvider = new SymbolWriterProvider();
/// The objects to dispose as part of this instance.
private readonly HashSet Disposables = new HashSet();
@@ -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();
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 }));
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
index f1ae86a2..2171895d 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReader.cs
@@ -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
{
+ /// Reads symbol data for an assembly.
internal class SymbolReader : ISymbolReader
{
- private ModuleDefinition Module;
- private Stream Stream;
- private ISymbolReader Using;
+ /*********
+ ** Fields
+ *********/
+ /// The module for which to read symbols.
+ private readonly ModuleDefinition Module;
- public SymbolReader( ModuleDefinition module, Stream stream )
+ /// The symbol file stream.
+ private readonly Stream Stream;
+
+ /// The underlying symbol reader.
+ private ISymbolReader Reader;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ /// The module for which to read symbols.
+ /// The symbol file stream.
+ 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);
}
+ /// Get the symbol writer provider for the assembly.
public ISymbolWriterProvider GetWriterProvider()
{
return new PortablePdbWriterProvider();
}
- public bool ProcessDebugHeader( ImageDebugHeader header )
+ /// Process a debug header in the symbol file.
+ /// The debug header.
+ 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 )
+ /// Read the method debug information for a method in the assembly.
+ /// The method definition.
+ public MethodDebugInformation Read(MethodDefinition method)
{
- return this.Using.Read( method );
+ return this.Reader.Read(method);
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.Reader.Dispose();
}
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
index e2a6d21e..02a70f1c 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolReaderProvider.cs
@@ -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
{
+ /// Provides assembly symbol readers for Mono.Cecil.
internal class SymbolReaderProvider : ISymbolReaderProvider
{
+ /*********
+ ** Fields
+ *********/
+ /// The underlying symbol reader provider.
private readonly ISymbolReaderProvider BaseProvider = new DefaultSymbolReaderProvider();
- private readonly Dictionary SymbolMapping = new Dictionary();
+ /// The symbol data loaded by absolute assembly path.
+ private readonly Dictionary SymbolsByAssemblyPath = new Dictionary(StringComparer.OrdinalIgnoreCase);
- public void AddSymbolMapping( string dllName, Stream symbolStream )
+
+ /*********
+ ** Public methods
+ *********/
+ /// Add the symbol file for a given assembly name, if it's not already registered.
+ /// The assembly file name.
+ /// The raw file stream for the symbols.
+ public void AddSymbolData(string fileName, Stream symbolStream)
{
- this.SymbolMapping.Add( dllName, symbolStream );
+ this.SymbolsByAssemblyPath.Add(fileName, symbolStream);
}
- public ISymbolReader GetSymbolReader( ModuleDefinition module, string fileName )
+ /// Get a symbol reader for a given module and assembly name.
+ /// The loaded assembly module.
+ /// The assembly file name.
+ 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 )
+ /// Get a symbol reader for a given module and symbol stream.
+ /// The loaded assembly module.
+ /// The loaded symbol file stream.
+ 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);
}
}
}
diff --git a/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs b/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
index 33e91db0..8f7e05d1 100644
--- a/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
+++ b/src/SMAPI/Framework/ModLoading/Symbols/SymbolWriterProvider.cs
@@ -4,19 +4,37 @@ using Mono.Cecil.Cil;
namespace StardewModdingAPI.Framework.ModLoading.Symbols
{
+ /// Provides assembly symbol writers for Mono.Cecil.
internal class SymbolWriterProvider : ISymbolWriterProvider
{
- private readonly ISymbolWriterProvider BaseProvider = new DefaultSymbolWriterProvider();
+ /*********
+ ** Fields
+ *********/
+ /// The default symbol writer provider.
+ private readonly ISymbolWriterProvider DefaultProvider = new DefaultSymbolWriterProvider();
- public ISymbolWriter GetSymbolWriter( ModuleDefinition module, string fileName )
+ /// The symbol writer provider for the portable PDB format.
+ private readonly ISymbolWriterProvider PortablePdbProvider = new PortablePdbWriterProvider();
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Get a symbol writer for a given module and assembly path.
+ /// The loaded assembly module.
+ /// The assembly name.
+ 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 )
+ /// Get a symbol writer for a given module and symbol stream.
+ /// The loaded assembly module.
+ /// The loaded symbol file stream.
+ 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);
}
}
}