Fixed patch manager to emit try-catch-finally blocks.
Solves issue with PBs not running
This commit is contained in:
@@ -53,9 +53,9 @@ namespace Torch.Managers.PatchManager
|
|||||||
_log.Debug(
|
_log.Debug(
|
||||||
$"Done patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
$"Done patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
_log.Fatal($"Error patching {_method.DeclaringType?.FullName}#{_method}");
|
_log.Fatal(exception, $"Error patching {_method.DeclaringType?.FullName}#{_method}");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -104,6 +104,11 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HashSet<MsilLabel> Labels { get; } = new HashSet<MsilLabel>();
|
public HashSet<MsilLabel> Labels { get; } = new HashSet<MsilLabel>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The try catch operation that is performed here.
|
||||||
|
/// </summary>
|
||||||
|
public MsilTryCatchOperation TryCatchOperation { get; set; } = null;
|
||||||
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Type, PropertyInfo> _setterInfoForInlines = new ConcurrentDictionary<Type, PropertyInfo>();
|
private static readonly ConcurrentDictionary<Type, PropertyInfo> _setterInfoForInlines = new ConcurrentDictionary<Type, PropertyInfo>();
|
||||||
|
|
||||||
@@ -147,6 +152,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
Operand?.CopyTo(result.Operand);
|
Operand?.CopyTo(result.Operand);
|
||||||
foreach (MsilLabel x in Labels)
|
foreach (MsilLabel x in Labels)
|
||||||
result.Labels.Add(x);
|
result.Labels.Add(x);
|
||||||
|
result.TryCatchOperation = TryCatchOperation;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,20 +178,6 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Emits this instruction to the given generator
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target">Emit target</param>
|
|
||||||
public void Emit(LoggingIlGenerator target)
|
|
||||||
{
|
|
||||||
foreach (MsilLabel label in Labels)
|
|
||||||
target.MarkLabel(label.LabelFor(target));
|
|
||||||
if (Operand != null)
|
|
||||||
Operand.Emit(target);
|
|
||||||
else
|
|
||||||
target.Emit(OpCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
54
Torch/Managers/PatchManager/MSIL/MsilTryCatchOperation.cs
Normal file
54
Torch/Managers/PatchManager/MSIL/MsilTryCatchOperation.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.Managers.PatchManager.MSIL
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a try/catch block operation type
|
||||||
|
/// </summary>
|
||||||
|
public enum MsilTryCatchOperationType
|
||||||
|
{
|
||||||
|
// TryCatchBlockIL:
|
||||||
|
// var exBlock = ILGenerator.BeginExceptionBlock();
|
||||||
|
// try{
|
||||||
|
// ILGenerator.BeginCatchBlock(typeof(Exception));
|
||||||
|
// } catch(Exception e) {
|
||||||
|
// ILGenerator.BeginCatchBlock(null);
|
||||||
|
// } catch {
|
||||||
|
// ILGenerator.BeginFinallyBlock();
|
||||||
|
// }finally {
|
||||||
|
// ILGenerator.EndExceptionBlock();
|
||||||
|
// }
|
||||||
|
BeginExceptionBlock,
|
||||||
|
BeginCatchBlock,
|
||||||
|
BeginFinallyBlock,
|
||||||
|
EndExceptionBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a try catch operation.
|
||||||
|
/// </summary>
|
||||||
|
public class MsilTryCatchOperation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Operation type
|
||||||
|
/// </summary>
|
||||||
|
public readonly MsilTryCatchOperationType Type;
|
||||||
|
/// <summary>
|
||||||
|
/// Type caught by this operation, or null if none.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Type CatchType;
|
||||||
|
|
||||||
|
public MsilTryCatchOperation(MsilTryCatchOperationType op, Type caughtType = null)
|
||||||
|
{
|
||||||
|
Type = op;
|
||||||
|
if (caughtType != null && op != MsilTryCatchOperationType.BeginCatchBlock)
|
||||||
|
throw new ArgumentException($"Can't use caught type with operation type {op}", nameof(caughtType));
|
||||||
|
CatchType = caughtType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -34,7 +34,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
/// <param name="generator">Output</param>
|
/// <param name="generator">Output</param>
|
||||||
public static void EmitInstructions(IEnumerable<MsilInstruction> insn, LoggingIlGenerator generator)
|
public static void EmitInstructions(IEnumerable<MsilInstruction> insn, LoggingIlGenerator generator)
|
||||||
{
|
{
|
||||||
MethodTranspiler.Emit(insn, generator);
|
MethodTranspiler.EmitMethod(insn.ToList(), generator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -114,7 +114,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
|
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[ReflectedGetter(Name="m_label")]
|
[ReflectedGetter(Name = "m_label")]
|
||||||
private static Func<Label, int> _labelID;
|
private static Func<Label, int> _labelID;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
@@ -146,6 +146,51 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
Backing.Emit(op, arg);
|
Backing.Emit(op, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Exceptions
|
||||||
|
/// <inheritdoc cref="ILGenerator.BeginExceptionBlock"/>
|
||||||
|
public Label BeginExceptionBlock()
|
||||||
|
{
|
||||||
|
_log?.Trace($"BeginExceptionBlock");
|
||||||
|
return Backing.BeginExceptionBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.BeginCatchBlock"/>
|
||||||
|
public void BeginCatchBlock(Type caught)
|
||||||
|
{
|
||||||
|
_log?.Trace($"BeginCatchBlock {caught}");
|
||||||
|
Backing.BeginCatchBlock(caught);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.BeginExceptFilterBlock"/>
|
||||||
|
public void BeginExceptFilterBlock()
|
||||||
|
{
|
||||||
|
_log?.Trace($"BeginExceptFilterBlock");
|
||||||
|
Backing.BeginExceptFilterBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.BeginFaultBlock"/>
|
||||||
|
public void BeginFaultBlock()
|
||||||
|
{
|
||||||
|
_log?.Trace($"BeginFaultBlock");
|
||||||
|
Backing.BeginFaultBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.BeginFinallyBlock"/>
|
||||||
|
public void BeginFinallyBlock()
|
||||||
|
{
|
||||||
|
_log?.Trace($"BeginFinallyBlock");
|
||||||
|
Backing.BeginFinallyBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ILGenerator.EndExceptionBlock"/>
|
||||||
|
public void EndExceptionBlock()
|
||||||
|
{
|
||||||
|
_log?.Trace($"EndExceptionBlock");
|
||||||
|
Backing.EndExceptionBlock();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
/// <inheritdoc cref="ILGenerator.MarkLabel(Label)"/>
|
||||||
public void MarkLabel(Label label)
|
public void MarkLabel(Label label)
|
||||||
{
|
{
|
||||||
|
@@ -16,6 +16,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public readonly MethodBase Method;
|
public readonly MethodBase Method;
|
||||||
|
public readonly MethodBody MethodBody;
|
||||||
private readonly byte[] _msilBytes;
|
private readonly byte[] _msilBytes;
|
||||||
|
|
||||||
internal Dictionary<int, MsilLabel> Labels { get; } = new Dictionary<int, MsilLabel>();
|
internal Dictionary<int, MsilLabel> Labels { get; } = new Dictionary<int, MsilLabel>();
|
||||||
@@ -35,7 +36,9 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
public MethodContext(MethodBase method)
|
public MethodContext(MethodBase method)
|
||||||
{
|
{
|
||||||
Method = method;
|
Method = method;
|
||||||
_msilBytes = Method.GetMethodBody().GetILAsByteArray();
|
MethodBody = method.GetMethodBody();
|
||||||
|
Debug.Assert(MethodBody != null, "Method body is null");
|
||||||
|
_msilBytes = MethodBody.GetILAsByteArray();
|
||||||
TokenResolver = new NormalTokenResolver(method);
|
TokenResolver = new NormalTokenResolver(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +46,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
{
|
{
|
||||||
ReadInstructions();
|
ReadInstructions();
|
||||||
ResolveLabels();
|
ResolveLabels();
|
||||||
|
ResolveCatchClauses();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadInstructions()
|
private void ReadInstructions()
|
||||||
@@ -53,7 +57,7 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
using (var reader = new BinaryReader(memory))
|
using (var reader = new BinaryReader(memory))
|
||||||
while (memory.Length > memory.Position)
|
while (memory.Length > memory.Position)
|
||||||
{
|
{
|
||||||
var opcodeOffset = (int) memory.Position;
|
var opcodeOffset = (int)memory.Position;
|
||||||
var instructionValue = (short)memory.ReadByte();
|
var instructionValue = (short)memory.ReadByte();
|
||||||
if (Prefixes.Contains(instructionValue))
|
if (Prefixes.Contains(instructionValue))
|
||||||
{
|
{
|
||||||
@@ -72,35 +76,47 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResolveCatchClauses()
|
||||||
|
{
|
||||||
|
foreach (ExceptionHandlingClause clause in MethodBody.ExceptionHandlingClauses)
|
||||||
|
{
|
||||||
|
var beginInstruction = FindInstruction(clause.TryOffset);
|
||||||
|
var catchInstruction = FindInstruction(clause.HandlerOffset);
|
||||||
|
var finalInstruction = FindInstruction(clause.HandlerOffset + clause.HandlerLength);
|
||||||
|
beginInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginExceptionBlock);
|
||||||
|
if ((clause.Flags & ExceptionHandlingClauseOptions.Clause) != 0)
|
||||||
|
catchInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginCatchBlock, clause.CatchType);
|
||||||
|
else if ((clause.Flags & ExceptionHandlingClauseOptions.Finally) != 0)
|
||||||
|
catchInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.BeginFinallyBlock);
|
||||||
|
finalInstruction.TryCatchOperation = new MsilTryCatchOperation(MsilTryCatchOperationType.EndExceptionBlock);
|
||||||
|
_log.Info($"Init try catch ({clause.Flags} {clause.Flags}):\n{beginInstruction}\n{catchInstruction}\n{finalInstruction}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MsilInstruction FindInstruction(int offset)
|
||||||
|
{
|
||||||
|
int min = 0, max = _instructions.Count;
|
||||||
|
while (min != max)
|
||||||
|
{
|
||||||
|
int mid = (min + max) / 2;
|
||||||
|
if (_instructions[mid].Offset < offset)
|
||||||
|
min = mid + 1;
|
||||||
|
else
|
||||||
|
max = mid;
|
||||||
|
}
|
||||||
|
return min >= 0 && min < _instructions.Count ? _instructions[min] : null;
|
||||||
|
}
|
||||||
|
|
||||||
private void ResolveLabels()
|
private void ResolveLabels()
|
||||||
{
|
{
|
||||||
foreach (var label in Labels)
|
foreach (var label in Labels)
|
||||||
{
|
{
|
||||||
int min = 0, max = _instructions.Count;
|
MsilInstruction target = FindInstruction(label.Key);
|
||||||
while (min != max)
|
target.Labels?.Add(label.Value);
|
||||||
{
|
|
||||||
int mid = (min + max) / 2;
|
|
||||||
if (_instructions[mid].Offset < label.Key)
|
|
||||||
min = mid + 1;
|
|
||||||
else
|
|
||||||
max = mid;
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
if (min >= _instructions.Count || min < 0)
|
|
||||||
{
|
|
||||||
_log.Trace(
|
|
||||||
$"Want offset {label.Key} for {label.Value}, instruction offsets at\n {string.Join("\n", _instructions.Select(x => $"IL_{x.Offset:X4} {x}"))}");
|
|
||||||
}
|
|
||||||
MsilInstruction prevInsn = min > 0 ? _instructions[min - 1] : null;
|
|
||||||
if ((prevInsn == null || prevInsn.Offset >= label.Key) ||
|
|
||||||
_instructions[min].Offset < label.Key)
|
|
||||||
_log.Error($"Label {label.Value} wanted {label.Key} but instruction is at {_instructions[min].Offset}. Previous instruction is at {prevInsn?.Offset ?? -1}");
|
|
||||||
#endif
|
|
||||||
_instructions[min]?.Labels?.Add(label.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public string ToHumanMsil()
|
public string ToHumanMsil()
|
||||||
{
|
{
|
||||||
return string.Join("\n", _instructions.Select(x => $"IL_{x.Offset:X4}: {x.StackChange():+0;-#} {x}"));
|
return string.Join("\n", _instructions.Select(x => $"IL_{x.Offset:X4}: {x.StackChange():+0;-#} {x}"));
|
||||||
|
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Windows.Documents;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
|
|
||||||
@@ -42,17 +43,60 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
|
methodContent = (IEnumerable<MsilInstruction>)transpiler.Invoke(null, paramList.ToArray());
|
||||||
}
|
}
|
||||||
methodContent = FixBranchAndReturn(methodContent, retLabel);
|
methodContent = FixBranchAndReturn(methodContent, retLabel);
|
||||||
|
var list = methodContent.ToList();
|
||||||
if (logMsil)
|
if (logMsil)
|
||||||
{
|
{
|
||||||
var list = methodContent.ToList();
|
|
||||||
IntegrityAnalysis(LogLevel.Info, list);
|
IntegrityAnalysis(LogLevel.Info, list);
|
||||||
foreach (var k in list)
|
|
||||||
k.Emit(output);
|
|
||||||
}
|
}
|
||||||
else
|
EmitMethod(list, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void EmitMethod(IReadOnlyList<MsilInstruction> instructions, LoggingIlGenerator target)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < instructions.Count; i++)
|
||||||
{
|
{
|
||||||
foreach (var k in methodContent)
|
MsilInstruction il = instructions[i];
|
||||||
k.Emit(output);
|
if (il.TryCatchOperation != null)
|
||||||
|
switch (il.TryCatchOperation.Type)
|
||||||
|
{
|
||||||
|
case MsilTryCatchOperationType.BeginExceptionBlock:
|
||||||
|
target.BeginExceptionBlock();
|
||||||
|
break;
|
||||||
|
case MsilTryCatchOperationType.BeginCatchBlock:
|
||||||
|
target.BeginCatchBlock(il.TryCatchOperation.CatchType);
|
||||||
|
break;
|
||||||
|
case MsilTryCatchOperationType.BeginFinallyBlock:
|
||||||
|
target.BeginFinallyBlock();
|
||||||
|
break;
|
||||||
|
case MsilTryCatchOperationType.EndExceptionBlock:
|
||||||
|
target.EndExceptionBlock();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (MsilLabel label in il.Labels)
|
||||||
|
target.MarkLabel(label.LabelFor(target));
|
||||||
|
|
||||||
|
MsilInstruction ilNext = i < instructions.Count - 1 ? instructions[i + 1] : null;
|
||||||
|
|
||||||
|
// Leave opcodes emitted by these:
|
||||||
|
if (il.OpCode == OpCodes.Endfilter && ilNext?.TryCatchOperation?.Type ==
|
||||||
|
MsilTryCatchOperationType.BeginCatchBlock)
|
||||||
|
continue;
|
||||||
|
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) &&
|
||||||
|
(ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock ||
|
||||||
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginCatchBlock ||
|
||||||
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.BeginFinallyBlock))
|
||||||
|
continue;
|
||||||
|
if ((il.OpCode == OpCodes.Leave || il.OpCode == OpCodes.Leave_S) &&
|
||||||
|
ilNext?.TryCatchOperation?.Type == MsilTryCatchOperationType.EndExceptionBlock)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (il.Operand != null)
|
||||||
|
il.Operand.Emit(target);
|
||||||
|
else
|
||||||
|
target.Emit(il.OpCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +153,8 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack += k.StackChange();
|
stack += k.StackChange();
|
||||||
|
if (k.TryCatchOperation != null)
|
||||||
|
line.AppendLine($"// .{k.TryCatchOperation.Type} ({k.TryCatchOperation.CatchType})");
|
||||||
line.AppendLine($"{i:X4} S:{stack:D2} dS:{k.StackChange():+0;-#}\t{k}" + (unreachable ? "\t// UNREACHABLE" : ""));
|
line.AppendLine($"{i:X4} S:{stack:D2} dS:{k.StackChange():+0;-#}\t{k}" + (unreachable ? "\t// UNREACHABLE" : ""));
|
||||||
if (k.Operand is MsilOperandBrTarget br)
|
if (k.Operand is MsilOperandBrTarget br)
|
||||||
{
|
{
|
||||||
@@ -146,21 +192,13 @@ namespace Torch.Managers.PatchManager.Transpile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Emit(IEnumerable<MsilInstruction> input, LoggingIlGenerator output)
|
|
||||||
{
|
|
||||||
foreach (MsilInstruction k in FixBranchAndReturn(input, null))
|
|
||||||
k.Emit(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<MsilInstruction> FixBranchAndReturn(IEnumerable<MsilInstruction> insn, Label? retTarget)
|
private static IEnumerable<MsilInstruction> FixBranchAndReturn(IEnumerable<MsilInstruction> insn, Label? retTarget)
|
||||||
{
|
{
|
||||||
foreach (MsilInstruction i in insn)
|
foreach (MsilInstruction i in insn)
|
||||||
{
|
{
|
||||||
if (retTarget.HasValue && i.OpCode == OpCodes.Ret)
|
if (retTarget.HasValue && i.OpCode == OpCodes.Ret)
|
||||||
{
|
{
|
||||||
MsilInstruction j = new MsilInstruction(OpCodes.Br).InlineTarget(new MsilLabel(retTarget.Value));
|
var j = i.CopyWith(OpCodes.Br).InlineTarget(new MsilLabel(retTarget.Value));
|
||||||
foreach (MsilLabel l in i.Labels)
|
|
||||||
j.Labels.Add(l);
|
|
||||||
_log.Trace($"Replacing {i} with {j}");
|
_log.Trace($"Replacing {i} with {j}");
|
||||||
yield return j;
|
yield return j;
|
||||||
}
|
}
|
||||||
|
@@ -184,6 +184,7 @@
|
|||||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandInline.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilOperandInline.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MSIL\MsilOperandSwitch.cs" />
|
<Compile Include="Managers\PatchManager\MSIL\MsilOperandSwitch.cs" />
|
||||||
<Compile Include="Managers\PatchManager\MethodRewritePattern.cs" />
|
<Compile Include="Managers\PatchManager\MethodRewritePattern.cs" />
|
||||||
|
<Compile Include="Managers\PatchManager\MSIL\MsilTryCatchOperation.cs" />
|
||||||
<Compile Include="Managers\PatchManager\PatchShimAttribute.cs" />
|
<Compile Include="Managers\PatchManager\PatchShimAttribute.cs" />
|
||||||
<Compile Include="Managers\PatchManager\PatchContext.cs" />
|
<Compile Include="Managers\PatchManager\PatchContext.cs" />
|
||||||
<Compile Include="Managers\PatchManager\PatchManager.cs" />
|
<Compile Include="Managers\PatchManager\PatchManager.cs" />
|
||||||
|
Reference in New Issue
Block a user