Adding exception handlers with Mono.cecil isn't difficult, it just requires you to know how exception handlers was laid O UT in the metadata.
Let say you have the C # method:
static void Throw (){ throw new Exception ("oups");}
If you decompile it, it should look somewhat similar to this:
.method private static hidebysig default void Throw () cil managed { IL_0000: ldstr "oups" IL_0005: newobj instance void class [mscorlib]System.Exception::.ctor(string) IL_000a: throw }
Now let say so want to inject code in this method such as it's similar to the C # code:
static void Throw (){ try { throw new Exception ("oups"); } catch (Exception e) { Console.WriteLine (e); }}
That's, you simply want-wrap the existing code in a try catch handler. You can do it easily with Cecil the This is:
var method = ...; var il = method.Body.GetILProcessor (); var write = il.Create ( OpCodes.Call, module.Import (typeof (Console).GetMethod ("WriteLine", new [] { typeof (object)}))); var ret = il.Create (OpCodes.Ret); var leave = il.Create (OpCodes.Leave, ret); il.InsertAfter ( method.Body.Instructions.Last (), write); il.InsertAfter (write, leave); il.InsertAfter (leave, ret); var handler = new ExceptionHandler (ExceptionHandlerType.Catch) { TryStart = method.Body.Instructions.First (), TryEnd = write, HandlerStart = write, HandlerEnd = ret, CatchType = module.Import (typeof (Exception)), }; method.Body.ExceptionHandlers.Add (handler);
This code was manipulating the previous method to look like this:
.method private static hidebysig default void Throw () cil managed { .maxstack 1 .try { // 0 IL_0000: ldstr "oups" IL_0005: newobj instance void class [mscorlib]System.Exception::‘.ctor‘(string) IL_000a: throw } // end .try 0 catch class [mscorlib]System.Exception { // 0 IL_000b: call void class [mscorlib]System.Console::WriteLine(object) IL_0010: leave IL_0015 } // end handler 0 IL_0015: ret }
We ' re adding three new instructions:a call to Console.WriteLine, a leave to gracefully exit the catch handler, and Finall Y (pun intended), a ret. Then we ' re simply creating a Exceptionhandler instance to represent a try catch handler whose try encompasses the existing Body, and whose catch is the WriteLine statement.
One important thing to note are that the end instruction of a range are not contained inside the range. It ' s basically a [trystart:tryend[range.
Add a try-catch with Mono Cecil