Skip to content

Instantly share code, notes, and snippets.

@pardeike
Created January 14, 2024 23:33
Show Gist options
  • Save pardeike/0d949f193837918e093f6ae67791afe7 to your computer and use it in GitHub Desktop.
Save pardeike/0d949f193837918e093f6ae67791afe7 to your computer and use it in GitHub Desktop.
Creating a filter clause in Cecil
/*
The following code creates this class:
using System;
public static void Method1()
{
try
{
Console.WriteLine("code");
}
catch (Exception ex) when (flag)
{
Console.WriteLine(ex.Message);
}
}
*/
using Mono.Cecil;
using TypeAttributes = Mono.Cecil.TypeAttributes;
using MethodAttributes = Mono.Cecil.MethodAttributes;
using FieldAttributes = Mono.Cecil.FieldAttributes;
void Main()
{
var mp = new ModuleParameters { Architecture = TargetArchitecture.AMD64, Kind = ModuleKind.Dll };
using var assembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition("ClassExceptionFilter", Version.Parse("1.0.0.0")), "FilterBlockTest", mp);
var module = assembly.MainModule;
var m_Writeline = module.ImportReference(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
var m_get_Message = module.ImportReference(typeof(Exception).GetProperty("Message").GetGetMethod());
var t_Exception = module.ImportReference(typeof(Exception));
//Class : ClassExceptionFilter
var testType = new TypeDefinition("", "ClassExceptionFilter", TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.Public, module.TypeSystem.Object);
module.Types.Add(testType);
var f_flag = new FieldDefinition("flag", FieldAttributes.Private | FieldAttributes.Static, module.TypeSystem.Boolean);
testType.Fields.Add(f_flag);
//Method : Method1
var method = new MethodDefinition("Method1", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, module.TypeSystem.Void);
testType.Methods.Add(method);
method.Body.Variables.Add(new VariableDefinition(t_Exception));
method.Body.InitLocals = true;
var il = method.Body.GetILProcessor();
var x = il;
var code = Create(il, OpCodes.Ldstr, "code");
il.Append(code);
il.Emit(OpCodes.Call, m_Writeline);
var ret = Create(x, OpCodes.Ret);
il.Emit(OpCodes.Leave, ret);
var isinst = Create(x, OpCodes.Isinst, t_Exception);
il.Append(isinst);
il.Emit(OpCodes.Dup);
var stloc = Create(x, OpCodes.Stloc_0);
il.Emit(OpCodes.Brtrue, stloc);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldc_I4_0);
var endfilter = Create(x, OpCodes.Endfilter);
il.Emit(OpCodes.Br, endfilter);
il.Append(stloc);
il.Emit(OpCodes.Ldsfld, f_flag);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Cgt_Un);
il.Append(endfilter);
var pop = Create(x, OpCodes.Pop);
il.Append(pop);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Callvirt, m_get_Message);
il.Emit(OpCodes.Call, m_Writeline);
il.Emit(OpCodes.Leave, ret);
il.Append(ret);
method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Filter) // use Filter instead of Catch!
{
CatchType = module.ImportReference(typeof(System.Exception)),
FilterStart = isinst, // add this for filter!
TryStart = code,
TryEnd = isinst,
HandlerStart = pop,
HandlerEnd = ret
});
// only one ExceptionHandlers!
assembly.Write(@"C:\Users\Brrainz\Desktop\FilterBlockTest.dll");
}
public static Instruction Create(ILProcessor il, OpCode code) => il.Create(code);
public static Instruction Create(ILProcessor il, OpCode code, string str) => il.Create(code, str);
public static Instruction Create(ILProcessor il, OpCode code, TypeReference tref) => il.Create(code, tref);
public static Instruction Create(ILProcessor il, OpCode code, Instruction ins) => il.Create(code, ins);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment