private void WriteConstant(object constant)
 {
     if (constant == null)
     {
         _output.Write("nullref");
     }
     else
     {
         var typeName = DisassemblerHelpers.PrimitiveTypeName(constant.GetType().FullName);
         if (typeName != null && typeName != "string")
         {
             _output.Write(typeName);
             _output.Write('(');
             var cf = constant as float?;
             var cd = constant as double?;
             if (cf.HasValue && (float.IsNaN(cf.Value) || float.IsInfinity(cf.Value)))
             {
                 _output.Write("0x{0:x8}", BitConverter.ToInt32(BitConverter.GetBytes(cf.Value), 0));
             }
             else if (cd.HasValue && (double.IsNaN(cd.Value) || double.IsInfinity(cd.Value)))
             {
                 _output.Write("0x{0:x16}", BitConverter.DoubleToInt64Bits(cd.Value));
             }
             else
             {
                 DisassemblerHelpers.WriteOperand(_output, constant);
             }
             _output.Write(')');
         }
         else
         {
             DisassemblerHelpers.WriteOperand(_output, constant);
         }
     }
 }
        public void DisassembleField(FieldDefinition field)
        {
            _output.WriteDefinition(".field ", field);
            if (field.HasLayoutInfo)
            {
                _output.Write("[" + field.Offset + "] ");
            }
            WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, _fieldVisibility);
            const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;

            WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), _fieldAttributes);
            if (field.HasMarshalInfo)
            {
                WriteMarshalInfo(field.MarshalInfo);
            }
            field.FieldType.WriteTo(_output);
            _output.Write(' ');
            _output.Write(DisassemblerHelpers.Escape(field.Name));
            if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA)
            {
                _output.Write(" at I_{0:x8}", field.RVA);
            }
            if (field.HasConstant)
            {
                _output.Write(" = ");
                WriteConstant(field.Constant);
            }
            _output.WriteLine();
            if (field.HasCustomAttributes)
            {
                _output.MarkFoldStart();
                WriteAttributes(field.CustomAttributes);
                _output.MarkFoldEnd();
            }
        }
 private void WriteParameters(Collection <ParameterDefinition> parameters)
 {
     for (var i = 0; i < parameters.Count; i++)
     {
         var p = parameters[i];
         if (p.IsIn)
         {
             _output.Write("[in] ");
         }
         if (p.IsOut)
         {
             _output.Write("[out] ");
         }
         if (p.IsOptional)
         {
             _output.Write("[opt] ");
         }
         p.ParameterType.WriteTo(_output);
         _output.Write(' ');
         if (p.HasMarshalInfo)
         {
             WriteMarshalInfo(p.MarshalInfo);
         }
         _output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p);
         if (i < parameters.Count - 1)
         {
             _output.Write(',');
         }
         _output.WriteLine();
     }
 }
        private void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na)
        {
            var type = na.Argument.Type;

            if (type.MetadataType == MetadataType.Class || type.MetadataType == MetadataType.ValueType)
            {
                _output.Write("enum ");
                if (type.Scope != type.Module)
                {
                    _output.Write("class ");
                    _output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(type)));
                }
                else
                {
                    type.WriteTo(_output, ILNameSyntax.TypeName);
                }
            }
            else
            {
                type.WriteTo(_output);
            }
            _output.Write(' ');
            _output.Write(DisassemblerHelpers.Escape(na.Name));
            _output.Write(" = ");
            if (na.Argument.Value is string value)
            {
                // secdecls use special syntax for strings
                _output.Write("string('{0}')", TextWriterTokenWriter.ConvertString(value).Replace("'", "\'"));
            }
            else
            {
                WriteConstant(na.Argument.Value);
            }
        }
        public void WriteModuleHeader(ModuleDefinition module)
        {
            if (module.HasExportedTypes)
            {
                foreach (var exportedType in module.ExportedTypes)
                {
                    _output.Write(".class extern ");
                    if (exportedType.IsForwarder)
                    {
                        _output.Write("forwarder ");
                    }
                    _output.Write(exportedType.DeclaringType != null ? exportedType.Name : exportedType.FullName);
                    OpenBlock(false);
                    if (exportedType.DeclaringType != null)
                    {
                        _output.WriteLine(".class extern {0}", DisassemblerHelpers.Escape(exportedType.DeclaringType.FullName));
                    }
                    else
                    {
                        _output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name));
                    }
                    CloseBlock();
                }
            }

            _output.WriteLine(".module {0}", module.Name);
            _output.WriteLine("// MVID: {0}", module.Mvid.ToString("B").ToUpperInvariant());
            // TODO: imagebase, file alignment, stackreserve, subsystem
            _output.WriteLine(".corflags 0x{0:x} // {1}", module.Attributes, module.Attributes.ToString());

            WriteAttributes(module.CustomAttributes);
        }
 public void WriteAssemblyReferences(ModuleDefinition module)
 {
     foreach (var mref in module.ModuleReferences)
     {
         _output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(mref.Name));
     }
     foreach (var aref in module.AssemblyReferences)
     {
         _output.Write(".assembly extern ");
         if (aref.IsWindowsRuntime)
         {
             _output.Write("windowsruntime ");
         }
         _output.Write(DisassemblerHelpers.Escape(aref.Name));
         OpenBlock(false);
         if (aref.PublicKeyToken != null)
         {
             _output.Write(".publickeytoken = ");
             WriteBlob(aref.PublicKeyToken);
             _output.WriteLine();
         }
         if (aref.Version != null)
         {
             _output.WriteLine(".ver {0}:{1}:{2}:{3}", aref.Version.Major, aref.Version.Minor, aref.Version.Build, aref.Version.Revision);
         }
         CloseBlock();
     }
 }
        public void WriteAssemblyHeader(AssemblyDefinition asm)
        {
            _output.Write(".assembly ");
            if (asm.Name.IsWindowsRuntime)
            {
                _output.Write("windowsruntime ");
            }
            _output.Write(DisassemblerHelpers.Escape(asm.Name.Name));
            OpenBlock(false);
            WriteAttributes(asm.CustomAttributes);
            WriteSecurityDeclarations(asm);
            if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0)
            {
                _output.Write(".publickey = ");
                WriteBlob(asm.Name.PublicKey);
                _output.WriteLine();
            }
            if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None)
            {
                _output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm);
                if (asm.Name.HashAlgorithm == AssemblyHashAlgorithm.SHA1)
                {
                    _output.Write(" // SHA1");
                }
                _output.WriteLine();
            }
            var v = asm.Name.Version;

            if (v != null)
            {
                _output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision);
            }
            CloseBlock();
        }
