Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Source/Implementation/Implementation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<RootNamespace>Prepatcher</RootNamespace>
<AssemblyName>PrepatcherImpl</AssemblyName>
<DebugType>embedded</DebugType>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>none</DebugType>
</PropertyGroup>

<ItemGroup>

Expand Down
11 changes: 10 additions & 1 deletion Source/Implementation/Loader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 1 addition & 11 deletions Source/Implementation/Patches/AssemblyLoadingFreePatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
135 changes: 124 additions & 11 deletions Source/Implementation/Process/ModifiableAssembly.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -21,31 +24,97 @@ 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)
{
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()
Expand All @@ -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();
}

Expand All @@ -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;
}
}
}