/// <summary>
        /// Reads a single exception handler from the provided input stream.
        /// </summary>
        /// <param name="body">The method body containing the exception handler.</param>
        /// <param name="reader">The input stream.</param>
        /// <param name="isFat"><c>true</c> if the fat format should be used, <c>false</c> otherwise.</param>
        /// <returns>The exception handler.</returns>
        public static CilExceptionHandler FromReader(CilMethodBody body, IBinaryStreamReader reader, bool isFat)
        {
            CilExceptionHandlerType handlerType;
            int tryStartOffset;
            int tryEndOffset;
            int handlerStartOffset;
            int handlerEndOffset;

            // Read raw structure.
            if (isFat)
            {
                handlerType        = (CilExceptionHandlerType)reader.ReadUInt32();
                tryStartOffset     = reader.ReadInt32();
                tryEndOffset       = tryStartOffset + reader.ReadInt32();
                handlerStartOffset = reader.ReadInt32();
                handlerEndOffset   = handlerStartOffset + reader.ReadInt32();
            }
            else
            {
                handlerType        = (CilExceptionHandlerType)reader.ReadUInt16();
                tryStartOffset     = reader.ReadUInt16();
                tryEndOffset       = tryStartOffset + reader.ReadByte();
                handlerStartOffset = reader.ReadUInt16();
                handlerEndOffset   = handlerStartOffset + reader.ReadByte();
            }

            int exceptionTokenOrFilterStart = reader.ReadInt32();

            // Create handler.
            var handler = new CilExceptionHandler
            {
                HandlerType = handlerType,
                TryStart    = body.Instructions.GetByOffset(tryStartOffset)?.CreateLabel() ??
                              new CilOffsetLabel(tryStartOffset),
                TryEnd       = body.Instructions.GetByOffset(tryEndOffset)?.CreateLabel() ?? new CilOffsetLabel(tryEndOffset),
                HandlerStart = body.Instructions.GetByOffset(handlerStartOffset)?.CreateLabel() ??
                               new CilOffsetLabel(handlerStartOffset),
                HandlerEnd = body.Instructions.GetByOffset(handlerEndOffset)?.CreateLabel() ??
                             new CilOffsetLabel(handlerEndOffset),
            };

            // Interpret last field.
            switch (handler.HandlerType)
            {
            case CilExceptionHandlerType.Exception when body.Owner.Module.TryLookupMember(exceptionTokenOrFilterStart, out var member):
                handler.ExceptionType = member as ITypeDefOrRef;

                break;

            case CilExceptionHandlerType.Filter:
                handler.FilterStart = body.Instructions.GetByOffset(exceptionTokenOrFilterStart)?.CreateLabel()
                                      ?? new CilOffsetLabel(exceptionTokenOrFilterStart);
                break;;
            }

            return(handler);
        }
Ejemplo n.º 2
0
        private static void ReadExceptionHandlers(CilRawFatMethodBody fatBody, CilMethodBody result)
        {
            foreach (var section in fatBody.ExtraSections)
            {
                if (section.IsEHTable)
                {
                    var reader = new ByteArrayReader(section.Data);
                    int size = section.IsFat
                        ? CilExceptionHandler.FatExceptionHandlerSize
                        : CilExceptionHandler.TinyExceptionHandlerSize;

                    while (reader.CanRead(size))
                        result.ExceptionHandlers.Add(CilExceptionHandler.FromReader(result, reader, section.IsFat));
                }
            }
        }
