public void Attach(MDbgProcess process) { process.PostDebugEvent += (sender, e) => { log.Log(e.CallbackType.ToString()); if (e.CallbackType == ManagedCallbackType.OnException2) { var ce = (CorException2EventArgs)e.CallbackArgs; if (ce.EventType == CorDebugExceptionCallbackType.DEBUG_EXCEPTION_FIRST_CHANCE) { var thread = process.Threads.Lookup(ce.Thread); foreach (var frame in thread.Frames) { if (!frame.IsManaged || frame.Function.FullName.StartsWith("System.")) break; log.Log("{0}({1})", frame.Function.FullName, string.Join(", ", frame.Function.GetArguments(frame).Select( arg => string.Format("{0} = {1}", arg.Name, arg.GetStringValue(false))))); } } } }; }
/// <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, 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); }
internal MDbgAppDomain(MDbgProcess process, CorAppDomain appDomain, int number) { Debug.Assert(process != null); Debug.Assert(appDomain != null); m_process = process; m_appDomain = appDomain; m_number = number; }
/// <summary> /// Creates an empty stepper. /// </summary> /// <param name="process">non-null process that this is stepping</param> public StepperDescriptor(MDbgProcess process) { if (process == null) { throw new ArgumentNullException("process"); } m_process = process; }
internal MDbgModule(MDbgProcess process, CorModule managedModule, int number) { Debug.Assert(process != null && managedModule != null); m_process = process; m_module = managedModule; m_functions = new MDbgFunctionMgr(this); m_number = number; }
// Helper to append generic args from tyenum in pretty format. // This will add a string like '<int, Foo<string>>' internal static void AddGenericArgs(StringBuilder sb, MDbgProcess proc, IEnumerable tyenum) { int i = 0; foreach(CorType t1 in tyenum) { sb.Append((i == 0) ? '<' : ','); InternalUtil.PrintCorType(sb, proc, t1); i++; } if (i > 0) { sb.Append('>'); } }
/// <summary> /// Gets the current output of the template function. /// </summary> /// <remarks> /// Assumes that debuggedProc can be examined safely, and that the current output is stored in a static /// variable called __CurrentOutput in the class containing the template function. /// Alternatively, if the </remarks> /// <param name="debuggedProc">The Process that is being debugged.</param> /// <returns>The current output of the template function.</returns> private string GetCurrentOutput(MDbgProcess debuggedProc) { MDbgValue val = null; int lineNumber = (debuggedProc.Threads.HaveActive && debuggedProc.Threads.Active.HaveCurrentFrame && debuggedProc.Threads.Active.CurrentFrame.SourcePosition != null) ? debuggedProc.Threads.Active.CurrentFrame.SourcePosition.Line : 0; if (lineNumber == LAST_LINE_IN_MAIN) { val = debuggedProc.ResolveVariable("obj", debuggedProc.Threads.Active.CurrentFrame); } else if (debuggedProc.Threads.Active.CurrentFrame.SourcePosition != null) { if (debuggedProc.Threads.Active.CurrentFrame.SourcePosition.Path.Contains(Path.Combine("ArchAngel.Debugger.DebugProcess", "Commands.cs"))) { return ""; } val = debuggedProc.ResolveVariable("instance", debuggedProc.Threads.Active.CurrentFrame) ?? debuggedProc.ResolveVariable("this", debuggedProc.Threads.Active.CurrentFrame); if (val == null) return "Could not get value of current output"; string funcName = TestNamespace + "." + TestClassname + ".GetCurrentStringBuilder"; val = ResolveFunction(debuggedProc, val, funcName); val = ResolveFunction(debuggedProc, val, "System.Text.StringBuilder.ToString"); } if (val == null) return "Could not get value of current output"; string currentOutput = val.GetStringValue(1); currentOutput = currentOutput.Remove(0, 1); currentOutput = currentOutput.Remove(currentOutput.Length - 1, 1); return currentOutput; }
/// <summary>Starts the debugging process. This is synchronised on the Debugger /// object it is called on.</summary> /// <remarks> /// Assumes that the DebuggerSync object has been set up correctly and that something /// is listening to the BackgroundWorker events. It will lock indefinitely if something /// doesn't tell it to continue by calling set on the DebuggerSync.ContinueDebugExecution /// object. /// </remarks> public void Run() { lock (this) { int pid = DebugProcess.GetDebugProcessId(); CommandReceiver obj = DebugProcess.GetCommandReceiver(); // Get Assembly Search paths. These are used for finding // any assemblies that are used by the template. List<string> assemblySearchPaths = new List<string>(); foreach (string assemblyLocation in AssemblyLocations) { string dir = Path.GetDirectoryName(assemblyLocation).ToLower(); if (assemblySearchPaths.BinarySearch(dir) < 0) { assemblySearchPaths.Add(dir); assemblySearchPaths.Sort(); } } obj.ExecuteCommand(new RunFunctionCommand(CompiledAssemblyLocation, TestNamespace, TestClassname, TestFunctionName, ArgumentList, UserOptions, AaprojXml, IsFunctionStatic)); // This is a race condition, but it is required because we can't create the breakpoints // before attaching to the process. MDbgEngine debugger = new MDbgEngine(); proc = debugger.Attach(pid); _CurrentlyRunningBreakpoints.Clear(); foreach (int bp in _Breakpoints) { _CurrentlyRunningBreakpoints.Add(bp, proc.Breakpoints.CreateBreakpoint(CodeFilename, bp)); } proc.Breakpoints.CreateBreakpoint("Commands.cs", LAST_LINE_IN_MAIN); proc.Breakpoints.CreateBreakpoint(CodeFilename, LAST_LINE_IN_FUNCTION); _CurrentlyRunningProcess = proc; while (proc.IsAlive) { // Let the debuggee run and wait until it hits a debug event. switch (_DebuggerSync.NextDebugAction) { case DebugActionType.Continue: proc.Go().WaitOne(); break; case DebugActionType.StepInto: proc.StepInto(false).WaitOne(); break; case DebugActionType.StepOver: proc.StepOver(false).WaitOne(); break; case DebugActionType.StepOut: proc.StepOut().WaitOne(); break; case DebugActionType.Stop: _CurrentlyRunningProcess = null; proc.Breakpoints.DeleteAll(); proc.Detach(); break; } if (!proc.IsAlive) { proc = null; break; } // Get a DebugInformation object filled with the info we need. DebugInformation di = GetDebugInformation(proc); // If this is the last line, we need to stop debugging. if (di.StartLineNumber == LAST_LINE_IN_MAIN) { di.Stopped = false; di.StopReason = StopReason.DebuggerFinished; di.StopReasonText = "Debugger Finished"; _DebuggerSync.DebugBackgroundWorker.ReportProgress(99, di); _CurrentlyRunningProcess = null; proc.Breakpoints.DeleteAll(); proc.Detach(); break; } // Any other lines in the main function should just be skipped. if (di.SourceFile == "Commands.cs") { _DebuggerSync.NextDebugAction = DebugActionType.Continue; continue; } if (di.StartLineNumber == LAST_LINE_IN_FUNCTION) { _DebuggerSync.NextDebugAction = DebugActionType.StepOut; continue; } // If an exception was thrown, report it then stop debugging. if (di.ExceptionThrown) { di.Stopped = false; _DebuggerSync.DebugBackgroundWorker.ReportProgress(99, di); _CurrentlyRunningProcess = null; proc.Breakpoints.DeleteAll(); proc.Detach(); break; } di.Stopped = true; _DebuggerSync.DebugBackgroundWorker.ReportProgress(50, di); _DebuggerSync.ContinueDebugExecution.WaitOne(); continue; } } _CurrentlyRunningProcess = null; }
/// <summary> /// Creates a default 'source level step' on process with current active frame and active thread. /// </summary> /// <param name="process">non-null process </param> /// <param name="type">type of step (in, out, over)</param> /// <param name="singleStepInstructions">false to step source level, true to step single instructions</param> /// <returns></returns> public static StepperDescriptor CreateSourceLevelStep(MDbgProcess process, StepperType type, bool singleStepInstructions) { StepperDescriptor s = new StepperDescriptor(process); s.StepperType = type; // // Handle Step-out case. // if (type == StepperType.Out) { return s; } // // Handle step-over / step-in case // bool stepInto = (type == StepperType.In); // Cache current s.Thread = process.Threads.Active.CorThread; s.Frame = s.Thread.ActiveFrame; CorDebugMappingResult mappingResult; uint ip; if (!singleStepInstructions) { // For source-level stepping, skip some interceptors. These are random, and cause // random differences in stepping across different runtimes; and user generally don't care // about interceptors. // It's actually a debatable policy about which interceptors to skip and stop on. s.InterceptMask = CorDebugIntercept.INTERCEPT_ALL & ~(CorDebugIntercept.INTERCEPT_SECURITY | CorDebugIntercept.INTERCEPT_CLASS_INIT); } s.Frame.GetIP(out ip, out mappingResult); if (singleStepInstructions || (mappingResult != CorDebugMappingResult.MAPPING_EXACT && mappingResult != CorDebugMappingResult.MAPPING_APPROXIMATE)) { // Leave step ranges null } else { // Getting the step ranges is what really makes this a source-level step. MDbgFunction f = process.Modules.LookupFunction(s.Frame.Function); COR_DEBUG_STEP_RANGE[] sr = f.GetStepRangesFromIP((int)ip); if (sr != null) { s.SetStepRanges(sr, true); } else { // Leave step ranges null. } } return s; }
/// <summary> /// Creates a source level stepper /// </summary> /// <param name="process"></param> /// <param name="type"></param> /// <returns></returns> public static StepperDescriptor CreateSourceLevelStep(MDbgProcess process, StepperType type) { bool stepNativeCode = false; return CreateSourceLevelStep(process, type, stepNativeCode); }
/// <summary> /// Skip past fake attach events. /// </summary> /// <param name="debugger"></param> /// <param name="proc"></param> public static void DrainAttach(MDbgEngine debugger, MDbgProcess proc) { bool fOldStatus = debugger.Options.StopOnNewThread; debugger.Options.StopOnNewThread = false; // skip while waiting for AttachComplete proc.Go().WaitOne(); Debug.Assert(proc.StopReason is AttachCompleteStopReason); debugger.Options.StopOnNewThread = true; // needed for attach= true; // needed for attach // Drain the rest of the thread create events. while (proc.CorProcess.HasQueuedCallbacks(null)) { proc.Go().WaitOne(); Debug.Assert(proc.StopReason is ThreadCreatedStopReason); } debugger.Options.StopOnNewThread = fOldStatus; }
/// <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 ProcessSample GetCallstacks(MDbgProcess proc, bool onlyMainThread , bool withArgs = false, bool originFirst = false) { if (onlyMainThread) return DebuggerUtils.GetCallstacks(proc, m_intMainThreadId, withArgs, originFirst); else return DebuggerUtils.GetCallstacks(proc, -1, withArgs, originFirst); }
private void Initialize(MDbgProcess process, string name, CorValue value) { m_process = process; m_name = name; m_corValue = value; }
public void StartListening() { if (m_processId == -1) return; if (m_blnIsListening) return; m_debugger = new MDbgEngine(); m_process = null; m_blnIsListening = true; Task t = Task.Factory.StartNew(() => { try { string timeString1 = DebuggerUtils.GetTimeString(true); m_process = DebuggerUtils.AttachToProcess(m_processId, m_debugger); LastLogFileName = Path.Combine(LogFileDirectory, m_process.Name + "(" + m_processId + ") T" + timeString1 + ".log"); } catch (Exception ex) { DebuggerUtils.HandleException(ex); } try { //m_process.Go(); //m_process.Go().WaitOne(); //m_process.Detach(); //m_debugger.Options.StopOnLogMessage = true; m_debugger.Options.StopOnException = true; //m_debugger.Options.StopOnExceptionEnhanced = false; m_debugger.Options.StopOnUnhandledException = true; m_blnIsListening = true; while (m_process.IsAlive) { //if (e.CallbackType == ManagedCallbackType.OnException2) //{ // var ce = (CorException2EventArgs)e.CallbackArgs; // if (ce.EventType == CorDebugExceptionCallbackType.DEBUG_EXCEPTION_FIRST_CHANCE) // { // var thread = process.Threads.Lookup(ce.Thread); // foreach (var frame in thread.Frames) // { // if (!frame.IsManaged || frame.Function.FullName.StartsWith("System.")) // break; // log.Log("{0}({1})", frame.Function.FullName, string.Join(", ", frame.Function.GetArguments(frame).Select( // arg => string.Format("{0} = {1}", arg.Name, arg.GetStringValue(false))))); // } // } //} try { m_process.Go().WaitOne(); //if (e.CallbackType == ManagedCallbackType.OnBreakpoint) //m_process.Go().WaitOne(); object o = m_process.StopReason; ExceptionThrownStopReason stopReason = o as ExceptionThrownStopReason; if (stopReason != null) { if (stopReason.EventType == Microsoft.Samples.Debugging.CorDebug.NativeApi.CorDebugExceptionCallbackType.DEBUG_EXCEPTION_UNHANDLED) { string timeString = DebuggerUtils.GetTimeString(true); if (WriteDumpOnUncaughtExceptions) { m_strLastDumpFileName = Path.Combine(m_strDumpFileDirectory, m_process.Name + timeString + ".dmp"); DumpWriter.WriteDump(m_process.CorProcess.Id, m_strLastDumpFileName, DumpOptions.WithFullMemory); } } if (LogExceptions) { //File.AppendAllText(LastLogFileName, DateTime.Now.ToString("dd\\MM\\yyyy mm:hh:ss.fff]") + DebuggerUtils.GetExceptionDescFromProcess(m_process) + "\n"); try { string exceptionDesc = DebuggerUtils.GetExceptionDescFromProcess(m_process, true); //Console.Out.WriteLine("----------------------------------------------------"); //Console.Out.WriteLine(exceptionDesc); File.AppendAllText(LastLogFileName, "----------------------------------------------------\n" + DateTime.Now.ToString("dd\\MM\\yyyy mm:hh:ss.fff]") + exceptionDesc + "\n"); m_sbProcessLog.AppendLine("----------------------------------------------------\n"); m_sbProcessLog.AppendLine(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss.fff")); m_sbProcessLog.AppendLine(exceptionDesc); } catch (Exception ex) { DebuggerUtils.HandleException(ex); } //m_process.Go(); } } } catch (Exception ex) { DebuggerUtils.HandleException(ex); } } m_blnIsListening = false; } catch (Exception ex) { DebuggerUtils.HandleException(ex); } //m_process.PostDebugEvent += m_processEventHandler; }); }
public MDbgValue ParseExpression(string variableName, MDbgProcess process, MDbgFrame scope) { Debug.Assert(process != null); return process.ResolveVariable(variableName, scope); }
public CorValue ParseExpression2(string value, MDbgProcess process, MDbgFrame scope) { if (value.Length == 0) { return null; } CorGenericValue result; if (TryCreatePrimitiveValue(value, out result)) { //value is a primitive type return result; } if (value[0] == '"' && value[value.Length - 1] == '"') { //value is a string return CreateString(value); } //value is some variable Debug.Assert(process != null); MDbgValue var = process.ResolveVariable(value, scope); return (var == null ? null : var.CorValue); }
public static string GetExceptionDescFromProcess(MDbgProcess process, bool printInnerExcptions = false) { object o = process.StopReason; ExceptionThrownStopReason m = o as ExceptionThrownStopReason; StringBuilder retVal = new StringBuilder(); string strEventType = ""; if (m != null) strEventType = m.EventType.ToString(); MDbgThread activeThread = null; if (process.Threads.HaveActive && process.Threads.Active.CurrentException.TypeName != "N/A") { activeThread = process.Threads.Active; } else { foreach (MDbgThread t in process.Threads) { if (t.CurrentException.TypeName != "N/A") { activeThread = t; break; } } } if (activeThread.CurrentException == null) return null; retVal.AppendLine(strEventType); //collect exception data MDbgValue ex = activeThread.CurrentException; retVal.Append(GetStringFromException(activeThread, ex)); if (printInnerExcptions) { ex = ex.GetField("_innerException"); for (uint i = 1; !ex.IsNull; ex = ex.GetField("_innerException"), i++) { retVal.AppendLine("---InnerException" + i + ": "); retVal.Append(GetStringFromException(null, ex)); } } return retVal.ToString(); }
/// <summary> /// /// </summary> /// <param name="proc">the process</param> /// <param name="threadId">a specific thread to read -1 = all threads</param> /// <param name="withArgs">evaluate arguments (more detail)</param> /// <returns></returns> public static ProcessSample GetCallstacks(MDbgProcess proc, int threadId = -1, bool withArgs = false, bool originFirst = false) { ProcessSample samples = new ProcessSample(); MDbgThreadCollection tc = proc.Threads; //Console.WriteLine("Attached to pid:{0}", proc.CorProcess.Id); foreach (MDbgThread t in tc) { if (threadId != -1 && t.Id != threadId) continue; if (!DebuggerUtils.CheckValidState(t)) continue; StackSample sample = GetThreadStacks(t, withArgs, originFirst); samples.Samples.Add(sample); } return samples; }
/// <summary>Gets information about the current state of the debugger.</summary> /// <returns>A filled DebugInformation object. Contains exception information if available.</returns> /// <remarks>Assumes that the process is safe to examine.</remarks> /// <param name="debuggedProc">The Process to examine.</param> private DebugInformation GetDebugInformation(MDbgProcess debuggedProc) { DebugInformation di = new DebugInformation(); object stopReason = debuggedProc.StopReason; if (debuggedProc.Threads.HaveActive && debuggedProc.Threads.Active.HaveCurrentFrame) { di.LocalVariableInformation = GetScopeVariables(debuggedProc.Threads.Active.CurrentFrame); } // AttachComplete is triggered once the debugger if (stopReason is AttachCompleteStopReason) { di.CurrentOutput = ""; di.Stopped = true; di.StartLineNumber = 0; GetStopReasonInfo(stopReason, out di.StopReasonText, out di.StopReason); return di; } if (stopReason is ExceptionThrownStopReason || stopReason is UnhandledExceptionThrownStopReason) { ExceptionInformation ei = GetExceptionInformation(debuggedProc); di.ExceptionInformation = ei; di.ExceptionThrown = true; } GetStopReasonInfo(stopReason, out di.StopReasonText, out di.StopReason); if (debuggedProc.Threads.HaveActive == false || debuggedProc.Threads.Active.HaveCurrentFrame == false || debuggedProc.Threads.Active.CurrentFrame.SourcePosition == null) { di.Stopped = false; di.StartLineNumber = int.MinValue; di.EndLineNumber = int.MinValue; di.StartColumnNumber = int.MinValue; di.EndColumnNumber = int.MinValue; } else { MDbgFrame currentFrame = debuggedProc.Threads.Active.CurrentFrame; if (currentFrame.SourcePosition != null) { di.StartLineNumber = currentFrame.SourcePosition.Line; di.StartColumnNumber = currentFrame.SourcePosition.StartColumn - 1; di.EndColumnNumber = currentFrame.SourcePosition.EndColumn - 1; di.EndLineNumber = currentFrame.SourcePosition.EndLine; } else { di.StartLineNumber = 0; di.StartColumnNumber = 0; di.EndColumnNumber = 0; di.EndLineNumber = 0; } di.CurrentOutput = GetCurrentOutput(debuggedProc); if (di.CurrentOutput == null) { di.Stopped = false; di.StopReason = StopReason.StepComplete; di.StartLineNumber = int.MinValue; di.EndLineNumber = int.MinValue; di.StartColumnNumber = int.MinValue; di.EndColumnNumber = int.MinValue; } } return di; }
/// <summary> /// Fills an ExceptionInformation object with information about the /// current exception in the active thread. /// </summary> /// <param name="debuggedProc">The Process to extract exception from.</param> /// <returns>A filled ExceptionInformation object, or null if there is no current exception.</returns> private ExceptionInformation GetExceptionInformation(MDbgProcess debuggedProc) { ExceptionInformation ei = new ExceptionInformation(); //ei.StackTrace = GetStackTrace(debuggedProc.Threads.Active); ExceptionInformation inner = ei; MDbgValue ex = debuggedProc.ResolveVariable("$exception", debuggedProc.Threads.Active.CurrentFrame); if (ex == null) return null; do { MDbgValue messageValue = ResolveFunction(debuggedProc, ex, "System.Exception.get_Message"); if (messageValue != null) { inner.Message = messageValue.GetStringValue(true); } else { inner.Message = "Could not retrieve the exception message"; } MDbgValue stackTrace = ResolveFunction(debuggedProc, ex, "System.Exception.get_StackTrace"); if (stackTrace != null) { inner.StackTraceString = stackTrace.GetStringValue(true); } else { inner.StackTraceString = "Could not retrieve stack trace"; } ex = ResolveFunction(debuggedProc, ex, "System.Exception.get_InnerException"); if (ex != null && ex.IsNull != true) { inner.InnerExceptionInfo = new ExceptionInformation(); inner = inner.InnerExceptionInfo; } } while (ex != null && ex.IsNull != true); return ei; }
// Set whether the GUI is in "Run-mode" or "Break-mode" // OnOff = true if we're stopping; false if we're going to start running // This must be called on the UI thread. // This will also set the ActiveProcess property so that other events on the // UI thread can see if it's safe to access Mdbg objects. private void SetCommandInputState(bool OnOff) { // Enable / disable UI elements. cmdInput.Enabled = OnOff; breakCmd.Enabled=!OnOff; // Although the underlying MDbg engine supports multiple processes, // We'll only support 1 process from the UI to keep things simple. bool fHasProcess = GuiExtension.Debugger.Processes.HaveActive; // If we're stopped, and we don't already have a process, then allow creating one. bool fAllowCreate = OnOff && !fHasProcess; menuItemLaunch.Enabled = fAllowCreate; menuItemAttach.Enabled = fAllowCreate; // If we're stopped, and we do have a process, allow killing it. bool fAllowKill = OnOff && fHasProcess; menuItemDetach.Enabled = fAllowKill; menuItemKill.Enabled = fAllowKill; SetTitle(OnOff); if(OnOff) { // Enter "Break" Mode if (fHasProcess) { m_process = GuiExtension.Debugger.Processes.Active; } else { m_process = null; } Activate(); // bring GUI up when we e.g. hit breakpoint this.Cursor = Cursors.Default; ShowCurrentLocation(); // calculate current source location. SourceViewerForm.OnBreak(); WritePrompt(); cmdInput.Focus(); } else { m_process = null; // Enter "Run" mode m_CurrentSourcePosition = null; SourceViewerForm.OnRun(); this.Cursor = Cursors.AppStarting; } }
/// <summary> /// returns a list of samples (in time) of list (per thread) of CallstackSamples /// </summary> /// <param name="pid">the process id to attach to</param> /// <param name="numOfSamples"></param> /// <param name="timeBetweenSamplesInMillis"></param> /// <returns></returns> public List<ProcessSample> GetSample(MDbgProcess proc, int numOfSamples, int timeBetweenSamplesInMillis, bool extraDetails = false, bool originFirst = false) { List<ProcessSample> samples = new List<ProcessSample>(); try { m_intMainThreadId = -1; if (m_onlyMainThread) { MDbgThread mainthread = GetMainThread(proc); m_intMainThreadId = mainthread.Id; //if (e.CallbackType == ManagedCallbackType.OnException2) //{ // var ce = (CorException2EventArgs)e.CallbackArgs; // if (ce.EventType == CorDebugExceptionCallbackType.DEBUG_EXCEPTION_FIRST_CHANCE) // { // var thread = process.Threads.Lookup(ce.Thread); // foreach (var frame in thread.Frames) // { // if (!frame.IsManaged || frame.Function.FullName.StartsWith("System.")) // break; // log.Log("{0}({1})", frame.Function.FullName, string.Join(", ", frame.Function.GetArguments(frame).Select( // arg => string.Format("{0} = {1}", arg.Name, arg.GetStringValue(false))))); // } // } //} } if (m_intMainThreadId == -1) { m_onlyMainThread = false; } Console.WriteLine("startTime: " + DateTime.Now.ToString("hh:mm:ss.fff")); int sleepTime = timeBetweenSamplesInMillis; Stopwatch s = Stopwatch.StartNew(); for (int i = 0; i < numOfSamples; i++) { ProcessSample frames = GetCallstacks(proc, m_onlyMainThread, extraDetails, originFirst); samples.Add(frames); //samples.Insert(0,frames); s.Reset(); s.Start(); proc.Go(); //sleepTime -= (int)s.ElapsedMilliseconds; //sleep if (sleepTime > 0) Thread.Sleep(sleepTime); //reset sleep time sleepTime = timeBetweenSamplesInMillis; s.Reset(); s.Start(); proc.AsyncStop().WaitOne(); //sleepTime -= (int)s.ElapsedMilliseconds; } Console.WriteLine("EndTime: " + DateTime.Now.ToString("hh:mm:ss.fff")); } finally { //if (proc != null) { proc.Detach().WaitOne(); } } return samples; }
// Print CorType to the given string builder. // Will print generic info. internal static void PrintCorType(StringBuilder sb, MDbgProcess proc, CorType ct) { switch (ct.Type) { case CorElementType.ELEMENT_TYPE_CLASS: case CorElementType.ELEMENT_TYPE_VALUETYPE: // We need to get the name from the metadata. We can get a cached metadata importer // from a MDbgModule, or we could get a new one from the CorModule directly. // Is this hash lookup to get a MDbgModule cheaper than just re-querying for the importer? CorClass cc = ct.Class; MDbgModule m = proc.Modules.Lookup(cc.Module); Type tn = m.Importer.GetType(cc.Token); sb.Append(tn.FullName); AddGenericArgs(sb, proc, ct.TypeParameters); return; // Primitives case CorElementType.ELEMENT_TYPE_BOOLEAN: sb.Append("System.Boolean"); return; case CorElementType.ELEMENT_TYPE_CHAR: sb.Append("System.Char"); return; case CorElementType.ELEMENT_TYPE_I1: sb.Append("System.SByte"); return; case CorElementType.ELEMENT_TYPE_U1: sb.Append("System.Byte"); return; case CorElementType.ELEMENT_TYPE_I2: sb.Append("System.Int16"); return; case CorElementType.ELEMENT_TYPE_U2: sb.Append("System.UInt16"); return; case CorElementType.ELEMENT_TYPE_I4: sb.Append("System.Int32"); return; case CorElementType.ELEMENT_TYPE_U4: sb.Append("System.Uint32"); return; case CorElementType.ELEMENT_TYPE_I8: sb.Append("System.Int64"); return; case CorElementType.ELEMENT_TYPE_U8: sb.Append("System.UInt64"); return; case CorElementType.ELEMENT_TYPE_I: sb.Append("System.IntPtr"); return; case CorElementType.ELEMENT_TYPE_U: sb.Append("System.UIntPtr"); return; case CorElementType.ELEMENT_TYPE_R4: sb.Append("System.Single"); return; case CorElementType.ELEMENT_TYPE_R8: sb.Append("System.Double"); return; // Well known class-types. case CorElementType.ELEMENT_TYPE_OBJECT: sb.Append("System.Object"); return; case CorElementType.ELEMENT_TYPE_STRING: sb.Append("System.String"); return; // Special compound types. Based off first type-param case CorElementType.ELEMENT_TYPE_SZARRAY: case CorElementType.ELEMENT_TYPE_ARRAY: case CorElementType.ELEMENT_TYPE_BYREF: case CorElementType.ELEMENT_TYPE_PTR: CorType t = ct.FirstTypeParameter; PrintCorType(sb, proc, t); switch(ct.Type) { case CorElementType.ELEMENT_TYPE_SZARRAY: sb.Append("[]"); return; case CorElementType.ELEMENT_TYPE_ARRAY: int rank = ct.Rank; sb.Append('['); for(int i = 0; i < rank - 1; i++) { sb.Append(','); } sb.Append(']'); return; case CorElementType.ELEMENT_TYPE_BYREF: sb.Append("&"); return; case CorElementType.ELEMENT_TYPE_PTR: sb.Append("*"); return; } Debug.Assert(false); // shouldn't have gotten here. return; case CorElementType.ELEMENT_TYPE_FNPTR: sb.Append("*(...)"); return; case CorElementType.ELEMENT_TYPE_TYPEDBYREF: sb.Append("typedbyref"); return; default: sb.Append("<unknown>"); return; } } // end PrintClass
private MDbgThread GetMainThread(MDbgProcess proc) { MDbgThread mainthread = null; foreach (MDbgThread thread in proc.Threads) { if (DebuggerUtils.CheckValidState(thread)) { MDbgFrame[] frames = new MDbgFrame[0]; try { frames = thread.Frames.ToArray(); } catch { } foreach (MDbgFrame f in frames) { string line = DebuggerUtils.GetFrameString(f); if (line.Contains("System.Windows.Application.Run") || line.Contains("Program.Main") || line.Contains("System.Windows.Forms.Application.Run")) { mainthread = thread; //m_intMainThreadId = thread.Id; break; } } } } return mainthread; }
/// <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, CorValue value) { Debug.Assert(process != null && name != null); // corValue can be null for native variables in MC++ Initialize(process, name, value); }
internal MDbgModuleCollection(MDbgProcess process) { Debug.Assert(process != null); m_process = process; }
internal MDbgThreadCollection(MDbgProcess process) { m_process = process; m_freeThreadNumber = 0; }
internal MDbgBreakpointCollection(MDbgProcess process) { Debug.Assert(process != null); m_process = process; }
internal MDbgDebuggerVarCollection(MDbgProcess process) { m_process = process; }