/// <summary> /// Creates a new instance of the <see cref="StackImbalanceException"/> class. /// </summary> /// <param name="body">The method body in which the inconsistency was detected.</param> /// <param name="offset">The offset at which the inconsistency was detected.</param> public StackImbalanceException(CilMethodBody body, int offset) : base(string.Format("Stack imbalance was detected at offset IL_{0:X4} in method body of {1}", offset, body.Owner)) { Body = body; Offset = offset; }
/// <summary> /// Creates a CIL method body from a raw CIL method body. /// </summary> /// <param name="method">The method that owns the method body.</param> /// <param name="rawBody">The raw method body.</param> /// <param name="operandResolver">The object instance to use for resolving operands of an instruction in the /// method body.</param> /// <returns>The method body.</returns> public static CilMethodBody FromRawMethodBody(MethodDefinition method, CilRawMethodBody rawBody, ICilOperandResolver operandResolver = null) { var result = new CilMethodBody(method); if (operandResolver is null) operandResolver = result; // Read raw instructions. var reader = new ByteArrayReader(rawBody.Code); var disassembler = new CilDisassembler(reader); result.Instructions.AddRange(disassembler.ReadAllInstructions()); // Read out extra metadata. if (rawBody is CilRawFatMethodBody fatBody) { result.MaxStack = fatBody.MaxStack; result.InitializeLocals = fatBody.InitLocals; ReadLocalVariables(method.Module, result, fatBody); ReadExceptionHandlers(fatBody, result); } else { result.MaxStack = 8; result.InitializeLocals = false; } // Resolve operands. foreach (var instruction in result.Instructions) instruction.Operand = ResolveOperand(result, instruction, operandResolver) ?? instruction.Operand; return result; }
/// <inheritdoc /> public DynamicCilOperandResolver(SerializedModuleDefinition contextModule, CilMethodBody methodBody, IList <object> tokens) : base(contextModule, methodBody) { _tokens = tokens ?? throw new ArgumentNullException(nameof(tokens)); _readerContext = contextModule.ReaderContext; _importer = new ReferenceImporter(contextModule); }
/// <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 ReadLocalVariables( ModuleDefinition module, CilMethodBody result, CilRawFatMethodBody fatBody) { if (fatBody.LocalVarSigToken != MetadataToken.Zero && module.TryLookupMember(fatBody.LocalVarSigToken, out var member) && member is StandAloneSignature { Signature : LocalVariablesSignature localVariablesSignature })
private static byte[] BuildRawCodeStream(IMetadataTokenProvider provider, CilMethodBody body) { using var codeStream = new MemoryStream(); var writer = new BinaryStreamWriter(codeStream); var assembler = new CilAssembler(writer, new CilOperandBuilder(provider)); assembler.WriteInstructions(body.Instructions); return(codeStream.ToArray()); }
private static object ResolveOperand(CilMethodBody methodBody, CilInstruction instruction, ICilOperandResolver resolver) { switch (instruction.OpCode.OperandType) { case CilOperandType.InlineBrTarget: case CilOperandType.ShortInlineBrTarget: return new CilInstructionLabel( methodBody.Instructions.GetByOffset(((ICilLabel) instruction.Operand).Offset)); case CilOperandType.InlineField: case CilOperandType.InlineMethod: case CilOperandType.InlineSig: case CilOperandType.InlineTok: case CilOperandType.InlineType: return resolver.ResolveMember((MetadataToken) instruction.Operand); case CilOperandType.InlineString: return resolver.ResolveString((MetadataToken) instruction.Operand); case CilOperandType.InlineSwitch: var result = new List<ICilLabel>(); var labels = (IEnumerable<ICilLabel>) instruction.Operand; foreach (var label in labels) { var target = methodBody.Instructions.GetByOffset(label.Offset); result.Add(target == null ? label : new CilInstructionLabel(target)); } return result; case CilOperandType.InlineVar: case CilOperandType.ShortInlineVar: return resolver.ResolveLocalVariable(Convert.ToInt32(instruction.Operand)); case CilOperandType.InlineArgument: case CilOperandType.ShortInlineArgument: return resolver.ResolveParameter(Convert.ToInt32(instruction.Operand)); case CilOperandType.InlineI: case CilOperandType.InlineI8: case CilOperandType.InlineNone: case CilOperandType.InlineR: case CilOperandType.ShortInlineI: case CilOperandType.ShortInlineR: return instruction.Operand; case CilOperandType.InlinePhi: throw new NotSupportedException(); default: throw new ArgumentOutOfRangeException(); } }
private static void ReadLocalVariables(ModuleDefinition module, CilMethodBody result, CilRawFatMethodBody fatBody) { if (fatBody.LocalVarSigToken != MetadataToken.Zero && module.TryLookupMember(fatBody.LocalVarSigToken, out var member) && member is StandAloneSignature signature && signature.Signature is LocalVariablesSignature localVariablesSignature) { foreach (var type in localVariablesSignature.VariableTypes) result.LocalVariables.Add(new CilLocalVariable(type)); } }
public CilMaxStackCalculator(CilMethodBody body) { _body = body ?? throw new ArgumentNullException(nameof(body)); if (_body.Instructions.Count > 0) { _agenda = new Stack <StackState>(); _recordedStackSizes = new int?[_body.Instructions.Count]; } else { _agenda = null; _recordedStackSizes = null; } }
/// <summary> /// Creates a CIL method body from a dynamic method. /// </summary> /// <param name="method">The method that owns the method body.</param> /// <param name="dynamicMethodObj">The Dynamic Method/Delegate/DynamicResolver.</param> /// <param name="operandResolver"> /// The object instance to use for resolving operands of an instruction in the /// method body. /// </param> /// <param name="importer"> /// The object instance to use for importing operands of an instruction in the /// method body. /// </param> /// <returns>The method body.</returns> public static CilMethodBody FromDynamicMethod( MethodDefinition method, object dynamicMethodObj, ICilOperandResolver operandResolver = null, ReferenceImporter importer = null) { if (!(method.Module is SerializedModuleDefinition module)) { throw new ArgumentException("Method body should reference a serialized module."); } var result = new CilMethodBody(method); operandResolver ??= new CilOperandResolver(method.Module, result); importer ??= new ReferenceImporter(method.Module); dynamicMethodObj = DynamicMethodHelper.ResolveDynamicResolver(dynamicMethodObj); //Get Runtime Fields var code = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_code"); var scope = FieldReader.ReadField <object>(dynamicMethodObj, "m_scope"); var tokenList = FieldReader.ReadField <List <object> >(scope, "m_tokens"); var localSig = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_localSignature"); var ehHeader = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_exceptionHeader"); var ehInfos = FieldReader.ReadField <IList <object> >(dynamicMethodObj, "m_exceptions"); // Read raw instructions. var reader = new ByteArrayReader(code); var disassembler = new CilDisassembler(reader); result.Instructions.AddRange(disassembler.ReadAllInstructions()); //Local Variables DynamicMethodHelper.ReadLocalVariables(result, method, localSig); //Exception Handlers DynamicMethodHelper.ReadReflectionExceptionHandlers(result, ehInfos, ehHeader, importer); // Resolve all operands. foreach (var instruction in result.Instructions) { instruction.Operand = DynamicMethodHelper.ResolveOperandReflection(module.ReaderContext, result, instruction, operandResolver, tokenList, importer) ?? instruction.Operand; } return(result); }
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 CilRawMethodBody BuildFatMethodBody(IMetadataTokenProvider provider, CilMethodBody body, byte[] code) { // Serialize local variables. MetadataToken token; if (body.LocalVariables.Count == 0) { token = MetadataToken.Zero; } else { var localVarSig = new LocalVariablesSignature(body.LocalVariables.Select(v => v.VariableType)); var standAloneSig = new StandAloneSignature(localVarSig); token = provider.GetStandAloneSignatureToken(standAloneSig); } var fatBody = new CilRawFatMethodBody(CilMethodBodyAttributes.Fat, (ushort)body.MaxStack, token, code); fatBody.InitLocals = body.InitializeLocals; // Build up EH table section. if (body.ExceptionHandlers.Count > 0) { fatBody.HasSections = true; bool needsFatFormat = body.ExceptionHandlers.Any(e => e.IsFat); var attributes = CilExtraSectionAttributes.EHTable; if (needsFatFormat) { attributes |= CilExtraSectionAttributes.FatFormat; } var rawSectionData = SerializeExceptionHandlers(provider, body.ExceptionHandlers, needsFatFormat); var section = new CilExtraSection(attributes, rawSectionData); fatBody.ExtraSections.Add(section); } return(fatBody); }
/// <summary> /// Creates a new instance of the <see cref="PhysicalCilOperandResolver"/> class. /// </summary> /// <param name="contextModule">The context module.</param> /// <param name="methodBody">The method body that references the operands.</param> public PhysicalCilOperandResolver(ModuleDefinition contextModule, CilMethodBody methodBody) { _contextModule = contextModule ?? throw new ArgumentNullException(nameof(contextModule)); _methodBody = methodBody ?? throw new ArgumentNullException(nameof(methodBody)); }
public CilLabelVerifier(CilMethodBody body) { _body = body ?? throw new ArgumentNullException(nameof(body)); _diagnostics = null; _cachedName = null; }
/// <summary> /// Determines the number of values that are popped from the stack by this instruction. /// </summary> /// <param name="instruction">The instruction.</param> /// <param name="parent">The method body that this instruction resides in. When passed on <c>null</c>, /// a method body of a System.Void method is assumed.</param> /// <returns>The number of values popped from the stack.</returns> /// <exception cref="ArgumentOutOfRangeException">Occurs when the instruction's operation code provides an /// invalid stack behaviour.</exception> public static int GetStackPopCount(this CilInstruction instruction, CilMethodBody parent) { return(GetStackPopCount(instruction, parent == null || (parent.Owner.Signature.ReturnType?.IsTypeOf("System", "Void")).GetValueOrDefault())); }
private static byte[] BuildRawCodeStream(MethodBodySerializationContext context, CilMethodBody body) { using var codeStream = new MemoryStream(); var bag = context.DiagnosticBag; var writer = new BinaryStreamWriter(codeStream); var assembler = new CilAssembler( writer, new CilOperandBuilder(context.TokenProvider, bag), body.Owner.SafeToString(), bag); assembler.WriteInstructions(body.Instructions); return(codeStream.ToArray()); }
/// <summary> /// Creates a new collection of CIL instructions stored in a method body. /// </summary> /// <param name="body">The method body that owns the collection.</param> public CilInstructionCollection(CilMethodBody body) { Owner = body ?? throw new ArgumentNullException(nameof(body)); }
/// <summary> /// Determines the number of values that are popped from the stack by this instruction. /// </summary> /// <param name="instruction">The instruction.</param> /// <param name="parent">The method body that this instruction resides in. When passed on <c>null</c>, /// a method body of a System.Void method is assumed.</param> /// <returns>The number of values popped from the stack.</returns> /// <exception cref="ArgumentOutOfRangeException">Occurs when the instruction's operation code provides an /// invalid stack behaviour.</exception> public static int GetStackPopCount(this CilInstruction instruction, CilMethodBody parent) => GetStackPopCount(instruction, parent == null || parent.Owner.Signature.ReturnType.IsTypeOf("System", "Void"));