Ejemplo n.º 1
0
        /// <summary>
        /// Process an unplugged IL chunk.
        /// </summary>
        /// <param name="aChunk">The chunk to process.</param>
        /// <returns>The resulting ASM chunk or null if processing failed.</returns>
        private ASMChunk ProcessUnpluggedILChunk(ILChunk aChunk)
        {
            ASMChunk result = new ASMChunk();

            string methodSignature = Utils.GetMethodSignature(aChunk.Method);
            string MethodID = TheScannerState.GetMethodID(aChunk.Method);
            
            //Add the method to the debug database
            DB_Method dbMethod = null;
            if (TheSettings.DebugBuild)
            {
                dbMethod = new DB_Method();
                dbMethod.Id = MethodID;
                dbMethod.MethodSignature = methodSignature;
                dbMethod.Plugged = false;
                dbMethod.ASMStartPos = -1;
                dbMethod.ASMEndPos = -1;
                result.DBMethod = dbMethod;
                DebugDatabase.AddMethod(dbMethod);
            }

            result.ASM.AppendLine("; IL Scanned Method"); //DEBUG INFO
            result.ASM.AppendLine("; " + methodSignature); //DEBUG INFO
            //Outputs the label that is the start of this method
            result.ASM.AppendLine(MethodID + ":");

            //Construct the stack frame state for the start of this method
            StackFrame currFrame = new StackFrame();
            TheScannerState.CurrentStackFrame = currFrame;
            TheScannerState.CurrentILChunk = aChunk;

            //Insert the method start op
            //See comments on method start op for what it does etc.
            int addASMLineNum = 0;
            {
                //TODO - Add DBILOpInfo for MethodStart op

                result.ASM.AppendLine("; MethodStart"); // DEBUG INFO
                //Get the ASM of the op
                string asm = MethodStartOp.Convert(null, TheScannerState);
                //Split the ASM into lines
                string[] asmLines = asm.Replace("\r", "").Split('\n');
                
                //This code inserts the ASM line by line, outputting labels for
                //  each line of ASM.
                //Start at any existing offset for the current op
                //  - prevents duplication of labels
                int asmLineNum = addASMLineNum;
                //For each line of ASM:
                foreach (string asmLine in asmLines)
                {
                    //If the line isn't already a label:
                    if (!asmLine.Split(';')[0].Trim().EndsWith(":"))
                    {
                        //Output the ASM label
                        result.ASM.AppendLine(string.Format("{0}.IL_{1}_{2}:", MethodID, 0, asmLineNum));
                    }
                    //Append the ASM
                    result.ASM.AppendLine(asmLine);
                    //Increment the ASM line num
                    asmLineNum++;
                }
                //Set the overall ASM line offset for current op to final 
                //  offset
                addASMLineNum = asmLineNum;
            }

            #region GC
            
            //If Garbage Collection code should be added to this method:
            if (aChunk.ApplyGC)
            {
                //Inc ref count of all args passed to the method 
                //      - see ILReader for GC cleanup / dec ref count (use search: "Dec ref count" exc. quotes)
                List<Type> allParams = aChunk.Method.GetParameters()
                    .Select(x => x.ParameterType)
                    .ToList();
                //Non-static methods have first arg as instance reference
                if (!aChunk.Method.IsStatic)
                {
                    allParams.Insert(0, aChunk.Method.DeclaringType);
                }
                //If the number of args for this method > 0
                if (allParams.Count > 0)
                {
                    //Store the new ASM to append afterwards
                    string asm = "";

                    //For each arg:
                    for (int i = 0; i < allParams.Count; i++)
                    {
                        Type aVarType = allParams[i];
                        //If the arg is of a type managed by the GC
                        if (Utils.IsGCManaged(aVarType))
                        {
                            //Load the arg
                            asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldarg]
                                            .Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Ldarg,
                                    ValueBytes = BitConverter.GetBytes(i)
                                }, TheScannerState);
                            //Call increment ref count
                            asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call]
                                            .Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                    MethodToCall = TheScannerState.IncrementRefCountMethod
                                }, TheScannerState);
                        }
                    }

                    //Append the new ASM - see MethodStart for explanation above
                    string[] asmLines = asm.Replace("\r", "").Split('\n');
                    int asmLineNum = addASMLineNum;
                    foreach (string asmLine in asmLines)
                    {
                        if (!asmLine.Split(';')[0].Trim().EndsWith(":"))
                        {
                            result.ASM.AppendLine(string.Format("{0}.IL_{1}_{2}:", MethodID, 0, asmLineNum));
                        }
                        result.ASM.AppendLine(asmLine);
                        asmLineNum++;
                    }
                    addASMLineNum = asmLineNum;
                }
            }

            #endregion

            //Stores the label of the last IL op that was a debug NOP
            //  - See documentation for use of Debug NOPs / INT3s
            string debugNopLabel = null;
            
            //Stores the start position of the current IL op in the ASM
            int ASMStartPos = 0;
            //Get a list of all the IL ops
            List<ILOpInfo> TheILOpInfos = aChunk.ILOpInfos;
            //For each IL op:
            foreach (ILOpInfo anILOpInfo in TheILOpInfos)
            {
                //We surround all this with a try-catch block 
                //  so that if processing the current IL op causes an exception, we don't abort processing 
                //  of the entire method. We will end up with invalid ASM code in the output, but at least
                //  the developer will receive all the errors with their code not just one per build.
                try
                {
                    #region Debug 

                    //Create the debug
                    DB_ILOpInfo dbILOpInfo = null;
                    if (TheSettings.DebugBuild)
                    {
                        dbILOpInfo = new DB_ILOpInfo();
                        dbILOpInfo.Id = Guid.NewGuid();
                        dbILOpInfo.MethodID = MethodID;
                        dbILOpInfo.OpCode = anILOpInfo.opCode.Value;
                        dbILOpInfo.CustomOpCode = 0;
                        dbILOpInfo.NextPosition = anILOpInfo.NextPosition;
                        dbILOpInfo.Position = anILOpInfo.Position;
                        if (anILOpInfo.ValueBytes != null)
                        {
                            if (anILOpInfo.ValueBytes.Length < 8000)
                            {
                                dbILOpInfo.ValueBytes = new System.Data.Linq.Binary(anILOpInfo.ValueBytes);
                            }
                            else
                            {
                                OutputWarning(new Exception("ValueBytes not set because data too large. Op: " + anILOpInfo.opCode.Name + ", Op offset: " + anILOpInfo.Position.ToString("X2") + "\r\n" + methodSignature));
                                anILOpInfo.ValueBytes = null;
                            }
                        }
                        dbILOpInfo.ASMInsertLabel = true;
                        anILOpInfo.DBILOpInfo = dbILOpInfo;

                        dbILOpInfo.ASMStartPos = anILOpInfo.ASMStartPos = ASMStartPos;
                    }

                    #endregion

                    //Stores all the new ASM for this IL op
                    //  - This ASM gets appended to the result at the end of the try-section
                    //    thus it only gets appended if there are no processing errors.
                    string asm = "";

                    #region Exception Handling

                    //We needs to check if we are in try, catch or finally blocks (a.k.a critical sections):
                    ExceptionHandledBlock exBlock = aChunk.GetExceptionHandledBlock(anILOpInfo.Position);
                    //If we are in a critical section:
                    if (exBlock != null)
                    {
                        //If this IL op is the first op of a try-section:
                        if (exBlock.Offset == anILOpInfo.Position)
                        {
                            //Insert the start of 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!
                            
                            result.ASM.AppendLine("; Try-block start"); // DEBUG INFO
                            //For each finally block:
                            foreach (FinallyBlock finBlock in exBlock.FinallyBlocks)
                            {
                                // 1. Load the pointer to the handler code:
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldftn].Convert(new ILOpInfo()
                                {
                                    //Load function pointer op
                                    opCode = System.Reflection.Emit.OpCodes.Ldftn,
                                    //Load a pointer to the current method
                                    MethodToCall = aChunk.Method,
                                    //At this offset: The first IL op of the finally block
                                    LoadAtILOffset = finBlock.Offset
                                }, TheScannerState);
                                // 2. Load the pointer to the filter code:
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldc_I4].Convert(new ILOpInfo()
                                {
                                    //Load a constant value
                                    opCode = System.Reflection.Emit.OpCodes.Ldc_I4,
                                    //The value is 0x00000000 - since this is a finally handler
                                    ValueBytes = BitConverter.GetBytes(0x00000000)
                                }, TheScannerState);
                                // Call Exceptions.AddExceptionHandlerInfo
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                    MethodToCall = TheScannerState.AddExceptionHandlerInfoMethod
                                }, TheScannerState);
                            }
                            foreach (CatchBlock catchBlock in exBlock.CatchBlocks)
                            {
                                // 1. Load the pointer to the handler code:
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldftn].Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Ldftn,
                                    MethodToCall = aChunk.Method,
                                    LoadAtILOffset = catchBlock.Offset
                                }, TheScannerState);
                                //TODO - We need to sort out a way of doing filter functions
                                // 2. Load the pointer to the filter code:
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldc_I4].Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Ldc_I4,
                                    //The value is 0xFFFFFFFF - since this is a catch handler (and filters aren't implemented yet!)
                                    ValueBytes = BitConverter.GetBytes(0xFFFFFFFF)
                                }, TheScannerState);
                                // Call Exceptions.AddExceptionHandlerInfo
                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                {
                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                    MethodToCall = TheScannerState.AddExceptionHandlerInfoMethod
                                }, TheScannerState);
                            }
                        }

                        //We need to check if the current IL op is the first op
                        //  of a catch block. This is because C# catch blocks are
                        //  compiled with a "pop" instruction as the first op if
                        //  the catch block has no filter. Presumably, this is because
                        //  C# would be expecting the current exception to be on the
                        //  stack.

                        //Get any catch blocks we are currently in.
                        List<CatchBlock> potCatchBlocks = (from catchBlocks in exBlock.CatchBlocks
                                                           where (catchBlocks.Offset <= anILOpInfo.Position &&
                                                                  catchBlocks.Offset + catchBlocks.Length >= anILOpInfo.Position)
                                                           select catchBlocks).ToList();
                        //If we are in a catch block:
                        if (potCatchBlocks.Count > 0)
                        {
                            CatchBlock catchBlock = potCatchBlocks.First();
                            //If this is the first op of the catch block:
                            if (catchBlock.Offset == anILOpInfo.Position)
                            {
                                result.ASM.AppendLine("; Catch-block start"); // DEBUG INFO

                                //Ignore the first pop-op of the catch block
                                if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Pop)
                                {
                                    //Do an immediate append rather than using the "asm" variable as we will be calling
                                    // "continue" - see below.
                                    //For debug, we must insert this op's label in to the ASM.
                                    string label = string.Format("{0}.IL_{1}_{2}", MethodID, anILOpInfo.Position, 0);
                                    result.ASM.AppendLine(label + ":");
                                    result.ASM.AppendLine("; Skipped first pop of catch handler"); // DEBUG INFO
                                    //End processing of this op by skipping to the next!
                                    continue;
                                }
                            }
                        }

                        //We want to be able to output some debug info if we are starting a finally block
                        //  just so that our ASM is more intellgible / debuggable.
                        List<FinallyBlock> potFinallyBlocks = (from finallyBlocks in exBlock.FinallyBlocks
                                                               where (finallyBlocks.Offset <= anILOpInfo.Position &&
                                                                      finallyBlocks.Offset + finallyBlocks.Length >= anILOpInfo.Position)
                                                               select finallyBlocks).ToList();
                        if (potFinallyBlocks.Count > 0)
                        {
                            FinallyBlock finallyBlock = potFinallyBlocks.First();

                            if (finallyBlock.Offset == anILOpInfo.Position)
                            {
                                result.ASM.AppendLine("; Finally-block start"); // DEBUG INFO
                            }
                        }
                    }

                    #endregion

                    #region Debug 

                    if (TheSettings.DebugBuild)
                    {
                        //If this chunk hasn't been marked as no-debug ops:
                        if (!aChunk.NoDebugOps)
                        {
                            // Insert a debug nop just before the op
                            //  - This allows us to step an entire IL op at a time rather than just one
                            //    line of ASM at a time.
                            result.ASM.AppendLine("; Debug Nop"); // DEBUG INFO
                            // Insert the nop
                            asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Nop].Convert(anILOpInfo, TheScannerState);
                            //See above for how this append code works
                            string[] asmLines = asm.Replace("\r", "").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                            int asmLineNum = addASMLineNum;
                            //Clear the current debug nop label so we can get the first label
                            //  of the new ASM and use it as the debug nop label for this IL op.
                            debugNopLabel = null;
                            foreach (string asmLine in asmLines)
                            {
                                if (!asmLine.Split(';')[0].Trim().EndsWith(":"))
                                {
                                    string label = string.Format("{0}.IL_{1}_{2}", MethodID, anILOpInfo.Position, asmLineNum);
                                    //If we do not currently have a debug nop label for this IL op:
                                    if (debugNopLabel == null)
                                    {
                                        //Set the current debug nop label.
                                        debugNopLabel = label;
                                    }
                                    result.ASM.AppendLine(label + ":");
                                }
                                result.ASM.AppendLine(asmLine);
                                asmLineNum++;
                            }
                            addASMLineNum = asmLineNum;
                            //We just added all the ASM for this op generated so far, so clean the "asm" variable
                            asm = "";
                        }
                        //Set the debug nop label for this IL op as the last inserted debug nop label
                        dbILOpInfo.DebugOpMeta = "DebugNopLabel=" + debugNopLabel + ";";
                    }

                    #endregion

                    //Insert some method end code just before the ret op.
                    if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Ret)
                    {
                        //Method End op inserts code such as storing the return value
                        //  in the return argument and restoring the stack base pointer
                        result.ASM.AppendLine("; MethodEnd"); // DEBUG INFO
                        asm += "\r\n" + MethodEndOp.Convert(null, TheScannerState);
                    }


                    if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Leave ||
                        (int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Leave_S)
                    #region Exception Handling
                    {
                        //Leave is for leaving a critical section
                        //We handle it by a higher-level implementation rather than 
                        //  leaving it to each architecture to implement.

                        //Leave is handled by inserting a call to the Exceptions.HandleLeave method

                        //This value is an offset from the next IL op to the line to continue execution at
                        //  if there isno current exception and no finally handler.
                        int ILOffset = 0;
                        if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Leave)
                        {
                            ILOffset = BitConverter.ToInt32(anILOpInfo.ValueBytes, 0);
                        }
                        else
                        {
                            ILOffset = (int)anILOpInfo.ValueBytes[0];
                        }

                        //Get the IL number of the next op
                        int startILNum = anILOpInfo.NextPosition;
                        //Add the offset to get the IL op num to jump to
                        int ILNumToGoTo = startILNum + ILOffset;

                        // Load the address of the op to continue execution at if there is no exception and
                        //  no finally handler.
                        asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldftn].Convert(new ILOpInfo()
                        {
                            opCode = System.Reflection.Emit.OpCodes.Ldftn,
                            MethodToCall = aChunk.Method,
                            LoadAtILOffset = ILNumToGoTo
                        }, TheScannerState);
                        // Call Exceptions.HandleLeave
                        asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                        {
                            opCode = System.Reflection.Emit.OpCodes.Call,
                            MethodToCall = TheScannerState.ExceptionsHandleLeaveMethod
                        }, TheScannerState);
                    }
                    else if ((int)anILOpInfo.opCode.Value == (int)ILOps.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

                        asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                        {
                            opCode = System.Reflection.Emit.OpCodes.Call,
                            MethodToCall = TheScannerState.ExceptionsHandleEndFinallyMethod
                        }, TheScannerState);
                    }

                    #endregion
                    else if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Castclass)
                    {
                        //This IL op is ignored for now. We assume the the Microsoft compiler (csc.exe) 
                        //makes the correct casting checks etc
                        //And even if it doesn't, at the kernel level it is useful to be able to play
                        //  tricks with converting objects to/from MS types and custom kernel types 
                        //  e.g. System.String to Kernel.FOS_System.String
                    }
                    else
                    {
                        //Indicates whether the IL op should actually be processed or not.
                        //  - At this stage, there are a few cases when the Il op should not be
                        //    processed but the new ASM should still be appended.
                        bool processOp = true;

                        #region Special-case op handling

                        //If the op is a call:
                        if ((int)anILOpInfo.opCode.Value == (int)ILOps.ILOp.OpCodes.Call)
                        {
                            //If the method to call is actually in mscorlib:
                            if (anILOpInfo.MethodToCall != null && anILOpInfo.MethodToCall.DeclaringType.AssemblyQualifiedName.
                                Contains("mscorlib"))
                            {
                                //We do not want to process ops which attempt to call methods in mscorlib!
                                processOp = false;

                                //We do not allow calls to methods declared in MSCorLib.
                                //Some of these calls can just be ignored (e.g. GetTypeFromHandle is
                                //  called by typeof operator).
                                //Ones which can't be ignored, will result in an error...by virtue of
                                //  the fact that they were ignored when they were required.

                                //But just to make sure we save ourselves a headache later when
                                //  runtime debugging, output a message saying we ignored the call.
                                result.ASM.AppendLine("; Call to method defined in MSCorLib ignored:"); // DEBUG INFO
                                result.ASM.AppendLine("; " + anILOpInfo.MethodToCall.DeclaringType.FullName + "." + anILOpInfo.MethodToCall.Name); // DEBUG INFO

                                //If the method is a call to a constructor in MsCorLib:
                                if (anILOpInfo.MethodToCall is ConstructorInfo)
                                {
                                    //Then we can presume it was a call to a base-class constructor (e.g. the Object constructor)
                                    //  and so we just need to remove any args that were loaded onto the stack.
                                    result.ASM.AppendLine("; Method to call was constructor so removing params"); // DEBUG INFO
                                    //Remove args from stack
                                    //If the constructor was non-static, then the first arg is the instance reference.
                                    if (!anILOpInfo.MethodToCall.IsStatic)
                                    {
                                        asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Pop].Convert(new ILOpInfo()
                                        {
                                            opCode = System.Reflection.Emit.OpCodes.Pop
                                        }, TheScannerState);
                                    }
                                    foreach (ParameterInfo anInfo in anILOpInfo.MethodToCall.GetParameters())
                                    {
                                        asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Pop].Convert(new ILOpInfo()
                                        {
                                            opCode = System.Reflection.Emit.OpCodes.Pop
                                        }, TheScannerState);
                                    }
                                }
                            }
                            //If the method to call wasn't to a method in MsCorLib, we may need to set the method to call:
                            else if(anILOpInfo.SetToGCDecRefCountMethod)
                            {
                                anILOpInfo.MethodToCall = TheScannerState.DecrementRefCountMethod;
                            }
                        }

                        #endregion

                        //If the op should be processed:
                        if(processOp)
                        {
                            #region GC 

                            //GC requires us to decrement ref count of any field/local/arg
                            //  that is about to be overwritten
                            //NewILOps - Unimplemented and new IL Ops need checking and below
                            //           adding if necessary

                            if (aChunk.ApplyGC)
                            {
                                bool IncRefCount = false;

                                switch ((ILOps.ILOp.OpCodes)anILOpInfo.opCode.Value)
                                {
                                    case ILOps.ILOp.OpCodes.Stsfld:
                                        {
                                            int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0);
                                            FieldInfo theField = TheScannerState.CurrentILChunk.Method.Module.ResolveField(metadataToken);
                                            if (Utils.IsGCManaged(theField.FieldType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldsfld].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldsfld,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc:
                                        {
                                            UInt16 localIndex = (UInt16)Utils.ReadInt16(anILOpInfo.ValueBytes, 0);
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[localIndex].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc_0:
                                        {
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[0].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc_0].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc_0
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc_1:
                                        {
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[1].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc_1].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc_1
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc_2:
                                        {
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[2].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc_2].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc_2
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc_3:
                                        {
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[3].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc_3].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc_3
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stloc_S:
                                        {
                                            UInt16 localIndex = (UInt16)anILOpInfo.ValueBytes[0];
                                            if (Utils.IsGCManaged(aChunk.LocalVariables[localIndex].TheType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldloc_S].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldloc_S,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stfld:
                                        {
                                            int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0);
                                            FieldInfo theField = aChunk.Method.Module.ResolveField(metadataToken);
                                            if (Utils.IsGCManaged(theField.FieldType))
                                            {
                                                // Items on stack:
                                                //  - Object reference
                                                //  - (New) Value to store
                                                //
                                                // We want to load the current value of the field
                                                //  for which we must duplicate the object ref
                                                // But first, we must remove the (new) value to store
                                                //  off the stack, while also storing it to put back
                                                //  on the stack after so the store can continue
                                                //
                                                // So:
                                                //      1. Switch value to store and object ref on stack
                                                //      3. Duplicate the object ref
                                                //      4. Load the field value
                                                //      5. Call dec ref count
                                                //      6. Switch value to store and object ref back again

                                                //USE A SWITCH STACK ITEMS OP!!

                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                }, TheScannerState);
                                                StackItem switchItem1 = TheScannerState.CurrentStackFrame.Stack.Pop();
                                                StackItem switchItem2 = TheScannerState.CurrentStackFrame.Stack.Pop();
                                                TheScannerState.CurrentStackFrame.Stack.Push(switchItem1);
                                                TheScannerState.CurrentStackFrame.Stack.Push(switchItem2);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Dup].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Dup
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldfld].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldfld,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                }, TheScannerState);
                                                switchItem1 = TheScannerState.CurrentStackFrame.Stack.Pop();
                                                switchItem2 = TheScannerState.CurrentStackFrame.Stack.Pop();
                                                TheScannerState.CurrentStackFrame.Stack.Push(switchItem1);
                                                TheScannerState.CurrentStackFrame.Stack.Push(switchItem2);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Stelem:
                                    case ILOps.ILOp.OpCodes.Stelem_Ref:
                                        {
                                            bool doDecrement = false;
                                            bool isRefOp = false;
                                            if ((ILOps.ILOp.OpCodes)anILOpInfo.opCode.Value == ILOps.ILOp.OpCodes.Stelem_Ref)
                                            {
                                                doDecrement = TheScannerState.CurrentStackFrame.Stack.Peek().isGCManaged;
                                                isRefOp = true;
                                            }
                                            else
                                            {
                                                int metadataToken = Utils.ReadInt32(anILOpInfo.ValueBytes, 0);
                                                Type elementType = aChunk.Method.Module.ResolveType(metadataToken);
                                                doDecrement = Utils.IsGCManaged(elementType);
                                            }

                                            if (doDecrement)
                                            {
                                                // Items on stack:
                                                //  - Array reference
                                                //  - Index
                                                //  - (New) Value to store
                                                //
                                                // We want to load the current value of the element at Index in the array
                                                //  for which we must duplicate the array ref and index
                                                // But first, we must remove the (new) value to store
                                                //  off the stack, while also storing it to put back
                                                //  on the stack after so the store can continue
                                                //
                                                // So:
                                                //      1. Switch (rotate) 1 times the top 3 values so that index is on top
                                                //      2. Duplicate the index
                                                //      3. Switch (rotate) 2 times the top 4 values so that array ref is on top
                                                //      4. Duplicate the array ref
                                                //      5. Switch (rotate) 4 times the top 5 values so that duplicate array ref and index are on top
                                                //      6. Do LdElem op to load existing element value
                                                //      7. Call GC.DecrementRefCount
                                                //      8. Switch (rotate) 1 times the top 3 values so that the stack is in its original state
                                                //      (9. Continue to increment ref count as normal)
                                                //
                                                // The following is a diagram of the stack manipulation occurring here:
                                                //      Key: A=Array ref, I=Index, V=Value to store, E=Loaded element
                                                //      Top-most stack item appears last
                                                //  
                                                //     1) Rotate x 1    2) Duplicate       3)  Rot x 2         4)  Dup
                                                //  A,I,V ---------> V,A,I ---------> V,A,I,I ---------> I,I,V,A ---------> I,I,V,A,A
                                                //
                                                //
                                                //          5) Rot x 4           6) Ldelem        7) Call GC (Dec)
                                                //  I,I,V,A,A ---------> I,V,A,A,I ---------> I,V,A,E ---------> I,V,A
                                                //
                                                //
                                                //      8) Rot x 1       9)  Dup         10) Call GC (Inc)
                                                //  I,V,A ---------> A,I,V ---------> A,I,V,V ---------> A,I,V

                                                #region 1.
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(3)
                                                }, TheScannerState);

                                                rotateStackItems(3, 1);
                                                #endregion
                                                #region 2.
                                                    asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Dup].Convert(new ILOpInfo()
                                                    {
                                                        opCode = System.Reflection.Emit.OpCodes.Dup
                                                    }, TheScannerState);
                                                #endregion
                                                #region 3.
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(4)
                                                }, TheScannerState);
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(4)
                                                }, TheScannerState);

                                                rotateStackItems(4, 2);
                                                #endregion
                                                #region 4.
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Dup].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Dup
                                                }, TheScannerState);
                                                #endregion
                                                #region 5.
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(5)
                                                }, TheScannerState);
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(5)
                                                }, TheScannerState);
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(5)
                                                }, TheScannerState);
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(5)
                                                }, TheScannerState);

                                                rotateStackItems(5, 4);
                                                #endregion
                                                #region 6.
                                                asm += "\r\n" + TargetILOps[isRefOp ? ILOps.ILOp.OpCodes.Ldelem_Ref : ILOps.ILOp.OpCodes.Ldelem].Convert(new ILOpInfo()
                                                {
                                                    opCode = isRefOp ? System.Reflection.Emit.OpCodes.Ldelem_Ref : System.Reflection.Emit.OpCodes.Ldelem,
                                                    ValueBytes = anILOpInfo.ValueBytes,
                                                    Position = anILOpInfo.Position
                                                }, TheScannerState);
                                                #endregion
                                                #region 7.
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);
                                                #endregion
                                                #region 8.
                                                asm += "\r\n" + StackSwitchOp.Convert(new ILOpInfo()
                                                {
                                                    ValueBytes = BitConverter.GetBytes(3)
                                                }, TheScannerState);

                                                rotateStackItems(3, 1);
                                                #endregion

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Starg:
                                        {
                                            Int16 index = Utils.ReadInt16(anILOpInfo.ValueBytes, 0);
                                            index -= (Int16)(!aChunk.Method.IsStatic ? 1 : 0);
                                            if (Utils.IsGCManaged(aChunk.Method.GetParameters()[index].ParameterType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldarg].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldarg,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                    case ILOps.ILOp.OpCodes.Starg_S:
                                        {
                                            Int16 index = (Int16)anILOpInfo.ValueBytes[0];
                                            index -= (Int16)(!aChunk.Method.IsStatic ? 1 : 0);
                                            if (Utils.IsGCManaged(aChunk.Method.GetParameters()[index].ParameterType))
                                            {
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Ldarg_S].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Ldarg_S,
                                                    ValueBytes = anILOpInfo.ValueBytes
                                                }, TheScannerState);
                                                asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                                {
                                                    opCode = System.Reflection.Emit.OpCodes.Call,
                                                    MethodToCall = TheScannerState.DecrementRefCountMethod
                                                }, TheScannerState);

                                                IncRefCount = true;
                                            }
                                        }
                                        break;
                                }

                                if(IncRefCount &&
                                   !TheScannerState.CurrentStackFrame.Stack.Peek().isNewGCObject)
                                {
                                    TheScannerState.CurrentStackFrame.Stack.Peek().isNewGCObject = false;

                                    asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Dup].Convert(new ILOpInfo()
                                    {
                                        opCode = System.Reflection.Emit.OpCodes.Dup
                                    }, TheScannerState);
                                    asm += "\r\n" + TargetILOps[ILOps.ILOp.OpCodes.Call].Convert(new ILOpInfo()
                                    {
                                        opCode = System.Reflection.Emit.OpCodes.Call,
                                        MethodToCall = TheScannerState.IncrementRefCountMethod
                                    }, TheScannerState);
                                }
                            }

                            #endregion

                            result.ASM.AppendLine("; " + anILOpInfo.opCode.Name); //DEBUG INFO

                            ILOps.ILOp TheIlOp = TargetILOps[(ILOps.ILOp.OpCodes)anILOpInfo.opCode.Value];

                            #region Debug

                            if (TheSettings.DebugBuild)
                            {
                                if (anILOpInfo.opCode.Name == "nop" && !aChunk.NoDebugOps)
                                {
                                    anILOpInfo.IsDebugOp = dbILOpInfo.IsDebugOp = true;
                                    dbILOpInfo.DebugOpMeta += "breakpoint;";
                                }
                                else
                                {
                                    dbILOpInfo.IsDebugOp = false;
                                }
                            }

                            #endregion

                            // Convert the IL op to ASM!
                            asm += "\r\n" + TheIlOp.Convert(anILOpInfo, TheScannerState);
                        }
                    }
                    {
                        // Append the new ASm to the result ASM :)
                        // See above (MethodStart op) for thow this code works.
                        string[] asmLines = asm.Replace("\r", "").Split("\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        int asmLineNum = addASMLineNum;
                        foreach (string asmLine in asmLines)
                        {
                            if (!asmLine.Split(';')[0].Trim().EndsWith(":"))
                            {
                                result.ASM.AppendLine(string.Format("{0}.IL_{1}_{2}:", MethodID, anILOpInfo.Position, asmLineNum));
                            }
                            result.ASM.AppendLine(asmLine);
                            asmLineNum++;
                        }
                        addASMLineNum = asmLineNum;
                    }

                    #region Debug

                    if (TheSettings.DebugBuild)
                    {
                        dbILOpInfo.ASMEndPos = anILOpInfo.ASMEndPos = result.ASM.Length;

                        DebugDatabase.AddILOpInfo(dbILOpInfo);
                    }

                    #endregion
                }
                catch(KeyNotFoundException)
                {
                    result.ASM.AppendLine("; ERROR! Target architecture does not support this IL op."); //DEBUG INFO
                    OutputError(new Exception("Target architecture does not support ILOp! Op type: " + anILOpInfo.opCode.Name + ", Op offset: " + anILOpInfo.Position.ToString("X2") + "\r\n" + methodSignature));
                }
                catch (Exception ex)
                {
                    result.ASM.AppendLine("; ERROR! ILScanner failed to process."); //DEBUG INFO
                    OutputError(new Exception("Could not process an ILOp! Op type: " + anILOpInfo.opCode.Name + ", Op offset: " + anILOpInfo.Position.ToString("X2") + "\r\n" + methodSignature, ex));
                }

                ASMStartPos = result.ASM.Length;
                addASMLineNum = 0;
            }

            #region Debug

            if (TheSettings.DebugBuild)
            {
                //Add debug info for local variables of this method
                int locIndex = 0;
                foreach (LocalVariable localItem in aChunk.LocalVariables)
                {
                    DB_LocalVariable dbLocalVar = new DB_LocalVariable();
                    dbLocalVar.BytesSize = localItem.sizeOnStackInBytes;
                    dbLocalVar.Id = Guid.NewGuid();
                    dbLocalVar.Index = locIndex;
                    //We always call ProcessType just in case we missed a type
                    //  when loading assemblies
                    dbLocalVar.TypeID = ProcessType(localItem.TheType).Id;
                    dbLocalVar.MethodID = dbMethod.Id;
                    DebugDatabase.AddLocalVariable(dbLocalVar);
                    locIndex++;
                }
            }

            #endregion

            return result;
        }
