Example #1
0
        /// <summary>
        /// Injects the try-catch-finally related IL ops into the specified method.
        /// </summary>
        /// <param name="theMethodInfo">The method to inject ops into.</param>
        /// <param name="theILBlock">The IL block for the method to inject ops into.</param>
        private static void InjectTryCatchFinally(Types.MethodInfo theMethodInfo, ILBlock theILBlock)
        {
            // Replace Leave and Leave_S ops
            for (int i = 0; i < theILBlock.ILOps.Count; i++)
            {
                ILOp theOp = theILBlock.ILOps[i];

                if ((ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Leave ||
                    (ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Leave_S)
                {
                    theILBlock.ILOps.RemoveAt(i);

                    int ILOffset = 0;
                    if (theOp.LoadAtILOpAfterOp == null)
                    {
                        if ((int)theOp.opCode.Value == (int)ILOp.OpCodes.Leave)
                        {
                            ILOffset = BitConverter.ToInt32(theOp.ValueBytes, 0);
                        }
                        else
                        {
                            ILOffset = (int)theOp.ValueBytes[0];
                        }
                    }

                    theILBlock.ILOps.Insert(i, new ILOp()
                    {
                        Offset = theOp.Offset,
                        BytesSize = theOp.BytesSize,
                        opCode = System.Reflection.Emit.OpCodes.Ldftn,
                        LoadAtILOffset = theOp.NextOffset + ILOffset,
                        LoadAtILOpAfterOp = theOp.LoadAtILOpAfterOp,
                        MethodToCall = theILBlock.TheMethodInfo.UnderlyingInfo
                    });
                    theILBlock.ILOps.Insert(i + 1, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Call,
                        MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.ExceptionsHandleLeaveMethodAttribute)].First().UnderlyingInfo
                    });

                    i++;
                }
                else if ((int)theOp.opCode.Value == (int)ILOp.OpCodes.Endfinally)
                {
                    //Endfinally is for leaving a (critical) finally section
                    //We handle it by a higher-level implementation rather than 
                    //  leaving it to each architecture to implement.

                    //Endfinally is handled by inserting a call to the Exceptions.HandleEndFinally method

                    theILBlock.ILOps.RemoveAt(i);

                    ILOp newOp;
                    theILBlock.ILOps.Insert(i, newOp = new ILOp()
                    {
                        Offset = theOp.Offset,
                        BytesSize = theOp.BytesSize,
                        opCode = System.Reflection.Emit.OpCodes.Call,
                        MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.ExceptionsHandleEndFinallyMethodAttribute)].First().UnderlyingInfo
                    });

                    //Replace references to this endfinally op
                    for (int j = 0; j < theILBlock.ILOps.Count; j++)
                    {
                        if (theILBlock.ILOps[j].LoadAtILOpAfterOp == theOp)
                        {
                            theILBlock.ILOps[j].LoadAtILOpAfterOp = newOp;
                        }
                    }
                }
            }


            foreach (ExceptionHandledBlock exBlock in theILBlock.ExceptionHandledBlocks)
            {
                #region Try-sections
                //      Insert the start of try-block
                //          Also remember that other ops (e.g. branch and leave) can hold references
                //          to the first op INSIDE a try block, even if they themselves are OUTSIDE 
                //          the block. This means we need to correct which op has the Offset value
                //          set so those ops point at the new start op of the try block.

                //Consists of adding a new ExceptionHandlerInfos
                //  built from the info in exBlock so we:
                //      - Add infos for all finally blocks first
                //      - Then add infos for all catch blocks
                //  Since finally code is always run after catch code in C#,
                //      by adding catch handlers after finally handlers, they 
                //      appear as the inner-most exception handlers and so get 
                //      run before finally handlers.

                //To add a new ExceptionHandlerInfo we must set up args for 
                //  calling Exceptions.AddExceptionHandlerInfo:
                // 1. We load a pointer to the handler
                //      - This is calculated from an offset from the start of the function to the handler
                // 2. We load a pointer to the filter
                //      - This is calculated from an offset from the start of the function to the filter
                //      Note: Filter has not been implemented as an actual filter. 
                //            At the moment, 0x00000000 indicates a finally handler,
                //                           0xFFFFFFFF indicates no filter block 
                //                                      (i.e. an unfiltered catch handler)
                //                           0xXXXXXXXX has undetermined behaviour!

                //For each finally block:
                int insertPos = theILBlock.PositionOf(theILBlock.At(exBlock.Offset));
                foreach (FinallyBlock finBlock in exBlock.FinallyBlocks)
                {
                    // 1. Load the pointer to the handler code:
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Ldftn, 
                        MethodToCall = theMethodInfo.UnderlyingInfo,
                        LoadAtILOffset = finBlock.Offset
                    });
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Ldc_I4,
                        ValueBytes = BitConverter.GetBytes(0x00000000)
                    });
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Call,
                        MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.AddExceptionHandlerInfoMethodAttribute)].First().UnderlyingInfo
                    });
                }
                foreach (CatchBlock catchBlock in exBlock.CatchBlocks)
                {
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Ldftn,
                        MethodToCall = theMethodInfo.UnderlyingInfo,
                        LoadAtILOffset = catchBlock.Offset
                    });
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Ldc_I4,
                        ValueBytes = BitConverter.GetBytes(0xFFFFFFFF)
                    });
                    theILBlock.ILOps.Insert(insertPos++, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Call,
                        MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.AddExceptionHandlerInfoMethodAttribute)].First().UnderlyingInfo
                    });
                }
                #endregion
            }
        }
Example #2
0
        /// <summary>
        /// Handles catch handles (of exception blocks) for the specified method.
        /// </summary>
        /// <param name="theMethodInfo">The method to handle.</param>
        /// <param name="theILBlock">The IL block for the method to handle.</param>
        private static void DealWithCatchHandlers(Types.MethodInfo theMethodInfo, ILBlock theILBlock)
        {
            foreach (ExceptionHandledBlock exBlock in theILBlock.ExceptionHandledBlocks)
            {
                #region Catch-sections

                // Strip the first pop of catch-handler

                foreach (CatchBlock aCatchBlock in exBlock.CatchBlocks)
                {
                    ILOp catchPopOp = theILBlock.At(aCatchBlock.Offset);
                    int pos = theILBlock.PositionOf(catchPopOp);
                    theILBlock.ILOps.RemoveAt(pos);
                    theILBlock.ILOps.Insert(pos, new ILOp()
                    {
                        opCode = System.Reflection.Emit.OpCodes.Nop,
                        Offset = catchPopOp.Offset,
                        BytesSize = catchPopOp.BytesSize
                    });
                }

                #endregion
            }
        }