// // // // // $Revision: 2274 $ // using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Debugger.Wrappers.CorDebug; namespace Debugger { public enum EvalState {EvaluationScheduled, Evaluating, EvaluatedSuccessfully, EvaluatedException, EvaluatedNoResult, EvaluatedError}; /// /// This class holds information about function evaluation. /// public class Eval: DebuggerObject { delegate void EvaluationInvoker(ICorDebugEval corEval); class EvalSetupException: System.Exception { public EvalSetupException(string msg):base(msg) { } } Process process; Value result; string description; EvaluationInvoker evaluationInvoker; EvalState state = EvalState.EvaluationScheduled; ICorDebugEval corEval; string errorMsg; [Debugger.Tests.Ignore] public Process Process { get { return process; } } ICorDebugEval CorEval { get { return corEval; } } public Value Result { get { switch(this.State) { case EvalState.EvaluationScheduled: throw new CannotGetValueException("Evaluation pending"); case EvalState.Evaluating: throw new TooLongEvaluation(); case EvalState.EvaluatedSuccessfully: return result; case EvalState.EvaluatedException: return result; case EvalState.EvaluatedNoResult: return result;//throw new CannotGetValueException("No return value"); case EvalState.EvaluatedError: throw new CannotGetValueException(errorMsg); default: throw new DebuggerException("Unknown state"); } } } public string Description { get { return description; } } public EvalState State { get { return state; } } public bool Evaluated { get { return state == EvalState.EvaluatedSuccessfully || state == EvalState.EvaluatedException || state == EvalState.EvaluatedNoResult || state == EvalState.EvaluatedError; } } Eval(Process process, string description, EvaluationInvoker evaluationInvoker) { this.process = process; this.description = description; this.evaluationInvoker = evaluationInvoker; process.ScheduleEval(this); process.Debugger.MTA2STA.AsyncCall(delegate { process.StartEvaluation(); }); } internal bool IsCorEval(ICorDebugEval corEval) { return this.corEval == corEval; } /// Synchronously calls a function and returns its return value public static Value InvokeMethod(Process process, System.Type type, string name, Value thisValue, Value[] args) { return InvokeMethod(MethodInfo.GetFromName(process, type, name, args.Length), thisValue, args); } /// Synchronously calls a function and returns its return value public static Value InvokeMethod(MethodInfo method, Value thisValue, Value[] args) { return AsyncInvokeMethod(method, thisValue, args).EvaluateNow(); } public static Eval AsyncInvokeMethod(MethodInfo method, Value thisValue, Value[] args) { return new Eval( method.Process, "Function call: " + method.DeclaringType.FullName + "." + method.Name, delegate(ICorDebugEval corEval) { StartMethodInvoke(corEval, method, thisValue, args); } ); } static void StartMethodInvoke(ICorDebugEval corEval, MethodInfo method, Value thisValue, Value[] args) { List corArgs = new List(); args = args ?? new Value[0]; try { if (thisValue != null) { if (!(thisValue.IsObject)) { throw new EvalSetupException("Can not evaluate on a value which is not an object"); } if (!method.DeclaringType.IsInstanceOfType(thisValue)) { throw new EvalSetupException("Can not evaluate because the object is not of proper type"); } corArgs.Add(thisValue.SoftReference); } foreach(Value arg in args) { corArgs.Add(arg.SoftReference); } } catch (CannotGetValueException e) { throw new EvalSetupException(e.Message); } ICorDebugType[] genericArgs = method.DeclaringType.GenericArgumentsAsCorDebugType; corEval.CastTo().CallParameterizedFunction( method.CorFunction, (uint)genericArgs.Length, genericArgs, (uint)corArgs.Count, corArgs.ToArray() ); //corEval.CallFunction(method.CorFunction, (uint)corArgs.Count, corArgs.ToArray()); } public static Value NewString(Process process, string textToCreate) { return AsyncNewString(process, textToCreate).EvaluateNow(); } public static Value NewPrimitiveValue(Process process, object val) { return AsyncNewValue(process, val).EvaluateNow(); } internal static CorElementType GetElementType(Type t) { TypeCode code = Type.GetTypeCode(t); switch (code) { case TypeCode.Boolean : return CorElementType.BOOLEAN; case TypeCode.Byte : return CorElementType.U1; case TypeCode.Char : return CorElementType.CHAR; case TypeCode.Double : return CorElementType.R8; case TypeCode.Int16 : return CorElementType.I2; case TypeCode.Int32 : return CorElementType.I4; case TypeCode.Int64 : return CorElementType.I8; case TypeCode.SByte : return CorElementType.I1; case TypeCode.Single : return CorElementType.R4; case TypeCode.UInt16 : return CorElementType.U2; case TypeCode.UInt32 : return CorElementType.U4; case TypeCode.UInt64 : return CorElementType.U8; } return CorElementType.I4; } public static Eval AsyncNewValue(Process process, object val) { return new Eval( process, "new value", delegate(ICorDebugEval corEval) {corEval.CreateValue((uint)GetElementType(val.GetType()),null);}); } public static Eval AsyncNewString(Process process, string textToCreate) { return new Eval( process, "New string: " + textToCreate, delegate(ICorDebugEval corEval) { corEval.NewString(textToCreate); } ); } public static Value NewObject(Process process, ICorDebugClass classToCreate) { return AsyncNewObject(process, classToCreate).EvaluateNow(); } public static Eval AsyncNewObject(Process process, ICorDebugClass classToCreate) { return new Eval( process, "New object: " + classToCreate.Token, delegate(ICorDebugEval corEval) { corEval.NewObjectNoConstructor(classToCreate); } ); } public static Value NewObject(Process process, DebugType debugType) { ICorDebugType ppTypeArgs=null; ICorDebugValue ppArgs=null; Eval e = new Eval( process, "New object: " + debugType.Token, delegate(ICorDebugEval corEval) { corEval.CastTo().NewParameterizedObject (debugType.GetDefaultConstructor(),(uint)debugType.GenericArguments.Count,ref ppTypeArgs,0,ref ppArgs); } ); return e.EvaluateNow(); } public static Value NewObjectNoConstructor(DebugType debugType) { return AsyncNewObjectNoConstructor(debugType).EvaluateNow(); } /*static Eval CreateEval(Process process, string description, EvalStarter evalStarter) { ICorDebugEval corEval = CreateCorEval(process); Eval newEval = new Eval(process, description, corEval); try { evalStarter(newEval); } catch (COMException e) { if ((uint)e.ErrorCode == 0x80131C26) { throw new GetValueException("Can not evaluate in optimized code"); } else if ((uint)e.ErrorCode == 0x80131C28) { throw new GetValueException("Object is in wrong AppDomain"); } else if ((uint)e.ErrorCode == 0x8013130A) { // Happens on getting of Sytem.Threading.Thread.ManagedThreadId; See SD2-1116 throw new GetValueException("Function does not have IL code"); } else if ((uint)e.ErrorCode == 0x80131C23) { // The operation failed because it is a GC unsafe point. (Exception from HRESULT: 0x80131C23) // This can probably happen when we break and the thread is in native code throw new GetValueException("Thread is in GC unsafe point"); } else { throw; } } process.NotifyEvaluationStarted(newEval); process.AsyncContinue(DebuggeeStateAction.Keep); return newEval; }*/ public static Eval AsyncNewObjectNoConstructor(DebugType debugType) { return new Eval( debugType.Process, "New object: " + debugType.FullName, delegate(ICorDebugEval corEval) { corEval.CastTo().NewParameterizedObjectNoConstructor(debugType.CorType.Class, (uint)debugType.GenericArguments.Count, debugType.GenericArgumentsAsCorDebugType); } ); } /// True if setup was successful internal bool SetupEvaluation(Thread targetThread) { process.AssertPaused(); try { if (targetThread.IsLastFunctionNative) { throw new EvalSetupException("Can not evaluate because native frame is on top of stack"); } if (!targetThread.IsAtSafePoint) { throw new EvalSetupException("Can not evaluate because thread is not at a safe point"); } // TODO: What if this thread is not suitable? corEval = targetThread.CorThread.CreateEval(); try { evaluationInvoker(corEval); } catch (COMException e) { if ((uint)e.ErrorCode == 0x80131C26) { throw new EvalSetupException("Can not evaluate in optimized code"); } else if ((uint)e.ErrorCode == 0x80131C28) { throw new EvalSetupException("Object is in wrong AppDomain"); } else if ((uint)e.ErrorCode == 0x8013130A) { // Happens on getting of Sytem.Threading.Thread.ManagedThreadId; See SD2-1116 throw new EvalSetupException("Function does not have IL code"); }else { throw; } } state = EvalState.Evaluating; return true; } catch (EvalSetupException e) { state = EvalState.EvaluatedError; errorMsg = e.Message; return false; } } public Value EvaluateNow() { int ticks = Environment.TickCount; while (!Evaluated) { if (process.IsPaused) { process.StartEvaluation(); } bool not_eval = false; process.WaitForPause(out not_eval); if (not_eval) { this.corEval.Abort(); break; } } return this.Result; } private static ICorDebugEval corEval2; public static Value CreateValue(Process process, object val) { corEval2 = process.SelectedThread.CorThread.CreateEval(); Value res = new Value(process, new IExpirable[] {}, new IMutable[] {}, delegate { return corEval2.CreateValue((uint)GetElementType(val.GetType()),null); }); //res.PrimitiveValue = val; return res; } internal void NotifyEvaluationComplete(bool successful) { // Eval result should be ICorDebugHandleValue so it should survive Continue() if (corEval.Result == null) { state = EvalState.EvaluatedNoResult; } else { if (successful) { state = EvalState.EvaluatedSuccessfully; } else { state = EvalState.EvaluatedException; } result = new Value(process, new IExpirable[] {}, new IMutable[] {}, delegate { return corEval.Result; }); } } } }