bool IsPrimitiveType(MDbgValue value) { return(value.TypeName == "bool" || value.TypeName == "byte" || value.TypeName == "sbyte" || value.TypeName == "char" || value.TypeName == "decimal" || value.TypeName == "double" || value.TypeName == "float" || value.TypeName == "int" || value.TypeName == "uint" || value.TypeName == "long" || value.TypeName == "ulong" || value.TypeName == "object" || value.TypeName == "short" || value.TypeName == "ushort"); }
// Tries to lazily add the immediate children for a given node. // called on UI thread. static public void TryExpandNode(MainForm parent, TreeNode node) { MDbgValue val = (MDbgValue)node.Tag; if (val == null) { return; } node.Tag = null; // only expand it once. Else we'll keep readding the children on each select. MDbgValue[] items = null; parent.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc) { Debug.Assert(proc != null); Debug.Assert(!proc.IsRunning); Debug.Assert(val.Process == proc); if (val.IsArrayType) { items = val.GetArrayItems(); } else if (val.IsComplexType) { items = val.GetFields().Concat( val.GetProperties()).ToArray(); } }); // Nothing to expand. if (items == null) { return; } // This node had a dummy sub-node so that it's marked as expandable. When we get the // BeforeExpand event, then we kill the dummy node and replace with real nodes. // We use a dummy node instead of real nodes because it lets us avoid having to add all the real nodes // (which may be a lot of work). node.Nodes.Clear(); // delete dummy node. foreach (MDbgValue field in items) { PrintInternal(parent, field, node.Nodes); } }
public O2MDbgVariable(MDbgValue mdbgValue, string _parentType, string _assemblyName) { IsProperty = false; parentType = _parentType; assemblyName = _assemblyName; name = mdbgValue.Name; try { value = mdbgValue.GetStringValue(false); } catch (Exception ex) { DI.log.ex(ex, "in O2MDbgVariable(MDbgValue mdbgValue), while trying to get value for: " + mdbgValue.Name); } type = mdbgValue.TypeName; complexType = mdbgValue.IsComplexType; }
//----------------------------------------------------------------------------- // Print the value to the treeview // This will clear out the TreeView and repopulate it with the Value. // Called on UI thread. //----------------------------------------------------------------------------- static public void Print(MainForm parent, MDbgValue val, TreeView t) { t.BeginUpdate(); t.Nodes.Clear(); if (val == null) { t.Nodes.Add("(Error:Expression not valid in this scope)"); } else { PrintInternal(parent, val, t.Nodes); } t.EndUpdate(); }
// Resolve the expression to a value. // Returns "Null" if we can't resolve the arg. // called on UI thread. MDbgValue Resolve(string arg) { MDbgValue var = null; MainForm.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc) { MDbgFrame frame = GetCurrentFrame(proc); if (frame == null) { return; } var = proc.ResolveExpression(arg, frame); }); return(var); }
/// <summary> /// Acts on the current callback, based on the current debugger behavior for this stop /// option policy. /// </summary> /// <param name="currentProcess">Current MDbgProcess.</param> /// <param name="args">Callback arguments.</param> public override void ActOnCallback(MDbgProcess currentProcess, CustomPostCallbackEventArgs args) { CorEventArgs eventArgs = args.CallbackArgs as CorEventArgs; switch (m_behavior) { case DebuggerBehavior.Stop: args.Controller.Stop(eventArgs.Thread, MDbgUtil.CreateStopReasonFromEventArgs(eventArgs, currentProcess)); break; case DebuggerBehavior.Log: CommandBase.WriteOutput(eventArgs.ToString() + "\n"); break; case DebuggerBehavior.Notify: CommandBase.WriteOutput(eventArgs.ToString() + "\n"); MDbgThread currentThread = currentProcess.Threads.GetThreadFromThreadId((args.CallbackArgs as CorThreadEventArgs).Thread.Id); try { // Getting the current notification may not be implemented. MDbgValue notification = currentThread.CurrentNotification; if (notification != null) { CommandBase.WriteOutput(notification.GetStringValue(true, "-", null)); } else { CommandBase.WriteOutput("custom notification is null\n"); } } catch (NotImplementedException) { Trace.WriteLine("Custom Notifications Not Implemented"); } break; } }
private void PrintCurrentException() { MDbgValue ex = Debugger.Processes.Active.Threads.Active.CurrentException; if (ex.IsNull) { // No current exception is available. Perhaps the user switched to a different // thread which was not throwing an exception. return; } CommandBase.WriteOutput("Exception=" + ex.GetStringValue(0)); foreach (MDbgValue f in ex.GetFields()) { string outputType; string outputValue; if (f.Name == "_xptrs" || f.Name == "_xcode" || f.Name == "_stackTrace" || f.Name == "_remoteStackTraceString" || f.Name == "_remoteStackIndex" || f.Name == "_exceptionMethodString") { outputType = MDbgOutputConstants.Ignore; } else { outputType = MDbgOutputConstants.StdOutput; } outputValue = f.GetStringValue(0); // remove new line characters in string if (outputValue != null && (f.Name == "_exceptionMethodString" || f.Name == "_remoteStackTraceString")) { outputValue = outputValue.Replace('\n', '#'); } CommandBase.WriteOutput(outputType, "\t" + f.Name + "=" + outputValue); } }
/// <summary> /// Eval a function in the target process. /// </summary> /// <param name="functionNameFromScope">The full function name.</param> MDbgValue FunctionEval(string functionNameFromScope) { CorAppDomain corAD = this.MDbgProcess.Threads.Active.CorThread.AppDomain; MDbgFunction function = this.MDbgProcess.ResolveFunctionNameFromScope( functionNameFromScope, corAD); CorEval eval = this.MDbgProcess.Threads.Active.CorThread.CreateEval(); eval.CallFunction(function.CorFunction, new CorValue[0]); MDbgProcess.Go().WaitOne(); MDbgValue value = null; if (MDbgProcess.StopReason is EvalCompleteStopReason) { CorValue result = (MDbgProcess.StopReason as EvalCompleteStopReason).Eval.Result; if (result != null) { value = new MDbgValue(MDbgProcess, result); } } return(value); }
string SerializeValue(MDbgValue value, bool itemsOnly = false) { return(SerializeValue(value, itemsOnly, maxCollectionItemsInResolve)); }
public O2MDbgVariable(MDbgValue mdbgValue, O2MDbgVariable _parentVariable) : this(mdbgValue, _parentVariable.parentType, _parentVariable.assemblyName) { parentVariable = _parentVariable; }
private static string DumpValue(MDbgValue value) { return(string.Format("{0} = {1}", value.Name, value.GetStringValue(false))); }
XElement XmlSerialize(MDbgValue val, int valueId, string displayName = null, string substituteValue = null) { if (val == null) { return(new XElement("value", new XAttribute("name", displayName ?? "<unknown>"), new XAttribute("id", valueId), new XAttribute("isProperty", false), new XAttribute("isStatic", false), new XAttribute("isFake", false), new XAttribute("isComplex", false), new XAttribute("isArray", false), new XAttribute("value", substituteValue ?? "<N/A>"), new XAttribute("typeName", "<N/A>"))); } string name = val.Name; XElement result = new XElement("value", new XAttribute("name", displayName ?? name), new XAttribute("id", valueId), new XAttribute("isProperty", val.IsProperty), new XAttribute("isFake", val.IsFake), new XAttribute("rawDisplayValue", substituteValue ?? val.DisplayValue ?? ""), new XAttribute("isPublic", !val.IsPrivate), new XAttribute("isStatic", val.IsStatic), new XAttribute("typeName", val.TypeName)); try { if (val.IsArrayType) { // It would be nice to display array length here too. // Add a "dummy" sub-node to signify that this node is expandable. We then trap // the BeforeExpand event to add the real children. result.Add(new XAttribute("isComplex", true), new XAttribute("isArray", true)); } else if (val.IsListType) { result.Add(new XAttribute("isComplex", true), new XAttribute("isList", true)); } else if (val.IsDictionaryType) { result.Add(new XAttribute("isComplex", true), new XAttribute("isDictionary", true)); } else if (val.IsComplexType) { if (IsPrimitiveType(val)) //boxed primitive types will appear a ComplexTypes { string stValue = val.DisplayValue.Trim('{', '}'); result.Add(new XAttribute("isComplex", false), new XAttribute("value", substituteValue ?? stValue)); } else { // This will include both instance and static fields // It will also include all base class fields. //string stValue = val.InvokeToString(); result.Add(new XAttribute("isComplex", true), // new XAttribute("value", stValue), new XAttribute("isArray", false)); } } else { // This is a catch-all for primitives. string stValue = val.GetStringValue(false); result.Add(new XAttribute("isComplex", false), //new XAttribute("isArray", false), new XAttribute("value", substituteValue ?? stValue)); } } catch (System.Runtime.InteropServices.COMException) { result.Add(new XAttribute("isComplex", false), new XAttribute("isArray", false), new XAttribute("value", "<unavailable>")); } return(result); }
public void ProcessInvoke(string command) { //<invokeId>:<action>:<args> string[] parts = command.Split(new[] { ':' }, 3); string id = parts[0]; string action = parts[1]; string args = parts[2]; string result = ""; blockNotifications = true; try { if (IsInBreakMode) { if (action == "locals") { if (reportedValues.ContainsKey(args)) { MDbgValue value = reportedValues[args]; result = SerializeValue(value); } } else if (action == "resolve_primitive") //UI request for short info for tooltips { try { MDbgValue value = ResolveVariable(args); if (value != null) { if (value.IsArrayType || value.IsListType || value.IsDictionaryType) { result = SerializeValue(value, itemsOnly: true, itemsMaxCount: maxCollectionItemsInPrimitiveResolve); } else { if (value.IsComplexType) { //Complex types have no 'value' attribute set as they are expandable //but for the tooltips we need to show some value. So invoke 'object.ToString' //and inject the result as 'value' attribute string stValue = value.GetStringValue(false); var xml = XmlSerialize(value, -1, args); xml.Add(new XAttribute("value", stValue)); result = xml.ToString(); } else { result = Serialize(value, args); } } } } catch { result = null; } } else if (action == "resolve") { try { MDbgValue value = ResolveExpression(args); string itemName = args; //args can be variable (t.Index), method call (t.Test()) or set command (t.Index=7) //set command may also be "watched" in IDE as the var name (t.Index) bool isSetter = args.IsSetExpression(); if (isSetter) { itemName = args.Split('=').First(); } if (isSetter) { //vale may be boxed so resolve the expression to ensure it is not MDbgValue latestValue = value; if (shell.Debugger.Processes.Active.IsEvalSafe()) { try { latestValue = ResolveExpression(itemName); } catch { } } result = "<items>" + Serialize(latestValue, itemName) + "</items>"; ThreadPool.QueueUserWorkItem(x => { Thread.Sleep(100); MessageQueue.AddNotification(NppCategory.Watch + result); }); } else { //return the invocation result as it is without boxing/unboxing considerations if (value != null) { result = "<items>" + Serialize(value, itemName) + "</items>"; } } } catch { result = "<items/>"; } } else if (action == "inspect") { //not enabled yet //try //{ // MDbgValue value = Inspect(args); // if (value != null) // result = "<items>" + Serialize(value, args) + "</items>"; //} //catch //{ // result = "<items/>"; //} } } } catch (Exception e) { result = "Error: " + e.Message; } blockNotifications = false; MessageQueue.AddNotification(NppCategory.Invoke + id + ":" + result); }
string SerializeValue(MDbgValue value, bool itemsOnly, int itemsMaxCount) { string result = ""; MDbgValue[] items = null; MDbgValue[] diaplayItems = null; //decorated (fake) display items int tempMaxCount = itemsMaxCount; tempMaxCount++; if (value.IsArrayType) { items = value.GetArrayItems(tempMaxCount); } else if (value.IsListType) { diaplayItems = value.GenerateListItems(tempMaxCount); } else if (value.IsDictionaryType) { diaplayItems = value.GenerateDictionaryItems(tempMaxCount); } if (!itemsOnly && value.IsComplexType) { if (!IsPrimitiveType(value)) //boxed primitive type have their MDbgValue set to ComplexType { items = value.GetFields().ToArray(); try { items = items.Concat(value.GetProperties()).ToArray(); } catch { } } } if (items != null || itemsOnly) { string logicalItems = ""; if (diaplayItems != null) { MDbgValue truncatedValue = null; if (diaplayItems.Count() > itemsMaxCount) { truncatedValue = diaplayItems.Last(); } logicalItems = diaplayItems.Select(x => { x.IsFake = true; if (truncatedValue != null && x == truncatedValue) { return(Serialize(x, "...", "...")); } else { return(Serialize(x)); } }).Join(); } string rawItems = ""; if (items != null) { bool hasIndexer = value.IsListType || value.IsDictionaryType; MDbgValue truncatedValue = null; if (items.Count() > itemsMaxCount) { truncatedValue = items.Last(); } rawItems = items.Where(x => !x.Name.Contains("$")) //ignore any internal vars .Where(x => !hasIndexer || x.Name != "Item") .Select(x => { if (truncatedValue != null && x == truncatedValue) { return(Serialize(x, "...", "...")); } else { return(Serialize(x)); } }) .Join(); } result = "<items>" + logicalItems + rawItems + "</items>"; } return(result); }
public static void PrintCmd(string arguments, O2Thread.FuncVoidT1 <string> o2Callback) { const string debuggerVarsOpt = "d"; const string noFuncevalOpt = "nf"; const string expandDepthOpt = "r"; var ap = new ArgParser(arguments, debuggerVarsOpt + ";" + noFuncevalOpt + ";" + expandDepthOpt + ":1"); bool canDoFunceval = !ap.OptionPassed(noFuncevalOpt); int?expandDepth = null; // we use optional here because // different codes bellow has different // default values. if (ap.OptionPassed(expandDepthOpt)) { expandDepth = ap.GetOption(expandDepthOpt).AsInt; if (expandDepth < 0) { throw new MDbgShellException("Depth cannot be negative."); } } MDbgFrame frame = CommandBase.Debugger.Processes.Active.Threads.Active.CurrentFrame; if (ap.OptionPassed(debuggerVarsOpt)) { // let's print all debugger variables MDbgProcess p = CommandBase.Debugger.Processes.Active; foreach (MDbgDebuggerVar dv in p.DebuggerVars) { var v = new MDbgValue(p, dv.CorValue); CommandBase.WriteOutput(dv.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval)); } } else { if (ap.Count == 0) { // get all active variables MDbgFunction f = frame.Function; var vars = new ArrayList(); MDbgValue[] vals = f.GetActiveLocalVars(frame); if (vals != null) { vars.AddRange(vals); } vals = f.GetArguments(frame); if (vals != null) { vars.AddRange(vals); } foreach (MDbgValue v in vars) { CommandBase.WriteOutput(v.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval)); } } else { // user requested printing of specific variables for (int j = 0; j < ap.Count; ++j) { MDbgValue var = CommandBase.Debugger.Processes.Active.ResolveVariable(ap.AsString(j), frame); if (var != null) { CommandBase.WriteOutput(ap.AsString(j) + "=" + var.GetStringValue(expandDepth == null ? 1 : (int)expandDepth, canDoFunceval)); } else { throw new MDbgShellException("Variable not found"); } } } } }
public ExpressionParsingResult ParseExpression(string expression) { //the expression is either setter of method invoke var result = new ExpressionParsingResult(); result.IsSetter = expression.IsSetExpression(); result.Expression = expression; int bracketIndex = expression.IndexOfAny(new[] { '(', '=' }); string methodName = expression.Substring(0, bracketIndex).Trim(); string args = expression.Substring(bracketIndex).Replace("(", "").Replace(")", "").Replace("=", "").Trim(); string[] methodParts = methodName.Split('.'); if (methodParts.Length == 1 && result.IsSetter) //myVar=3 { result.IsLocalVariable = true; } result.ExpressionValue = args; string reference; if (methodParts.Length == 1) { //varName reference = methodParts[0]; } else { //<<TypeName>|<CodeReference>>.<MethodName> reference = string.Join(".", methodParts.Take(methodParts.Length - 1).ToArray()); } try { if ((expression.IsInvokeExpression() || expression.IsSetExpression()) && methodParts.Length == 1) { MDbgValue callingObject = process.ResolveVariable("this", process.Threads.Active.CurrentFrame); var mName = methodParts[0]; //either instance or static (e.g. "do()") MDbgFunction func = process.ResolveFunctionNameFromScope(mName); if (func != null) //method call { result.IsLocalVariable = false; if (func.MethodInfo.IsStatic) //static method call { result.Instance = null; result.Member = process.Threads.Active.CurrentFrame.Function.MethodInfo.DeclaringType.FullName + "." + mName; } else { result.Instance = callingObject.CorValue; result.Member = mName; } } else //variable assignment { var variable = process.ResolveVariable(reference, process.Threads.Active.CurrentFrame); if (variable != null)//local variable assignment { result.IsLocalVariable = true; result.Instance = variable.CorValue; result.Member = reference; } else { if (callingObject == null) //static member assignment { result.IsLocalVariable = false; result.Instance = null; result.Member = process.Threads.Active.CurrentFrame.Function.MethodInfo.DeclaringType.FullName + "." + mName; } else //instance member assignment { result.IsLocalVariable = false; result.Instance = callingObject.CorValue; result.Member = methodParts.Last(); } } } } else { var instance = process.ResolveVariable(reference, process.Threads.Active.CurrentFrame); if (instance != null) { result.Instance = instance.CorValue; result.Member = methodParts.Last(); } } } catch { } if (result.Instance == null && result.Member == null) { result.Member = methodName; } CorEval eval = process.Threads.Active.CorThread.CreateEval(); // Get Variables ArrayList vars = new ArrayList(); String arg; if (args.Length != 0) { foreach (var item in args.Split(',')) { arg = item.Trim(); CorValue v = process.m_engine.ParseExpression(arg, process, process.Threads.Active.CurrentFrame); if (v == null) { throw new Exception("Cannot resolve expression or variable " + arg); } if (v is CorGenericValue) { vars.Add(v as CorValue); } else { CorHeapValue hv = v.CastToHeapValue(); if (hv != null) { // we cannot pass directly heap values, we need to pass reference to heap valus CorReferenceValue myref = eval.CreateValue(CorElementType.ELEMENT_TYPE_CLASS, null).CastToReferenceValue(); myref.Value = hv.Address; vars.Add(myref); } else { vars.Add(v); } } } } result.Arguments = (CorValue[])vars.ToArray(typeof(CorValue)); return(result); }
public CorValue VariableExpressionInvoke(ExpressionParsingResult info) { //based on MdbgCommands.SetCmd(string arguments) if (info.Instance == null) { throw new Exception("Cannot resolve variable "); } if (info.Arguments == null || !info.Arguments.Any()) { throw new Exception("Cannot resolve arguments "); } // Arguments has to be in the form of variable=varName, variable=value or variable=(<type>)value, // where we use the ldasm naming convention (e.g. "int", "sbyte", "ushort", etc...) for <type>. // Example inputs: var=myInt, var=45, var=(long)45 MDbgValue lsMVar = new MDbgValue(process, info.Instance); CorValue val = info.Arguments.First(); CorGenericValue valGeneric = val as CorGenericValue; bool bIsReferenceValue = val is CorReferenceValue; if (lsMVar != null) { if (valGeneric != null) { CorValue lsVar = lsMVar.CorValue; if (lsVar == null) { throw new Exception("cannot set constant values to unavailable variables"); } // val is a primitive value CorGenericValue lsGenVal = lsVar.CastToGenericValue(); if (lsGenVal == null) { throw new Exception("cannot set constant values to non-primitive values"); } try { // We want to allow some type coercion. Eg, casting between integer precisions. lsMVar.Value = val; // This may do type coercion } catch (MDbgValueWrongTypeException) { throw new Exception(String.Format("Type mismatch. Can't convert from {0} to {1}", val.Type, lsGenVal.Type)); } } else if (bIsReferenceValue) { //reget variable lsMVar = process.ResolveVariable(info.Member, process.Threads.Active.CurrentFrame); lsMVar.Value = val; } else { if (val.CastToHeapValue() != null) { throw new Exception("Heap values should be assigned only to debugger variables"); } if (val.CastToGenericValue() != null) { lsMVar.Value = val.CastToGenericValue(); } else { lsMVar.Value = val.CastToReferenceValue(); } } } // as a last thing we do is to return new value of the variable lsMVar = process.ResolveVariable(info.Member, process.Threads.Active.CurrentFrame); return(lsMVar.CorValue); }
//----------------------------------------------------------------------------- // Recursive helper to populate tree view. // val - value to print // c - node collection to add to. // Called on UI thread. //----------------------------------------------------------------------------- static public void PrintInternal(MainForm parent, MDbgValue val, TreeNodeCollection c) { string name = val.Name; try { TreeNode node = null; string st = null; parent.ExecuteOnWorkerThreadIfStoppedAndBlock(delegate(MDbgProcess proc) { Debug.Assert(proc != null); Debug.Assert(!proc.IsRunning); Debug.Assert(proc == val.Process); if (val.IsArrayType) { // It would be nice to display array length here too. // Add a "dummy" sub-node to signify that this node is expandable. We then trap // the BeforeExpand event to add the real children. node = new TreeNode(name + " (type='" + val.TypeName + "') array:", new TreeNode[1] { new TreeNode("dummy") }); } else if (val.IsComplexType) { // This will include both instance and static fields // It will also include all base class fields. node = new TreeNode(name + " (type='" + val.TypeName + "') fields:", new TreeNode[1] { new TreeNode("dummy") }); } else { // This is a catch-all for primitives. string stValue = val.GetStringValue(false, "-", null); st = (name + " (type='" + val.TypeName + "') value=" + stValue); } }); // Now add the node. if (node != null) { node.Tag = val; c.Add(node); } else if (st != null) { c.Add(st); } else { Debug.Assert(false, "No data set."); } } catch (System.Runtime.InteropServices.COMException) { // Inspecting the vars may fail at the ICorDebug level. c.Add(name + "= <unavailable>"); } }
public static void FuncEvalCmd(string arguments, IMDbgShell Shell, O2Thread.FuncVoidT1 <string> execOnEval) { try { var activeProcess = DI.o2MDbg.ActiveProcess; //Debugger.Processes.Active const string appDomainOption = "ad"; var ap = new ArgParser(arguments, appDomainOption + ":1"); if (!(ap.Count >= 1)) { throw new MDbgShellException("Not Enough arguments"); } // Currently debugger picks first function -- we have not implementing resolving overloaded functions. // Good example is Console.WriteLine -- there is 18 different types: // 1) [06000575] Void WriteLine() // 2) [06000576] Void WriteLine(Boolean) // 3) [06000577] Void WriteLine(Char) // 4) [06000578] Void WriteLine(Char[]) // 5) [06000579] Void WriteLine(Char[], Int32, Int32) // 6) [0600057a] Void WriteLine(Decimal) // 7) [0600057b] Void WriteLine(Double) // 8) [0600057c] Void WriteLine(Single) // 9) [0600057d] Void WriteLine(Int32) // 10) [0600057e] Void WriteLine(UInt32) // 11) [0600057f] Void WriteLine(Int64) // 12) [06000580] Void WriteLine(UInt64) // 13) [06000581] Void WriteLine(Object) // 14) [06000582] Void WriteLine(String) // 15) [06000583] Void WriteLine(String, Object) // 16) [06000584] Void WriteLine(String, Object, Object) // 17) [06000585] Void WriteLine(String, Object, Object, Object) // 18) [06000586] Void WriteLine(String, Object, Object, Object, Object, ...) // 19) [06000587] Void WriteLine(String, Object[]) // CorAppDomain appDomain; if (ap.OptionPassed(appDomainOption)) { MDbgAppDomain ad = activeProcess.AppDomains[ap.GetOption(appDomainOption).AsInt]; if (ad == null) { throw new ArgumentException("Invalid Appdomain Number"); } appDomain = ad.CorAppDomain; } else { appDomain = activeProcess.Threads.Active.CorThread.AppDomain; } MDbgFunction func = activeProcess.ResolveFunctionNameFromScope(ap.AsString(0), appDomain); if (null == func) { throw new MDbgShellException(String.Format(CultureInfo.InvariantCulture, "Could not resolve {0}", new Object[] { ap.AsString(0) })); } CorEval eval = activeProcess.Threads.Active.CorThread.CreateEval(); // Get Variables var vars = new ArrayList(); String arg; for (int i = 1; i < ap.Count; i++) { arg = ap.AsString(i); CorValue v = Shell.ExpressionParser.ParseExpression2(arg, activeProcess, activeProcess.Threads.Active. CurrentFrame); if (v == null) { throw new MDbgShellException("Cannot resolve expression or variable " + ap.AsString(i)); } if (v is CorGenericValue) { vars.Add(v); } else { CorHeapValue hv = v.CastToHeapValue(); if (hv != null) { // we cannot pass directly heap values, we need to pass reference to heap valus CorReferenceValue myref = eval.CreateValue(CorElementType.ELEMENT_TYPE_CLASS, null).CastToReferenceValue(); myref.Value = hv.Address; vars.Add(myref); } else { vars.Add(v); } } } eval.CallFunction(func.CorFunction, (CorValue[])vars.ToArray(typeof(CorValue))); activeProcess.Go().WaitOne(); // now display result of the funceval if (!(activeProcess.StopReason is EvalCompleteStopReason)) { // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "Func-eval not fully completed and debuggee has stopped"); Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "Result of funceval won't be printed when finished."); } else { eval = (activeProcess.StopReason as EvalCompleteStopReason).Eval; Debug.Assert(eval != null); CorValue cv = eval.Result; if (cv != null) { var mv = new MDbgValue(activeProcess, cv); if (execOnEval != null) // if this callback is set then execute { execOnEval(mv.GetStringValue(1)); return; } Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "result = " + mv.GetStringValue(1)); if (cv.CastToReferenceValue() != null) { if (activeProcess.DebuggerVars.SetEvalResult(cv)) { Shell.IO.WriteOutput(MDbgOutputConstants.StdOutput, "results saved to $result"); } } } } } catch (Exception ex) { DI.log.ex(ex, "in FuncEvalCmd"); } if (execOnEval != null) // need to call this here so that the sync AutoResetEvent is set { execOnEval(null); } }