/// <summary> /// Releases all resources used by the MDbgModule. /// </summary> public void Dispose() { // Our funtion list may hold onto unmanaged SymbolMethod objects, so dispose that too. m_functions.Dispose(); m_functions = null; // Release unmanaged resources. m_symReader = null; m_module = null; m_importer = null; }
/// <summary> /// Constructor /// </summary> /// <param name="frame">The CorFrame frame object</param> /// <param name="importer">The meta data importer for the module this frame is contained within</param> internal FrameInfo(CorFrame frame, CorMetadataImport importer) { if (frame == null) { throw new ArgumentNullException("frame"); } if (importer == null) { throw new ArgumentNullException("importer"); } thisFrame = frame; metaImporter = importer; functionShortName = ""; functionFullName = ""; moduleShortName = ""; moduleFullName = ""; functionFileName = null; functionLineNumber = -1; //-1 is set by deafult which means no line number SourcePosition functionPos = null; //position in this function where we are //make binder and reader for the metadata if (thisFrame.FrameType == CorFrameType.InternalFrame) { functionFullName = functionShortName = InternalFrameToString(); } else { try { functionPos = GetMetaDataInfo(importer); } catch (Exception e) { // We are not able to find information about the source code functionFileName = "unknown method: " + e.Message; } } if (functionPos != null) { functionLineNumber = functionPos.Line; functionFileName = Path.GetFileName(functionPos.Path); } else { functionLineNumber = -1; //no line number available functionFileName = functionFileName ?? "source unavailable"; } }
/// <summary> /// Dispose managed and unmanaged objects /// </summary> /// <param name="disposing">Dispose managed objects</param> protected virtual void Dispose(bool disposing) { if (disposing) { // Free other state (managed objects). metaImporter = null; symDocs = null; offsets = null; startLines = null; endLines = null; startColumns = null; endColumns = null; } // Free your own state (unmanaged objects). }
IEnumerable <Type> GetAllTypes(EvaluationContext gctx) { CorEvaluationContext ctx = (CorEvaluationContext)gctx; foreach (CorModule mod in ctx.Session.GetModules()) { CorMetadataImport mi = ctx.Session.GetMetadataForModule(mod.Name); if (mi != null) { foreach (Type t in mi.DefinedTypes) { yield return(t); } } } }
/// <summary> /// Constructor /// </summary> /// <param name="frame">The CorFrame frame object</param> /// <param name="importer">The meta data importer for the module this frame is contained within</param> internal FrameInfo(CorFrame frame, CorMetadataImport importer) { if (frame == null) { throw new ArgumentNullException("frame"); } if (importer == null) { throw new ArgumentNullException("importer"); } thisFrame = frame; metaImporter = importer; functionShortName = ""; functionFullName = ""; moduleShortName = ""; moduleFullName = ""; functionFileName = ""; functionLineNumber = -1; //-1 is set by deafult which means no line number SourcePosition functionPos = null; //position in this function where we are //make binder and reader for the metadata if (thisFrame.FrameType == CorFrameType.InternalFrame) { functionFullName = functionShortName = InternalFrameToString(); } else { functionPos = GetMetaDataInfo(importer); } if (functionPos != null) { functionLineNumber = functionPos.Line; functionFileName = Path.GetFileName(functionPos.Path); } else { ResourceManager stackStrings = new ResourceManager(typeof(Resources)); functionLineNumber = -1; //no line number available functionFileName = stackStrings.GetString("sourceUnavailable"); } }
/*private void CorProcess_OnStepComplete(object sender, CorStepCompleteEventArgs e) * { * // if (iCount++ % 100 == 0 && logOnBreakpoint) * DI.log.info("[{0}] CorProcess_OnStepComplete {1}", iStepCount++, getActiveFrameFunctionName(e)); * e.Continue = handleDebugFlowAction(); * } * * private void CorProcess_OnBreakpointSetError(object sender, CorBreakpointEventArgs e) * { * if (logOnBreakpoint) * DI.log.info("CorProcess_OnBreakpointSetError {0}", getActiveFrameFunctionName(e)); * e.Continue = true; * } * * private void CorProcess_OnBreakpoint(object sender, CorBreakpointEventArgs e) * { * DI.log.info("in CorProcess_OnBreakpoint"); * /*( if (handleBreakpoints) * { * if (logOnBreakpoint) * log.info("Breakpoint on {0}", getActiveFrameFunctionName(e)); * e.Continue = handleDebugFlowAction(); * }* / * e.Continue = true; * } * * private bool handleDebugFlowAction() * { * switch (onBreakPointAction) * { * case OnBreakPointAction.StepOut: * o2MDbgOLD.mdbgProcess.StepOut(); * break; * case OnBreakPointAction.StepInto: * o2MDbgOLD.mdbgProcess.StepInto(false); * break; * case OnBreakPointAction.StepOver: * o2MDbgOLD.mdbgProcess.StepOver(false); * break; * * case OnBreakPointAction.Stop: * return false; * case OnBreakPointAction.Continue: * return true; * } * return true; * } */ public static string getActiveFrameFunctionName(CorEventArgs e) { try { if (e.Thread.ActiveFrame == null) { return("e.Thread.ActiveFrame == null"); } //var corFunctionBreakpoint = (CorFunctionBreakpoint)e.Breakpoint; var corMetadataImport = new CorMetadataImport(e.Thread.ActiveFrame.Function.Class.Module); MethodInfo methodInfo = corMetadataImport.GetMethodInfo(e.Thread.ActiveFrame.Function.Token); return((methodInfo.DeclaringType.FullName ?? "(null)") + " :: " + (methodInfo.Name ?? "(null)")); } catch (Exception ex) { DI.log.ex(ex, "getActiveFrameFunctionName"); return(""); } }
public override object GetType(EvaluationContext gctx, string name, object[] gtypeArgs) { CorType[] typeArgs = CastArray <CorType> (gtypeArgs); CorEvaluationContext ctx = (CorEvaluationContext)gctx; foreach (CorModule mod in ctx.Session.GetModules()) { CorMetadataImport mi = ctx.Session.GetMetadataForModule(mod.Name); if (mi != null) { foreach (Type t in mi.DefinedTypes) { if (t.FullName == name) { CorClass cls = mod.GetClassFromToken(t.MetadataToken); return(cls.GetParameterizedType(CorElementType.ELEMENT_TYPE_CLASS, typeArgs)); } } } } return(null); }
internal static StackFrame CreateFrame(CorDebuggerSession session, CorFrame frame) { // TODO: Fix remaining. uint address = 0; //string typeFQN; //string typeFullName; string addressSpace = ""; string file = ""; int line = 0; int column = 0; string method = ""; string lang = ""; string module = ""; string type = ""; bool hasDebugInfo = false; bool hidden = false; bool external = true; if (frame.FrameType == CorFrameType.ILFrame) { if (frame.Function != null) { module = frame.Function.Module.Name; CorMetadataImport importer = new CorMetadataImport(frame.Function.Module); MethodInfo mi = importer.GetMethodInfo(frame.Function.Token); method = mi.DeclaringType.FullName + "." + mi.Name; type = mi.DeclaringType.FullName; addressSpace = mi.Name; ISymbolReader reader = session.GetReaderForModule(frame.Function.Module.Name); if (reader != null) { ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met != null) { CorDebugMappingResult mappingResult; frame.GetIP(out address, out mappingResult); SequencePoint prevSp = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Offset > address) { break; } prevSp = sp; } if (prevSp != null) { line = prevSp.Line; column = prevSp.Offset; file = prevSp.Document.URL; address = (uint)prevSp.Offset; } } } // FIXME: Still steps into. //hidden = mi.GetCustomAttributes (true).Any (v => v is System.Diagnostics.DebuggerHiddenAttribute); } lang = "Managed"; hasDebugInfo = true; } else if (frame.FrameType == CorFrameType.NativeFrame) { frame.GetNativeIP(out address); method = "<Unknown>"; lang = "Native"; } else if (frame.FrameType == CorFrameType.InternalFrame) { switch (frame.InternalFrameType) { case CorDebugInternalFrameType.STUBFRAME_M2U: method = "[Managed to Native Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_U2M: method = "[Native to Managed Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_LIGHTWEIGHT_FUNCTION: method = "[Lightweight Method Call]"; break; case CorDebugInternalFrameType.STUBFRAME_APPDOMAIN_TRANSITION: method = "[Application Domain Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_FUNC_EVAL: method = "[Function Evaluation]"; break; } } if (method == null) { method = "<Unknown>"; } var loc = new SourceLocation(method, file, line, column); return(new StackFrame((long)address, addressSpace, loc, lang, external, hasDebugInfo, hidden, null, null)); }
public static void Disassemble(byte[] ilCode, CorMetadataImport importer, out string[] lines, out int[] ip2line) { ArrayList ils = new ArrayList(); ip2line = new int[ilCode.Length]; int pc = 0; while (pc < ilCode.Length) { string instruction = ""; int instruction_start = pc; int opCodeSize; ILOpCode opCode = DecodeOpcode(ilCode, pc, out opCodeSize); pc += opCodeSize; switch ((OpcodeFormat)GenTables.opCodeTypeInfo[(int)opCode].Type) { default: Debug.Assert(false); break; case OpcodeFormat.InlineNone: instruction = GenTables.opCodeTypeInfo[(int)opCode].Name; break; case OpcodeFormat.ShortInlineI: case OpcodeFormat.ShortInlineVar: { byte arg = ilCode[pc]; pc++; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.InlineVar: { Int16 arg = BitConverter.ToInt16(ilCode, pc); pc += 2; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.InlineI: case OpcodeFormat.InlineRVA: { Int32 arg = BitConverter.ToInt32(ilCode, pc); pc += 4; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.InlineI8: { Int64 arg = BitConverter.ToInt64(ilCode, pc); pc += 8; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.ShortInlineR: { float arg = BitConverter.ToSingle(ilCode, pc); pc += 4; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.InlineR: { double arg = BitConverter.ToDouble(ilCode, pc); pc += 8; instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.ShortInlineBrTarget: { sbyte offset = (sbyte)ilCode[pc]; pc++; int dest = pc + offset; instruction = String.Format(CultureInfo.InvariantCulture, "{0} IL_{1,-4:X}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, dest }); break; } case OpcodeFormat.InlineBrTarget: { Int32 offset = BitConverter.ToInt32(ilCode, pc); pc += 4; int dest = pc + offset; instruction = String.Format(CultureInfo.InvariantCulture, "{0} IL_{1,-4:X}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, dest }); break; } case OpcodeFormat.InlineSwitch: case OpcodeFormat.InlinePhi: instruction = "MESSED UP!"; // variable size Debug.Assert(false); break; case OpcodeFormat.InlineString: case OpcodeFormat.InlineField: case OpcodeFormat.InlineType: case OpcodeFormat.InlineToken: case OpcodeFormat.InlineMethod: { int token = BitConverter.ToInt32(ilCode, pc); pc += 4; CorTokenType tokenType = TokenUtils.TypeFromToken(token); // if it is reference token we need to dereference it. string arg = null; switch (tokenType) { default: Debug.Assert(false); break; case CorTokenType.mdtTypeDef: int extendsToken; arg = importer.GetTypeNameFromDef(token, out extendsToken); break; case CorTokenType.mdtTypeRef: arg = importer.GetTypeNameFromRef(token); break; case CorTokenType.mdtTypeSpec: arg = "NYI"; break; case CorTokenType.mdtMethodDef: MethodInfo mi = importer.GetMethodInfo(token); Type dt = mi.DeclaringType; arg = (dt == null ? "" : dt.Name) + "." + mi.Name; break; case CorTokenType.mdtFieldDef: arg = "NYI"; break; case CorTokenType.mdtMemberRef: arg = importer.GetMemberRefName(token); break; case CorTokenType.mdtString: arg = "\"" + importer.GetUserString(token) + "\""; break; } // switch(tokenType) instruction = String.Format(CultureInfo.InvariantCulture, "{0} {1}", new Object[] { GenTables.opCodeTypeInfo[(int)opCode].Name, arg }); break; } case OpcodeFormat.InlineSig: instruction = GenTables.opCodeTypeInfo[(int)opCode].Name; pc += 4; break; } // switch((OpcodeFormat)GenTables.opCodeTypeInfo[(int)opCode].Type) ils.Add(String.Format(CultureInfo.InvariantCulture, "IL_{0,-4:X}: {1}", new Object[] { instruction_start, instruction })); // add ip2line mapping for (int i = instruction_start; i < pc; i++) { ip2line[i] = ils.Count - 1; // last line } } // while(pc<ilCode.Length) lines = (string[])ils.ToArray(typeof(string)); return; }
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()); }
internal static StackFrame CreateFrame(CorDebuggerSession session, CorFrame frame) { uint address = 0; string file = ""; int line = 0; string method = ""; string lang = ""; string module = ""; if (frame.FrameType == CorFrameType.ILFrame) { if (frame.Function != null) { module = frame.Function.Module.Name; CorMetadataImport importer = new CorMetadataImport(frame.Function.Module); MethodInfo mi = importer.GetMethodInfo(frame.Function.Token); method = mi.DeclaringType.FullName + "." + mi.Name; ISymbolReader reader = session.GetReaderForModule(frame.Function.Module.Name); if (reader != null) { ISymbolMethod met = reader.GetMethod(new SymbolToken(frame.Function.Token)); if (met != null) { uint offset; CorDebugMappingResult mappingResult; frame.GetIP(out offset, out mappingResult); SequencePoint prevSp = null; foreach (SequencePoint sp in met.GetSequencePoints()) { if (sp.Offset > offset) { break; } prevSp = sp; } if (prevSp != null) { line = prevSp.Line; file = prevSp.Document.URL; } } } } lang = "Managed"; } else if (frame.FrameType == CorFrameType.NativeFrame) { frame.GetNativeIP(out address); method = "<Unknown>"; lang = "Native"; } else if (frame.FrameType == CorFrameType.InternalFrame) { switch (frame.InternalFrameType) { case CorDebugInternalFrameType.STUBFRAME_M2U: method = "[Managed to Native Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_U2M: method = "[Native to Managed Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_LIGHTWEIGHT_FUNCTION: method = "[Lightweight Method Call]"; break; case CorDebugInternalFrameType.STUBFRAME_APPDOMAIN_TRANSITION: method = "[Application Domain Transition]"; break; case CorDebugInternalFrameType.STUBFRAME_FUNC_EVAL: method = "[Function Evaluation]"; break; } } if (method == null) { method = "<Unknown>"; } return(new StackFrame((long)address, module, method, file, line, lang)); }
/// <summary> /// Read the pdb file for this module and frame /// Retrieve infomation about the function /// </summary> /// <remarks> /// When an unmanaged app like reflector loads CLR, "Function.Module.Name" /// doesn't return a valid value and so this function returns null. /// </remarks> /// <returns>SourcePosition of the function</returns> private SourcePosition GetMetaDataInfo(CorMetadataImport importer) { SourcePosition functionPos = null; //position in this function where we are try { moduleFullName = thisFrame.Function.Module.Name; moduleShortName = System.IO.Path.GetFileName(moduleFullName); } catch (ArgumentException) { moduleFullName = ""; moduleShortName = ""; return(null); } //TODO: Implement a better method to determine the symbol path than just assuming it's in the same // directory string sympath = "."; //dealing with readinf the source in the module ISymbolReader metaReader = null; ISymbolBinder1 symbolBinder = new SymbolBinder(); try { if (moduleFullName.Length > 0) { metaReader = (symbolBinder as SymbolBinder). GetReaderForFile(importer.RawCOMObject, moduleFullName, sympath); } } catch (COMException) { //Debug.WriteLine(ed.ToString(CultureInfo.CurrentCulture.NumberFormat)); //will get here for any function which we cant read the .pdb file for //its not a big deal we just wont have source and line info } if (metaReader != null) { ISymbolMethod symMethod = null; try { symMethod = metaReader.GetMethod(new SymbolToken((int)thisFrame.Function.Token), thisFrame.Function.Version); int sequenceCount = symMethod.SequencePointCount; symDocs = new ISymbolDocument[sequenceCount]; offsets = new int[sequenceCount]; startLines = new int[sequenceCount]; startColumns = new int[sequenceCount]; endLines = new int[sequenceCount]; endColumns = new int[sequenceCount]; //Get the sequence points and store them in the apporpriate arrays. Seqeunce points //represent the different points in the files which correlate to il instruction and lines symMethod.GetSequencePoints(offsets, symDocs, startLines, startColumns, endLines, endColumns); functionPos = GetSourcePositionFromFrame(); } catch (COMException) { functionPos = null; } finally { symDocs = null; symMethod = null; } } CorType ctype = GetClassType(); if (ctype != null) { StringBuilder sb = new StringBuilder(); GetFunctionClassPath(sb, ctype); functionFullName = sb.ToString(); } else { functionFullName = ""; } MethodInfo methIn = importer.GetMethodInfo(thisFrame.Function.Token); functionFullName += "." + methIn.Name; functionShortName = methIn.Name; return(functionPos); }
public TypeDefEnum(CorMetadataImport corMeta) { m_corMeta = corMeta; }
private string PrintObject(int indentLevel, CorObjectValue ov, 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]"); } 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, $"{variableName}.{v.Name}", variablesToLog))); } } // 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, variableName, variablesToLog); // 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()); }