private void SerializeReturnValue(Microsoft.Samples.Debugging.MdbgEngine.MDbgValue value, CallStackEntry callStackEntry) { var methodInfo = callStackEntry.BreakpointMetadata.Details.MethodInfo; shell.WriteLine("Captured return value for {0}", methodInfo.Name); var path = Path.Combine(GetWorkingDirectory(), string.Format("{0}.{1}-{2}-{3}-returnvalue.txt", methodInfo.DeclaringType.FullName, methodInfo.Name, methodInfo.MetadataToken, callStackEntry.Identifier)); parameterSerializer.Serialize(path, new MDbgValue[] { value }); }
//----------------------------------------------------------------------------- // Print the value to the treeview // This will clear out the TreeView and repopulate it with the Value. //----------------------------------------------------------------------------- void Print(MDbgValue val, TreeView t) { t.BeginUpdate(); t.Nodes.Clear(); if (val == null) { t.Nodes.Add("(Error:Expression not valid in this scope)"); } else { PrintInternal(val, t.Nodes, 0); } t.EndUpdate(); }
/// <summary> /// Gets the specified Field. /// </summary> /// <param name="name">The Name of the Field to get.</param> /// <returns>The Value of the specified Field.</returns> public MDbgValue GetField(string name) { MDbgValue ret = null; foreach (MDbgValue v in GetFields()) { if (v.Name.Equals(name)) { ret = v; break; } } if (ret == null) { throw new MDbgValueException("Field '" + name + "' not found."); } return(ret); }
/// <summary> /// Gets Array Items. This function can be called only on one dimensional arrays. /// </summary> /// <returns>An array of the values for the Array Items.</returns> public MDbgValue[] GetArrayItems() { if (!IsArrayType) { throw new MDbgValueException("Type is not array type"); } CorValue value = Dereference(CorValue, null); CorArrayValue av = value.CastToArrayValue(); int[] dims = av.GetDimensions(); Debug.Assert(dims != null); ArrayList al = new ArrayList(); Debug.Assert(av.Rank == 1); for (int i = 0; i < dims[0]; i++) { MDbgValue v = new MDbgValue(Process, "[" + i + "]", av.GetElementAtPosition(i)); al.Add(v); } return((MDbgValue[])al.ToArray(typeof(MDbgValue))); }
/// <summary> /// Gets the Array Item for the specified indexes /// </summary> /// <param name="indexes">Which indexes to get the Array Item for.</param> /// <returns>The Value for the given indexes.</returns> public MDbgValue GetArrayItem(params int[] indexes) { if (!IsArrayType) throw new MDbgValueException("Type is not array type"); CorValue value = Dereference(CorValue, null); CorArrayValue av = value.CastToArrayValue(); Debug.Assert(av != null); if (av.Rank != indexes.Length) throw new MDbgValueException("Invalid number of dimensions."); StringBuilder sb = new StringBuilder("["); for (int i = 0; i < indexes.Length; ++i) { if (i != 0) sb.Append(","); sb.Append(indexes[i]); } sb.Append("]"); MDbgValue v = new MDbgValue(Process, sb.ToString(), av.GetElement(indexes)); return v; }
public static void UnwrapGCHandleCmd(string arguments) { ArgParser ap = new ArgParser(arguments); if (ap.Count != 1) { WriteError("Wrong arguments, should be name or address of a \"System.Runtime.InteropServices.GCHandle\" object."); return; } long handleAdd = 0; // First try to resolve the argument as a variable in the current frame MDbgValue var = Debugger.Processes.Active.ResolveVariable( ap.AsString(0), Debugger.Processes.Active.Threads.Active.CurrentFrame); if (var != null) { if (var.TypeName != "System.Runtime.InteropServices.GCHandle") { WriteError("Variable is not of type \"System.Runtime.InteropServices.GCHandle\"."); return; } foreach (MDbgValue field in var.GetFields()) { if (field.Name == "m_handle") { handleAdd = Int64.Parse(field.GetStringValue(0)); break; } } } else { // Trying to resolve as a raw address now try { handleAdd = ap.GetArgument(0).AsAddress; } catch (System.FormatException) { WriteError("Couldn't recognize the argument as a variable name or address"); return; } } IntPtr add = new IntPtr(handleAdd); CorReferenceValue result; try { result = Debugger.Processes.Active.CorProcess.GetReferenceValueFromGCHandle(add); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.CORDBG_E_BAD_REFERENCE_VALUE) { WriteError("Invalid handle address."); return; } else { throw; } } CorValue v = result.Dereference(); MDbgValue mv = new MDbgValue(Debugger.Processes.Active, v); if (mv.IsComplexType) { WriteOutput(string.Format("GCHandle to <{0}>", InternalUtil.PrintCorType(Debugger.Processes.Active, v.ExactType))); // now print fields as well foreach (MDbgValue f in mv.GetFields()) CommandBase.WriteOutput(" " + f.Name + "=" + f.GetStringValue(0)); } else { WriteOutput(string.Format("GCHandle to {0}", mv.GetStringValue(0))); } }
public static Dictionary<string, string> GetLocalVars(MDbgEngine pDebugger, List<string> specificVarNames = null, bool debuggerVarsOpt = false, bool noFuncevalOpt = false, int? expandDepthOpt = null) { Dictionary<string, string> retVal = new Dictionary<string, string>(); //const string debuggerVarsOpt = "d"; //const string noFuncevalOpt = "nf"; //const string expandDepthOpt = "r"; //ArgParser ap = new ArgParser(arguments, debuggerVarsOpt + ";" + noFuncevalOpt + ";" + expandDepthOpt + ":1"); bool canDoFunceval = !noFuncevalOpt; int? expandDepth = null; // we use optional here because // different codes bellow has different // default values. if (expandDepthOpt != null) { expandDepth = (int)expandDepthOpt; if (expandDepth < 0) throw new MDbgShellException("Depth cannot be negative."); } MDbgFrame frame = pDebugger.Processes.Active.Threads.Active.CurrentFrame; if (debuggerVarsOpt) { // let's print all debugger variables MDbgProcess p = pDebugger.Processes.Active; foreach (MDbgDebuggerVar dv in p.DebuggerVars) { MDbgValue v = new MDbgValue(p, dv.CorValue); string value = v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval); retVal.Add(dv.Name, value); } } else { //!debuggerVarsOpt && !noFuncevalOpt && expandDepthOpt == null && if (specificVarNames == null || specificVarNames.Count == 0) { // get all active variables MDbgFunction f = frame.Function; ArrayList 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) { string value = v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval); retVal.Add(v.Name, value); } } else { // user requested printing of specific variables for (int j = 0; j < specificVarNames.Count; ++j) { MDbgValue var = pDebugger.Processes.Active.ResolveVariable(specificVarNames[j], frame); if (var != null) { string value = var.GetStringValue(expandDepth == null ? 1 : (int)expandDepth, canDoFunceval); retVal.Add(specificVarNames[j], value); } else { throw new MDbgShellException("Variable not found"); } } } } return retVal; }
public static void FuncEvalCmd(string arguments) { const string appDomainOption = "ad"; ArgParser 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 = Debugger.Processes.Active.AppDomains[ap.GetOption(appDomainOption).AsInt]; if (ad == null) { throw new ArgumentException("Invalid Appdomain Number"); } appDomain = ad.CorAppDomain; } else { appDomain = Debugger.Processes.Active.Threads.Active.CorThread.AppDomain; } MDbgFunction func = Debugger.Processes.Active.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 = Debugger.Processes.Active.Threads.Active.CorThread.CreateEval(); // Get Variables ArrayList vars = new ArrayList(); String arg; for (int i = 1; i < ap.Count; i++) { arg = ap.AsString(i); CorValue v = Shell.ExpressionParser.ParseExpression2(arg, Debugger.Processes.Active, Debugger.Processes.Active.Threads.Active.CurrentFrame); if (v == null) { throw new MDbgShellException("Cannot resolve expression or variable " + ap.AsString(i)); } 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); } } } eval.CallFunction(func.CorFunction, (CorValue[])vars.ToArray(typeof(CorValue))); Debugger.Processes.Active.Go().WaitOne(); // now display result of the funceval if (!(Debugger.Processes.Active.StopReason is EvalCompleteStopReason)) { // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason WriteOutput("Func-eval not fully completed and debuggee has stopped"); WriteOutput("Result of funceval won't be printed when finished."); } else { eval = (Debugger.Processes.Active.StopReason as EvalCompleteStopReason).Eval; Debug.Assert(eval != null); CorValue cv = eval.Result; if (cv != null) { MDbgValue mv = new MDbgValue(Debugger.Processes.Active, cv); WriteOutput("result = " + mv.GetStringValue(1)); if (cv.CastToReferenceValue() != null) if (Debugger.Processes.Active.DebuggerVars.SetEvalResult(cv)) WriteOutput("results saved to $result"); } } Shell.DisplayCurrentLocation(); }
public static void NewObjCmd(string arguments) { ArgParser ap = new ArgParser(arguments); string className = ap.AsString(0); MDbgFunction func = Debugger.Processes.Active.ResolveFunctionName(null, className, ".ctor", Debugger.Processes.Active.Threads.Active.CorThread.AppDomain); if (null == func) throw new MDbgShellException(String.Format(CultureInfo.InvariantCulture, "Could not resolve {0}", ap.AsString(0))); CorEval eval = Debugger.Processes.Active.Threads.Active.CorThread.CreateEval(); ArrayList callArguments = new ArrayList(); // parse the arguments to newobj int i = 1; while (ap.Exists(i)) { string arg = ap.AsString(i); // this is a normal argument MDbgValue rsMVar = Debugger.Processes.Active.ResolveVariable(arg, Debugger.Processes.Active.Threads.Active.CurrentFrame); if (rsMVar == null) { // cordbg supports also limited literals -- currently only NULL & I4. if (string.Compare(arg, "null", true) == 0) { callArguments.Add(eval.CreateValue(CorElementType.ELEMENT_TYPE_CLASS, null)); } else { int v; if (!Int32.TryParse(arg, out v)) throw new MDbgShellException(string.Format(CultureInfo.InvariantCulture, "Argument '{0}' could not be resolved to variable or number", arg)); CorGenericValue gv = eval.CreateValue(CorElementType.ELEMENT_TYPE_I4, null).CastToGenericValue(); Debug.Assert(gv != null); gv.SetValue(v); callArguments.Add(gv); } } else { callArguments.Add(rsMVar.CorValue); } ++i; } eval.NewParameterizedObject(func.CorFunction, null, (CorValue[])callArguments.ToArray(typeof(CorValue))); Debugger.Processes.Active.Go().WaitOne(); // now display result of the funceval if (!(Debugger.Processes.Active.StopReason is EvalCompleteStopReason)) { // we could have received also EvalExceptionStopReason but it's derived from EvalCompleteStopReason WriteOutput("Newobj command not fully completed and debuggee has stopped"); WriteOutput("Result of Newobj won't be printed when finished."); } else { eval = (Debugger.Processes.Active.StopReason as EvalCompleteStopReason).Eval; Debug.Assert(eval != null); CorValue cv = eval.Result; if (cv != null) { MDbgValue mv = new MDbgValue(Debugger.Processes.Active, cv); WriteOutput("result = " + mv.GetStringValue(1)); if (Debugger.Processes.Active.DebuggerVars.SetEvalResult(cv)) WriteOutput("results saved to $result"); } } Shell.DisplayCurrentLocation(); }
//zos; CSScript.Npp related changes static internal T GetFieldValue <T>(this MDbgValue value, string name) { return((T)value.GetField(name).CorValue.CastToGenericValue().GetValue()); }
public static void PrintCmd(string arguments) { const string debuggerVarsOpt = "d"; const string noFuncevalOpt = "nf"; const string expandDepthOpt = "r"; ArgParser 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 = Debugger.Processes.Active.Threads.Active.CurrentFrame; if (ap.OptionPassed(debuggerVarsOpt)) { // let's print all debugger variables MDbgProcess p = Debugger.Processes.Active; foreach (MDbgDebuggerVar dv in p.DebuggerVars) { MDbgValue v = new MDbgValue(p, dv.CorValue); WriteOutput(dv.Name + "=" + v.GetStringValue(expandDepth == null ? 0 : (int)expandDepth, canDoFunceval)); } } else { if (ap.Count == 0) { // get all active variables MDbgFunction f = frame.Function; ArrayList 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) { 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 = Debugger.Processes.Active.ResolveVariable(ap.AsString(j), frame); if (var != null) { WriteOutput(ap.AsString(j) + "=" + var.GetStringValue(expandDepth == null ? 1 : (int)expandDepth, canDoFunceval)); } else { throw new MDbgShellException("Variable not found"); } } } } }
private string PrintObject(int indentLevel, CorObjectValue ov, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); bool fNeedToResumeThreads = true; // Print generics-aware type. string name = InternalUtil.PrintCorType(this.m_process, ov.ExactType); StringBuilder txt = new StringBuilder(); txt.Append(name); if (expandDepth > 0) { // we gather the field info of the class before we do // funceval since funceval requires running the debugger process // and this in turn can cause GC and invalidate our references. StringBuilder expandedDescription = new StringBuilder(); if (IsComplexType) { foreach (MDbgValue v in GetFields()) { expandedDescription.Append("\n").Append(IndentedString(indentLevel + 1, v.Name)). Append("=").Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, false))); } } // if the value we're printing is a nullable type that has no value (is null), we can't do a func eval // to get its value, since it will be boxed as a null pointer. We already have the information we need, so // we'll just take care of it now. Note that ToString() for null-valued nullable types just prints the // empty string. // bool hasValue = (bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue()); if (IsNullableType(ov.ExactType) && !(bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue())) { txt.Append(" < >"); } else if (ov.IsValueClass && canDoFunceval) // we could display even values for real Objects, but we will just show // "description" for valueclasses. { CorClass cls = ov.ExactType.Class; CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer; MetadataType mdType = importer.GetType(cls.Token) as MetadataType; if (mdType.ReallyIsEnum) { txt.AppendFormat(" <{0}>", InternalGetEnumString(ov, mdType)); } else if (m_process.IsRunning) txt.Append(" <N/A during run>"); else { MDbgThread activeThread = m_process.Threads.Active; CorValue thisValue; CorHeapValue hv = ov.CastToHeapValue(); if (hv != null) { // we need to pass reference value. CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION); thisValue = handle; } else thisValue = ov; try { CorEval eval = m_process.Threads.Active.CorThread.CreateEval(); m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_SUSPEND, activeThread.CorThread); MDbgFunction toStringFunc = m_process.ResolveFunctionName(null, "System.Object", "ToString", thisValue.ExactType.Class.Module.Assembly.AppDomain); Debug.Assert(toStringFunc != null); // we should be always able to resolve ToString function. eval.CallFunction(toStringFunc.CorFunction, new CorValue[] { thisValue }); m_process.Go(); do { m_process.StopEvent.WaitOne(); if (m_process.StopReason is EvalCompleteStopReason) { CorValue cv = eval.Result; Debug.Assert(cv != null); MDbgValue mv = new MDbgValue(m_process, cv); string valName = mv.GetStringValue(0); // just purely for esthetical reasons we 'discard' " if (valName.StartsWith("\"") && valName.EndsWith("\"")) valName = valName.Substring(1, valName.Length - 2); txt.Append(" <").Append(valName).Append(">"); break; } if ((m_process.StopReason is ProcessExitedStopReason) || (m_process.StopReason is EvalExceptionStopReason)) { txt.Append(" <N/A cannot evaluate>"); break; } // hitting bp or whatever should not matter -- we need to ignore it m_process.Go(); } while (true); } catch (COMException e) { // Ignore cannot copy a VC class error - Can't copy a VC with object refs in it. if (e.ErrorCode != (int)HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) { throw; } } catch (System.NotImplementedException) { fNeedToResumeThreads = false; } finally { if (fNeedToResumeThreads) { // we need to resume all the threads that we have suspended no matter what. m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, activeThread.CorThread); } } } } txt.Append(expandedDescription.ToString()); } return txt.ToString(); }
/// <summary> /// Gets the output of a function using MDbg. /// </summary> /// <example> /// <code lang="CS" title="Getting the Message from an Exception" description="An example showing how you would get the value of the Message property of an Exception. The variable ex is a MDbgValue object that represents the exception you are examining."> /// MDbgValue returnValue = ResolveFunction(debuggedProc, ex, "System.Exception.get_Message"); /// string message = returnValue.GetStringValue(true); /// </code> /// </example> /// <param name="debuggedProc">The process we are debugging.</param> /// <param name="ex">The MDbgValue object to execute the function on.</param> /// <param name="function">The full name of the function in MDbg syntax.</param> /// <returns>The MDbgValue that contains the return value of the function. If the function /// could not be evaluated, it returns null.</returns> private MDbgValue ResolveFunction(MDbgProcess debuggedProc, MDbgValue ex, string function) { CorAppDomain appDomain = debuggedProc.Threads.Active.CorThread.AppDomain; MDbgFunction func = debuggedProc.ResolveFunctionNameFromScope(function, appDomain); if (func == null) throw new Exception("A required function is missing. Are you running a template compiled with an different version of ArchAngel?"); CorEval eval = debuggedProc.Threads.Active.CorThread.CreateEval(); eval.CallFunction(func.CorFunction, new[] { ex.CorValue }); debuggedProc.Go().WaitOne(); if (!(debuggedProc.StopReason is EvalCompleteStopReason)) { return null; } eval = ((EvalCompleteStopReason)debuggedProc.StopReason).Eval; if (eval == null) { return null; } CorValue cv = eval.Result; if (cv != null) { MDbgValue mv = new MDbgValue(debuggedProc, cv); return mv; } return null; }
private static string GetStringFromException(MDbgThread activeThread, MDbgValue ex) { ExceptionInfo exinfo = GetExceptionInfo(activeThread, ex); StringBuilder retVal = new StringBuilder(); string exceptionType = exinfo.ExType; if (!string.IsNullOrWhiteSpace(exinfo.Function)) { retVal.AppendLine("at function: " + exinfo.Function); } if (!string.IsNullOrWhiteSpace(exinfo.Message)) { retVal.AppendLine("Message: " + exinfo.Message); } if (!string.IsNullOrWhiteSpace(exinfo.Source)) { retVal.AppendLine("in source file: " + exinfo.Source); } if (!string.IsNullOrWhiteSpace(exinfo.Callstack)) { retVal.AppendLine("Callstack: " + exinfo.Callstack); } return retVal.ToString(); }
private string PrintArray(int indentLevel, CorArrayValue av, int expandDepth, bool canDoFunceval, string variableName, Dictionary <string, int> variablesToLog) { Debug.Assert(expandDepth >= 0); if (variablesToLog == null) { } else if (variablesToLog.Any(variable => variable.Key.StartsWith($@"{variableName}."))) { variablesToLog = variablesToLog .Where(variable => variable.Key.StartsWith($@"{variableName}.")) .ToDictionary(variable => variable.Key, variable => variable.Value); expandDepth = 1; } else if (variablesToLog.Any(variable => variable.Key == variableName)) { var thisVariable = variablesToLog.First(variable => variable.Key == variableName); expandDepth = thisVariable.Value; variablesToLog = null; } else { return("[SKIP]"); } StringBuilder txt = new StringBuilder(); txt.Append("array ["); int[] dims = av.GetDimensions(); Debug.Assert(dims != null); for (int i = 0; i < dims.Length; ++i) { if (i != 0) { txt.Append(","); } txt.Append(dims[i]); } txt.Append("]"); if (expandDepth > 0 && av.Rank == 1 && av.ElementType != CorElementType.ELEMENT_TYPE_VOID) { for (int i = 0; i < dims[0]; i++) { MDbgValue v = new MDbgValue(Process, av.GetElementAtPosition(i)); var newVariableName = $"{variableName}.[{i}]"; var newVariablesToLog = variablesToLog == null ? null : variablesToLog .ToDictionary( variable => $"{newVariableName}{variable.Key.Remove(0, variableName.Length)}", variable => variable.Value); txt .Append("\n") .Append(IndentedString(indentLevel + 1, "[" + i + "] = ")) .Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, canDoFunceval, $"{variableName}.[{i}]", newVariablesToLog))); } } return(txt.ToString()); }
private static ExceptionInfo GetExceptionInfo(MDbgThread activeThread, MDbgValue ex) { ExceptionInfo exinfo = new ExceptionInfo(); exinfo.ExType = ex.TypeName; exinfo.Function = (ex.GetField("_exceptionMethodString").IsNull ? null : ex.GetField("_exceptionMethodString").ToString()); exinfo.Message = (ex.GetField("_message").IsNull ? null : ex.GetField("_message").GetStringValue(false)); exinfo.Source = (ex.GetField("_source").IsNull ? null : ex.GetField("_source").ToString()); //StringBuilder sbCallstack = new StringBuilder(); //try //{ // if (activeThread != null) // activeThread.Frames.ToList().ForEach(f => sbCallstack.AppendLine(f.ToString())); //} //catch (Exception ex1) //{ // DebuggerUtils.HandleExceptionSilently(ex1); //} exinfo.Callstack = DebuggerUtils.GetThreadStacks(activeThread, true).ToString(); return exinfo; }
public void Serialize(string path, IEnumerable<MDbgValue> valuesList) { var values = valuesList.ToList(); CorEval eval = debugger.Processes.Active.Threads.Active.CorThread.CreateEval(); var functionName = "BigBrother.Serialization.JsonSerializer.Serialize" + (values.Count + 1); CorAppDomain appDomain = debugger.Processes.Active.Threads.Active.CorThread.AppDomain; if (serializers.Count == 0) { //Load BigBrother into the AppDomain. Then we can call BigBrother.Serialization.JsonSerializer's methods. if (useLoadFrom) { eval.NewString("BigBrother.dll"); debugger.Processes.Active.Go().WaitOne(); var evalAssemblyName = eval.Result; var fnLoad = debugger.Processes.Active.ResolveFunctionNameFromScope("System.Reflection.Assembly.LoadFrom", appDomain); eval.CallParameterizedFunction(fnLoad.CorFunction, null, new CorValue[] { evalAssemblyName }); debugger.Processes.Active.Go().WaitOne(); } else { eval.NewString("BigBrother"); debugger.Processes.Active.Go().WaitOne(); var evalAssemblyName = eval.Result; var fnLoad = debugger.Processes.Active.ResolveFunctionNameFromScope("System.Reflection.Assembly.Load", appDomain); eval.CallParameterizedFunction(fnLoad.CorFunction, null, new CorValue[] { evalAssemblyName }); debugger.Processes.Active.Go().WaitOne(); } } if (!serializers.ContainsKey(functionName)) { serializers[functionName] = debugger.Processes.Active.ResolveFunctionNameFromScope(functionName, appDomain); } eval.NewString(path); debugger.Processes.Active.Go().WaitOne(); CorValue fileName = (debugger.Processes.Active.StopReason as EvalCompleteStopReason).Eval.Result; var corValues = new List<CorValue>(); corValues.Add(fileName); corValues.AddRange(values.Select(v => v.CorValue)); eval.CallParameterizedFunction(serializers[functionName].CorFunction, corValues.Select(v => v.ExactType).ToArray(), corValues.ToArray()); debugger.Processes.Active.Go().WaitOne(); if (debugger.Processes.Active.StopReason is EvalExceptionStopReason) { var stopReason = (EvalExceptionStopReason)debugger.Processes.Active.StopReason; string message = new MDbgValue(debugger.Processes.Active, stopReason.Eval.Result).GetStringValue(true); shell.WriteLine(message); } }
////////////////////////////////////////////////////////////////////////////////// // // Support for printing local printing variables // ////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets an Array of MDbgValues for the Active Local Vars in the given frame. /// </summary> /// <param name="managedFrame">The Frame to look in.</param> /// <returns>The MDbgValue[] Active Local Valiables.</returns> public MDbgValue[] GetActiveLocalVars(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) { throw new ArgumentException(); } CorFrame frame = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(frame.FunctionToken == m_function.Token); if (!(frame.FunctionToken == m_function.Token)) { throw new ArgumentException(); } EnsureIsUpToDate(); if (!m_haveSymbols) { // if we don't have symbols -- we'll print local variables as (loca1_0,local_1,local_2,...) // to give them names consistent with ILasm. int c = frame.GetLocalVariablesCount(); if (c < 0) { c = 0; // in case we cannot get locals, } // we'll hide them. MDbgValue[] locals = new MDbgValue[c]; for (int i = 0; i < c; ++i) { CorValue arg = null; try { arg = frame.GetLocalVariable(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) { throw; } } locals[i] = new MDbgValue(m_module.Process, "local_" + (i), arg); } return(locals); } uint ip; CorDebugMappingResult mappingResult; frame.GetIP(out ip, out mappingResult); ArrayList al = new ArrayList(); ISymbolScope scope = SymMethod.RootScope; AddLocalVariablesToList(frame, (int)ip, al, scope); return((MDbgValue[])al.ToArray(typeof(MDbgValue))); }
/// <summary> /// Gets Array Items. This function can be called only on one dimensional arrays. /// </summary> /// <returns>An array of the values for the Array Items.</returns> public MDbgValue[] GetArrayItems() { if (!IsArrayType) throw new MDbgValueException("Type is not array type"); CorValue value = Dereference(CorValue, null); CorArrayValue av = value.CastToArrayValue(); int[] dims = av.GetDimensions(); Debug.Assert(dims != null); ArrayList al = new ArrayList(); Debug.Assert(av.Rank == 1); for (int i = 0; i < dims[0]; i++) { MDbgValue v = new MDbgValue(Process, "[" + i + "]", av.GetElementAtPosition(i)); al.Add(v); } return (MDbgValue[])al.ToArray(typeof(MDbgValue)); }
// Helper to parse args to get a value for a GC handle. // // Syntax for gchandle. Ultimately need to compute an address. // gchandle(var) where var is System.Runtime.InteropServices.GCHandle, address=var.m_handle // gchandle(integer) where address =integer // gchandle(var, offset) where var is a valuetype, then we do address= (IntPtr*) (&var + offset*sizeof(IntPtr)) internal MDbgValue ParseGCHandleArgs(string stName, string[] args, MDbgFrame scope) { if (args.Length != 1 && args.Length != 2) { throw new MDbgException("Wrong number of args to gchandle function."); } string stVarBase = args[0]; MDbgValue varBase = ResolveVariable(stVarBase, scope); //MDbgValue varBase = Shell.ExpressionParser.ParseExpression(stVarBase,this, scope); IntPtr add; if (args.Length == 2) { if (varBase == null) { throw new MDbgException("Can't resolve var '" + stVarBase + "'"); } // Form: gchandle(var, offset) CorGenericValue gv = varBase.CorValue.CastToGenericValue(); IntPtr[] ar = null; if (gv != null) { ar = gv.GetValueAsIntPtrArray(); } if (ar == null) { throw new MDbgException("Variable '" + stVarBase + "' is not a value type."); } int offset = Int32.Parse(args[1], CultureInfo.InvariantCulture); add = ar[offset]; } else { if (varBase != null) { add = IntPtr.Zero; // Form: gchandle(var) if (varBase.TypeName != "System.Runtime.InteropServices.GCHandle") { throw new MDbgException("Variable is not of type \"System.Runtime.InteropServices.GCHandle\"."); } foreach (MDbgValue field in varBase.GetFields()) { if (field.Name == "m_handle") { int handleAddress = Int32.Parse(field.GetStringValue(0)); add = new IntPtr(handleAddress); break; } } } else { // Trying to resolve as a raw address now // form: gchandle(integer) int handleAddress; if (!Int32.TryParse(stVarBase, out handleAddress)) { throw new MDbgException("Couldn't recognize the argument as a variable name or address"); } add = new IntPtr(handleAddress); } } CorReferenceValue result; try { result = this.CorProcess.GetReferenceValueFromGCHandle(add); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode == (int)HResult.CORDBG_E_BAD_REFERENCE_VALUE) { throw new MDbgException("Invalid handle address."); } else { throw; } } MDbgValue var = new MDbgValue(this, stName, result); return var; }
private string PrintArray(int indentLevel, CorArrayValue av, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); StringBuilder txt = new StringBuilder(); txt.Append("array ["); int[] dims = av.GetDimensions(); Debug.Assert(dims != null); for (int i = 0; i < dims.Length; ++i) { if (i != 0) txt.Append(","); txt.Append(dims[i]); } txt.Append("]"); if (expandDepth > 0 && av.Rank == 1 && av.ElementType != CorElementType.ELEMENT_TYPE_VOID) { for (int i = 0; i < dims[0]; i++) { MDbgValue v = new MDbgValue(Process, av.GetElementAtPosition(i)); txt.Append("\n").Append(IndentedString(indentLevel + 1, "[" + i + "] = ")). Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, canDoFunceval))); } } return txt.ToString(); }
//----------------------------------------------------------------------------- // Recursive helper to populate tree view. // val - value to print // c - node collection to add to. // iDepth - track how far we are to avoid infinite recursion. //----------------------------------------------------------------------------- void PrintInternal(MDbgValue val, TreeNodeCollection c, int iDepth) { if (iDepth > 10) { return; } if (val.IsArrayType) { TreeNode n = new TreeNode(val.TypeName + " array:"); foreach (MDbgValue vField in val.GetArrayItems()) { PrintInternal(vField, n.Nodes, iDepth + 1); } c.Add(n); } else if (val.IsComplexType) { // This will include both instance and static fields // It will also include all base class fields. TreeNode n = new TreeNode(val.TypeName + " fields:"); foreach (MDbgValue vField in val.GetFields()) { PrintInternal(vField, n.Nodes, iDepth + 1); } c.Add(n); } else { // This is a ctach-call for primitives. string st = val.GetStringValue(false); c.Add(val.Name + "=" + st + " (type='" + val.TypeName + "')"); } }
private LocalVariableInformation GetLocalVariableInformation(MDbgValue value, VariableType variableType, int depth) { // Some MDbgValues don't have an associated CorValue. This occurs when there is no variable declaration in IL. if (value == null || value.CorValue == null) return null; if (createdLocals.ContainsKey(value.CorValue.Address)) return createdLocals[value.CorValue.Address]; var fields = new List<LocalVariableInformation>(); if (value.IsComplexType && value.IsNull == false && depth < 10) { MDbgValue[] fieldValues = value.GetFields(); foreach (var fieldValue in fieldValues) { fields.Add(GetLocalVariableInformation(fieldValue, VariableType.Field, depth + 1)); } } var information = new LocalVariableInformation { TypeName = value.TypeName, Name = value.Name, StringValue = value.GetStringValue(false), TypeOfVariable = variableType, IsPrimitive = !value.IsComplexType, Fields = fields }; createdLocals[value.CorValue.Address] = information; return information; }
private string PrintObject(int indentLevel, CorObjectValue ov, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); bool fNeedToResumeThreads = true; // Print generics-aware type. string name = InternalUtil.PrintCorType(this.m_process, ov.ExactType); StringBuilder txt = new StringBuilder(); txt.Append(name); if (expandDepth > 0) { // we gather the field info of the class before we do // funceval since funceval requires running the debugger process // and this in turn can cause GC and invalidate our references. StringBuilder expandedDescription = new StringBuilder(); if (IsComplexType) { foreach (MDbgValue v in GetFields()) { expandedDescription.Append("\n").Append(IndentedString(indentLevel + 1, v.Name)). Append("=").Append(IndentedBlock(indentLevel + 2, v.GetStringValue(expandDepth - 1, false))); } } // if the value we're printing is a nullable type that has no value (is null), we can't do a func eval // to get its value, since it will be boxed as a null pointer. We already have the information we need, so // we'll just take care of it now. Note that ToString() for null-valued nullable types just prints the // empty string. // bool hasValue = (bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue()); if (IsNullableType(ov.ExactType) && !(bool)(GetField("hasValue").CorValue.CastToGenericValue().GetValue())) { txt.Append(" < >"); } else if (ov.IsValueClass && canDoFunceval) // we could display even values for real Objects, but we will just show // "description" for valueclasses. { CorClass cls = ov.ExactType.Class; CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer; MetadataType mdType = importer.GetType(cls.Token) as MetadataType; if (mdType.ReallyIsEnum) { txt.AppendFormat(" <{0}>", InternalGetEnumString(ov, mdType)); } else if (m_process.IsRunning) { txt.Append(" <N/A during run>"); } else { MDbgThread activeThread = m_process.Threads.Active; CorValue thisValue; CorHeapValue hv = ov.CastToHeapValue(); if (hv != null) { // we need to pass reference value. CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION); thisValue = handle; } else { thisValue = ov; } try { CorEval eval = m_process.Threads.Active.CorThread.CreateEval(); m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_SUSPEND, activeThread.CorThread); MDbgFunction toStringFunc = m_process.ResolveFunctionName(null, "System.Object", "ToString", thisValue.ExactType.Class.Module.Assembly.AppDomain)[0]; Debug.Assert(toStringFunc != null); // we should be always able to resolve ToString function. eval.CallFunction(toStringFunc.CorFunction, new CorValue[] { thisValue }); m_process.Go(); do { m_process.StopEvent.WaitOne(); if (m_process.StopReason is EvalCompleteStopReason) { CorValue cv = eval.Result; Debug.Assert(cv != null); MDbgValue mv = new MDbgValue(m_process, cv); string valName = mv.GetStringValue(0); // just purely for esthetical reasons we 'discard' " if (valName.StartsWith("\"") && valName.EndsWith("\"")) { valName = valName.Substring(1, valName.Length - 2); } txt.Append(" <").Append(valName).Append(">"); break; } if ((m_process.StopReason is ProcessExitedStopReason) || (m_process.StopReason is EvalExceptionStopReason)) { txt.Append(" <N/A cannot evaluate>"); break; } // hitting bp or whatever should not matter -- we need to ignore it m_process.Go(); }while (true); } catch (COMException e) { // Ignore cannot copy a VC class error - Can't copy a VC with object refs in it. if (e.ErrorCode != (int)HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) { throw; } } catch (System.NotImplementedException) { fNeedToResumeThreads = false; } finally { if (fNeedToResumeThreads) { // we need to resume all the threads that we have suspended no matter what. m_process.CorProcess.SetAllThreadsDebugState(CorDebugThreadState.THREAD_RUN, activeThread.CorThread); } } } } txt.Append(expandedDescription.ToString()); } return(txt.ToString()); }
////////////////////////////////////////////////////////////////////////////////// // // Support for printing local printing variables // ////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets an Array of MDbgValues for the Active Local Vars in the given frame. /// </summary> /// <param name="managedFrame">The Frame to look in.</param> /// <returns>The MDbgValue[] Active Local Valiables.</returns> public MDbgValue[] GetActiveLocalVars(MDbgFrame managedFrame) { Debug.Assert(managedFrame != null); if (managedFrame == null) throw new ArgumentException(); CorFrame frame = managedFrame.CorFrame; // we only support this, when the frame is our function Debug.Assert(frame.FunctionToken == m_function.Token); if (!(frame.FunctionToken == m_function.Token)) throw new ArgumentException(); EnsureIsUpToDate(); if (!m_haveSymbols) { // if we don't have symbols -- we'll print local variables as (loca1_0,local_1,local_2,...) // to give them names consistent with ILasm. int c = frame.GetLocalVariablesCount(); if (c < 0) c = 0; // in case we cannot get locals, // we'll hide them. MDbgValue[] locals = new MDbgValue[c]; for (int i = 0; i < c; ++i) { CorValue arg = null; try { arg = frame.GetLocalVariable(i); } catch (System.Runtime.InteropServices.COMException e) { if (e.ErrorCode != (int)Microsoft.Samples.Debugging.CorDebug.HResult.CORDBG_E_IL_VAR_NOT_AVAILABLE) throw; } locals[i] = new MDbgValue(m_module.Process, "local_" + (i), arg); } return locals; } uint ip; CorDebugMappingResult mappingResult; frame.GetIP(out ip, out mappingResult); ArrayList al = new ArrayList(); ISymbolScope scope = SymMethod.RootScope; AddLocalVariablesToList(frame, (int)ip, al, scope); return (MDbgValue[])al.ToArray(typeof(MDbgValue)); }
/// <summary> /// Resolves a Variable name in a given scope. /// </summary> /// <param name="variableName">The name of the variable to resolve.</param> /// <param name="scope">The MDbgFrame to look in for that variable.</param> /// <returns>The MDbgValue that the given variable has in the given scope.</returns> public MDbgValue ResolveVariable(string variableName, MDbgFrame scope) { Debug.Assert(variableName != null); Debug.Assert(scope != null); // variableName should have this form: // [[module][#<appdomain>]!][(([namespace.]+)<type.>)|.]variable([.field]*) // Syntax in BNF form: // // Expr --> module_scope '!' var_expr // | var_expr // module_scope --> <module name> // as determined by Modules.Lookup // var_expr --> var_root // | var_expr '.' <id:field> // | var_expr '[' <integer> ']' // var_root --> psuedo_var | local_var | parameter_var | global_var | static_class_var\ // | 'gchandle(' ... ')' // see ParseGCHandleArgs // psuedo_var --> '$' <id> // as determined by DebuggerVars.HaveVariable // local_var --> <id> // as determined by f.GetActiveLocalVars // parameter_var --> <id> // as determined by f.GetArguments // global_var --> <id> // as determined by fields on global token in each module // static_class_var --> (<id:namespace> '.')* <id:class> '.' <id:static field> MDbgModule variableModule; // name of the module we should look into for variable resolution // will contain null, if no module was specified { // limit scope of moduleVar string[] moduleVar = variableName.Split(new char[] { '!' }, 2); Debug.Assert(moduleVar != null); if (moduleVar.Length > 2) { throw new MDbgException("Illegal variable syntax."); } else if (moduleVar.Length == 2) { variableModule = Modules.Lookup(moduleVar[0]); variableName = moduleVar[1]; if (variableModule == null) throw new MDbgException("Module not found"); } else variableModule = null; } // lookup 1st part MDbgValue var = null; int nextPart = 0; // Check for predicates if (variableName.StartsWith("gchandle(")) { string stName; string[] args; GetExpressionFunctionArgs(ref variableName, out stName, out args); nextPart = 1; var = this.ParseGCHandleArgs(stName, args, scope); } // end gchandle string[] nameParts = variableName.Split(new char[] { '.', '[' }); Debug.Assert(nameParts.Length >= 1); // there must be at least one part. if (var != null) { // already resolved, no extra work to do. } // Let's check if we are asking for debugger var. Those vars are prefixed with $. // if yes, return the var. else if (variableName.StartsWith("$") && variableModule == null // debugger vars cannot have module specifier ) { string varName = nameParts[nextPart]; Debug.Assert(varName.StartsWith("$")); if (DebuggerVars.HaveVariable(nameParts[nextPart])) { MDbgDebuggerVar dv = DebuggerVars[nameParts[0]]; var = new MDbgValue(this, dv.Name, dv.CorValue); } else var = null; nextPart++; } else { ArrayList vars = new ArrayList(); { // fill up vars with locals+arguments MDbgFunction f = scope.Function; MDbgValue[] vals = f.GetActiveLocalVars(scope); if (vals != null) vars.AddRange(vals); vals = f.GetArguments(scope); if (vals != null) vars.AddRange(vals); } // try to find a match in locals and arguments first foreach (MDbgValue v in vars) if (v.Name == nameParts[nextPart]) { var = v; nextPart++; break; } // if no match for locals and arguments, look for globals and static class members if (var == null) { // now let's try to resolve static var of form Namespace.namespace.typeName.var bool bGlobal = (nameParts[nextPart].Length == 0); if (bGlobal) nextPart++; foreach (MDbgModule m in this.Modules) { if (variableModule != null && variableModule != m) continue; // we're interested only in certain module if (bGlobal) // global variables { // nil type token is used to enum global static data members MetadataType gType = (MetadataType)m.Importer.GetType(0); FieldInfo[] gField = gType.GetFields(0); for (int i = 0; i < gField.Length; i++) { if (nameParts[nextPart] == gField[i].Name) { var = new MDbgValue(this, "." + gField[i].Name, scope.Function.Module.CorModule.GetGlobalVariableValue(gField[i].MetadataToken)); nextPart++; break; } } if (var != null) // done if we find the first match in any module break; } else // static class members { System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.Append(nameParts[nextPart]); for (int i = nextPart + 1; i < nameParts.Length; i++) { int typeToken = m.Importer.GetTypeTokenFromName(sb.ToString()); if (typeToken != CorMetadataImport.TokenNotFound) { // we resolved type, let's try to get statics CorClass cl = m.CorModule.GetClassFromToken(typeToken); Type classType = m.Importer.GetType(cl.Token); foreach (MetadataFieldInfo fi in classType.GetFields()) { if (fi.Name != nameParts[i]) continue; if (fi.IsStatic) { sb.Append(".").Append(nameParts[i]); CorValue fieldValue = cl.GetStaticFieldValue(fi.MetadataToken, scope.CorFrame); var = new MDbgValue(this, sb.ToString(), fieldValue); nextPart = i + 1; goto FieldValueFound; // done if we find the first match in any module } } } sb.Append(".").Append(nameParts[i]); } } } FieldValueFound: ; } }; if (var != null) { // now try to resolve remaining parts. for (int i = nextPart; i < nameParts.Length; i++) { string part = nameParts[i]; if (part.EndsWith("]")) { // it is probably array index string[] indexStrings = part.Substring(0, part.Length - 1).Split(','); Debug.Assert(indexStrings != null && indexStrings.Length > 0); int[] indexes = new int[indexStrings.Length]; for (int j = 0; j < indexStrings.Length; ++j) indexes[j] = Int32.Parse(indexStrings[j], CultureInfo.InvariantCulture); var = var.GetArrayItem(indexes); } else { // we'll treat it as field name var = var.GetField(part); } } } return var; }