Example #8
0
        private void WriteStructureHeader(ILStructure s)
        {
            switch (s.Type)
            {
            case ILStructureType.Loop:
                _output.Write("// loop start");
                if (s.LoopEntryPoint != null)
                {
                    _output.Write(" (head: ");
                    DisassemblerHelpers.WriteOffsetReference(_output, s.LoopEntryPoint);
                    _output.Write(')');
                }
                _output.WriteLine();
                break;

            case ILStructureType.Try:
                _output.WriteLine(".try");
                _output.WriteLine("{");
                break;

            case ILStructureType.Handler:
                switch (s.ExceptionHandler?.HandlerType)
                {
                case ExceptionHandlerType.Catch:
                case ExceptionHandlerType.Filter:
                    _output.Write("catch");
                    if (s.ExceptionHandler?.CatchType != null)
                    {
                        _output.Write(' ');
                        s.ExceptionHandler.CatchType.WriteTo(_output, ILNameSyntax.TypeName);
                    }
                    _output.WriteLine();
                    break;

                case ExceptionHandlerType.Finally:
                    _output.WriteLine("finally");
                    break;

                case ExceptionHandlerType.Fault:
                    _output.WriteLine("fault");
                    break;

                default:
                    throw new NotSupportedException();
                }
                _output.WriteLine("{");
                break;

            case ILStructureType.Filter:
                _output.WriteLine("filter");
                _output.WriteLine("{");
                break;

            default:
                throw new NotSupportedException();
            }
            _output.Indent();
        }
