diff --git a/Source/Implementation/Implementation.csproj b/Source/Implementation/Implementation.csproj index cc172a9..5c62b62 100644 --- a/Source/Implementation/Implementation.csproj +++ b/Source/Implementation/Implementation.csproj @@ -10,11 +10,9 @@ false Prepatcher PrepatcherImpl + embedded - - none - diff --git a/Source/Implementation/Loader.cs b/Source/Implementation/Loader.cs index adff048..39a289e 100644 --- a/Source/Implementation/Loader.cs +++ b/Source/Implementation/Loader.cs @@ -103,7 +103,16 @@ private static void LoadAssembly(ModifiableAssembly asm) { Lg.Verbose($"Loading assembly: {asm}"); - var loadedAssembly = Assembly.Load(asm.Bytes); + Assembly loadedAssembly; + if (asm.SymbolsLoaded) + { + Lg.Verbose($"Loading assembly with symbols: {asm}: "); + loadedAssembly = Assembly.Load(asm.Bytes, asm.SymbolBytes); + } + else + { + loadedAssembly = Assembly.Load(asm.Bytes); + } if (loadedAssembly.GetName().Name == AssemblyCollector.AssemblyCSharp) { newAsm = loadedAssembly; diff --git a/Source/Implementation/Patches/AssemblyLoadingFreePatch.cs b/Source/Implementation/Patches/AssemblyLoadingFreePatch.cs index d0d9821..24b254f 100644 --- a/Source/Implementation/Patches/AssemblyLoadingFreePatch.cs +++ b/Source/Implementation/Patches/AssemblyLoadingFreePatch.cs @@ -30,16 +30,6 @@ public static Assembly LoadFrom(string filePath) if (asmWithName != null) return asmWithName; - var rawAssembly = File.ReadAllBytes(filePath); - var fileInfo = new FileInfo(Path.Combine(Path.GetDirectoryName(filePath)!, Path.GetFileNameWithoutExtension(filePath)) + ".pdb"); - if (fileInfo.Exists) - { - var rawSymbolStore = File.ReadAllBytes(fileInfo.FullName); - return AppDomain.CurrentDomain.Load(rawAssembly, rawSymbolStore); - } - else - { - return AppDomain.CurrentDomain.Load(rawAssembly); - } + return Assembly.LoadFrom(filePath); } } diff --git a/Source/Implementation/Process/ModifiableAssembly.cs b/Source/Implementation/Process/ModifiableAssembly.cs index abdc4b6..1bf628a 100644 --- a/Source/Implementation/Process/ModifiableAssembly.cs +++ b/Source/Implementation/Process/ModifiableAssembly.cs @@ -1,6 +1,9 @@ using System.IO; using System.Reflection; using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Pdb; +using Verse; namespace Prepatcher.Process; @@ -21,6 +24,10 @@ public class ModifiableAssembly public byte[]? Bytes { get; private set; } private byte[]? RawBytes { get; } + public byte[]? SymbolBytes { get; private set; } + + public bool SymbolsLoaded { get; private set; } + private bool needsReload; public ModifiableAssembly(string ownerName, string friendlyName, Assembly sourceAssembly, IAssemblyResolver resolver) @@ -28,24 +35,86 @@ public ModifiableAssembly(string ownerName, string friendlyName, Assembly source OwnerName = ownerName; FriendlyName = friendlyName; SourceAssembly = sourceAssembly; - RawBytes = UnsafeAssembly.GetRawData(sourceAssembly); - AsmDefinition = AssemblyDefinition.ReadAssembly( - new MemoryStream(RawBytes), - new ReaderParameters + if (sourceAssembly.Location != "") + { + try { - AssemblyResolver = resolver - }); + AsmDefinition = AssemblyDefinition.ReadAssembly(sourceAssembly.Location, new ReaderParameters + { + AssemblyResolver = resolver, + ReadSymbols = true, + InMemory = true + }); + SymbolsLoaded = true; + CheckSymbols(); + + + } + catch (Exception e) + { + AsmDefinition = AssemblyDefinition.ReadAssembly(sourceAssembly.Location, new ReaderParameters + { + AssemblyResolver = resolver, + ReadSymbols = false, + InMemory = true + }); + SymbolsLoaded = false; + } + } + else + { + try + { + AsmDefinition = AssemblyDefinition.ReadAssembly( + new MemoryStream(RawBytes), + new ReaderParameters + { + AssemblyResolver = resolver, + ReadSymbols = true, + }); + SymbolsLoaded = true; + CheckSymbols(); + } + catch (Exception e) + { + AsmDefinition = AssemblyDefinition.ReadAssembly( + new MemoryStream(RawBytes), + new ReaderParameters + { + AssemblyResolver = resolver, + }); + SymbolsLoaded = false; + } + + } } public ModifiableAssembly(string ownerName, string friendlyName, string path, IAssemblyResolver resolver) { OwnerName = ownerName; FriendlyName = friendlyName; - AsmDefinition = AssemblyDefinition.ReadAssembly( - path, - new ReaderParameters { AssemblyResolver = resolver, InMemory = true } - ); + try + { + AsmDefinition = AssemblyDefinition.ReadAssembly(path, new ReaderParameters + { + AssemblyResolver = resolver, + ReadSymbols = true, + InMemory = true + }); + SymbolsLoaded = true; + CheckSymbols(); + } + catch (Exception e) + { + AsmDefinition = AssemblyDefinition.ReadAssembly(path, new ReaderParameters + { + AssemblyResolver = resolver, + ReadSymbols = false, + InMemory = true + }); + SymbolsLoaded = false; + } } public void SerializeToByteArray() @@ -59,7 +128,23 @@ public void SerializeToByteArray() Lg.Verbose($"Serializing: {FriendlyName}"); var stream = new MemoryStream(); - AsmDefinition.Write(stream); + if (SymbolsLoaded) + { + Lg.Verbose($"Serializing assembly with symbols loaded: {FriendlyName} {AsmDefinition.MainModule} {AsmDefinition.MainModule.symbol_reader.GetType()}"); + var symbolsStream = new MemoryStream(); + AsmDefinition.Write(stream, + new WriterParameters + { + SymbolStream = symbolsStream, + SymbolWriterProvider = new PdbWriterProvider() + }); + SymbolBytes = symbolsStream.ToArray(); + + } + else + { + AsmDefinition.Write(stream); + } Bytes = stream.ToArray(); } @@ -78,4 +163,32 @@ public override string ToString() { return FriendlyName; } + + private void CheckSymbols() + { + // embedded symbols are portable symbols compressed and inserted directly into assembly + // Mono.Cecil doesnt support writing embedded symbols into memory so we extract the portable provider from them + if (AsmDefinition.MainModule.symbol_reader is EmbeddedPortablePdbReader mainEmbedded) + { + AsmDefinition.MainModule.symbol_reader = mainEmbedded.reader; + + } + + if (!AsmDefinition.Modules.NullOrEmpty()) + { + foreach (var module in AsmDefinition.Modules) + { + if (module.symbol_reader is EmbeddedPortablePdbReader embedded) + { + module.symbol_reader = embedded.reader; + } + } + } + + // Mono has no support loading native pdb, we ignore them + if (AsmDefinition.MainModule.symbol_reader is NativePdbReader) + { + SymbolsLoaded = false; + } + } }