Created
January 14, 2024 23:33
-
-
Save pardeike/0d949f193837918e093f6ae67791afe7 to your computer and use it in GitHub Desktop.
Creating a filter clause in Cecil
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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