Example #9
0
 private void WriteTypeParameters(ITextOutput output, IGenericParameterProvider p)
 {
     if (p.HasGenericParameters)
     {
         output.Write('<');
         for (var i = 0; i < p.GenericParameters.Count; i++)
         {
             if (i > 0)
             {
                 output.Write(", ");
             }
             var gp = p.GenericParameters[i];
             if (gp.HasReferenceTypeConstraint)
             {
                 output.Write("class ");
             }
             else if (gp.HasNotNullableValueTypeConstraint)
             {
                 output.Write("valuetype ");
             }
             if (gp.HasDefaultConstructorConstraint)
             {
                 output.Write(".ctor ");
             }
             if (gp.HasConstraints)
             {
                 output.Write('(');
                 for (var j = 0; j < gp.Constraints.Count; j++)
                 {
                     if (j > 0)
                     {
                         output.Write(", ");
                     }
                     gp.Constraints[j].WriteTo(output, ILNameSyntax.TypeName);
                 }
                 output.Write(") ");
             }
             if (gp.IsContravariant)
             {
                 output.Write('-');
             }
             else if (gp.IsCovariant)
             {
                 output.Write('+');
             }
             output.Write(DisassemblerHelpers.Escape(gp.Name));
         }
         output.Write('>');
     }
 }
Example #10
0
        public void DisassembleEvent(EventDefinition ev)
        {
            // set current member

            _output.WriteDefinition(".event ", ev);
            WriteFlags(ev.Attributes, _eventAttributes);
            ev.EventType.WriteTo(_output, ILNameSyntax.TypeName);
            _output.Write(' ');
            _output.Write(DisassemblerHelpers.Escape(ev.Name));
            OpenBlock(false);
            WriteAttributes(ev.CustomAttributes);
            WriteNestedMethod(".addon", ev.AddMethod);
            WriteNestedMethod(".removeon", ev.RemoveMethod);
            WriteNestedMethod(".fire", ev.InvokeMethod);
            foreach (var method in ev.OtherMethods)
            {
                WriteNestedMethod(".other", method);
            }
            CloseBlock();
        }
Example #11
0
        public void DisassembleNamespace(string nameSpace, IEnumerable <TypeDefinition> types)
        {
            if (!string.IsNullOrEmpty(nameSpace))
            {
                _output.Write(".namespace " + DisassemblerHelpers.Escape(nameSpace));
                OpenBlock(false);
            }
            var oldIsInType = _isInType;

            _isInType = true;
            foreach (var td in types)
            {
                _cancellationToken.ThrowIfCancellationRequested();
                DisassembleType(td);
                _output.WriteLine();
            }
            if (!string.IsNullOrEmpty(nameSpace))
            {
                CloseBlock();
                _isInType = oldIsInType;
            }
        }
Example #12
0
        private void WriteSecurityDeclarations(ISecurityDeclarationProvider secDeclProvider)
        {
            if (!secDeclProvider.HasSecurityDeclarations)
            {
                return;
            }
            foreach (var secdecl in secDeclProvider.SecurityDeclarations)
            {
                _output.Write(".permissionset ");
                switch (secdecl.Action)
                {
                case SecurityAction.Request:
                    _output.Write("request");
                    break;

                case SecurityAction.Demand:
                    _output.Write("demand");
                    break;

                case SecurityAction.Assert:
                    _output.Write("assert");
                    break;

                case SecurityAction.Deny:
                    _output.Write("deny");
                    break;

                case SecurityAction.PermitOnly:
                    _output.Write("permitonly");
                    break;

                case SecurityAction.LinkDemand:
                    _output.Write("linkcheck");
                    break;

                case SecurityAction.InheritDemand:
                    _output.Write("inheritcheck");
                    break;

                case SecurityAction.RequestMinimum:
                    _output.Write("reqmin");
                    break;

                case SecurityAction.RequestOptional:
                    _output.Write("reqopt");
                    break;

                case SecurityAction.RequestRefuse:
                    _output.Write("reqrefuse");
                    break;

                case SecurityAction.PreJitGrant:
                    _output.Write("prejitgrant");
                    break;

                case SecurityAction.PreJitDeny:
                    _output.Write("prejitdeny");
                    break;

                case SecurityAction.NonCasDemand:
                    _output.Write("noncasdemand");
                    break;

                case SecurityAction.NonCasLinkDemand:
                    _output.Write("noncaslinkdemand");
                    break;

                case SecurityAction.NonCasInheritance:
                    _output.Write("noncasinheritance");
                    break;

                default:
                    _output.Write(secdecl.Action.ToString());
                    break;
                }
                _output.WriteLine(" = {");
                _output.Indent();
                for (var i = 0; i < secdecl.SecurityAttributes.Count; i++)
                {
                    var sa = secdecl.SecurityAttributes[i];
                    if (sa.AttributeType.Scope == sa.AttributeType.Module)
                    {
                        _output.Write("class ");
                        _output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(sa.AttributeType)));
                    }
                    else
                    {
                        sa.AttributeType.WriteTo(_output, ILNameSyntax.TypeName);
                    }
                    _output.Write(" = {");
                    if (sa.HasFields || sa.HasProperties)
                    {
                        _output.WriteLine();
                        _output.Indent();

                        foreach (var na in sa.Fields)
                        {
                            _output.Write("field ");
                            WriteSecurityDeclarationArgument(na);
                            _output.WriteLine();
                        }

                        foreach (var na in sa.Properties)
                        {
                            _output.Write("property ");
                            WriteSecurityDeclarationArgument(na);
                            _output.WriteLine();
                        }

                        _output.Unindent();
                    }
                    _output.Write('}');

                    if (i + 1 < secdecl.SecurityAttributes.Count)
                    {
                        _output.Write(',');
                    }
                    _output.WriteLine();
                }
                _output.Unindent();
                _output.WriteLine("}");
            }
        }
