/// <summary> /// Constructor for ProcessInfo /// </summary> /// <param name="procID">The id of the process</param> /// <param name="debugger">The debugger</param> public ProcessInfo(Process process, CorDebugger debug) { if (debug == null) { throw new ArgumentException("Null Debugger Exception"); } processThreads = new Dictionary <int, ThreadInfo>(); processCorThreads = new List <CorThread>(); generalThreadInfos = new Dictionary <int, ProcessThread>(); attachedCompletedProcessEvent = new ManualResetEvent(false); debugger = debug; processId = process.Id; generalProcessInfo = Process.GetProcessById(processId); //CorPublish cp = new CorPublish(); //cpp = cp.GetProcess(processId); processFullName = process.MainModule.FileName; processShortName = System.IO.Path.GetFileName(process.MainModule.FileName); FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(processFullName); description = fileInfo.FileDescription; company = fileInfo.CompanyName; //debuggerProcessInfo will be set when the updateInfo function is called //the reason for this is that the process must be stopped for this to take place //this happen only when we want it to }
public static void SetUpTestEnvironment() { if (testProcess == null || testProcessInfo == null || debugger == null || testProcess.HasExited) { Console.WriteLine("Starting the unit test helper from " + testProgram + " ..."); testProcess = Process.Start(testProgram, ""); //wait for program to finish initializing while (true) { try { if (File.Exists(testFile)) { debugger = new CorDebugger(CorDebugger.GetDefaultDebuggerVersion()); testProcessInfo = new ProcessInfo(testProcess, debugger); File.Delete(testFile); break; } } catch (Exception e) { Console.Error.WriteLine(e.ToString()); throw; } } } }
private static void Main(string[] args) { int pid; if (args.Length == 1 && int.TryParse(args[0], out pid)) { try { var process = Process.GetProcessById(int.Parse(args[0])); var mh = new CLRMetaHost(); mh.EnumerateLoadedRuntimes(process.Id); var version = MdbgVersionPolicy.GetDefaultAttachVersion(process.Id); var debugger = new CorDebugger(version); var processInfo = new ProcessInfo(process, debugger); foreach (var line in processInfo.GetDisplayStackTrace()) { Console.WriteLine(line); } } catch (Exception e) { Console.Error.WriteLine("Error getting process thread dump: " + e); } } else { Console.Error.WriteLine("Simple utility to generate .NET managed process thread dump (similar to Java jstack)"); Console.Error.WriteLine("Usage: " + AppDomain.CurrentDomain.FriendlyName + " <PID>"); } }
public static List <String> getListOfManagedProcess(bool showDetails) { var managedProcesses = new List <String>(); int currentProcessId = Process.GetCurrentProcess().Id; var corPublish = new CorPublish(); foreach (CorPublishProcess corPublishProcess in corPublish.EnumProcesses()) { if (currentProcessId != corPublishProcess.ProcessId) { // don't include the current process if (showDetails) { managedProcesses.Add("[" + corPublishProcess.ProcessId + "] [ver=" + CorDebugger.GetDebuggerVersionFromPid(corPublishProcess.ProcessId) + "] " + corPublishProcess.DisplayName); } else { managedProcesses.Add(corPublishProcess.DisplayName); } } } return(managedProcesses); }
static private MDbgProcess GetProcessFromCordb(ICorDebug cordbg) { Debugger.Processes.FreeStaleUnmanagedResources(); CorDebugger cordebugger = new CorDebugger(cordbg); Debugger.Processes.RegisterDebuggerForCleanup(cordebugger); return(new MDbgProcess(Debugger, cordebugger)); }
void AttachToProcessImpl(int procId) { attaching = true; MtaThread.Run(delegate { var iCorDebug = CoreClrShimUtil.CreateICorDebugForProcess(dbgShimInterop, procId, RuntimeLoadTimeout); dbg = new CorDebugger(iCorDebug); process = dbg.DebugActiveProcess(procId, false); SetupProcess(process); process.Continue(false); }); OnStarted(); }
protected override void OnRun(DebuggerStartInfo startInfo) { // Create the debugger string dversion = CorDebugger.GetDebuggerVersionFromFile(startInfo.Command); dbg = new CorDebugger(dversion); Dictionary <string, string> env = new Dictionary <string, string> (); foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) { env[(string)de.Key] = (string)de.Value; } foreach (KeyValuePair <string, string> var in startInfo.EnvironmentVariables) { env[var.Key] = var.Value; } // The second parameter of CreateProcess is the command line, and it includes the application being launched string cmdLine = "\"" + startInfo.Command + "\" " + startInfo.Arguments; process = dbg.CreateProcess(startInfo.Command, cmdLine, startInfo.WorkingDirectory, env); processId = process.Id; process.OnCreateProcess += new CorProcessEventHandler(OnCreateProcess); process.OnCreateAppDomain += new CorAppDomainEventHandler(OnCreateAppDomain); process.OnAssemblyLoad += new CorAssemblyEventHandler(OnAssemblyLoad); process.OnAssemblyUnload += new CorAssemblyEventHandler(OnAssemblyUnload); process.OnCreateThread += new CorThreadEventHandler(OnCreateThread); process.OnThreadExit += new CorThreadEventHandler(OnThreadExit); process.OnModuleLoad += new CorModuleEventHandler(OnModuleLoad); process.OnModuleUnload += new CorModuleEventHandler(OnModuleUnload); process.OnProcessExit += new CorProcessEventHandler(OnProcessExit); process.OnUpdateModuleSymbols += new UpdateModuleSymbolsEventHandler(OnUpdateModuleSymbols); process.OnDebuggerError += new DebuggerErrorEventHandler(OnDebuggerError); process.OnBreakpoint += new BreakpointEventHandler(OnBreakpoint); process.OnStepComplete += new StepCompleteEventHandler(OnStepComplete); process.OnBreak += new CorThreadEventHandler(OnBreak); process.OnNameChange += new CorThreadEventHandler(OnNameChange); process.OnEvalComplete += new EvalEventHandler(OnEvalComplete); process.OnEvalException += new EvalEventHandler(OnEvalException); process.Continue(false); OnStarted(); }
protected override void OnRun(DebuggerStartInfo startInfo) { MtaThread.Run(() => { var workingDir = PrepareWorkingDirectory(startInfo); var env = PrepareEnvironment(startInfo); var cmd = PrepareCommandLine(startInfo); int procId; var iCorDebug = CoreClrShimUtil.CreateICorDebugForCommand( dbgShimInterop, cmd, workingDir, env, RuntimeLoadTimeout, out procId); dbg = new CorDebugger(iCorDebug); process = dbg.DebugActiveProcess(procId, false); processId = process.Id; SetupProcess(process); process.Continue(false); }); OnStarted(); }
////////////////////////////////////////////////////////////////////////////////// // // Controlling Commands // ////////////////////////////////////////////////////////////////////////////////// /// <summary> /// creates a new debugged process. /// </summary> /// <param name="commandLine">The command to run.</param> /// <param name="commandArguments">The arguments for the command.</param> /// <param name="debugMode">The debug mode to run with.</param> /// <param name="deeVersion">The version of debugging interfaces that should be used for /// debugging of the started program. If this value is null, the default (latest) version /// of interface is used. /// </param> /// <returns>The resulting MDbgProcess.</returns> public MDbgProcess CreateProcess(string commandLine, string commandArguments, DebugModeFlag debugMode, string deeVersion) { CorDebugger debugger; if (deeVersion == null) { debugger = new CorDebugger(CorDebugger.GetDefaultDebuggerVersion()); } else { debugger = new CorDebugger(deeVersion); } MDbgProcess p = m_processMgr.CreateLocalProcess(debugger); p.DebugMode = debugMode; p.CreateProcess(commandLine, commandArguments); return(p); }
/// <summary> /// Returns the version of the runtime to debug in a process /// we are attaching to, assuming we can only pick one /// </summary> /// <param name="processId">The process to attach to</param> /// <returns>The version of the runtime to debug, or null if the policy can't decide</returns> public static string GetDefaultAttachVersion(int processId) { try { CLRMetaHost mh = new CLRMetaHost(); List <CLRRuntimeInfo> runtimes = new List <CLRRuntimeInfo>(mh.EnumerateLoadedRuntimes(processId)); if (runtimes.Count > 1) { // It is ambiguous so just give up return(null); } else if (runtimes.Count == 1) { return(runtimes[0].GetVersionString()); } } catch (EntryPointNotFoundException) { try { return(CorDebugger.GetDebuggerVersionFromPid(processId)); } catch (COMException) { } } // if we have neither failed nor detected a version at this point then there was no // CLR loaded. Now we try to determine what CLR the process will load by examining its // binary string binaryPath = GetBinaryPathFromPid(processId); if (binaryPath != null) { string version = GetDefaultRuntimeForFile(binaryPath); if (version != null) { return(version); } } // and if that doesn't work, return the version of the CLR the debugger is // running against (a very arbitrary choice) return(Environment.Version.ToString()); }
/// <summary> /// Refreshes the processes hash which stores info on all managed process running /// </summary> public void RefreshProcessList() { processes.Clear(); foreach (var process in Process.GetProcesses()) { if (Process.GetCurrentProcess().Id == process.Id) { // let's hide our process continue; } // list the loaded runtimes in each process, if the ClrMetaHost APIs are available CLRMetaHost mh; try { mh = new CLRMetaHost(); } catch (Exception) { continue; } IEnumerable <CLRRuntimeInfo> runtimes; try { runtimes = mh.EnumerateLoadedRuntimes(process.Id); } catch (Exception) { continue; } // TODO: only one CLR version for now... if (runtimes.Any()) { var version = MdbgVersionPolicy.GetDefaultAttachVersion(process.Id); var debugger = new CorDebugger(version); processes[process.Id] = new ProcessInfo(process, debugger); } } }
/// <summary> /// Attach to a process with the given Process ID /// </summary> /// <param name="processId">The Process ID to attach to.</param> /// <returns>The resulting MDbgProcess.</returns> public MDbgProcess Attach(int processId) { string deeVersion; try { deeVersion = CorDebugger.GetDebuggerVersionFromPid(processId); } catch { // GetDebuggerVersionFromPid isn't implemented on Win9x and so will // throw NotImplementedException. We'll also get an ArgumentException // if the specified process doesn't have the CLR loaded yet. // Rather than be selective (and potentially brittle), we'll handle all errors. // Ideally we'd assert (or log) that we're only getting the errors we expect, // but it's complex and ugly to do that in C#. // Fall back to guessing the version based on the filename. // Environment variables (eg. COMPLUS_Version) may have resulted // in a different choice. try { var cp = new CorPublish.CorPublish(); CorPublishProcess cpp = cp.GetProcess(processId); string programBinary = cpp.DisplayName; deeVersion = CorDebugger.GetDebuggerVersionFromFile(programBinary); } catch { // This will also fail if the process doesn't have the CLR loaded yet. // It could also fail if the image EXE has been renamed since it started. // For whatever reason, fall back to using the default CLR deeVersion = null; } } MDbgProcess p = m_processMgr.CreateLocalProcess(deeVersion); p.Attach(processId); return(p); }
protected virtual void PrintStartupLogo() { string myVersion = GetBinaryVersion(); IO.WriteOutput(MDbgOutputConstants.StdOutput, "MDbg (Managed debugger) v" + myVersion + " started.\n"); IO.WriteOutput(MDbgOutputConstants.StdOutput, "Copyright (C) Microsoft Corporation. All rights reserved.\n"); IO.WriteOutput(MDbgOutputConstants.StdOutput, "\nFor information about commands type \"help\";\nto exit program type \"quit\".\n\n"); // Check for and output any debugging warnings try { (new CorDebugger(CorDebugger.GetDefaultDebuggerVersion())).CanLaunchOrAttach(0, false); } catch (System.Runtime.InteropServices.COMException e) { IO.WriteOutput(MDbgOutputConstants.StdOutput, "WARNING: " + e.Message + "\n\n"); } }
void OnProcessExit(object sender, CorProcessEventArgs e) { TargetEventArgs args = new TargetEventArgs(TargetEventType.TargetExited); // If the main thread stopped, terminate the debugger session if (e.Process.Id == process.Id) { lock (terminateLock) { process = null; ThreadPool.QueueUserWorkItem(delegate { // The Terminate call will fail if called in the event handler dbg.Terminate(); dbg = null; GC.Collect(); }); } } OnTargetEvent(args); }
private void RefreshProcesses() { listBoxProcesses.Items.Clear(); CorPublish cp = null; int curPid = Process.GetCurrentProcess().Id; try { int count = 0; cp = new CorPublish(); { foreach (CorPublishProcess cpp in cp.EnumProcesses()) { if (curPid != cpp.ProcessId) // let's hide our process { string version = CorDebugger.GetDebuggerVersionFromPid(cpp.ProcessId); string s = "[" + cpp.ProcessId + "] [ver=" + version + "] " + cpp.DisplayName; listBoxProcesses.Items.Add(new Item(cpp.ProcessId, s)); count++; } } } // using if (count == 0) { listBoxProcesses.Items.Add(new Item(0, "(No active processes)")); } } catch (Exception) { if (cp == null) { listBoxProcesses.Items.Add(new Item(0, "(Can't enumerate processes")); } } }
protected override void OnRun(DebuggerStartInfo startInfo) { // Create the debugger string dversion; try { dversion = CorDebugger.GetDebuggerVersionFromFile(startInfo.Command); } catch { dversion = CorDebugger.GetDefaultDebuggerVersion(); } dbg = new CorDebugger(dversion); Dictionary <string, string> env = new Dictionary <string, string> (); foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) { env[(string)de.Key] = (string)de.Value; } foreach (KeyValuePair <string, string> var in startInfo.EnvironmentVariables) { env[var.Key] = var.Value; } // The second parameter of CreateProcess is the command line, and it includes the application being launched string cmdLine = "\"" + startInfo.Command + "\" " + startInfo.Arguments; int flags = 0; if (!startInfo.UseExternalConsole) { flags = 0x08000000; /* CREATE_NO_WINDOW*/ flags |= CorDebugger.CREATE_REDIRECT_STD; } process = dbg.CreateProcess(startInfo.Command, cmdLine, startInfo.WorkingDirectory, env, flags); processId = process.Id; process.OnCreateProcess += new CorProcessEventHandler(OnCreateProcess); process.OnCreateAppDomain += new CorAppDomainEventHandler(OnCreateAppDomain); process.OnAssemblyLoad += new CorAssemblyEventHandler(OnAssemblyLoad); process.OnAssemblyUnload += new CorAssemblyEventHandler(OnAssemblyUnload); process.OnCreateThread += new CorThreadEventHandler(OnCreateThread); process.OnThreadExit += new CorThreadEventHandler(OnThreadExit); process.OnModuleLoad += new CorModuleEventHandler(OnModuleLoad); process.OnModuleUnload += new CorModuleEventHandler(OnModuleUnload); process.OnProcessExit += new CorProcessEventHandler(OnProcessExit); process.OnUpdateModuleSymbols += new UpdateModuleSymbolsEventHandler(OnUpdateModuleSymbols); process.OnDebuggerError += new DebuggerErrorEventHandler(OnDebuggerError); process.OnBreakpoint += new BreakpointEventHandler(OnBreakpoint); process.OnStepComplete += new StepCompleteEventHandler(OnStepComplete); process.OnBreak += new CorThreadEventHandler(OnBreak); process.OnNameChange += new CorThreadEventHandler(OnNameChange); process.OnEvalComplete += new EvalEventHandler(OnEvalComplete); process.OnEvalException += new EvalEventHandler(OnEvalException); process.OnLogMessage += new LogMessageEventHandler(OnLogMessage); process.OnStdOutput += new CorTargetOutputEventHandler(OnStdOutput); process.OnException2 += new CorException2EventHandler(OnException2); process.Continue(false); OnStarted(); }
/// <summary> /// Helper function that parses inputs to run and crun commands. /// </summary> /// <param name="arguments">Argument to the run and crun command</param> /// <param name="debugMode">Returns desired debugging mode. Returns internal /// default if not specified /// </param> /// <param name="debuggeeVersion">Returns the debugger interface version. /// Is null if the version cannot be determined. /// </param> /// <param name="programToRun">Returns path of the program to execute.</param> /// <param name="programArguments">Returns arguments to pass to the program being /// run, including the binary name as the 0th argument</param> public static void PreParseRunArguments(string arguments, out DebugModeFlag debugMode, out string debuggeeVersion, out string programToRun, out string programArguments) { Debug.Assert(arguments != null); if (arguments == null) { throw new ArgumentException("Parameter cannot be null.", "arguments"); } debugMode = DebugModeFlag.Debug; // Is this the mode we want to always start in? int start, end; start = end = 0; // those flags are necessary so that people can run any program under debugger. // e.g to run program named '-debug.exe', they can write 'run -debug -debug' // // One obvious issue here is that if the binary name is same as the flag, then // user need to pass the flag to the run command so that the program name is not // interpreted as a flag. // bool debugModeFlagSet = false; bool versionFlagSet = false; debuggeeVersion = null; while (FindToken(arguments, ref start, ref end)) { Debug.Assert(start <= end); switch (arguments.Substring(start, end - start)) { case "-default": if (debugModeFlagSet) { goto default; } debugMode = DebugModeFlag.Default; debugModeFlagSet = true; break; case "-debug": case "-d": if (debugModeFlagSet) { goto default; } debugMode = DebugModeFlag.Debug; debugModeFlagSet = true; break; case "-optimize": case "-o": if (debugModeFlagSet) { goto default; } debugMode = DebugModeFlag.Optimized; debugModeFlagSet = true; break; case "-enc": if (debugModeFlagSet) { goto default; } debugMode = DebugModeFlag.Enc; debugModeFlagSet = true; break; case "-ver": if (versionFlagSet) { goto default; } if (!FindToken(arguments, ref start, ref end)) { throw new MDbgShellException("missing argument to -ver option"); } debuggeeVersion = arguments.Substring(start, end - start); versionFlagSet = true; break; default: // this means we have found some different token. // To keep comaptibility with cordbg, we assume that this is a program binary name. // Expand environment variables on the binary name so that we can use env vars in // the program path. Note that environment variables are not expanded in program // arguments so that we can pass in original strings. Programs can expand the environment // themselves if they wish so. string prog = Environment.ExpandEnvironmentVariables(arguments.Substring(start, end - start)); // program may be quoted, remove surrounding quotes // Note: ideally we'd have a general escapedPath format and escape/unescape methods to convert // but this is good enough for our purposes here. if (prog.Length >= 2 && prog.StartsWith("\"") && prog.EndsWith("\"")) { prog = prog.Substring(1, prog.Length - 2); } // may have omitted .exe extension, add it if necessary const string optExt = ".exe"; if (!prog.EndsWith(optExt, StringComparison.OrdinalIgnoreCase)) { prog += optExt; } // We're left with the program binary path programToRun = prog; // Use everything unmodified (including the possibly quoted binary path) as the run arguments programArguments = arguments.Substring(start); if (debuggeeVersion == null) { // user didn't specify, we need to guess it. try { debuggeeVersion = CorDebugger.GetDebuggerVersionFromFile(programToRun); } catch (COMException) { // we could not retrieve dee version. debuggeeVersion = null; } } // Rest of line processed, we're done. return; } } // we didn't find any token -- no other binary specified than options programToRun = null; programArguments = null; return; }
/// <summary> /// Given the full path to a binary, finds the CLR runtime version which /// it will bind to. /// </summary> /// <param name="filePath">The full path to a binary.</param> /// <returns>The version string that the binary will bind to; null if unknown.</returns> /// <remarks>If ICLRMetaHostPolicy can be asked, it is used. Otherwise /// fall back to mscoree!GetRequestedRuntimeVersion.</remarks> public static String GetDefaultRuntimeForFile(String filePath) { String version = null; CLRMetaHostPolicy policy; try { policy = new CLRMetaHostPolicy(); } catch (NotImplementedException) { policy = null; } catch (System.EntryPointNotFoundException) { policy = null; } if (policy != null) { // v4 codepath StringBuilder ver = new StringBuilder(); StringBuilder imageVer = new StringBuilder(); CLRRuntimeInfo rti = null; String configPath = null; if (System.IO.File.Exists(filePath + ".config")) { configPath = filePath + ".config"; } try { rti = policy.GetRequestedRuntime(CLRMetaHostPolicy.MetaHostPolicyFlags.metaHostPolicyHighCompat, filePath, configPath, ref ver, ref imageVer); } catch (System.Runtime.InteropServices.COMException) { Debug.Assert(rti == null); } if (rti != null) { version = rti.GetVersionString(); } else { version = null; } } else { // v2 codepath try { version = CorDebugger.GetDebuggerVersionFromFile(filePath); } catch (System.Runtime.InteropServices.COMException) { // we could not retrieve dee version. // Leave version null; Debug.Assert(version == null); } } return(version); }