using Mono.Cecil;
using Mono.Cecil.Cil;
/// <summary>Resolve EH-only funclet lookups to the root method's EH table and address space.</summary>
internal static class FuncletEhRuntimePatch
{
public const string HelperName = "XfeResolveEhFuncletRootV1";
public static bool Apply(AssemblyDefinition assembly)
{
var module = assembly.MainModule;
var eh = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.Runtime.ExceptionHandling.ExceptionHelper");
var lookup = eh.Methods.Single(method => method.Name == "TryGetMethodLSDA");
var existing = eh.Methods.SingleOrDefault(method => method.Name == HelperName);
if (existing is not null)
{
if (lookup.Body.Instructions.Count(instruction => instruction.Operand is MethodReference method && method.FullName == existing.FullName) != 1 ||
existing.Parameters.Count != 2 || existing.Body.Instructions.Count != 31)
throw new InvalidOperationException("Unexpected EH funclet root resolver patch.");
return true;
}
if (lookup.Body.Instructions.Count != 5 || lookup.Body.Instructions[3].Operand is not MethodReference original ||
original.Name != "TryGetMethodLSDA" || original.DeclaringType.FullName != "Cosmos.Kernel.Core.Runtime.GcInfo.MethodGcInfoLookup")
throw new InvalidOperationException("Pinned EH LSDA wrapper changed; refusing to replace it.");
var resolve = new MethodDefinition(HelperName, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.Void);
resolve.Parameters.Add(new("rootStart", ParameterAttributes.None, lookup.Parameters[1].ParameterType));
resolve.Parameters.Add(new("rootLsda", ParameterAttributes.None, lookup.Parameters[2].ParameterType));
resolve.Body.InitLocals = true;
var cursor = new VariableDefinition(new PointerType(module.TypeSystem.Byte)); resolve.Body.Variables.Add(cursor);
eh.Methods.Add(resolve);
var il = resolve.Body.GetILProcessor(); var end = il.Create(OpCodes.Ret);
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldind_I)); il.Append(il.Create(OpCodes.Ldind_U1));
il.Append(il.Create(OpCodes.Ldc_I4_3)); il.Append(il.Create(OpCodes.And)); il.Append(il.Create(OpCodes.Brfalse, end));
// Same signed relative-pointer format used by the unmodified pinned
// GCInfo decoder: LSDA delta is relative to its own int32 slot.
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldind_I)); il.Append(il.Create(OpCodes.Ldc_I4_1));
il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stloc, cursor));
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldloc, cursor));
il.Append(il.Create(OpCodes.Ldind_I4)); il.Append(il.Create(OpCodes.Conv_I)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stind_I));
il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldc_I4_4)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stloc, cursor));
il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldind_I));
il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldind_I4)); il.Append(il.Create(OpCodes.Conv_I));
il.Append(il.Create(OpCodes.Sub)); il.Append(il.Create(OpCodes.Stind_I)); il.Append(end); resolve.Body.MaxStackSize = 3;
lookup.Body.Instructions.Clear(); var wrapper = lookup.Body.GetILProcessor(); var notFound = wrapper.Create(OpCodes.Ldc_I4_0);
wrapper.Append(wrapper.Create(OpCodes.Ldarg_0)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_1)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_2));
wrapper.Append(wrapper.Create(OpCodes.Call, original)); wrapper.Append(wrapper.Create(OpCodes.Brfalse, notFound));
wrapper.Append(wrapper.Create(OpCodes.Ldarg_1)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_2)); wrapper.Append(wrapper.Create(OpCodes.Call, resolve));
wrapper.Append(wrapper.Create(OpCodes.Ldc_I4_1)); wrapper.Append(wrapper.Create(OpCodes.Ret)); wrapper.Append(notFound); wrapper.Append(wrapper.Create(OpCodes.Ret));
lookup.Body.MaxStackSize = 3;
return false;
}
}
using Mono.Cecil;
using Mono.Cecil.Cil;
/// <summary>Resolve EH-only funclet lookups to the root method's EH table and address space.</summary>
internal static class FuncletEhRuntimePatch
{
public const string HelperName = "XfeResolveEhFuncletRootV1";
public static bool Apply(AssemblyDefinition assembly)
{
var module = assembly.MainModule;
var eh = module.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.Runtime.ExceptionHandling.ExceptionHelper");
var lookup = eh.Methods.Single(method => method.Name == "TryGetMethodLSDA");
var existing = eh.Methods.SingleOrDefault(method => method.Name == HelperName);
if (existing is not null)
{
if (lookup.Body.Instructions.Count(instruction => instruction.Operand is MethodReference method && method.FullName == existing.FullName) != 1 ||
existing.Parameters.Count != 2 || existing.Body.Instructions.Count != 31)
throw new InvalidOperationException("Unexpected EH funclet root resolver patch.");
return true;
}
if (lookup.Body.Instructions.Count != 5 || lookup.Body.Instructions[3].Operand is not MethodReference original ||
original.Name != "TryGetMethodLSDA" || original.DeclaringType.FullName != "Cosmos.Kernel.Core.Runtime.GcInfo.MethodGcInfoLookup")
throw new InvalidOperationException("Pinned EH LSDA wrapper changed; refusing to replace it.");
var resolve = new MethodDefinition(HelperName, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.Void);
resolve.Parameters.Add(new("rootStart", ParameterAttributes.None, lookup.Parameters[1].ParameterType));
resolve.Parameters.Add(new("rootLsda", ParameterAttributes.None, lookup.Parameters[2].ParameterType));
resolve.Body.InitLocals = true;
var cursor = new VariableDefinition(new PointerType(module.TypeSystem.Byte)); resolve.Body.Variables.Add(cursor);
eh.Methods.Add(resolve);
var il = resolve.Body.GetILProcessor(); var end = il.Create(OpCodes.Ret);
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldind_I)); il.Append(il.Create(OpCodes.Ldind_U1));
il.Append(il.Create(OpCodes.Ldc_I4_3)); il.Append(il.Create(OpCodes.And)); il.Append(il.Create(OpCodes.Brfalse, end));
// Same signed relative-pointer format used by the unmodified pinned
// GCInfo decoder: LSDA delta is relative to its own int32 slot.
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldind_I)); il.Append(il.Create(OpCodes.Ldc_I4_1));
il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stloc, cursor));
il.Append(il.Create(OpCodes.Ldarg_1)); il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldloc, cursor));
il.Append(il.Create(OpCodes.Ldind_I4)); il.Append(il.Create(OpCodes.Conv_I)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stind_I));
il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldc_I4_4)); il.Append(il.Create(OpCodes.Add)); il.Append(il.Create(OpCodes.Stloc, cursor));
il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldarg_0)); il.Append(il.Create(OpCodes.Ldind_I));
il.Append(il.Create(OpCodes.Ldloc, cursor)); il.Append(il.Create(OpCodes.Ldind_I4)); il.Append(il.Create(OpCodes.Conv_I));
il.Append(il.Create(OpCodes.Sub)); il.Append(il.Create(OpCodes.Stind_I)); il.Append(end); resolve.Body.MaxStackSize = 3;
lookup.Body.Instructions.Clear(); var wrapper = lookup.Body.GetILProcessor(); var notFound = wrapper.Create(OpCodes.Ldc_I4_0);
wrapper.Append(wrapper.Create(OpCodes.Ldarg_0)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_1)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_2));
wrapper.Append(wrapper.Create(OpCodes.Call, original)); wrapper.Append(wrapper.Create(OpCodes.Brfalse, notFound));
wrapper.Append(wrapper.Create(OpCodes.Ldarg_1)); wrapper.Append(wrapper.Create(OpCodes.Ldarg_2)); wrapper.Append(wrapper.Create(OpCodes.Call, resolve));
wrapper.Append(wrapper.Create(OpCodes.Ldc_I4_1)); wrapper.Append(wrapper.Create(OpCodes.Ret)); wrapper.Append(notFound); wrapper.Append(wrapper.Create(OpCodes.Ret));
lookup.Body.MaxStackSize = 3;
return false;
}
}