Example #13
0
        private void DisassembleMethodInternal(MethodDefinition method)
        {
            //    .method public hidebysig  specialname
            //               instance default class [mscorlib]System.IO.TextWriter get_BaseWriter ()  cil managed
            //

            //emit flags
            WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, _methodVisibility);
            WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, _methodAttributeFlags);
            if (method.IsCompilerControlled)
            {
                _output.Write("privatescope ");
            }

            if ((method.Attributes & MethodAttributes.PInvokeImpl) == MethodAttributes.PInvokeImpl)
            {
                _output.Write("pinvokeimpl");
                if (method.HasPInvokeInfo && method.PInvokeInfo != null)
                {
                    var info = method.PInvokeInfo;
                    _output.Write("(\"" + TextWriterTokenWriter.ConvertString(info.Module.Name) + "\"");

                    if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name)
                    {
                        _output.Write(" as \"" + TextWriterTokenWriter.ConvertString(info.EntryPoint) + "\"");
                    }

                    if (info.IsNoMangle)
                    {
                        _output.Write(" nomangle");
                    }

                    if (info.IsCharSetAnsi)
                    {
                        _output.Write(" ansi");
                    }
                    else if (info.IsCharSetAuto)
                    {
                        _output.Write(" autochar");
                    }
                    else if (info.IsCharSetUnicode)
                    {
                        _output.Write(" unicode");
                    }

                    if (info.SupportsLastError)
                    {
                        _output.Write(" lasterr");
                    }

                    if (info.IsCallConvCdecl)
                    {
                        _output.Write(" cdecl");
                    }
                    else if (info.IsCallConvFastcall)
                    {
                        _output.Write(" fastcall");
                    }
                    else if (info.IsCallConvStdCall)
                    {
                        _output.Write(" stdcall");
                    }
                    else if (info.IsCallConvThiscall)
                    {
                        _output.Write(" thiscall");
                    }
                    else if (info.IsCallConvWinapi)
                    {
                        _output.Write(" winapi");
                    }

                    _output.Write(')');
                }
                _output.Write(' ');
            }

            _output.WriteLine();
            _output.Indent();
            if (method.ExplicitThis)
            {
                _output.Write("instance explicit ");
            }
            else if (method.HasThis)
            {
                _output.Write("instance ");
            }

            //call convention
            // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
            WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, _callingConvention);

            //return type
            method.ReturnType.WriteTo(_output);
            _output.Write(' ');
            if (method.MethodReturnType.HasMarshalInfo)
            {
                WriteMarshalInfo(method.MethodReturnType.MarshalInfo);
            }

            _output.Write(method.IsCompilerControlled
                ? DisassemblerHelpers.Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8"))
                : DisassemblerHelpers.Escape(method.Name));

            WriteTypeParameters(_output, method);

            //( params )
            _output.Write(" (");
            if (method.HasParameters)
            {
                _output.WriteLine();
                _output.Indent();
                WriteParameters(method.Parameters);
                _output.Unindent();
            }
            _output.Write(") ");
            //cil managed
            WriteEnum(method.ImplAttributes & MethodImplAttributes.CodeTypeMask, _methodCodeType);
            _output.Write((method.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed
                ? "managed "
                : "unmanaged ");
            WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), _methodImpl);

            _output.Unindent();
            OpenBlock(defaultCollapsed: _isInType);
            WriteAttributes(method.CustomAttributes);
            if (method.HasOverrides)
            {
                foreach (var methodOverride in method.Overrides)
                {
                    _output.Write(".override method ");
                    methodOverride.WriteTo(_output);
                    _output.WriteLine();
                }
            }
            WriteParameterAttributes(0, method.MethodReturnType, method.MethodReturnType);
            foreach (var p in method.Parameters)
            {
                WriteParameterAttributes(p.Index + 1, p, p);
            }
            WriteSecurityDeclarations(method);

            if (method.HasBody)
            {
                // create IL code mappings - used in debugger
                _methodBodyDisassembler.Disassemble(method.Body);
            }

            CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));
        }