Ejemplo n.º 2
0
 partial void DeleteDB_ILOpInfo(DB_ILOpInfo instance);
Ejemplo n.º 3
0
		private void detach_DB_ILOpInfos(DB_ILOpInfo entity)
		{
			this.SendPropertyChanging();
			entity.DB_Method = null;
		}
Ejemplo n.º 4
0
 partial void InsertDB_ILOpInfo(DB_ILOpInfo instance);
Ejemplo n.º 5
0
 partial void UpdateDB_ILOpInfo(DB_ILOpInfo instance);
Ejemplo n.º 6
0
 /// <summary>
 /// Removes the specified IL op info from the database.
 /// <para>To Do's: See <see cref="RemoveMethod"/>'s to do's.</para>
 /// </summary>
 /// <param name="anILOpInfo">The entry to remove.</param>
 /// <remarks>
 /// <para>
 /// For the moment this method does no more than just directly remove
 /// the entry from the database.
 /// </para>
 /// <para>
 /// <see cref="SubmitChanges"/> must be called at some point after this
 /// method for changes to actually be submitted to the database.
 /// </para>
 /// </remarks>
 public static void RemoveILOpInfo(DB_ILOpInfo anILOpInfo)
 {
     DB.DB_ILOpInfos.DeleteOnSubmit(anILOpInfo);
 }
