public static string GetLabel(MethodInfo aMethod, ILOpCode aOpCode) { return GetLabel(aMethod, aOpCode.Position); }
// This is called execute and not assemble, as the scanner // could be used for other things, profiling, analysis, reporting, etc public abstract void Execute(MethodInfo aMethod, ILOpCode aOpCode);
public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup, string aJumpTargetNoException = null) { if (aJumpTargetNoException == null) { aJumpTargetNoException = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.NextPosition); } string xJumpTo = null; if (aCurrentOpCode != null && aCurrentOpCode.CurrentExceptionHandler != null) { // todo add support for nested handlers, see comment in Engine.cs //if (!((aMethodInfo.CurrentHandler.HandlerOffset < aCurrentOpOffset) || (aMethodInfo.CurrentHandler.HandlerLength + aMethodInfo.CurrentHandler.HandlerOffset) <= aCurrentOpOffset)) { new Comment(String.Format("CurrentOffset = {0}, HandlerStartOffset = {1}", aCurrentOpCode.Position, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset)); if (aCurrentOpCode.CurrentExceptionHandler.HandlerOffset > aCurrentOpCode.Position) { switch (aCurrentOpCode.CurrentExceptionHandler.Flags) { case ExceptionHandlingClauseOptions.Clause: { xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } case ExceptionHandlingClauseOptions.Finally: { xJumpTo = ILOp.GetLabel(aMethodInfo, aCurrentOpCode.CurrentExceptionHandler.HandlerOffset); break; } default: { throw new Exception("ExceptionHandlerType '" + aCurrentOpCode.CurrentExceptionHandler.Flags.ToString() + "' not supported yet!"); } } } } // if aDoTest is true, we check ECX for exception flags if (!aDoTest) { //new CPU.Call("_CODE_REQUESTED_BREAK_"); if (xJumpTo == null) { Jump_Exception(aMethodInfo); } else { new CPU.Jump { DestinationLabel = xJumpTo }; } } else { new CPU.Test { DestinationReg = CPU.Registers.ECX, SourceValue = 2 }; if (aCleanup != null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.Equal, DestinationLabel = aJumpTargetNoException }; aCleanup(); if (xJumpTo == null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException }; } else { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo }; } } else { if (xJumpTo == null) { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = GetMethodLabel(aMethodInfo) + AppAssembler.EndOfMethodLabelNameException }; } else { new CPU.ConditionalJump { Condition = CPU.ConditionalTestEnum.NotEqual, DestinationLabel = xJumpTo }; } } } }
protected void EmitTracer(MethodInfo aMethod, ILOpCode aOp, string aNamespace, bool emitInt3NotNop, out bool INT3Emitted, out bool INT3PlaceholderEmitted, bool isNewSourcePoint) { // NOTE - These if statements can be optimized down - but clarity is // more important than the optimizations. Furthermore the optimizations available // would not offer much benefit // Determine if a new DebugStub should be emitted INT3Emitted = false; INT3PlaceholderEmitted = false; if (aOp.OpCode == ILOpCode.Code.Nop) { // Skip NOOP's so we dont have breakpoints on them //TODO: Each IL op should exist in IL, and descendants in IL.X86. // Because of this we have this hack return; } else if (DebugEnabled == false) { return; } else if (DebugMode == DebugMode.Source) { // If the current position equals one of the offsets, then we have // reached a new atomic C# statement if (!isNewSourcePoint) { return; } } // Check if the DebugStub has been disabled for this method if ((!IgnoreDebugStubAttribute) && (aMethod.DebugStubOff)) { return; } // This test fixes issue #15638 if (null != aNamespace) { // Check options for Debug Level // Set based on TracedAssemblies if (TraceAssemblies > TraceAssemblies.None) { if (TraceAssemblies < TraceAssemblies.All) { if (aNamespace.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase)) { return; } if (aNamespace.ToLower() == "system") { return; } if (aNamespace.StartsWith("Microsoft.", StringComparison.InvariantCultureIgnoreCase)) { return; } } if (TraceAssemblies < TraceAssemblies.Cosmos) { //TODO: Maybe an attribute that could be used to turn tracing on and off if (aNamespace.StartsWith("Cosmos.", StringComparison.InvariantCultureIgnoreCase)) { return; } } } else { return; } } else { return; } // If we made it this far without a return, emit the Tracer // We used to emit an INT3, but this meant the DS would brwak after every C# line // Breaking that frequently is of course, pointless and slow. // So now we emit mostly NOPs and only put an INT3 when told to. // We should only be told to put an INT3 at the start of method but this may change so search for more comments on this. if (emitInt3NotNop) { INT3Emitted = true; new INT3(); } else { INT3PlaceholderEmitted = true; new DebugNoop(); } }
public static void EmitExceptionLogic(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethodInfo, ILOpCode aCurrentOpCode, bool aDoTest, Action aCleanup) { EmitExceptionLogic(aAssembler, aMethodInfo, aCurrentOpCode, aDoTest, aCleanup, ILOp.GetLabel(aMethodInfo, aCurrentOpCode.NextPosition)); }
protected void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode, bool emitInt3NotNop, out bool INT3Emitted, bool hasSourcePoint) { string xLabel = TmpPosLabel(aMethod, aOpCode); Assembler.CurrentIlLabel = xLabel; new Cosmos.Assembler.Label(xLabel); if (aMethod.MethodBase.DeclaringType != typeof(VTablesImpl)) { Assembler.EmitAsmLabels = false; try { //Assembler.WriteDebugVideo(String.Format("Method {0}:{1}.", aMethod.UID, aOpCode.Position.ToString("X"))); //Assembler.WriteDebugVideo(xLabel); } finally { Assembler.EmitAsmLabels = true; } } uint? xStackDifference = null; if (mSymbols != null) { var xMLSymbol = new MethodIlOp(); xMLSymbol.LabelName = xLabel; var xStackSize = aOpCode.StackOffsetBeforeExecution.Value; xMLSymbol.StackDiff = -1; if (aMethod.MethodBase != null) { var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { var xLocalsSize = (from item in xBody.LocalVariables select ILOp.Align(ILOp.SizeOfType(item.LocalType), 4)).Sum(); xMLSymbol.StackDiff = checked((int)(xLocalsSize + xStackSize)); xStackDifference = (uint?)xMLSymbol.StackDiff; } } xMLSymbol.IlOffset = aOpCode.Position; xMLSymbol.MethodID = mCurrentMethodGuid; mSymbols.Add(xMLSymbol); DebugInfo.AddSymbols(mSymbols); } DebugInfo.AddSymbols(mSymbols, false); bool INT3PlaceholderEmitted = false; EmitTracer(aMethod, aOpCode, aMethod.MethodBase.DeclaringType.Namespace, emitInt3NotNop, out INT3Emitted, out INT3PlaceholderEmitted, hasSourcePoint); if (INT3Emitted || INT3PlaceholderEmitted) { var xINT3Label = new INT3Label(); xINT3Label.LabelName = xLabel; xINT3Label.MethodID = mCurrentMethodGuid; xINT3Label.LeaveAsINT3 = INT3Emitted; mINT3Labels.Add(xINT3Label); DebugInfo.AddINT3Labels(mINT3Labels); } if (DebugEnabled && StackCorruptionDetection && StackCorruptionDetectionLevel == StackCorruptionDetectionLevel.AllInstructions) { // if debugstub is active, emit a stack corruption detection. at this point, the difference between EBP and ESP // should be equal to the local variables sizes and the IL stack. // if not, we should break here. // first, calculate the expected difference if (xStackDifference == null) { xStackDifference = aMethod.LocalVariablesSize; xStackDifference += aOpCode.StackOffsetBeforeExecution; } new Comment("Stack difference = " + xStackDifference); // if debugstub is active, emit a stack corruption detection. at this point EBP and ESP should have the same value. // if not, we should somehow break here. new Mov { DestinationReg = Registers.EAX, SourceReg = RegistersEnum.ESP }; new Mov { DestinationReg = Registers.EBX, SourceReg = RegistersEnum.EBP }; if (xStackDifference != 0) { new Add { DestinationReg = Registers.EAX, SourceValue = xStackDifference }; } new Compare { SourceReg = RegistersEnum.EAX, DestinationReg = RegistersEnum.EBX }; new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = xLabel + ".StackCorruptionCheck_End" }; new ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value new Call { DestinationLabel = xLabel + ".StackCorruptionCheck_GetAddress" }; new Assembler.Label(xLabel + ".StackCorruptionCheck_GetAddress"); new Pop { DestinationReg = RegistersEnum.EAX }; new Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; new Call { DestinationLabel = "DebugStub_SendStackCorruptionOccurred" }; new Halt(); new Assembler.Label(xLabel + ".StackCorruptionCheck_End"); } }
protected void AfterOp(MethodInfo aMethod, ILOpCode aOpCode) { }
public static string TmpBranchLabel(MethodInfo aMethod, ILOpCode aOpCode) { return TmpPosLabel(aMethod, ((ILOpCodes.OpBranch)aOpCode).Value); }
public OpCodeAttribute(ILOpCode.Code OpCode) { this.opCode = OpCode; }
protected void InterpretInstruction(ILOpCode xNextOpCode, IDictionary<int, ILOpCode> aOpCodes, Stack<Type> aStack, ref bool aSituationChanged, int aMaxRecursionDepth) { xNextOpCode.InterpretStackTypes(aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth - 1); }