Example #14
0
        public void DisassembleType(TypeDefinition type)
        {
            // start writing IL
            _output.WriteDefinition(".class ", type);

            if ((type.Attributes & TypeAttributes.ClassSemanticMask) == TypeAttributes.Interface)
            {
                _output.Write("interface ");
            }
            WriteEnum(type.Attributes & TypeAttributes.VisibilityMask, _typeVisibility);
            WriteEnum(type.Attributes & TypeAttributes.LayoutMask, _typeLayout);
            WriteEnum(type.Attributes & TypeAttributes.StringFormatMask, _typeStringFormat);
            const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;

            WriteFlags(type.Attributes & ~masks, _typeAttributes);

            _output.Write(DisassemblerHelpers.Escape(type.DeclaringType != null ? type.Name : type.FullName));
            WriteTypeParameters(_output, type);
            _output.MarkFoldStart(defaultCollapsed: _isInType);
            _output.WriteLine();

            if (type.BaseType != null)
            {
                _output.Indent();
                _output.Write("extends ");
                type.BaseType.WriteTo(_output, ILNameSyntax.TypeName);
                _output.WriteLine();
                _output.Unindent();
            }
            if (type.HasInterfaces)
            {
                _output.Indent();
                for (var index = 0; index < type.Interfaces.Count; index++)
                {
                    if (index > 0)
                    {
                        _output.WriteLine(",");
                    }
                    _output.Write(index == 0 ? "implements " : "           ");
                    type.Interfaces[index].InterfaceType.WriteTo(_output, ILNameSyntax.TypeName);
                }
                _output.WriteLine();
                _output.Unindent();
            }

            _output.WriteLine("{");
            _output.Indent();
            var oldIsInType = _isInType;

            _isInType = true;
            WriteAttributes(type.CustomAttributes);
            WriteSecurityDeclarations(type);
            if (type.HasLayoutInfo)
            {
                _output.WriteLine(".pack {0}", type.PackingSize);
                _output.WriteLine(".size {0}", type.ClassSize);
                _output.WriteLine();
            }
            if (type.HasNestedTypes)
            {
                _output.WriteLine("// Nested Types");
                foreach (var nestedType in type.NestedTypes)
                {
                    _cancellationToken.ThrowIfCancellationRequested();
                    DisassembleType(nestedType);
                    _output.WriteLine();
                }
                _output.WriteLine();
            }
            if (type.HasFields)
            {
                _output.WriteLine("// Fields");
                foreach (var field in type.Fields)
                {
                    _cancellationToken.ThrowIfCancellationRequested();
                    DisassembleField(field);
                }
                _output.WriteLine();
            }
            if (type.HasMethods)
            {
                _output.WriteLine("// Methods");
                foreach (var m in type.Methods)
                {
                    _cancellationToken.ThrowIfCancellationRequested();
                    DisassembleMethod(m);
                    _output.WriteLine();
                }
            }
            if (type.HasEvents)
            {
                _output.WriteLine("// Events");
                foreach (var ev in type.Events)
                {
                    _cancellationToken.ThrowIfCancellationRequested();
                    DisassembleEvent(ev);
                    _output.WriteLine();
                }
                _output.WriteLine();
            }
            if (type.HasProperties)
            {
                _output.WriteLine("// Properties");
                foreach (var prop in type.Properties)
                {
                    _cancellationToken.ThrowIfCancellationRequested();
                    DisassembleProperty(prop);
                }
                _output.WriteLine();
            }
            CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName));
            _isInType = oldIsInType;
        }
Example #15
0
        public void Disassemble(MethodBody body)
        {
            // start writing IL code
            var method = body.Method;

            _output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA);
            _output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize);
            _output.WriteLine(".maxstack {0}", body.MaxStackSize);
            if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.Assembly.EntryPoint == method)
            {
                _output.WriteLine(".entrypoint");
            }

            if (method.Body.HasVariables)
            {
                _output.Write(".locals ");
                if (method.Body.InitLocals)
                {
                    _output.Write("init ");
                }
                _output.WriteLine("(");
                _output.Indent();
                foreach (var v in method.Body.Variables)
                {
                    _output.WriteDefinition("[" + v.Index + "] ", v);
                    v.VariableType.WriteTo(_output);
                    if (!string.IsNullOrEmpty(v.ToString()))
                    {
                        _output.Write(' ');
                        _output.Write(DisassemblerHelpers.Escape(v.ToString()));
                    }
                    if (v.Index + 1 < method.Body.Variables.Count)
                    {
                        _output.Write(',');
                    }
                    _output.WriteLine();
                }
                _output.Unindent();
                _output.WriteLine(")");
            }
            _output.WriteLine();

            if (_detectControlStructure && body.Instructions.Count > 0)
            {
                var inst          = body.Instructions[0];
                var branchTargets = GetBranchTargets(body.Instructions);
                WriteStructureBody(new ILStructure(body), branchTargets, ref inst);
            }
            else
            {
                foreach (var inst in method.Body.Instructions)
                {
                    inst.WriteTo(_output);
                    _output.WriteLine();
                }

                if (method.Body.HasExceptionHandlers)
                {
                    _output.WriteLine();
                    foreach (var eh in method.Body.ExceptionHandlers)
                    {
                        eh.WriteTo(_output);
                        _output.WriteLine();
                    }
                }
            }
        }