码迷,mamicode.com
首页 > 其他好文 > 详细

Add a try-catch with Mono Cecil

时间:2015-04-02 09:00:38      阅读:280      评论:0      收藏:0      [点我收藏+]

标签:

Adding exception handlers with Mono.Cecil is not difficult, it just requires you to know how exception handlers are laid out 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 that you 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 is, you simply want to wrap the existing code in a try catch handler. You can do it easily with Cecil this way:

    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 is 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 finally (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 is that the end instruction of a range is not contained inside the range. It‘s basically a [TryStart:TryEnd[ range.

Add a try-catch with Mono Cecil

标签:

原文地址:http://www.cnblogs.com/aaa6818162/p/4385847.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!