예제 #1
0
파일: IL.cs 프로젝트: leo60228/ikdasm
        void WriteIL(LineWriter lw, MethodBase mb, MethodBody body, Type[] genericTypeArguments, Type[] genericMethodArguments)
        {
            ParameterInfo[] parameters = mb.GetParameters();
            int             level      = lw.Column;

            byte[] code = body.GetILAsByteArray();
            lw.GoToColumn(level);
            lw.WriteLine("// Code size       {0} (0x{0:x})", code.Length);
            lw.GoToColumn(level);
            lw.WriteLine(".maxstack  {0}", body.MaxStackSize);

            IList <LocalVariableInfo> locals = body.LocalVariables;

            if (locals.Count != 0)
            {
                lw.GoToColumn(level);
                lw.Write(".locals ");
                if (body.InitLocals)
                {
                    lw.Write("init ");
                }
                lw.Write("(");
                bool first = true;
                foreach (var local in locals)
                {
                    if (!first)
                    {
                        lw.WriteLine(",");
                        lw.GoToColumn(level + 9);
                    }
                    first = false;
                    WriteSignatureType(lw, local.LocalType, TypeLocation.Local);
                    if (local.IsPinned)
                    {
                        lw.Write(" pinned");
                    }
                    WriteCustomModifiers(lw, local.__GetCustomModifiers());
                    lw.Write(" V_{0}", local.LocalIndex);
                }
                lw.WriteLine(")");
            }

            var exceptions  = new List <ExceptionHandlingClause>();
            var exceptions2 = new List <ExceptionHandlingClause>();

            SortExceptions(body.ExceptionHandlingClauses, exceptions, exceptions2);

            Stack <ExceptionHandlingClause> activeExceptions = new Stack <ExceptionHandlingClause>();
            ExceptionHandlingClause         currentException = null;
            bool extraNewLine      = false;
            int  nextFlatException = 0;
            int  nextException     = 0;
            bool handler           = false;
            int  pos = 0;

            while (pos < code.Length)
            {
                if (extraNewLine)
                {
                    lw.WriteLine();
                    extraNewLine = false;
                }
                if (currentException != null)
                {
                    if (currentException.HandlerOffset == pos)
                    {
                        switch (currentException.Flags)
                        {
                        case ExceptionHandlingClauseOptions.Clause:
                            lw.GoToColumn(level - 2);
                            if (currentException.TryOffset + currentException.TryLength == pos)
                            {
                                lw.WriteLine("}  // end .try");
                            }
                            else
                            {
                                lw.WriteLine("}  // end handler");
                            }
                            lw.GoToColumn(level - 2);
                            lw.Write("catch ");
                            if (currentException.CatchType.__IsMissing || !currentException.CatchType.IsGenericType)
                            {
                                WriteTypeDefOrRef(lw, currentException.CatchType);
                            }
                            else
                            {
                                WriteSignatureType(lw, currentException.CatchType);
                            }
                            lw.WriteLine(" ");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("{");
                            handler = true;
                            break;

                        case ExceptionHandlingClauseOptions.Finally:
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("}  // end .try");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("finally");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("{");
                            break;

                        case ExceptionHandlingClauseOptions.Fault:
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("}  // end .try");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("fault");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("{");
                            break;

                        case ExceptionHandlingClauseOptions.Filter:
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("}  // end filter");
                            lw.GoToColumn(level - 2);
                            lw.WriteLine("{  // handler");
                            handler = true;
                            break;

                        default:
                            throw new Managed.Reflection.BadImageFormatException();
                        }
                    }
                    else if (currentException.FilterOffset == pos && pos != 0)
                    {
                        lw.GoToColumn(level - 2);
                        if (handler)
                        {
                            lw.WriteLine("}  // end handler");
                        }
                        else
                        {
                            lw.WriteLine("}  // end .try");
                        }
                        lw.GoToColumn(level - 2);
                        lw.WriteLine("filter");
                        lw.GoToColumn(level - 2);
                        lw.WriteLine("{");
                    }
                }
                while (nextException < exceptions.Count &&
                       exceptions[nextException].TryOffset == pos)
                {
                    activeExceptions.Push(currentException);
                    ExceptionHandlingClause prevException = currentException;
                    currentException = exceptions[nextException++];
                    if (prevException != null && currentException.TryOffset == prevException.TryOffset && currentException.TryLength == prevException.TryLength)
                    {
                        // another handler for the same block
                        continue;
                    }
                    handler = false;
                    lw.GoToColumn(level);
                    lw.WriteLine(".try");
                    lw.GoToColumn(level);
                    lw.WriteLine("{");
                    level += 2;
                }
                lw.GoToColumn(level);
                int currPos = pos;
                lw.Write("IL_{0:x4}:  ", pos);
                int   level1      = lw.Column;
                short opcodeValue = code[pos++];
                if (opcodeValue == 0xFE)
                {
                    opcodeValue = (short)(0xFE00 + code[pos++]);
                }
                OpCode opcode = opcodes[opcodeValue + 512];
                lw.Write("{0}", opcode.Name);
                switch (opcode.OperandType)
                {
                case OperandType.InlineNone:
                    break;

                case OperandType.InlineBrTarget:
                    lw.GoToColumn(level1 + 11);
                    lw.Write("IL_{0:x4}", ReadInt32(code, ref pos) + pos);
                    break;

                case OperandType.ShortInlineBrTarget:
                    lw.GoToColumn(level1 + 11);
                    lw.Write("IL_{0:x4}", (sbyte)code[pos++] + pos);
                    break;

                case OperandType.InlineMethod:
                {
                    lw.GoToColumn(level1 + 11);
                    int        token = ReadInt32(code, ref pos);
                    MethodBase methodOrConstructor = ResolveMethod(token, genericTypeArguments, genericMethodArguments);
                    if ((methodOrConstructor.CallingConvention & CallingConventions.Any) == CallingConventions.VarArgs)
                    {
                        CustomModifiers[] customModifiers;
                        Type[]            optionalParameterTypes = ResolveOptionalParameterTypes(token, genericTypeArguments, genericMethodArguments, out customModifiers);
                        WriteInlineMethod(lw, methodOrConstructor, optionalParameterTypes, customModifiers);
                    }
                    else
                    {
                        WriteInlineMethod(lw, methodOrConstructor, Type.EmptyTypes, null);
                    }
                }
                break;

                case OperandType.InlineField:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineField(lw, ResolveField(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments));
                    break;

                case OperandType.InlineI:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineI(lw, ReadInt32(code, ref pos));
                    break;

                case OperandType.InlineI8:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineI8(lw, ReadInt64(code, ref pos));
                    break;

                case OperandType.ShortInlineI:
                    lw.GoToColumn(level1 + 11);
                    lw.Write("{0}", (sbyte)code[pos++]);
                    break;

                case OperandType.InlineR:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineR(lw, ReadDouble(code, ref pos), false);
                    break;

                case OperandType.ShortInlineR:
                    lw.GoToColumn(level1 + 11);
                    WriteShortInlineR(lw, ReadSingle(code, ref pos), false);
                    break;

                case OperandType.InlineType:
                    if (opcode == OpCodes.Constrained)
                    {
                        // "constrained." is too long to fit in the opcode column
                        lw.Write(" ");
                    }
                    else
                    {
                        lw.GoToColumn(level1 + 11);
                    }
                    WriteInlineType(lw, ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments);
                    break;

                case OperandType.InlineTok:
                {
                    int token = ReadInt32(code, ref pos);
                    switch (token >> 24)
                    {
                    case 0x01:
                    case 0x02:
                        lw.GoToColumn(level1 + 11);
                        WriteTypeDefOrRef(lw, ResolveType(token, genericTypeArguments, genericMethodArguments));
                        break;

                    case 0x1B:
                    {
                        Type type = ResolveType(token, genericTypeArguments, genericMethodArguments);
                        if (type.IsGenericTypeDefinition)
                        {
                            // HACK because typeof(Foo<>).MakeGenericType(typeof(Foo<>).GetGenericArguments()) == typeof(Foo<>)
                            // we need to inflate the builder here
                            type = type.MakeGenericType(type.GetGenericArguments());
                        }
                        lw.GoToColumn(level1 + 11);
                        WriteSignatureType(lw, type);
                        break;
                    }

                    case 0x04:
                    case 0x06:
                    case 0x0A:
                    case 0x2B:
                    {
                        MemberInfo member = ResolveMember(token, genericTypeArguments, genericMethodArguments);
                        if (member is FieldInfo)
                        {
                            lw.GoToColumn(level1 + 11);
                            lw.Write("field ");
                            WriteInlineField(lw, (FieldInfo)member);
                        }
                        else
                        {
                            var mb1 = (MethodBase)member;
                            lw.GoToColumn(level1 + 11);
                            if (mb1.__IsMissing || !mb1.IsGenericMethod || compat != CompatLevel.V20)
                            {
                                lw.Write("method ");
                            }
                            WriteInlineMethod(lw, mb1, Type.EmptyTypes, null);
                        }
                        break;
                    }

                    default:
                        throw new NotImplementedException("token type = " + (token >> 24));
                    }
                }
                break;

                case OperandType.InlineVar:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineVar(lw, mb, opcode, parameters, ReadInt16(code, ref pos));
                    break;

                case OperandType.ShortInlineVar:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineVar(lw, mb, opcode, parameters, code[pos++]);
                    break;

                case OperandType.InlineString:
                    lw.GoToColumn(level1 + 11);
                    WriteInlineString(lw, module.ResolveString(ReadInt32(code, ref pos)), level);
                    break;

                case OperandType.InlineSwitch:
                {
                    lw.GoToColumn(level1 + 11);
                    lw.WriteLine("( ");
                    int count  = ReadInt32(code, ref pos);
                    int offset = pos + 4 * count;
                    for (int i = 0; i < count - 1; i++)
                    {
                        lw.GoToColumn(level + 22);
                        lw.WriteLine("IL_{0:x4},", offset + ReadInt32(code, ref pos));
                    }
                    lw.GoToColumn(level + 22);
                    lw.Write("IL_{0:x4})", offset + ReadInt32(code, ref pos));
                }
                break;

                case OperandType.InlineSig:
                    lw.GoToColumn(level1 + 11);
                    WriteStandAloneMethodSig(lw, module.__ResolveStandAloneMethodSig(ReadInt32(code, ref pos), genericTypeArguments, genericMethodArguments), false, false);
                    break;

                default:
                    throw new InvalidOperationException();
                }
                lw.WriteLine();

                if (opcode == OpCodes.Leave || opcode == OpCodes.Leave_S)
                {
                    if (pos < code.Length)
                    {
                        lw.WriteLine();
                    }
                }
                else if (opcode != OpCodes.Switch && opcode != OpCodes.Rethrow && opcode != OpCodes.Endfilter && opcode != OpCodes.Endfinally)
                {
                    switch (opcode.FlowControl)
                    {
                    case FlowControl.Branch:
                    case FlowControl.Cond_Branch:
                    case FlowControl.Throw:
                    case FlowControl.Return:
                        extraNewLine = true;
                        break;
                    }
                }
                if (nextFlatException < exceptions2.Count && exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength == currPos)
                {
                    if (extraNewLine && pos < code.Length)
                    {
                        extraNewLine = false;
                        lw.WriteLine();
                    }
                    lw.GoToColumn(level);
                    if (exceptions2[nextFlatException].FilterOffset == 0)
                    {
                        lw.Write(".try IL_{0:x4} to IL_{1:x4} catch ", exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength);
                        if (exceptions2[nextFlatException].CatchType.__IsMissing || !exceptions2[nextFlatException].CatchType.IsGenericType)
                        {
                            WriteTypeDefOrRef(lw, exceptions2[nextFlatException].CatchType);
                        }
                        else
                        {
                            WriteSignatureType(lw, exceptions2[nextFlatException].CatchType);
                        }
                        lw.WriteLine(" handler IL_{0:x4} to IL_{1:x4}", exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
                    }
                    else
                    {
                        lw.WriteLine(".try IL_{0:x4} to IL_{1:x4} filter IL_{2:x4} handler IL_{3:x4} to IL_{4:x4}",
                                     exceptions2[nextFlatException].TryOffset, exceptions2[nextFlatException].TryOffset + exceptions2[nextFlatException].TryLength,
                                     exceptions2[nextFlatException].FilterOffset,
                                     exceptions2[nextFlatException].HandlerOffset, exceptions2[nextFlatException].HandlerOffset + exceptions2[nextFlatException].HandlerLength);
                    }
                    nextFlatException++;
                }

                while (currentException != null && currentException.HandlerOffset + currentException.HandlerLength == pos)
                {
                    ExceptionHandlingClause prevException = currentException;
                    currentException = activeExceptions.Pop();
                    if (currentException == null || currentException.TryOffset != prevException.TryOffset || currentException.TryLength != prevException.TryLength)
                    {
                        if (extraNewLine && pos < code.Length)
                        {
                            extraNewLine = false;
                            lw.WriteLine();
                        }
                        level -= 2;
                        lw.GoToColumn(level);
                        lw.WriteLine("}  // end handler");
                        handler = false;
                    }
                    else
                    {
                        handler = true;
                    }
                }
            }
        }