How to access the Exception variable more than once in an injected try catch handler with Mono.Cecil?

StackOverflow https://stackoverflow.com/questions/23683662

  •  23-07-2023
  •  | 
  •  

Question

I am adding a try catch block surrounding the method body using Mono.Cecil

All is going well, even I can call a method with the caught Exception exception1 parameter in the catch block, as it seems the exception1 value is on top of the stack.

However after the call the value is removed from the stack, and if I would like to call an other method with the exception1 as parameter I can not figure out how to access it an ldloc before the call.

So the following code is working, I just do not know how to call an other method in the catch block with the caught exception value as parameter.

var statementInTheCatchBlock = il.Create(OpCodes.Call, module.Import(typeof(AnyType).GetMethod("AnyMethod", new[] { typeof(Exception) })));
var ret = il.Create(OpCodes.Ret);
var leave = il.Create(OpCodes.Leave, ret);

il.InsertAfter(method.Body.Instructions.Last(), statementInTheCatchBlock);
il.InsertAfter(statementInTheCatchBlock, leave);
il.InsertAfter(leave, ret);

var handler = new ExceptionHandler(ExceptionHandlerType.Catch)
{
    TryStart = method.Body.Instructions.First(),
    TryEnd = statementInTheCatchBlock,
    HandlerStart = statementInTheCatchBlock,
    HandlerEnd = ret,
    CatchType = module.Import(typeof(Exception)),
};
method.Body.ExceptionHandlers.Add(handler);

Thx in advance

Was it helpful?

Solution

Finally I've managed to find out. The key is define an own variable and in the first instruction in the catch block store the top of the eval stack in this var:

var exceptionVariable = new VariableDefinition("e", method.Module.Import(typeof (Exception)));
method.Body.Variables.Add(exceptionVariable);

var last = method.Body.Instructions.Last();
Instruction tryEnd;
il.InsertAfter(last, tryEnd = last = il.Create(OpCodes.Stloc_S, exceptionVariable));
il.InsertAfter(last, last = il.Create(OpCodes.Ldloc_S, exceptionVariable));
il.InsertAfter(last, last = anyCallInstructionWithExceptionParamter);
il.InsertAfter(last, last = il.Create(OpCodes.Ldloc_S, exceptionVariable));
il.InsertAfter(last, last = otherCallInstructionWithExceptionParamter);
il.InsertAfter(last, last = leave);
il.InsertAfter(last, ret);

var handler = new ExceptionHandler(ExceptionHandlerType.Catch)
{
    TryStart = method.Body.Instructions.First(),
    TryEnd = tryEnd,
    HandlerStart = tryEnd,
    HandlerEnd = ret,
    CatchType = module.Import(typeof (Exception)),
};

Thanks for all who spent time with this (it was 3 hours for me :-( )

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top