protected override ExceptionHandler readExceptionHandler() { var eh = new ExceptionHandler((ExceptionHandlerType)reader.ReadInt32()); int tryOffset = reader.ReadInt32(); eh.TryStart = getInstruction(tryOffset); eh.TryEnd = getInstructionOrNull(tryOffset + reader.ReadInt32()); int handlerOffset = reader.ReadInt32(); eh.HandlerStart = getInstruction(handlerOffset); eh.HandlerEnd = getInstructionOrNull(handlerOffset + reader.ReadInt32()); switch (eh.HandlerType) { case ExceptionHandlerType.Catch: eh.CatchType = (TypeReference)module.LookupToken(reader.ReadInt32()); break; case ExceptionHandlerType.Filter: eh.FilterStart = getInstruction(reader.ReadInt32()); break; case ExceptionHandlerType.Finally: case ExceptionHandlerType.Fault: default: reader.ReadInt32(); break; } return eh; }
public void InitForm(MethodDefinition md, int ehIndex) { if (_method == md && _ehIndex == ehIndex) return; _method = md; _ehIndex = ehIndex; if (_ehIndex < 0) { _eh = new ExceptionHandler(ExceptionHandlerType.Catch); _eh.CatchType = _method.Module.Import(typeof(System.Exception)); InitTypes(ExceptionHandlerType.Catch); } else { _eh = _method.Body.ExceptionHandlers[_ehIndex]; if(_eh.CatchType == null) _eh.CatchType = _method.Module.Import(typeof(System.Exception)); InitTypes(_eh.HandlerType); } txtCatchType.Text = _eh.CatchType.FullName; InsUtils.InitInstructionsCombobox(cboTryStart, _method, _eh.TryStart, ref instructionsStr); InsUtils.InitInstructionsCombobox(cboTryEnd, _method, _eh.TryEnd, ref instructionsStr); InsUtils.InitInstructionsCombobox(cboHandlerStart, _method, _eh.HandlerStart, ref instructionsStr); InsUtils.InitInstructionsCombobox(cboHandlerEnd, _method, _eh.HandlerEnd, ref instructionsStr); InsUtils.InitInstructionsCombobox(cboFilterStart, _method, _eh.FilterStart, ref instructionsStr); //InsUtils.InitInstructionsCombobox(cboFilterEnd, _method, _eh.FilterEnd, ref instructionsStr); }
private bool ThrowsGeneralException (ExceptionHandler exceptionHandler) { for (Instruction currentInstruction = exceptionHandler.HandlerStart; currentInstruction != exceptionHandler.HandlerEnd; currentInstruction = currentInstruction.Next) { if (currentInstruction.OpCode.Code == Code.Rethrow) return true; } return false; }
public ILBlock(ILBlockType type, int startOffset, int endOffset, Mono.Cecil.Cil.ExceptionHandler handler = null) { this.Children = new List <ILBlock>(); base(); this.Type = type; this.StartOffset = startOffset; this.EndOffset = endOffset; this.ExceptionHandler = handler; return; }
internal void Debug_RemoveExceptionHandler(ExceptionHandler eh, MethodBody mb) { var catchStart = mb.Instructions.IndexOf(eh.HandlerStart) - 1; var catchEnd = mb.Instructions.IndexOf(eh.HandlerEnd); for (var i = catchEnd - 1; i >= catchStart; i--) { mb.Instructions.RemoveAt(i); } mb.ExceptionHandlers.Remove(eh); }
private void ComputeExceptionHandlerData(Dictionary<int, ExceptionHandlerData> datas, ExceptionHandler handler) { ExceptionHandlerData data; if (!datas.TryGetValue(handler.TryStart.Offset, out data)) { data = new ExceptionHandlerData(this.ComputeRange(handler.TryStart, handler.TryEnd)); datas.Add(handler.TryStart.Offset, data); } this.ComputeExceptionHandlerData(data, handler); }
private static void ProcessMethod(AssemblyDefinition def, TypeDefinition type, MethodDefinition method) { if (!method.HasBody || method.Body.Instructions.Count < 1) return; var newHandler = new ExceptionHandler(ExceptionHandlerType.Catch); newHandler.TryStart = method.Body.Instructions[0]; newHandler.TryEnd = method.Body.Instructions[method.Body.Instructions.Count - 1]; // todo: add handler to body (create new static class to avoid code bloat) and register bounds with newHandler method.Body.ExceptionHandlers.Add(newHandler); }
string getExceptionString(ExceptionHandler ex) { var sb = new StringBuilder(); if (ex.TryStart != null) sb.Append(string.Format("TRY: {0}-{1}", getLabel(ex.TryStart), getLabel(ex.TryEnd))); if (ex.FilterStart != null) sb.Append(string.Format(", FILTER: {0}", getLabel(ex.FilterStart))); if (ex.HandlerStart != null) sb.Append(string.Format(", HANDLER: {0}-{1}", getLabel(ex.HandlerStart), getLabel(ex.HandlerEnd))); sb.Append(string.Format(", TYPE: {0}", ex.HandlerType)); if (ex.CatchType != null) sb.Append(string.Format(", CATCH: {0}", ex.CatchType)); return sb.ToString(); }
static string FormatHandlerType(ExceptionHandler handler) { var handler_type = handler.HandlerType; var type = handler_type.ToString ().ToLowerInvariant (); switch (handler_type) { case ExceptionHandlerType.Catch: return string.Format ("{0} {1}", type, handler.CatchType.FullName); case ExceptionHandlerType.Filter: throw new NotImplementedException (); default: return type; } }
private void ComputeExceptionHandlerData(ExceptionHandlerData data, ExceptionHandler handler) { BlockRange range = this.ComputeRange(handler.HandlerStart, handler.HandlerEnd); switch (handler.HandlerType) { case ExceptionHandlerType.Catch: data.Catches.Add(new CatchHandlerData(handler.CatchType, range)); break; case ExceptionHandlerType.Filter: throw new NotImplementedException(); case ExceptionHandlerType.Finally: data.FinallyRange = range; break; case ExceptionHandlerType.Fault: data.FaultRange = range; break; } }
static void patchXamarinFormsCoreDll(string path, string typeName, string methodName) { var assembly = AssemblyDefinition.ReadAssembly (path); ModuleDefinition module = assembly.MainModule; TypeDefinition mainClass = module.GetType (typeName); MethodDefinition method = mainClass.Methods.Single (m => m.Name == methodName); var printPath = Path.GetFileName (path.Replace ("\\", "/").Replace ("../", "")); Console.WriteLine (string.Format ("Patch {0}.dll: {1}: {2}", printPath, methodName, method.Body.ExceptionHandlers.Count > 0 ? "already done" : "patch now")); if (method.Body.ExceptionHandlers.Count == 0) { var il = method.Body.GetILProcessor (); var write = il.Create (OpCodes.Call, module.Import (typeof(Console).GetMethod ("WriteLine", new [] { typeof(object) }))); var ret = il.Create (OpCodes.Ret); var leave = il.Create (OpCodes.Leave, ret); il.InsertAfter (method.Body.Instructions.Last (), write); il.InsertAfter (write, leave); il.InsertAfter (leave, ret); var handler = new ExceptionHandler (ExceptionHandlerType.Catch) { TryStart = method.Body.Instructions.First (), TryEnd = write, HandlerStart = write, HandlerEnd = ret, CatchType = module.Import (typeof(Exception)), }; method.Body.ExceptionHandlers.Add (handler); string pathPatched = path + ".patched.dll"; assembly.Write (pathPatched); File.Copy (pathPatched, path, true); File.Delete (pathPatched); } }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; Module moduleFrom = method.Module; System.Reflection.MethodBody bodyFrom = method.GetMethodBody(); byte[] data = bodyFrom?.GetILAsByteArray(); if (data == null) { throw new NotSupportedException("Body-less method"); } MethodDefinition def = Definition; ModuleDefinition moduleTo = def.Module; Mono.Cecil.Cil.MethodBody bodyTo = def.Body; ILProcessor processor = bodyTo.GetILProcessor(); Type[] typeArguments = null; if (method.DeclaringType.IsGenericType) { typeArguments = method.DeclaringType.GetGenericArguments(); } Type[] methodArguments = null; if (method.IsGenericMethod) { methodArguments = method.GetGenericArguments(); } foreach (LocalVariableInfo info in bodyFrom.LocalVariables) { TypeReference type = moduleTo.ImportReference(info.LocalType); if (info.IsPinned) { type = new PinnedType(type); } bodyTo.Variables.Add(new VariableDefinition(type)); } using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) { while (reader.BaseStream.Position < reader.BaseStream.Length) { int offset = (int)reader.BaseStream.Position; Instruction instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; ReadOperand(reader, instr); bodyTo.Instructions.Add(instr); } } foreach (Instruction instr in bodyTo.Instructions) { switch (instr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instr.Operand = GetInstruction((int)instr.Operand); break; case OperandType.InlineSwitch: int[] offsets = (int[])instr.Operand; Instruction[] targets = new Instruction[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { targets[i] = GetInstruction(offsets[i]); } instr.Operand = targets; break; } } foreach (ExceptionHandlingClause clause in bodyFrom.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler((ExceptionHandlerType)clause.Flags); bodyTo.ExceptionHandlers.Add(handler); handler.TryStart = GetInstruction(clause.TryOffset); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : clause.CatchType == null ? null : moduleTo.ImportReference(clause.CatchType); } void ReadOperand(BinaryReader reader, Instruction instr) { int index, offs, length; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: instr.Operand = null; break; case OperandType.InlineSwitch: length = reader.ReadInt32(); offs = (int)reader.BaseStream.Position + (4 * length); int[] targets = new int[length]; for (int i = 0; i < length; i++) { targets[i] = reader.ReadInt32() + offs; } instr.Operand = targets; break; case OperandType.ShortInlineBrTarget: offs = reader.ReadSByte(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.InlineBrTarget: offs = reader.ReadInt32(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.ShortInlineI: instr.Operand = instr.OpCode == OpCodes.Ldc_I4_S ? reader.ReadSByte() : (object)reader.ReadByte(); break; case OperandType.InlineI: instr.Operand = reader.ReadInt32(); break; case OperandType.ShortInlineR: instr.Operand = reader.ReadSingle(); break; case OperandType.InlineR: instr.Operand = reader.ReadDouble(); break; case OperandType.InlineI8: instr.Operand = reader.ReadInt64(); break; case OperandType.InlineSig: throw new NotSupportedException("Parsing CallSites at runtime currently not supported"); case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: switch (moduleFrom.ResolveMember(reader.ReadInt32(), typeArguments, methodArguments)) { case Type i: instr.Operand = moduleTo.ImportReference(i); break; case FieldInfo i: instr.Operand = moduleTo.ImportReference(i); break; case MethodBase i: instr.Operand = moduleTo.ImportReference(i); break; } break; case OperandType.InlineType: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveType(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineMethod: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveMethod(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineField: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveField(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: index = instr.OpCode.OperandType == OperandType.ShortInlineVar ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = bodyTo.Variables[index]; break; case OperandType.InlineArg: case OperandType.ShortInlineArg: index = instr.OpCode.OperandType == OperandType.ShortInlineArg ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = def.Parameters[index]; break; case OperandType.InlinePhi: // No opcode seems to use this default: throw new NotSupportedException($"Unsupported opcode ${instr.OpCode.Name}"); } } Instruction GetInstruction(int offset) { int last = bodyTo.Instructions.Count - 1; if (offset < 0 || offset > bodyTo.Instructions[last].Offset) { return(null); } int min = 0; int max = last; while (min <= max) { int mid = min + ((max - min) / 2); Instruction instr = bodyTo.Instructions[mid]; if (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
void InjectUsingStatement(MethodBody methodBody, Instruction bodyStart, OpCode loadLocation, Instruction handlerEnd, Instruction leave) { var startFinally = Instruction.Create(loadLocation); var endFinally = Instruction.Create(OpCodes.Endfinally); methodBody.Instructions.Add(leave); methodBody.Instructions.Add(startFinally); methodBody.Instructions.Add(Instruction.Create(OpCodes.Brfalse_S, endFinally)); methodBody.Instructions.Add(Instruction.Create(loadLocation)); methodBody.Instructions.Add(Instruction.Create(OpCodes.Callvirt, ModuleDefinition.ImportReference(typeof(IDisposable).GetMethod("Dispose")))); methodBody.Instructions.Add(endFinally); var handler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = bodyStart, TryEnd = startFinally, HandlerStart = startFinally, HandlerEnd = handlerEnd }; methodBody.ExceptionHandlers.Add(handler); }
private void CopyExceptionHandlers(ExceptionHandler sourceHandler, Dictionary<Instruction, Instruction> instMap, MethodBody destBody) { var destHandler = new ExceptionHandler(sourceHandler.HandlerType) { CatchType = sourceHandler.CatchType != null ? Import(sourceHandler.CatchType) : null, FilterStart = MapInstructionSafe(instMap, sourceHandler.FilterStart), HandlerStart = MapInstructionSafe(instMap, sourceHandler.HandlerStart), HandlerEnd = MapInstructionSafe(instMap, sourceHandler.HandlerEnd), TryStart = MapInstructionSafe(instMap, sourceHandler.TryStart), TryEnd = MapInstructionSafe(instMap, sourceHandler.TryEnd) }; destBody.ExceptionHandlers.Add(destHandler); }
internal static void EncapsulateMethodBodyWithTryFinallyBlock(this ILProcessor ilProcessor, Instruction firstInstruction, Action <ILProcessor, Instruction> insertBeforReturn) { var body = ilProcessor.Body; if (body.Method.IsConstructor && !body.Method.IsStatic) { var ctor = GetFirstConstructorInstruction(body); if (ctor != null) { if (body.Instructions.IndexOf(ctor) > 2) { var lastInstruction = body.Instructions.Last(); var firtLDarg0BeforeCtor = ctor.GetFirstPreviousLdarg_0(); if (firstInstruction != firtLDarg0BeforeCtor) { EncapsulateWithTryCatch(ilProcessor, firstInstruction, firtLDarg0BeforeCtor); } if (ctor.GetFirstNotNopInstruction().Equals(lastInstruction)) { insertBeforReturn(ilProcessor, lastInstruction); return; } } if (firstInstruction.Next.OpCode != OpCodes.Nop) { firstInstruction = Instruction.Create(OpCodes.Nop); ilProcessor.InsertAfter(ctor, firstInstruction); } } } var returnStart = ilProcessor.FixReturns(); var beforeReturn = Instruction.Create(OpCodes.Endfinally); ilProcessor.InsertBefore(returnStart, beforeReturn); if (body.Instructions.First().Equals(firstInstruction)) { Instruction tryStart = Instruction.Create(OpCodes.Nop); ilProcessor.InsertBefore(firstInstruction, tryStart); } Instruction finallyStart = Instruction.Create(OpCodes.Nop); ilProcessor.InsertBefore(beforeReturn, finallyStart); insertBeforReturn(ilProcessor, beforeReturn); var handler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = firstInstruction, TryEnd = finallyStart, HandlerStart = finallyStart, HandlerEnd = returnStart, }; body.ExceptionHandlers.Add(handler); }
void ReadSection (MethodBody body, BinaryReader br) { br.BaseStream.Position += 3; br.BaseStream.Position &= ~3; byte flags = br.ReadByte (); if ((flags & (byte) MethodDataSection.FatFormat) == 0) { int length = br.ReadByte () / 12; br.ReadBytes (2); for (int i = 0; i < length; i++) { ExceptionHandler eh = new ExceptionHandler ( (ExceptionHandlerType) (br.ReadInt16 () & 0x7)); eh.TryStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ())); eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + Convert.ToInt32 (br.ReadByte ())); eh.HandlerStart = GetInstruction (body, Convert.ToInt32 (br.ReadInt16 ())); eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + Convert.ToInt32 (br.ReadByte ())); ReadExceptionHandlerEnd (eh, br, body); body.ExceptionHandlers.Add (eh); } } else { br.BaseStream.Position--; int length = (br.ReadInt32 () >> 8) / 24; if ((flags & (int) MethodDataSection.EHTable) == 0) br.ReadBytes (length * 24); for (int i = 0; i < length; i++) { ExceptionHandler eh = new ExceptionHandler ( (ExceptionHandlerType) (br.ReadInt32 () & 0x7)); eh.TryStart = GetInstruction (body, br.ReadInt32 ()); eh.TryEnd = GetInstruction (body, eh.TryStart.Offset + br.ReadInt32 ()); eh.HandlerStart = GetInstruction (body, br.ReadInt32 ()); eh.HandlerEnd = GetInstruction (body, eh.HandlerStart.Offset + br.ReadInt32 ()); ReadExceptionHandlerEnd (eh, br, body); body.ExceptionHandlers.Add (eh); } } if ((flags & (byte) MethodDataSection.MoreSects) != 0) ReadSection (body, br); }
// inline ? void ReadExceptionHandlers(int count, Func<int> read_entry, Func<int> read_length) { for (int i = 0; i < count; i++) { var handler = new ExceptionHandler ( (ExceptionHandlerType) (read_entry () & 0x7)); handler.TryStart = GetInstruction (read_entry ()); handler.TryEnd = GetInstruction (GetInstructionOffset (handler.TryStart) + read_length ()); handler.HandlerStart = GetInstruction (read_entry ()); handler.HandlerEnd = GetInstruction (GetInstructionOffset (handler.HandlerStart) + read_length ()); ReadExceptionHandlerSpecific (handler); if (handler.TryStart != null && handler.HandlerStart != null) this.body.ExceptionHandlers.Add (handler); } }
void WriteExceptionHandlerSpecific (ExceptionHandler handler) { switch (handler.HandlerType) { case ExceptionHandlerType.Catch: WriteMetadataToken (metadata.LookupToken (handler.CatchType)); break; case ExceptionHandlerType.Filter: WriteInt32 (handler.FilterStart.Offset); break; default: WriteInt32 (0); break; } }
protected ExceptionHandler CreateExceptionHandler() { try { var eh = new ExceptionHandler((ExceptionHandlerType) Types.SelectedItem); if (eh.HandlerType == ExceptionHandlerType.Filter) eh.FilterStart = FilterStart.SelectedOperand; eh.TryStart = TryStart.SelectedOperand; eh.TryEnd = TryEnd.SelectedOperand; eh.HandlerStart = HandlerStart.SelectedOperand; eh.HandlerEnd = HandlerEnd.SelectedOperand; if (CatchType.SelectedOperand != null) eh.CatchType = MethodDefinition.DeclaringType.Module.Import(CatchType.SelectedOperand); return eh; } catch (Exception) { MessageBox.Show(@"Reflexil is unable to create this exception handler"); return null; } }
void addExceptionHandler(ExceptionHandler handler) { if (handler == null) return; pushMember(handler.CatchType); }
public void Inject() { if (!IsInjected) { string logEndpoint = ConfigurationManager.AppSettings.AllKeys.Contains("Endpoint") ? ConfigurationManager.AppSettings["Endpoint"].Trim() : string.Empty; string logName = ConfigurationManager.AppSettings.AllKeys.Contains("LogName") ? ConfigurationManager.AppSettings["LogName"].Trim() : string.Empty; string environment = ConfigurationManager.AppSettings.AllKeys.Contains("Environment") ? ConfigurationManager.AppSettings["Environment"].Trim() : string.Empty; string ipaddress = "127.0.0.1"; //string applicationName,string logEndpoint,string logName,string environment,string ipaddress //DynamicMethod dynamicMethod=new DynamicMethod(); var il = _methodDefinition.Body.GetILProcessor(); var module = _methodDefinition.Module; var sourceInstructions = _methodDefinition.Body.Instructions.ToList(); int sourceInstCount = sourceInstructions.Count; var copyInstructionCount = _methodDefinition.ReturnType.FullName == typeof(void).FullName?sourceInstCount - 1:sourceInstCount - 2; var destInstructions = new List <Instruction>(); destInstructions.Add(il.Create(OpCodes.Nop)); destInstructions.Add(il.Create(OpCodes.Nop)); for (int i = 0; i < copyInstructionCount; i++) { if (sourceInstructions[i].OpCode != OpCodes.Br_S) { destInstructions.Add(sourceInstructions[i]); } } var startCatch = destInstructions.Count; //destInstructions.Add(il.Create(OpCodes.Leave_S, destInstructions[startCatch - 1])); destInstructions.Add(il.Create(OpCodes.Pop)); destInstructions.Add(il.Create(OpCodes.Nop)); if (_methodDefinition.ReturnType.FullName != typeof(void).FullName) { var defval = il.Create(OpCodes.Ldnull); var stloc = il.Create(OpCodes.Stloc_0); //var leaves = il.Create(OpCodes.Leave_S, stloc); destInstructions.Add(defval); destInstructions.Add(stloc); } else { destInstructions.Add(il.Create(OpCodes.Nop)); } //destInstructions.Add(leaves); int endCatchPos = destInstructions.Count; destInstructions.Add(il.Create(OpCodes.Nop)); if (_methodDefinition.ReturnType.FullName != typeof(void).FullName) { destInstructions.Add(sourceInstructions[sourceInstCount - 2]); } destInstructions.Add(sourceInstructions[sourceInstCount - 1]); var leaveInst = destInstructions[endCatchPos]; destInstructions.Insert(startCatch, il.Create(OpCodes.Leave_S, leaveInst)); destInstructions.Insert(endCatchPos + 1, il.Create(OpCodes.Leave_S, leaveInst)); //var write = il.Create(OpCodes.Call, module.Import(typeof(ExceptionExtension).GetMethod("WriteToLog"))); //il.InsertAfter(_methodDefinition.Body.Instructions.Last(), firstParam); //il.InsertAfter(firstParam, secondParam); //il.InsertAfter(secondParam, thirdParam); //il.InsertAfter(thirdParam, forthParam); //il.InsertAfter(forthParam, fifthParam); //il.InsertAfter(fifthParam, write); //il.InsertAfter(write, leave); var handler = new Mono.Cecil.Cil.ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = destInstructions[1], TryEnd = destInstructions[startCatch + 1], HandlerStart = destInstructions[startCatch + 1], HandlerEnd = destInstructions[endCatchPos + 2], CatchType = module.Import(typeof(Exception)), }; _methodDefinition.Body.Instructions.Clear(); foreach (var destInstruction in destInstructions) { _methodDefinition.Body.Instructions.Add(destInstruction); } _methodDefinition.Body.ExceptionHandlers.Add(handler); } }
internal static MethodBody Clone(MethodBody body, MethodDefinition parent, ImportContext context) { MethodBody nb = new MethodBody(parent); nb.MaxStack = body.MaxStack; nb.InitLocals = body.InitLocals; nb.CodeSize = body.CodeSize; CilWorker worker = nb.CilWorker; if (body.HasVariables) { foreach (VariableDefinition var in body.Variables) { nb.Variables.Add(new VariableDefinition( var.Name, var.Index, parent, context.Import(var.VariableType))); } } foreach (Instruction instr in body.Instructions) { Instruction ni = new Instruction(instr.OpCode); switch (instr.OpCode.OperandType) { case OperandType.InlineParam: case OperandType.ShortInlineParam: if (instr.Operand == body.Method.This) { ni.Operand = nb.Method.This; } else { int param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = parent.Parameters [param]; } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = body.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = nb.Variables [var]; break; case OperandType.InlineField: ni.Operand = context.Import((FieldReference)instr.Operand); break; case OperandType.InlineMethod: ni.Operand = context.Import((MethodReference)instr.Operand); break; case OperandType.InlineType: ni.Operand = context.Import((TypeReference)instr.Operand); break; case OperandType.InlineTok: if (instr.Operand is TypeReference) { ni.Operand = context.Import((TypeReference)instr.Operand); } else if (instr.Operand is FieldReference) { ni.Operand = context.Import((FieldReference)instr.Operand); } else if (instr.Operand is MethodReference) { ni.Operand = context.Import((MethodReference)instr.Operand); } break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: case OperandType.InlineSwitch: break; default: ni.Operand = instr.Operand; break; } worker.Append(ni); } for (int i = 0; i < body.Instructions.Count; i++) { Instruction instr = nb.Instructions [i]; Instruction oldi = body.Instructions [i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { Instruction [] olds = (Instruction [])oldi.Operand; Instruction [] targets = new Instruction [olds.Length]; for (int j = 0; j < targets.Length; j++) { targets [j] = GetInstruction(body, nb, olds [j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand); } } if (!body.HasExceptionHandlers) { return(nb); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.Type); neh.TryStart = GetInstruction(body, nb, eh.TryStart); neh.TryEnd = GetInstruction(body, nb, eh.TryEnd); neh.HandlerStart = GetInstruction(body, nb, eh.HandlerStart); neh.HandlerEnd = GetInstruction(body, nb, eh.HandlerEnd); switch (eh.Type) { case ExceptionHandlerType.Catch: neh.CatchType = context.Import(eh.CatchType); break; case ExceptionHandlerType.Filter: neh.FilterStart = GetInstruction(body, nb, eh.FilterStart); neh.FilterEnd = GetInstruction(body, nb, eh.FilterEnd); break; } nb.ExceptionHandlers.Add(neh); } return(nb); }
static void EmitDebugEpilogue(MethodDefinition wrapper, ILProcessor il, DebugVariables vars) { if (vars != null) { var disposeMethod = vars.ErrorHelperType.Methods.First( method => method.Name == "Dispose"); // Store then reload the result from the call var resultLocal = new VariableDefinition(wrapper.ReturnType); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Body.Variables.Add(resultLocal); il.Emit(OpCodes.Stloc, resultLocal); } // Special case End to turn on error checking. if (il.Body.Method.Name == "End") { il.Emit(OpCodes.Call, vars.Get_CurrentContext); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Conv_I1); il.Emit(OpCodes.Call, vars.Set_ErrorChecking); } // We need a NOP to set up the finally handler range correctly. var nopInstruction = Instruction.Create(OpCodes.Nop); var loadInstruction = Instruction.Create(OpCodes.Ldloca, vars.ErrorHelperLocal); var disposeInstruction = Instruction.Create(OpCodes.Call, disposeMethod); var endFinallyInstruction = Instruction.Create(OpCodes.Endfinally); var endTryInstruction = Instruction.Create(OpCodes.Leave, nopInstruction); il.Append(endTryInstruction); il.Append(loadInstruction); il.Append(disposeInstruction); il.Append(endFinallyInstruction); il.Append(nopInstruction); var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally); finallyHandler.TryStart = vars.BeginTry; finallyHandler.TryEnd = loadInstruction; finallyHandler.HandlerStart = loadInstruction; finallyHandler.HandlerEnd = nopInstruction; il.Body.ExceptionHandlers.Add(finallyHandler); if (resultLocal.VariableType.FullName != Program.TypeVoid.FullName) { il.Emit(OpCodes.Ldloc, resultLocal); } } }
static void EmitStringBuilderEpilogue(MethodDefinition wrapper, MethodDefinition native, ParameterDefinition parameter, MethodBody body, ILProcessor il) { var p = parameter.ParameterType; if (p.Name == "StringBuilder") { // void GetShaderInfoLog(..., StringBuilder foo) // try { // foo_sb_ptr = Marshal.AllocHGlobal(sb.Capacity + 1); -- already emitted // glGetShaderInfoLog(..., foo_sb_ptr); -- already emitted // MarshalPtrToStringBuilder(foo_sb_ptr, foo); // } // finally { // Marshal.FreeHGlobal(foo_sb_ptr); // } // Make sure we have imported BindingsBase::MasrhalPtrToStringBuilder and Marshal::FreeHGlobal var ptr_to_sb = wrapper.Module.Import(TypeBindingsBase.Methods.First(m => m.Name == "MarshalPtrToStringBuilder")); var free_hglobal = wrapper.Module.Import(TypeMarshal.Methods.First(m => m.Name == "FreeHGlobal")); var block = new ExceptionHandler(ExceptionHandlerType.Finally); block.TryStart = body.Instructions[0]; var variable_name = parameter.Name + " _sb_ptr"; var v = body.Variables.First(m => m.Name == variable_name); il.Emit(OpCodes.Ldloc, v.Index); il.Emit(OpCodes.Ldarg, parameter.Index); il.Emit(OpCodes.Call, ptr_to_sb); block.TryEnd = body.Instructions.Last(); block.HandlerStart = body.Instructions.Last(); il.Emit(OpCodes.Ldloc, v.Index); il.Emit(OpCodes.Call, free_hglobal); block.HandlerEnd = body.Instructions.Last(); } }
// FIXME: Clean up.. factor out functionality into smaller, better pieces? Remove some generated nops? protected virtual void CreateCoroutine() { // create coroutine method coroutine = new MethodDefinition ("Resume", Mono.Cecil.MethodAttributes.HideBySig | Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Virtual, module.TypeSystem.Void); var il = coroutine.Body.GetILProcessor (); // process the method we want to transform and... // 1) Replace all Ldarg, Starg opcodes with Ldfld, Stfld (argsFields) // 2) Replace all Ldloc, Stloc opcodes with Ldfld, Stfld (localsFields) // 3) Before Ret, add Future<T>.Value = ...; or Future.Status = FutureStatus.Fulfilled; // 4) Replace calls to Future.Wait or Thread.Yield with continuation // 5) Remove calls to Future<T>.op_Implicit preceeding Ret Visit (method); // remap the jumps- pass 1 (required because exception handling extracts some of these) MapAllInstructions (method.Body); // the whole body of the method must be an exception handler var exceptionType = module.Import (getException.ReturnType); var exception = new VariableDefinition (exceptionType); coroutine.Body.Variables.Add (exception); VariableDefinition skipFinallyBlocks = null; // add exception handlers int i = 0; var catchBlocks = new List<IList<Instruction>> (); var finallyBlocks = new List<IList<Instruction>> (); MethodDefinition finallyMethod = null; foreach (var eh in method.Body.ExceptionHandlers.OrderBy (e => e.TryStart.Offset).OrderBy (e => e.TryEnd.Offset)) { // set the next ePC to this handler block // we can get away with just setting an exception block selector (epc) // at the beginning of the block because jumps into the middle of a try block are not allowed // (see ECMA-335 12.4.2.8.2.7) InsertBefore (eh.TryStart, new Instruction [] { il.Create (OpCodes.Ldarg_0), il.Create (OpCodes.Ldarg_0), il.Create (OpCodes.Ldfld, epcFld), il.Create (OpCodes.Ldc_I8, 1L << i), il.Create (OpCodes.Or), il.Create (OpCodes.Stfld, epcFld) }); // clear the bit for this handler at end of try block // This awkward bit of code below is necessary because one handler's end can be another's start var clearEpc = new List<Instruction> () { il.Create (OpCodes.Ldarg_0), il.Create (OpCodes.Ldarg_0), il.Create (OpCodes.Ldfld, epcFld), il.Create (OpCodes.Ldc_I8, ~(1L << i)), il.Create (OpCodes.And), il.Create (OpCodes.Stfld, epcFld) }; if (eh.HandlerType == ExceptionHandlerType.Finally) { finallyMethod = new MethodDefinition ("$finally" + i, Mono.Cecil.MethodAttributes.Private, module.TypeSystem.Void); coroutineType.Methods.Add (finallyMethod); clearEpc.Add (il.Create (OpCodes.Ldarg_0)); clearEpc.Add (il.Create (OpCodes.Call, finallyMethod)); } InstructionMap.Insert (InstructionMap.IndexOfKey (eh.HandlerEnd), clearEpc [0], clearEpc); // have to fixup leaves from catch blocks to unset our epcs for handlers that are all in the same spot var lastHandler = method.Body.ExceptionHandlers.OrderBy (h => h.HandlerStart.Offset).LastOrDefault ((l, c) => l.HandlerEnd == c.HandlerStart, eh); var subsequent = lastHandler.HandlerEnd;//InstructionMap [lastHandler.HandlerEnd].FirstOrDefault (); //if (subsequent != null) MapInstructions (subsequent, clearEpc [0]); // extract the handler block var handlerBody = ExtractInstructionRange (eh.HandlerStart, clearEpc [0]); var block = new List<Instruction> (); //fixup common issue // FIXME: this solution is a kludge if (handlerBody [0].OpCode == OpCodes.Stfld) { handlerBody.Insert (0, il.Create (OpCodes.Stloc, exception)); handlerBody.Insert (1, il.Create (OpCodes.Ldarg_0)); handlerBody.Insert (2, il.Create (OpCodes.Ldloc, exception)); if (eh.CatchType.FullName != "System.Exception") handlerBody.Insert (3, il.Create (OpCodes.Isinst, eh.CatchType)); } var skip = il.Create (OpCodes.Nop); // check if our epc bit is set block.Add (il.Create (OpCodes.Ldarg_0)); block.Add (il.Create (OpCodes.Ldfld, epcFld)); block.Add (il.Create (OpCodes.Ldc_I8, 1L << i)); block.Add (il.Create (OpCodes.And)); block.Add (il.Create (OpCodes.Brfalse, skip)); // clear epc bits as we go block.Add (il.Create (OpCodes.Ldarg_0)); block.Add (il.Create (OpCodes.Ldarg_0)); block.Add (il.Create (OpCodes.Ldfld, epcFld)); block.Add (il.Create (OpCodes.Ldc_I8, ~(1L << i))); block.Add (il.Create (OpCodes.And)); block.Add (il.Create (OpCodes.Stfld, epcFld)); switch (eh.HandlerType) { case ExceptionHandlerType.Catch: // guard by exception type (only if it's more specifc than System.Exception) if (eh.CatchType.FullName != "System.Exception") { block.Add (il.Create (OpCodes.Dup)); block.Add (il.Create (OpCodes.Isinst, eh.CatchType)); block.Add (il.Create (OpCodes.Brfalse, skip)); block.Add (il.Create (OpCodes.Isinst, eh.CatchType)); } block.AddRange (handlerBody); block.Add (skip); catchBlocks.Add (block); break; //FIXME: Finally blocks need to be surrounded in try..catch! case ExceptionHandlerType.Finally: if (skipFinallyBlocks == null) { skipFinallyBlocks = new VariableDefinition (module.TypeSystem.Boolean); coroutine.Body.Variables.Add (skipFinallyBlocks); } // replace the endfinally with a ret (patching jumps of course :) subsequent = il.Create (OpCodes.Ret); handlerBody.RedirectJumps (handlerBody [handlerBody.Count - 1], subsequent); handlerBody.RemoveAt (handlerBody.Count - 1); handlerBody.Add (subsequent); // finalize our finally method var fil = finallyMethod.Body.GetILProcessor (); foreach (var inst in handlerBody) { fil.Append (inst); if (inst.OpCode == OpCodes.Dup && dupLoc != null) finallyMethod.Body.Variables.Add (dupLoc); } block.Add (il.Create (OpCodes.Ldarg_0)); block.Add (il.Create (OpCodes.Call, finallyMethod)); block.Add (skip); finallyBlocks.Add (block); break; default: throw new NotImplementedException ("Exception handler blocks of type: " + eh.HandlerType.ToString ()); } method.Body.ExceptionHandlers.Remove (eh); i++; } // add state machine var firstInst = il.Create (OpCodes.Ldarg_0); var loadPC = il.Create (OpCodes.Ldfld, pcFld); il.Append (firstInst); il.Append (loadPC); // add continuation jump table var jumpTable = new Mono.Cecil.Cil.Instruction [continuations.Count + 1]; jumpTable [0] = InstructionMap.First (kv => kv.Value.Count != 0).Value [0]; // add mapped new instructions foreach (var ci in InstructionMap) { foreach (var inst in ci.Value) il.Append (inst); } // create global catch/fault blocks var ehFirst = il.Create (OpCodes.Nop); il.Append (ehFirst); foreach (var block in catchBlocks) foreach (var inst in block) il.Append (inst); il.Emit (OpCodes.Stloc, exception); il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldloc, exception); il.Emit (OpCodes.Callvirt, module.Import (setException)); // if method is void-returning, we gotta throw it if (method.ReturnType.IsVoid ()) { il.Emit (OpCodes.Ldloc, exception); il.Emit (OpCodes.Throw); } il.Emit (OpCodes.Leave, ret); var globalEh = new ExceptionHandler (ExceptionHandlerType.Catch) { CatchType = exceptionType, TryStart = firstInst, TryEnd = ehFirst, HandlerStart = ehFirst }; coroutine.Body.ExceptionHandlers.Add (globalEh); var catchEhFirst = il.Create (OpCodes.Stloc, exception); var catchEh = new ExceptionHandler (ExceptionHandlerType.Catch) { CatchType = exceptionType, TryStart = ehFirst, TryEnd = catchEhFirst, HandlerStart = catchEhFirst, }; coroutine.Body.ExceptionHandlers.Add (catchEh); il.Append (catchEhFirst); il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldloc, exception); il.Emit (OpCodes.Callvirt, module.Import (setException)); // if method is void-returning, we gotta throw it if (method.ReturnType.IsVoid ()) { il.Emit (OpCodes.Ldloc, exception); il.Emit (OpCodes.Throw); } il.Emit (OpCodes.Leave, ret); if (finallyBlocks.Any ()) { ehFirst = il.Create (OpCodes.Ldloc, skipFinallyBlocks); il.Append (ehFirst); globalEh.HandlerEnd = ehFirst; catchEh.HandlerEnd = ehFirst; var endFinally = il.Create (OpCodes.Endfinally); il.Emit (OpCodes.Brtrue, endFinally); foreach (var block in finallyBlocks) foreach (var inst in block) il.Append (inst); il.Append (endFinally); globalEh = new ExceptionHandler (ExceptionHandlerType.Finally) { TryStart = firstInst, TryEnd = ehFirst, HandlerStart = ehFirst }; coroutine.Body.ExceptionHandlers.Add (globalEh); } else { catchEh.HandlerEnd = ret; } globalEh.HandlerEnd = ret; il.Append (ret); // add continuations i = 1; foreach (var continuation in continuations) { // set the next PC before the jump var inst = il.Create (OpCodes.Ldarg_0); // FIXME: Not as efficient as possible.. since continuation is a Ret we inserted, we had to redir jumps to it previously MapInstructions (continuation, inst); il.InsertBefore (continuation, inst); il.InsertBefore (continuation, il.Create (OpCodes.Ldc_I4, i)); il.InsertBefore (continuation, il.Create (OpCodes.Stfld, pcFld)); jumpTable [i++] = continuation.Next; if (skipFinallyBlocks != null) { il.InsertBefore (continuation, il.Create (OpCodes.Ldc_I4_1)); il.InsertBefore (continuation, il.Create (OpCodes.Stloc, skipFinallyBlocks)); } il.Replace (continuation, il.Create (OpCodes.Leave, ret)); } il.InsertAfter (loadPC, il.Create (OpCodes.Switch, jumpTable)); coroutine.Body.InitLocals = true; coroutine.Body.ComputeOffsetsAndMaxStack (); }
void ReadExceptionHandlerSpecific(ExceptionHandler handler) { switch (handler.HandlerType) { case ExceptionHandlerType.Catch: handler.CatchType = reader.LookupToken (ReadToken ()) as TypeReference; break; case ExceptionHandlerType.Filter: handler.FilterStart = GetInstruction (ReadInt32 ()); break; default: Advance (4); break; } }
/// <summary> /// Clone the given method body. /// </summary> /// <param name="bo">The original method body.</param> /// <param name="m">The method which will own the newly cloned method body.</param> /// <returns>A clone of the original method body.</returns> public static MethodBody Clone(this MethodBody bo, MethodDefinition m) { if (bo == null) { return(null); } MethodBody bc = new MethodBody(m); bc.MaxStackSize = bo.MaxStackSize; bc.InitLocals = bo.InitLocals; bc.LocalVarToken = bo.LocalVarToken; bc.Instructions.AddRange(bo.Instructions.Select(o => { Instruction c = Instruction.Create(OpCodes.Nop); c.OpCode = o.OpCode; c.Operand = o.Operand; c.Offset = o.Offset; return(c); })); foreach (Instruction c in bc.Instructions) { if (c.Operand is Instruction target) { c.Operand = bc.Instructions[bo.Instructions.IndexOf(target)]; } else if (c.Operand is Instruction[] targets) { c.Operand = targets.Select(i => bc.Instructions[bo.Instructions.IndexOf(i)]).ToArray(); } } bc.ExceptionHandlers.AddRange(bo.ExceptionHandlers.Select(o => { ExceptionHandler c = new ExceptionHandler(o.HandlerType); c.TryStart = o.TryStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.TryStart)]; c.TryEnd = o.TryEnd == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.TryEnd)]; c.FilterStart = o.FilterStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.FilterStart)]; c.HandlerStart = o.HandlerStart == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.HandlerStart)]; c.HandlerEnd = o.HandlerEnd == null ? null : bc.Instructions[bo.Instructions.IndexOf(o.HandlerEnd)]; c.CatchType = o.CatchType; return(c); })); bc.Variables.AddRange(bo.Variables.Select(o => { VariableDefinition c = new VariableDefinition(o.VariableType); return(c); })); #if !CECIL0_9 m.CustomDebugInformations.AddRange(bo.Method.CustomDebugInformations); // Abstract. TODO: Implement deep CustomDebugInformations copy. m.DebugInformation.SequencePoints.AddRange(bo.Method.DebugInformation.SequencePoints.Select(o => { SequencePoint c = new SequencePoint(bc.Instructions.FirstOrDefault(i => i.Offset == o.Offset), o.Document); c.StartLine = o.StartLine; c.StartColumn = o.StartColumn; c.EndLine = o.EndLine; c.EndColumn = o.EndColumn; return(c); })); #endif return(bc); }
public virtual DialogResult ShowDialog(MethodDefinition mdef, ExceptionHandler selected) { MethodDefinition = mdef; SelectedExceptionHandler = selected; return ShowDialog(); }
/// <summary> /// Generate a new DynamicMethod with which you can invoke the previous state. /// If the NativeDetour holds a reference to a managed method, a copy of the original method is returned. /// If the NativeDetour holds a reference to a native function, an "undo-call-redo" trampoline with a matching signature is returned. /// </summary> public MethodBase GenerateTrampoline(MethodBase signature = null) { MethodBase remoteTrampoline = OnGenerateTrampoline?.InvokeWhileNull <MethodBase>(this, signature); if (remoteTrampoline != null) { return(remoteTrampoline); } if (!IsValid) { throw new ObjectDisposedException(nameof(NativeDetour)); } if (_BackupMethod != null) { // If we're detouring an IL method and have an IL copy, invoke the IL copy. // Note that this ignores the passed signature. return(_BackupMethod); } /* * if (signature == null) * signature = _BackupMethod; */ if (signature == null) { throw new ArgumentNullException("A signature must be given if the NativeDetour doesn't hold a reference to a managed method."); } // Otherwise, undo the detour, call the method and reapply the detour. MethodBase methodCallable = Method; if (methodCallable == null) { methodCallable = DetourHelper.GenerateNativeProxy(Data.Method, signature); } Type returnType = (signature as MethodInfo)?.ReturnType ?? typeof(void); ParameterInfo[] args = signature.GetParameters(); Type[] argTypes = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { argTypes[i] = args[i].ParameterType; } using (DynamicMethodDefinition dmd = new DynamicMethodDefinition( $"Trampoline:Native<{Method?.GetID(simple: true) ?? ((long) Data.Method).ToString("X16")}>?{GetHashCode()}", returnType, argTypes )) { ILProcessor il = dmd.GetILProcessor(); ExceptionHandler eh = new ExceptionHandler(ExceptionHandlerType.Finally); il.Body.ExceptionHandlers.Add(eh); il.EmitDetourCopy(_BackupNative, Data.Method, Data.Type); // Store the return value in a local as we can't preserve the stack across exception block boundaries. VariableDefinition localResult = null; if (returnType != typeof(void)) { il.Body.Variables.Add(localResult = new VariableDefinition(il.Import(returnType))); } // Label blockTry = il.BeginExceptionBlock(); int instriTryStart = il.Body.Instructions.Count; for (int i = 0; i < argTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i); } if (methodCallable is MethodInfo) { il.Emit(OpCodes.Call, (MethodInfo)methodCallable); } else if (methodCallable is ConstructorInfo) { il.Emit(OpCodes.Call, (ConstructorInfo)methodCallable); } else { throw new NotSupportedException($"Method type {methodCallable.GetType().FullName} not supported."); } if (localResult != null) { il.Emit(OpCodes.Stloc, localResult); } il.Emit(OpCodes.Leave, (object)null); Instruction instrLeave = il.Body.Instructions[il.Body.Instructions.Count - 1]; // il.BeginFinallyBlock(); int instriTryEnd = il.Body.Instructions.Count; int instriFinallyStart = il.Body.Instructions.Count; // Reapply the detour even if the method threw an exception. il.EmitDetourApply(Data); // il.EndExceptionBlock(); int instriFinallyEnd = il.Body.Instructions.Count; Instruction instrLeaveTarget = null; if (localResult != null) { il.Emit(OpCodes.Ldloc, localResult); instrLeaveTarget = il.Body.Instructions[il.Body.Instructions.Count - 1]; } il.Emit(OpCodes.Ret); instrLeaveTarget = instrLeaveTarget ?? il.Body.Instructions[il.Body.Instructions.Count - 1]; instrLeave.Operand = instrLeaveTarget; // TODO: Are the exception handler indices correct? eh.TryStart = il.Body.Instructions[instriTryStart]; eh.TryEnd = il.Body.Instructions[instriTryEnd]; eh.HandlerStart = il.Body.Instructions[instriTryEnd]; eh.HandlerEnd = il.Body.Instructions[instriFinallyEnd]; return(dmd.Generate()); } }
internal static MethodBody Clone (MethodBody body, MethodDefinition parent, ImportContext context) { MethodBody nb = new MethodBody (parent); nb.MaxStack = body.MaxStack; nb.InitLocals = body.InitLocals; nb.CodeSize = body.CodeSize; foreach (VariableDefinition var in body.Variables) nb.Variables.Add (new VariableDefinition ( context.Import (var.VariableType))); foreach (Instruction instr in body.Instructions) { Instruction ni = new Instruction (instr.OpCode); switch (instr.OpCode.OperandType) { case OperandType.InlineParam : case OperandType.ShortInlineParam : int param = body.Method.Parameters.IndexOf ((ParameterDefinition) instr.Operand); ni.Operand = parent.Parameters [param]; break; case OperandType.InlineVar : case OperandType.ShortInlineVar : int var = body.Variables.IndexOf ((VariableDefinition) instr.Operand); ni.Operand = nb.Variables [var]; break; case OperandType.InlineField : ni.Operand = context.Import ((FieldReference) instr.Operand); break; case OperandType.InlineMethod : ni.Operand = context.Import ((MethodReference) instr.Operand); break; case OperandType.InlineType : ni.Operand = context.Import ((TypeReference) instr.Operand); break; case OperandType.InlineTok : if (instr.Operand is TypeReference) ni.Operand = context.Import ((TypeReference) instr.Operand); else if (instr.Operand is FieldReference) ni.Operand = context.Import ((FieldReference) instr.Operand); else if (instr.Operand is MethodReference) ni.Operand = context.Import ((MethodReference) instr.Operand); break; case OperandType.ShortInlineBrTarget : case OperandType.InlineBrTarget : break; default : ni.Operand = instr.Operand; break; } nb.Instructions.Add (ni); } for (int i = 0; i < body.Instructions.Count; i++) { Instruction instr = nb.Instructions [i]; if (instr.OpCode.OperandType != OperandType.ShortInlineBrTarget && instr.OpCode.OperandType != OperandType.InlineBrTarget) continue; instr.Operand = GetInstruction (body, nb, (Instruction) body.Instructions [i].Operand); } foreach (ExceptionHandler eh in body.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler (eh.Type); neh.TryStart = GetInstruction (body, nb, eh.TryStart); neh.TryEnd = GetInstruction (body, nb, eh.TryEnd); neh.HandlerStart = GetInstruction (body, nb, eh.HandlerStart); neh.HandlerEnd = GetInstruction (body, nb, eh.HandlerEnd); switch (eh.Type) { case ExceptionHandlerType.Catch : neh.CatchType = context.Import (eh.CatchType); break; case ExceptionHandlerType.Filter : neh.FilterStart = GetInstruction (body, nb, eh.FilterStart); neh.FilterEnd = GetInstruction (body, nb, eh.FilterEnd); break; } nb.ExceptionHandlers.Add (neh); } return nb; }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; Module moduleFrom = method.Module; System.Reflection.MethodBody bodyFrom = method.GetMethodBody(); byte[] data = bodyFrom?.GetILAsByteArray(); if (data == null) { throw new NotSupportedException("Body-less method"); } MethodDefinition def = Definition; ModuleDefinition moduleTo = def.Module; Mono.Cecil.Cil.MethodBody bodyTo = def.Body; ILProcessor processor = bodyTo.GetILProcessor(); Type[] typeArguments = null; if (method.DeclaringType.IsGenericType) { typeArguments = method.DeclaringType.GetGenericArguments(); } Type[] methodArguments = null; if (method.IsGenericMethod) { methodArguments = method.GetGenericArguments(); } foreach (LocalVariableInfo info in bodyFrom.LocalVariables) { TypeReference type = moduleTo.ImportReference(info.LocalType); if (info.IsPinned) { type = new PinnedType(type); } bodyTo.Variables.Add(new VariableDefinition(type)); } using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) { for (Instruction instr = null, prev = null; reader.BaseStream.Position < reader.BaseStream.Length; prev = instr) { int offset = (int)reader.BaseStream.Position; instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; if (prev != null) { prev.Next = instr; } instr.Previous = prev; ReadOperand(reader, instr); bodyTo.Instructions.Add(instr); } } foreach (Instruction instr in bodyTo.Instructions) { switch (instr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instr.Operand = GetInstruction((int)instr.Operand); break; case OperandType.InlineSwitch: int[] offsets = (int[])instr.Operand; Instruction[] targets = new Instruction[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { targets[i] = GetInstruction(offsets[i]); } instr.Operand = targets; break; } } foreach (ExceptionHandlingClause clause in bodyFrom.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler((ExceptionHandlerType)clause.Flags); bodyTo.ExceptionHandlers.Add(handler); handler.TryStart = GetInstruction(clause.TryOffset); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : clause.CatchType == null ? null : moduleTo.ImportReference(clause.CatchType); } void ReadOperand(BinaryReader reader, Instruction instr) { int index, offs, length; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: instr.Operand = null; break; case OperandType.InlineSwitch: length = reader.ReadInt32(); offs = (int)reader.BaseStream.Position + (4 * length); int[] targets = new int[length]; for (int i = 0; i < length; i++) { targets[i] = reader.ReadInt32() + offs; } instr.Operand = targets; break; case OperandType.ShortInlineBrTarget: offs = reader.ReadSByte(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.InlineBrTarget: offs = reader.ReadInt32(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.ShortInlineI: instr.Operand = instr.OpCode == OpCodes.Ldc_I4_S ? reader.ReadSByte() : (object)reader.ReadByte(); break; case OperandType.InlineI: instr.Operand = reader.ReadInt32(); break; case OperandType.ShortInlineR: instr.Operand = reader.ReadSingle(); break; case OperandType.InlineR: instr.Operand = reader.ReadDouble(); break; case OperandType.InlineI8: instr.Operand = reader.ReadInt64(); break; case OperandType.InlineSig: instr.Operand = moduleTo.ImportCallSite(moduleFrom, moduleFrom.ResolveSignature(reader.ReadInt32())); break; case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Any); break; case OperandType.InlineType: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Type); break; case OperandType.InlineMethod: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Method); break; case OperandType.InlineField: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Field); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: index = instr.OpCode.OperandType == OperandType.ShortInlineVar ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = bodyTo.Variables[index]; break; case OperandType.InlineArg: case OperandType.ShortInlineArg: index = instr.OpCode.OperandType == OperandType.ShortInlineArg ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = def.Parameters[index]; break; case OperandType.InlinePhi: // No opcode seems to use this default: throw new NotSupportedException($"Unsupported opcode ${instr.OpCode.Name}"); } } MemberReference ResolveTokenAs(int token, TokenResolutionMode resolveMode) { try { switch (resolveMode) { case TokenResolutionMode.Type: return(moduleTo.ImportReference(moduleFrom.ResolveType(token, typeArguments, methodArguments))); case TokenResolutionMode.Method: return(moduleTo.ImportReference(moduleFrom.ResolveMethod(token, typeArguments, methodArguments))); case TokenResolutionMode.Field: return(moduleTo.ImportReference(moduleFrom.ResolveField(token, typeArguments, methodArguments))); case TokenResolutionMode.Any: switch (moduleFrom.ResolveMember(token, typeArguments, methodArguments)) { case Type i: return(moduleTo.ImportReference(i)); case MethodBase i: return(moduleTo.ImportReference(i)); case FieldInfo i: return(moduleTo.ImportReference(i)); case var resolved: throw new NotSupportedException($"Invalid resolved member type {resolved.GetType()}"); } default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } catch (MissingMemberException) { // we could not resolve the method normally, so lets read the import table // but we can only do that if the module was loaded from disk // this can still throw if the assembly is a dynamic one, but if that's broken, you have bigger issues string filePath = moduleFrom.Assembly.Location; if (!File.Exists(filePath)) { // in this case, the fallback cannot be followed, and so throwing the original error gives the user information throw; } // TODO: make this cached somehow so its not read and re-opened a bunch using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filePath, new ReaderParameters { ReadingMode = ReadingMode.Deferred })) { ModuleDefinition module = assembly.Modules.First(m => m.Name == moduleFrom.Name); // this should only fail if the token itself is somehow wrong MemberReference reference = (MemberReference)module.LookupToken(token); // the explicit casts here are to throw if they are incorrect // normally the references would need to be imported, but moduleTo isn't written to anywhere switch (resolveMode) { case TokenResolutionMode.Type: return((TypeReference)reference); case TokenResolutionMode.Method: return((MethodReference)reference); case TokenResolutionMode.Field: return((FieldReference)reference); case TokenResolutionMode.Any: return(reference); default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } } } Instruction GetInstruction(int offset) { int last = bodyTo.Instructions.Count - 1; if (offset < 0 || offset > bodyTo.Instructions[last].Offset) { return(null); } int min = 0; int max = last; while (min <= max) { int mid = min + ((max - min) / 2); Instruction instr = bodyTo.Instructions[mid]; if (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
/// <summary> /// CopyMethod copies a method definition into a new copy which can be added /// to another module. /// </summary> /// <param name="method">The MethodDefinition to copy</param> /// <returns>A copy of the MethodDefinition</returns> public static MethodDefinition CopyMethod(MethodDefinition method) { MethodDefinition newMethod = new MethodDefinition(method.Name, method.Attributes, method.ReturnType); foreach (ParameterDefinition param in method.Parameters) { ParameterDefinition newParam = new ParameterDefinition(param.Name, param.Attributes, param.ParameterType); newMethod.Parameters.Add(newParam); } foreach (CustomAttribute attr in method.CustomAttributes) { CustomAttribute newAttr = new CustomAttribute(attr.Constructor); foreach (CustomAttributeArgument arg in attr.ConstructorArguments) { CustomAttributeArgument newArg = new CustomAttributeArgument(arg.Type, arg.Value); newAttr.ConstructorArguments.Add(newArg); } foreach (CustomAttributeNamedArgument arg in attr.Fields) { CustomAttributeNamedArgument newArg = new CustomAttributeNamedArgument(arg.Name, new CustomAttributeArgument(arg.Argument.Type, arg.Argument.Value)); newAttr.Fields.Add(newArg); } newMethod.CustomAttributes.Add(newAttr); } if (method.Body != null) { if (newMethod.Body == null) newMethod.Body = new MethodBody(newMethod); foreach (Instruction inst in method.Body.Instructions) { newMethod.Body.Instructions.Add(inst); } foreach (VariableDefinition var in method.Body.Variables) { VariableDefinition newVar = new VariableDefinition(var.Name, var.VariableType); newMethod.Body.Variables.Add(newVar); } foreach (ExceptionHandler handler in method.Body.ExceptionHandlers) { ExceptionHandler newHandler = new ExceptionHandler(handler.HandlerType); newHandler.HandlerStart = handler.HandlerStart; newHandler.HandlerEnd = handler.HandlerEnd; newHandler.TryStart = handler.TryStart; newHandler.TryEnd = handler.TryEnd; newHandler.FilterStart = handler.FilterStart; newHandler.CatchType = handler.CatchType; newMethod.Body.ExceptionHandlers.Add(newHandler); } newMethod.Body.InitLocals = method.Body.InitLocals; } return newMethod; }
bool JumpToErr(CodeBody body, StackFrame frame, Exception err) { var posnow = frame.GetCode(); List <Mono.Cecil.Cil.ExceptionHandler> ehs = new List <ExceptionHandler>(); Mono.Cecil.Cil.ExceptionHandler ehNear = null; int ehNearB = -1; foreach (var eh in body.bodyNative.ExceptionHandlers) { if (eh.HandlerType == ExceptionHandlerType.Catch) { Type ehtype = GetType(eh.CatchType).TypeForSystem; if (ehtype == err.GetType() || err.GetType().IsSubclassOf(ehtype)) //if(GetType(eh.CatchType)== environment.GetType(err.GetType())) { if (eh.TryStart.Offset <= posnow.Offset && eh.TryEnd.Offset >= posnow.Offset) { if (ehNear == null) { ehNear = eh;//第一个 ehNearB = GetBaseCount(ehtype, err.GetType()); } else { if (eh.TryStart.Offset > ehNear.TryStart.Offset || eh.TryEnd.Offset < ehNear.TryEnd.Offset)//范围更小 { ehNear = eh; ehNearB = GetBaseCount(ehtype, err.GetType()); } else if (eh.TryStart.Offset == ehNear.TryStart.Offset || eh.TryEnd.Offset == ehNear.TryEnd.Offset) //范围相等 { if (ehtype == err.GetType()) //类型一致,没有比这个更牛的了 { ehNear = eh; ehNearB = GetBaseCount(ehtype, err.GetType()); } else if (GetType(ehNear.CatchType).TypeForSystem == err.GetType())//上次找到的就是第一,不用比了 { continue; } else //比较上次找到的类型,和这次找到的类型的亲缘性; { int newehNearB = GetBaseCount(ehtype, err.GetType()); if (newehNearB == -1) { continue; } if (newehNearB < ehNearB) { ehNear = eh; ehNearB = newehNearB; } } } } ehs.Add(eh); } } } } if (ehNear != null) { frame.stackCalc.Push(err); frame.SetCodePos(ehNear.HandlerStart.Offset);// ._pos = ehNear.HandlerStart; RunCodeWithTry(body, frame); return(true); } return(false); }
internal ControlFlowNode(int blockIndex, ExceptionHandler exceptionHandler, ControlFlowNode endFinallyOrFaultNode) { BlockIndex = blockIndex; NodeType = endFinallyOrFaultNode != null ? ControlFlowNodeType.FinallyOrFaultHandler : ControlFlowNodeType.CatchHandler; ExceptionHandler = exceptionHandler; EndFinallyOrFaultNode = endFinallyOrFaultNode; Debug.Assert((exceptionHandler.HandlerType == ExceptionHandlerType.Finally || exceptionHandler.HandlerType == ExceptionHandlerType.Fault) == (endFinallyOrFaultNode != null)); Offset = exceptionHandler.HandlerStart.Offset; }
private ExceptionHandler Copy(DeepCopier copier, ExceptionHandler def) { var ret= new ExceptionHandler(def.HandlerType); if(def.CatchType != null) ret.CatchType = CopyReference(copier,def.CatchType); copier.Log("< ExceptionHandler "); copier.CopyAll(def,ret,ret,"CatchType"); return ret; }
void WriteHandlerSpecific (ExceptionHandler eh) { switch (eh.Type) { case ExceptionHandlerType.Catch : WriteToken (eh.CatchType.MetadataToken); break; case ExceptionHandlerType.Filter : m_codeWriter.Write ((uint) eh.FilterStart.Offset); break; default : m_codeWriter.Write (0); break; } }
public static MethodDefinition Inject(ModuleDefinition mod, MethodDefinition mtd) { MethodDefinition ret = new MethodDefinition(mtd.Name, mtd.Attributes, mod.TypeSystem.Void); ret.Attributes = mtd.Attributes; ret.ImplAttributes = mtd.ImplAttributes; if (mtd.IsPInvokeImpl) { ret.PInvokeInfo = mtd.PInvokeInfo; bool has = false; foreach (ModuleReference modRef in mod.ModuleReferences) if (modRef.Name == ret.PInvokeInfo.Module.Name) { has = true; ret.PInvokeInfo.Module = modRef; break; } if (!has) mod.ModuleReferences.Add(ret.PInvokeInfo.Module); } if (mtd.HasCustomAttributes) { foreach (CustomAttribute attr in mtd.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); ret.CustomAttributes.Add(nAttr); } } foreach (GenericParameter param in mtd.GenericParameters) { var p = new GenericParameter(param.Name, ret); if (param.HasCustomAttributes) { foreach (CustomAttribute attr in param.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); p.CustomAttributes.Add(nAttr); } } ret.GenericParameters.Add(p); } ret.ReturnType = ImportType(mtd.ReturnType, mod, ret, null); foreach (ParameterDefinition param in mtd.Parameters) { var p = new ParameterDefinition(param.Name, param.Attributes, ImportType(param.ParameterType, mod, ret, null)); if (param.HasCustomAttributes) { foreach (CustomAttribute attr in param.CustomAttributes) { CustomAttribute nAttr = new CustomAttribute(ImportMethod(attr.Constructor, mod, ret, null), attr.GetBlob()); p.CustomAttributes.Add(nAttr); } } ret.Parameters.Add(p); } if (mtd.HasBody) { MethodBody old = mtd.Body; MethodBody bdy = new MethodBody(ret); bdy.MaxStackSize = old.MaxStackSize; bdy.InitLocals = old.InitLocals; ILProcessor psr = bdy.GetILProcessor(); foreach (VariableDefinition var in old.Variables) bdy.Variables.Add(new VariableDefinition(var.Name, ImportType(var.VariableType, mod, ret, null))); foreach (Instruction inst in old.Instructions) { switch (inst.OpCode.OperandType) { case OperandType.InlineArg: case OperandType.ShortInlineArg: if (inst.Operand == old.ThisParameter) psr.Emit(inst.OpCode, bdy.ThisParameter); else { int param = mtd.Parameters.IndexOf(inst.Operand as ParameterDefinition); psr.Emit(inst.OpCode, ret.Parameters[param]); } break; case OperandType.InlineVar: case OperandType.ShortInlineVar: int var = old.Variables.IndexOf(inst.Operand as VariableDefinition); psr.Emit(inst.OpCode, bdy.Variables[var]); break; case OperandType.InlineField: psr.Emit(inst.OpCode, ImportField(inst.Operand as FieldReference, mod, null)); break; case OperandType.InlineMethod: if (inst.Operand == mtd) psr.Emit(inst.OpCode, ret); else psr.Emit(inst.OpCode, ImportMethod(inst.Operand as MethodReference, mod, ret, null)); break; case OperandType.InlineType: psr.Emit(inst.OpCode, ImportType(inst.Operand as TypeReference, mod, ret, null)); break; case OperandType.InlineTok: if (inst.Operand is TypeReference) psr.Emit(inst.OpCode, ImportType(inst.Operand as TypeReference, mod, ret, null)); else if (inst.Operand is FieldReference) psr.Emit(inst.OpCode, ImportField(inst.Operand as FieldReference, mod, null)); else if (inst.Operand is MethodReference) psr.Emit(inst.OpCode, ImportMethod(inst.Operand as MethodReference, mod, ret, null)); break; default: psr.Append(inst.Clone()); break; } } for (int i = 0; i < bdy.Instructions.Count; i++) { Instruction inst = bdy.Instructions[i]; Instruction o = old.Instructions[i]; if (inst.OpCode.OperandType == OperandType.InlineSwitch) { Instruction[] olds = (Instruction[])o.Operand; Instruction[] news = new Instruction[olds.Length]; for (int ii = 0; ii < news.Length; ii++) news[ii] = bdy.Instructions[old.Instructions.IndexOf(olds[ii])]; inst.Operand = news; } else if (inst.OpCode.OperandType == OperandType.ShortInlineBrTarget || inst.OpCode.OperandType == OperandType.InlineBrTarget) inst.Operand = bdy.Instructions[old.Instructions.IndexOf(inst.Operand as Instruction)]; } foreach (ExceptionHandler eh in old.ExceptionHandlers) { ExceptionHandler neh = new ExceptionHandler(eh.HandlerType); if (old.Instructions.IndexOf(eh.TryStart) != -1) neh.TryStart = bdy.Instructions[old.Instructions.IndexOf(eh.TryStart)]; if (old.Instructions.IndexOf(eh.TryEnd) != -1) neh.TryEnd = bdy.Instructions[old.Instructions.IndexOf(eh.TryEnd)]; if (old.Instructions.IndexOf(eh.HandlerStart) != -1) neh.HandlerStart = bdy.Instructions[old.Instructions.IndexOf(eh.HandlerStart)]; if (old.Instructions.IndexOf(eh.HandlerEnd) != -1) neh.HandlerEnd = bdy.Instructions[old.Instructions.IndexOf(eh.HandlerEnd)]; switch (eh.HandlerType) { case ExceptionHandlerType.Catch: neh.CatchType = ImportType(eh.CatchType, mod, ret, null); break; case ExceptionHandlerType.Filter: neh.FilterStart = bdy.Instructions[old.Instructions.IndexOf(eh.FilterStart)]; //neh.FilterEnd = bdy.Instructions[old.Instructions.IndexOf(eh.FilterEnd)]; break; } bdy.ExceptionHandlers.Add(neh); } ret.Body = bdy; } return ret; }
void ReadExceptionHandlerEnd (ExceptionHandler eh, BinaryReader br, MethodBody body) { switch (eh.Type) { case ExceptionHandlerType.Catch : MetadataToken token = new MetadataToken (br.ReadInt32 ()); eh.CatchType = m_reflectReader.GetTypeDefOrRef (token, new GenericContext (body.Method)); break; case ExceptionHandlerType.Filter : eh.FilterStart = GetInstruction (body, br.ReadInt32 ()); eh.FilterEnd = GetInstruction (body, eh.HandlerStart.Previous.Offset); break; default : br.ReadInt32 (); break; } }
public virtual DialogResult ShowDialog(MethodDefinition mdef, ExceptionHandler selected) { m_mdef = mdef; m_selectedexceptionhandler = selected; return base.ShowDialog(); }