Ejemplo n.º 3
0
        private void WriteExceptionHandler(MethodBodySerializationContext context, IBinaryStreamWriter writer, CilExceptionHandler handler, bool useFatFormat)
        {
            if (handler.IsFat && !useFatFormat)
            {
                throw new InvalidOperationException("Can only serialize fat exception handlers in fat format.");
            }

            // Write handler type and boundaries.
            if (useFatFormat)
            {
                writer.WriteUInt32((uint)handler.HandlerType);
                writer.WriteUInt32((uint)handler.TryStart.Offset);
                writer.WriteUInt32((uint)(handler.TryEnd.Offset - handler.TryStart.Offset));
                writer.WriteUInt32((uint)handler.HandlerStart.Offset);
                writer.WriteUInt32((uint)(handler.HandlerEnd.Offset - handler.HandlerStart.Offset));
            }
            else
            {
                writer.WriteUInt16((ushort)handler.HandlerType);
                writer.WriteUInt16((ushort)handler.TryStart.Offset);
                writer.WriteByte((byte)(handler.TryEnd.Offset - handler.TryStart.Offset));
                writer.WriteUInt16((ushort)handler.HandlerStart.Offset);
                writer.WriteByte((byte)(handler.HandlerEnd.Offset - handler.HandlerStart.Offset));
            }

            // Write handler type or filter start.
            switch (handler.HandlerType)
            {
            case CilExceptionHandlerType.Exception:
            {
                var provider = context.TokenProvider;

                var token = handler.ExceptionType switch
                {
                    TypeReference typeReference => provider.GetTypeReferenceToken(typeReference),
                    TypeDefinition typeDefinition => provider.GetTypeDefinitionToken(typeDefinition),
                    TypeSpecification typeSpecification => provider.GetTypeSpecificationToken(typeSpecification),
                    _ => context.DiagnosticBag.RegisterExceptionAndReturnDefault <MetadataToken>(
                        new ArgumentOutOfRangeException(
                            $"Invalid or unsupported exception type ({handler.ExceptionType.SafeToString()})"))
                };
                writer.WriteUInt32(token.ToUInt32());
                break;
            }

            case CilExceptionHandlerType.Filter:
                writer.WriteUInt32((uint)handler.FilterStart.Offset);
                break;

            case CilExceptionHandlerType.Finally:
            case CilExceptionHandlerType.Fault:
                writer.WriteUInt32(0);
                break;

            default:
                context.DiagnosticBag.RegisterException(new ArgumentOutOfRangeException(
                                                            $"Invalid or unsupported handler type ({handler.HandlerType.SafeToString()}"));
                break;
            }
        }
        private void WriteExceptionHandler(IMetadataTokenProvider provider, IBinaryStreamWriter writer, CilExceptionHandler handler, bool useFatFormat)
        {
            if (handler.IsFat && !useFatFormat)
            {
                throw new InvalidOperationException("Can only serialize fat exception handlers in fat format.");
            }

            // Write handler type and boundaries.
            if (useFatFormat)
            {
                writer.WriteUInt32((uint)handler.HandlerType);
                writer.WriteUInt32((uint)handler.TryStart.Offset);
                writer.WriteUInt32((uint)(handler.TryEnd.Offset - handler.TryStart.Offset));
                writer.WriteUInt32((uint)handler.HandlerStart.Offset);
                writer.WriteUInt32((uint)(handler.HandlerEnd.Offset - handler.HandlerStart.Offset));
            }
            else
            {
                writer.WriteUInt16((ushort)handler.HandlerType);
                writer.WriteUInt16((ushort)handler.TryStart.Offset);
                writer.WriteByte((byte)(handler.TryEnd.Offset - handler.TryStart.Offset));
                writer.WriteUInt16((ushort)handler.HandlerStart.Offset);
                writer.WriteByte((byte)(handler.HandlerEnd.Offset - handler.HandlerStart.Offset));
            }

            // Write handler type or filter start.
            switch (handler.HandlerType)
            {
            case CilExceptionHandlerType.Exception:
            {
                var token = handler.ExceptionType switch
                {
                    TypeReference typeReference => provider.GetTypeReferenceToken(typeReference),
                    TypeDefinition typeDefinition => provider.GetTypeDefinitionToken(typeDefinition),
                    TypeSpecification typeSpecification => provider.GetTypeSpecificationToken(typeSpecification),
                    _ => throw new ArgumentOutOfRangeException()
                };
                writer.WriteUInt32(token.ToUInt32());
                break;
            }

            case CilExceptionHandlerType.Filter:
                writer.WriteUInt32((uint)handler.FilterStart.Offset);
                break;

            case CilExceptionHandlerType.Finally:
            case CilExceptionHandlerType.Fault:
                writer.WriteUInt32(0);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }