/// <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); }
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)); } } }
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(); } }