/// <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); }
public MDbgFunction Get(CorDebug.CorFunction managedFunction) { int funcVersion; funcVersion = managedFunction.Version; // now get version from our cache. MDbgFunction mdbgFunction = RetrieveFromCache(managedFunction.Token, funcVersion); if (mdbgFunction == null) { mdbgFunction = new MDbgFunction(m_module, managedFunction); AddToCache(managedFunction.Token, funcVersion, mdbgFunction); } return mdbgFunction; }
// http://stackoverflow.com/questions/8094441/is-it-ok-to-abuse-coclassattribute-to-provide-a-default-implementation-for-an static void Main(string[] args) { // Error 2 Cannot create an instance of the abstract class or interface 'TestCoClass.IApp' X:\jsc.svn\examples\rewrite\TestCoClass\TestCoClass\Program.cs 37 21 TestCoClass var x = new IApp { foo = "foo" }; var doc = new Document(); // Error 1 Cannot implicitly convert type 'TestCoClass.Document' to 'TestCoClass.IApp'. An explicit conversion exists (are you missing a cast?) X:\jsc.svn\examples\rewrite\TestCoClass\TestCoClass\Program.cs 41 23 TestCoClass //IApp xx = doc; var xx = doc.ToApp(); // Constructs a FooImpl ICorDebug foo = new CorDebug { MyProperty = 5 }; foo.Bar(); }
protected virtual void Dispose(bool disposing) { if (_isDisposed) { return; } if (disposing) { } CorDebug?.Dispose(); CorProcess?.Dispose(); _callbacks?.Dispose(); CorDebug = null; _process = null; _callbacks = null; _isDisposed = true; }
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(); }
public StepCompleteStopReason(CorDebug.CorStepper stepper, CorDebugStepReason stepReason) { Debug.Assert(stepper != null); m_stepReason = stepReason; m_stepper = stepper; }
// Builds the friendly string for an enum value private string InternalGetEnumString(CorDebug.CorObjectValue ov, MetadataType type) { Debug.Assert(type != null); // Enums should always have a type IList<KeyValuePair<string, ulong>> values = type.EnumValues; // Get the underlying value ulong value = Convert.ToUInt64(ov.CastToGenericValue().UnsafeGetValueAsType(type.EnumUnderlyingType), CultureInfo.InvariantCulture); // Find a reasonable value to display var result = new StringBuilder(); ulong remainingValue = value; bool firstTime = true; for (int i = values.Count - 1; i >= 0; i--) { if ((values[i].Value == value) || (type.ReallyIsFlagsEnum && (values[i].Value != 0) && ((values[i].Value & value) == values[i].Value))) { remainingValue &= ~(values[i].Value); // Remove the flags from the total needed for flags enums if (!firstTime) { if (type.ReallyIsFlagsEnum) { result.Insert(0, ", "); } else { result.Insert(0, " / "); } } result.Insert(0, values[i].Key); firstTime = false; } } if (remainingValue != 0) { if (firstTime) { // No matches whatsoever result.Insert(0, remainingValue); } else { // Flags enum with leftover bits result.AppendFormat(" (Unnamed bits: {0})", remainingValue); } } return result.ToString(); }
/// <summary> /// Create a new instance of the FunctionRemapCompleteStopReason class. /// </summary> /// <param name="appDomain">The appDomain where remapping is occuring.</param> /// <param name="thread">The thread on which the remapping is occuring.</param> /// <param name="managedFunction">The version of function the debugger remapped to.</param> public FunctionRemapCompleteStopReason(CorDebug.CorAppDomain appDomain, CorDebug.CorThread thread, CorDebug.CorFunction managedFunction) { Debug.Assert(appDomain != null); Debug.Assert(thread != null); Debug.Assert(managedFunction != null); m_appDomain = appDomain; m_thread = thread; m_function = managedFunction; }
/// <summary> /// Looks up a CorFunction. /// </summary> /// <param name="managedFunction">Which CorFunction to lookup.</param> /// <returns>The coresponding MDbgFunction.</returns> public MDbgFunction LookupFunction(CorDebug.CorFunction managedFunction) { return Lookup(managedFunction.Module).GetFunction(managedFunction); }
internal MDbgModule(MDbgProcess process, CorDebug.CorModule managedModule, int number) { Debug.Assert(process != null && managedModule != null); m_process = process; m_module = managedModule; m_functions = new MDbgFunctionMgr(this); m_number = number; }
/// <summary> /// Lookup an MDbgProcss from a CorProcess. /// </summary> /// <param name="process">The CorProcess.</param> /// <returns>The MDbgProcess.</returns> public MDbgProcess Lookup(CorDebug.CorProcess process) { foreach (MDbgProcess p in m_items) { if (p.CorProcess == process) { return p; } } return null; }
internal void Unregister(CorDebug.CorAppDomain appDomain) { Debug.Assert(m_items.ContainsKey(appDomain)); m_items.Remove(appDomain); }
/// <summary> /// Locates MDbgAppDomain object from CorAppDomain object. /// </summary> /// <param name="appDomain">appDomain object from CorXXX layer.</param> /// <returns>MdbgAppDomain object</returns> public MDbgAppDomain Lookup(CorDebug.CorAppDomain appDomain) { return (MDbgAppDomain) m_items[appDomain]; }
internal MDbgFunction(MDbgModule managedModule, CorDebug.CorFunction managedFunction) { Debug.Assert(managedModule != null); Debug.Assert(managedFunction != null); Debug.Assert(managedFunction.Version >= 0 && managedFunction.Version - 1 <= managedModule.EditsCounter); // version numbers starts with 1 m_module = managedModule; m_function = managedFunction; EnsureIsUpToDate(); }
/// <summary> /// Registers a Custom Stepper /// Registrations are valid only for one callback, i.e. the object is /// automatically deregistered after the callback is fired. If the user wishes to /// receive additional callback, the registration has to be done again in the /// callback. /// </summary> /// <param name="stepper">The CorStepper to run.</param> /// <param name="handler">The CustomStepperEventHandler to use.</param> public void RegisterCustomStepper(CorDebug.CorStepper stepper, CustomStepperEventHandler handler) { Debug.Assert(stepper != null); if (stepper == null) throw new ArgumentException("cannot be null", "stepper"); if (handler == null) { // explicit deregistration if (customSteppers != null) customSteppers.Remove(stepper); } else { // adding registration if (customSteppers == null) customSteppers = new ListDictionary(); else if (customSteppers.Contains(stepper)) throw new InvalidOperationException("Handler alrady registered for the custom stepper"); customSteppers.Add(stepper, handler); } }
/// <summary> /// Sets a stepper for the process. Process will stop with step complete, /// once this stepper completes the step. /// This function just sets the active stepper, but it doesn't continue the process. /// Once the stepper is set, a Go() command needs to be called. /// </summary> /// <returns>A WaitHandle for the Stop event.</returns> public void SetActiveStepper(CorDebug.CorStepper activeStepper) { // we are not interested in finishing old step. if (m_activeStepper != null) m_activeStepper.Deactivate(); m_activeStepper = activeStepper; }
/// <summary>Creates an empty process object. /// This object can be used to start a debugging session by calling /// CreateProcess or Attach method on it. /// </summary> /// <param name="engine">Root engine object that manages this process.</param> /// <param name="debugger">CorDebugger object that will be used to do an actual /// debugging</param> public MDbgProcess(MDbgEngine engine, CorDebug.CorDebugger debugger) { Debug.Assert(engine != null && debugger != null); if (engine == null) throw new ArgumentException("Value cannot be null.", "engine"); if (debugger == null) throw new ArgumentException("Value cannot be null.", "debugger"); m_engine = engine; m_threadMgr = new MDbgThreadCollection(this); m_appDomainMgr = new MDbgAppDomainCollection(this); m_moduleMgr = new MDbgModuleCollection(this); m_breakpointMgr = new MDbgBreakpointCollection(this); m_debuggerVarMgr = new MDbgDebuggerVarCollection(this); m_corDebugger = debugger; // we'll register as last code, so that other fields are already registered. m_number = engine.Processes.RegisterProcess(this); }
private string PrintArray(int indentLevel, CorDebug.CorArrayValue av, int expandDepth, bool canDoFunceval) { Debug.Assert(expandDepth >= 0); var 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++) { // Arrays not starting with 0 are not implemented var 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(); }
internal MDbgModule Register(CorDebug.CorModule managedModule) { MDbgModule mdbgModule; if (m_items.ContainsKey(managedModule)) { mdbgModule = (MDbgModule) m_items[managedModule]; return mdbgModule; } mdbgModule = new MDbgModule(m_process, managedModule, m_freeModuleNumber++); m_items.Add(managedModule, mdbgModule); return mdbgModule; }
/// <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); }
/// <summary> /// Create a new instance of the MDANotificationStopReason class. /// </summary> /// <param name="mda">Generated MDA notification.</param> public MDANotificationStopReason(CorDebug.CorMDA mda) { Debug.Assert(mda != null); m_mda = mda; }
internal MDbgAppDomain Register(CorDebug.CorAppDomain appDomain) { MDbgAppDomain mdbgAppDomain; // appdomains may get registered mutliple times if we get a fake-attach event right before a real event. if (!m_items.Contains(appDomain)) { mdbgAppDomain = new MDbgAppDomain(m_process, appDomain, m_freeAppDomainNumber++); m_items.Add(appDomain, mdbgAppDomain); return mdbgAppDomain; } return (MDbgAppDomain) m_items[appDomain]; }
/// <summary> /// Locates MDbgBreakpoint object from the CorBreakpoint object. /// </summary> /// <param name="corBreakpoint">breakpoint object from CorXXX layer.</param> /// <returns>MDbgBreakpoint object</returns> /// <remarks> /// returns null if there the breakpoint was not known to the breakpoint /// collection. /// </remarks> public MDbgBreakpoint Lookup(CorDebug.CorBreakpoint corBreakpoint) { foreach (MDbgBreakpoint b in m_items) { foreach (CorDebug.CorBreakpoint cb in b.CorBreakpoints) { if (cb == corBreakpoint) { return b; } } } return null; }
internal MDbgAppDomain(MDbgProcess process, CorDebug.CorAppDomain appDomain, int number) { Debug.Assert(process != null); Debug.Assert(appDomain != null); m_process = process; m_appDomain = appDomain; m_number = number; }
private void Initialize(MDbgProcess process, string name, CorDebug.CorValue value) { m_process = process; m_name = name; m_corValue = value; }
internal void Unregister(CorDebug.CorModule managedModule) { Debug.Assert(m_items.ContainsKey(managedModule)); m_items.Remove(managedModule); }
private void Unbox(ref CorDebug.CorValue value) { CorDebug.CorBoxValue boxVal = value.CastToBoxValue(); if (boxVal != null) value = boxVal.GetObject(); }
/// <summary> /// Gets the MDbgFunction for a given CorFunction. /// </summary> /// <param name="managedFunction">The CorFunction to lookup.</param> /// <returns>The coresponding MDbgFunction.</returns> public MDbgFunction GetFunction(CorDebug.CorFunction managedFunction) { return m_functions.Get(managedFunction); }
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> /// Looks up a CorModule. /// </summary> /// <param name="managedModule">Which CorModule to lookup.</param> /// <returns>The coresponding MDbgModule.</returns> public MDbgModule Lookup(CorDebug.CorModule managedModule) { return (MDbgModule) m_items[managedModule]; }
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; }