/// <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"); } CorDebug.CorValue value = Dereference(CorValue); CorDebug.CorArrayValue av = value.CastToArrayValue(); Debug.Assert(av != null); if (av.Rank != indexes.Length) { throw new MDbgValueException("Invalid number of dimensions."); } var sb = new StringBuilder("["); for (int i = 0; i < indexes.Length; ++i) { if (i != 0) { sb.Append(","); } sb.Append(indexes[i]); } sb.Append("]"); var v = new MDbgValue(Process, sb.ToString(), av.GetElement(indexes)); return(v); }
/// <summary> /// Creates a new instance of the MDbgValue Object. /// This constructor is public so that applications can use this class to print values (CorValue). /// CorValue's can be returned for example by funceval(CorEval.Result). /// </summary> /// <param name="process">The Process that will own the Value.</param> /// <param name="value">The CorValue that this MDbgValue will start with.</param> public MDbgValue(MDbgProcess process, CorDebug.CorValue value) { // value can be null, but we should always know what process we are // looking at. Debug.Assert(process != null); Initialize(process, null, value); }
private void Unbox(ref CorDebug.CorValue value) { CorDebug.CorBoxValue boxVal = value.CastToBoxValue(); if (boxVal != null) { value = boxVal.GetObject(); } }
private CorDebug.CorValue Dereference(CorDebug.CorValue value) { while (true) { CorDebug.CorReferenceValue rv = value.CastToReferenceValue(); if (rv == null) { break; // not a reference } if (rv.IsNull) { return(null); // reference to null } CorDebug.CorValue newValue = rv.Dereference(); if (newValue == null) { break; // couldn't dereference the reference (eg. void*) } value = newValue; } return(value); }
private string MakePtrString(CorDebug.CorValue value) { var sb = new StringBuilder(); while (true) { CorDebug.CorReferenceValue rv = value.CastToReferenceValue(); if (rv == null) { break; // not a reference } if (sb.Length > 0) { sb.Append("->"); } sb.Append("0x" + rv.Value.ToString("X", CultureInfo.CurrentUICulture)); CorDebug.CorValue newValue = null; try { newValue = rv.Dereference(); } catch (COMException ce) { if (ce.ErrorCode != (int)CorDebug.HResult.CORDBG_E_BAD_REFERENCE_VALUE) { throw; // some other error } } if (newValue == null) { break; // couldn't dereference the reference (eg. void* or invalid ref) } value = newValue; } return(sb.ToString()); }
/// <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"); } CorDebug.CorValue value = Dereference(CorValue); CorDebug.CorArrayValue av = value.CastToArrayValue(); int[] dims = av.GetDimensions(); Debug.Assert(dims != null); var al = new ArrayList(); Debug.Assert(av.Rank == 1); for (int i = 0; i < dims[0]; i++) { var v = new MDbgValue(Process, "[" + i + "]", av.GetElementAtPosition(i)); al.Add(v); } return((MDbgValue[])al.ToArray(typeof(MDbgValue))); }
private void Initialize(MDbgProcess process, string name, CorDebug.CorValue value) { m_process = process; m_name = name; m_corValue = value; }
private MDbgValue[] InternalGetFields() { var al = new ArrayList(); //dereference && (unbox); CorDebug.CorValue value = Dereference(CorValue); if (value == null) { throw new MDbgValueException("null value"); } Unbox(ref value); CorDebug.CorObjectValue ov = value.CastToObjectValue(); CorDebug.CorType cType = ov.ExactType; CorDebug.CorFrame cFrame = null; if (Process.Threads.HaveActive) { // we need a current frame to display thread local static values if (Process.Threads.Active.HaveCurrentFrame) { cFrame = Process.Threads.Active.CurrentFrame.CorFrame; } } MDbgModule classModule; // initialization CorDebug.CorClass corClass = ov.Class; classModule = Process.Modules.Lookup(corClass.Module); // iteration through class hierarchy do { Type classType; //int parentToken; classType = classModule.Importer.GetType(corClass.Token); //classModule.Importer.GetTypeNameFromDef(classToken,out parentToken); foreach (MetadataFieldInfo fi in classType.GetFields()) { CorValue fieldValue = null; try { if (fi.IsLiteral) { fieldValue = null; // for now we just hide the constant fields. continue; } else if (fi.IsStatic) { fieldValue = cType.GetStaticFieldValue(fi.MetadataToken, cFrame); } else // we are asuming normal field value // GetFieldValueForTYpe Supersedes GetFieldValue // Will replace when all issues are resolved. //fieldValue = ov.GetFieldValueForType(cType, (uint)fi.Token); { fieldValue = ov.GetFieldValue(corClass, fi.MetadataToken); } } catch (COMException) { // we won't report any problems. } al.Add(new MDbgValue(Process, fi.Name, fieldValue)); } cType = cType.Base; if (cType == null) { break; } corClass = cType.Class; classModule = Process.Modules.Lookup(corClass.Module); } while (true); return((MDbgValue[])al.ToArray(typeof(MDbgValue))); }
/// <summary> /// Creates a new instance of the MDbgValue Object. /// This constructor is public so that applications can use this class to print values (CorValue). /// CorValue's can be returned for example by funceval(CorEval.Result). /// </summary> /// <param name="process">The Process that will own the Value.</param> /// <param name="name">The name of the variable.</param> /// <param name="value">The CorValue that this MDbgValue will start with.</param> public MDbgValue(MDbgProcess process, string name, CorDebug.CorValue value) { Debug.Assert(process != null && name != null); // corValue can be null for native variables in MC++ Initialize(process, name, value); }
private string PrintObject(int indentLevel, CorDebug.CorObjectValue ov, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); // Print generics-aware type. string name = InternalUtil.PrintCorType(m_process, ov.ExactType); var 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. var 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 (ov.IsValueClass && canDoFunceval) // we could display even values for real Objects, but we will just show // "description" for valueclasses. { CorDebug.CorClass cls = ov.ExactType.Class; CorMetadataImport importer = m_process.Modules.Lookup(cls.Module).Importer; var 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; CorDebug.CorValue thisValue; CorDebug.CorHeapValue hv = ov.CastToHeapValue(); if (hv != null) { // we need to pass reference value. CorDebug.CorHandleValue handle = hv.CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION); thisValue = handle; } else { thisValue = ov; } try { CorDebug.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[] { thisValue }); m_process.Go(); do { m_process.StopEvent.WaitOne(); if (m_process.StopReason is EvalCompleteStopReason) { CorDebug.CorValue cv = eval.Result; Debug.Assert(cv != null); var 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 canot copy a VC class error - Can't copy a VC with object refs in it. if (e.ErrorCode != (int)CorDebug.HResult.CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) { throw; } } finally { // 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()); }
////////////////////////////////////////////////////////////////////////////////// // // Implementation Part // ////////////////////////////////////////////////////////////////////////////////// private string InternalGetValue(int indentLevel, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); CorDebug.CorValue value = CorValue; if (value == null) { return("<N/A>"); } // Record the memory addresses if displaying them is enabled string prefix = String.Empty; if (m_process.m_engine.Options.ShowAddresses) { string ptrStr = MakePtrString(value); if (!String.IsNullOrEmpty(ptrStr)) { prefix = "(" + ptrStr + ") "; } } try { value = Dereference(value); } catch (COMException ce) { if (ce.ErrorCode == (int)CorDebug.HResult.CORDBG_E_BAD_REFERENCE_VALUE) { return(prefix + "<invalid reference value>"); } throw; } if (value == null) { return(prefix + "<null>"); } Unbox(ref value); switch (value.Type) { case CorElementType.ELEMENT_TYPE_BOOLEAN: case CorElementType.ELEMENT_TYPE_I1: case CorElementType.ELEMENT_TYPE_U1: case CorElementType.ELEMENT_TYPE_I2: case CorElementType.ELEMENT_TYPE_U2: case CorElementType.ELEMENT_TYPE_I4: case CorElementType.ELEMENT_TYPE_U4: case CorElementType.ELEMENT_TYPE_I: case CorElementType.ELEMENT_TYPE_U: case CorElementType.ELEMENT_TYPE_I8: case CorElementType.ELEMENT_TYPE_U8: case CorElementType.ELEMENT_TYPE_R4: case CorElementType.ELEMENT_TYPE_R8: case CorElementType.ELEMENT_TYPE_CHAR: { object v = value.CastToGenericValue().GetValue(); string result; var vFormattable = v as IFormattable; if (vFormattable != null) { result = vFormattable.ToString(null, CultureInfo.CurrentUICulture); } else { result = v.ToString(); } // let's put quotes around char values if (value.Type == CorElementType.ELEMENT_TYPE_CHAR) { result = "'" + result + "'"; } return(prefix + result); } case CorElementType.ELEMENT_TYPE_CLASS: case CorElementType.ELEMENT_TYPE_VALUETYPE: CorDebug.CorObjectValue ov = value.CastToObjectValue(); return(prefix + PrintObject(indentLevel, ov, expandDepth, canDoFunceval)); case CorElementType.ELEMENT_TYPE_STRING: CorDebug.CorStringValue sv = value.CastToStringValue(); return(prefix + '"' + sv.String + '"'); case CorElementType.ELEMENT_TYPE_SZARRAY: case CorElementType.ELEMENT_TYPE_ARRAY: CorDebug.CorArrayValue av = value.CastToArrayValue(); return(prefix + PrintArray(indentLevel, av, expandDepth, canDoFunceval)); case CorElementType.ELEMENT_TYPE_PTR: return(prefix + "<non-null pointer>"); case CorElementType.ELEMENT_TYPE_BYREF: case CorElementType.ELEMENT_TYPE_TYPEDBYREF: case CorElementType.ELEMENT_TYPE_OBJECT: default: return(prefix + "<printing value of type: " + value.Type + " not implemented>"); } }
private void Initialize(MDbgProcess process, string name, CorDebug.CorValue value) { m_process = process; m_name = name; m_corValue = value; }