Ejemplo n.º 7
0
 /// <summary>
 /// Adds the pre-created IL op info to the database. All the entries's
 /// required parameters (i.e. ones which cannot be null) should 
 /// be set.
 /// <para>To Do's: See <see cref="AddMethod"/>'s to do's.</para>
 /// </summary>
 /// <param name="anILOpInfo">The entry to add.</param>
 /// <remarks>
 /// <para>
 /// For the moment this method does no more than just directly add
 /// the entry to the database.
 /// </para>
 /// <para>
 /// <see cref="SubmitChanges"/> must be called at some point after this
 /// method for changes to actually be submitted to the database.
 /// </para>
 /// </remarks>
 public static void AddILOpInfo(DB_ILOpInfo anILOpInfo)
 {
     anILOpInfo.ValueBytes = null;
     DB.DB_ILOpInfos.InsertOnSubmit(anILOpInfo);
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Loads the current line's IL Op info (assuming we aren't in a plugged method)
        /// </summary>
        private void LoadCurrentIlOp()
        {
            if(currentMethod != null && (!currentMethod.Plugged.HasValue || !currentMethod.Plugged.Value))
            {
                string currLabel = currentNearestMethodBasedLabel;
                try
                {
                    int pos = int.Parse(currLabel.Split('.')[1].Split('_')[1]);

                    IEnumerable<DB_ILOpInfo> PotIlOps = (from infos in currentMethod.DB_ILOpInfos
                                                         where (infos.Position == pos)
                                                         select infos);

                    if (PotIlOps.Count() > 0)
                    {
                        if (currentILOpInfo != null)
                        {
                            lastILOpInfo = currentILOpInfo;
                        }
                        currentILOpInfo = PotIlOps.First();
                    }
                }
                catch(IndexOutOfRangeException)
                {
                    //Not an unplugged method (somehow?) so not a valid name 
                    //so splitting fails
                    //Just ignore

                    if (currentILOpInfo != null)
                    {
                        lastILOpInfo = currentILOpInfo;
                    }
                    currentILOpInfo = null;
                }
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Sends a request for the brwak address.
        /// </summary>
        public void GetBreakAddress()
        {
            currentMethod = null;
            currentMethodASM = null;
            currentNearestLabels = null;
            currentNearestMethodBasedLabel = null;
            if (currentILOpInfo != null)
            {
                lastILOpInfo = currentILOpInfo;
            }
            currentILOpInfo = null;
            arguments = null;
            locals = null;
            currentCSLine = null;
            currentCSMethod = null;
            currentCSSymbol = null;

            TheSerial.Write((byte)DebugCommands.GetBreakAddress);
            WaitForCommand();
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Gets the assembler text for the specified IL Op.
        /// </summary>
        /// <param name="anILOp">The IL Op to get the ASM for.</param>
        /// <returns>The ASM text.</returns>
        public string GetILOpASM(DB_ILOpInfo anILOp)
        {
            string result = null;

            string methodASM = GetMethodASM(anILOp.DB_Method);
            result = methodASM.Substring(anILOp.ASMStartPos, anILOp.ASMEndPos - anILOp.ASMStartPos);

            return result;
        }