int IDebugRemoteCorDebug.DebugActiveProcessEx(IDebugPort2 pPort, uint id, int win32Attach, out object ppProcess) { ppProcess = null; try { MessageCentre.DebugMessage(Resources.ResourceStrings.Attach); AD_PROCESS_ID pid = new AD_PROCESS_ID(); pid.ProcessIdType = (uint)AD_PROCESS_ID_TYPE.AD_PROCESS_ID_SYSTEM; pid.dwProcessId = id; IDebugProcess2 iDebugProcess; pPort.GetProcess(pid, out iDebugProcess); CorDebugProcess process = (CorDebugProcess)iDebugProcess; // StartDebugging() will either get a connected device into a debuggable state and start the dispatch thread, or throw. process.StartDebugging(this, false); ppProcess = process; return(COM_HResults.S_OK); } catch (ProcessExitException) { MessageCentre.DebugMessage(Resources.ResourceStrings.AttachFailedProcessDied); return(COM_HResults.S_FALSE); } catch (Exception ex) { MessageCentre.DebugMessage(Resources.ResourceStrings.AttachFailed); MessageCentre.InternalErrorMessage(false, ex.Message); return(COM_HResults.S_FALSE); } }
private IDebugProcess2 GetProcess(IDebugPort2 port) { IDebugProcess2 process; EngineUtils.CheckOk(port.GetProcess(_processId, out process)); return(process); }
public static IDebugProcess2 GetProcess(this IDebugPort2 port, AD_PROCESS_ID processId) { Contract.Requires <ArgumentNullException>(port != null, "port"); IDebugProcess2 process; ErrorHandler.ThrowOnFailure(port.GetProcess(processId, out process)); return(process); }
int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 pPort, string pszExe, string pszArgs, string pszDir, string bstrEnv, string pszOptions, enum_LAUNCH_FLAGS dwLaunchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 pCallback, out IDebugProcess2 ppProcess) { ppProcess = null; if (string.IsNullOrEmpty(pszOptions)) { return(VSConstants.E_FAIL); } uint procId; if (!uint.TryParse(pszOptions, out procId)) { return(VSConstants.E_FAIL); } var env = bstrEnv.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Split(new[] { '=' })) .Where(x => x.Length >= 2) .ToDictionary(x => x[0], x => x[1].Split(new[] { ';' })); if (env.ContainsKey("QTRCC")) { foreach (var rccFile in env["QTRCC"]) { FileSystem.RegisterRccFile(rccFile); } } IDebugProcess2 nativeProc; var nativeProcId = new AD_PROCESS_ID { ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, dwProcessId = procId }; if (pPort.GetProcess(nativeProcId, out nativeProc) != VSConstants.S_OK) { return(VSConstants.E_FAIL); } var program = Program.Create(this, nativeProc, pszExe, pszArgs); if (program == null) { return(VSConstants.E_FAIL); } programs.Add(program.ProcessId, program); ppProcess = program; return(VSConstants.S_OK); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended( string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_pollThread == null); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); Debug.Assert(_ad7ProgramId == Guid.Empty); process = null; _engineCallback = new EngineCallback(this, ad7Callback); try { // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(); _pollThread.RunOperation(() => { var endpoint = new IPEndPoint(IPAddress.Parse(args.Split('=')[1]), 8085); _debuggedProcess = new DebuggedProcess(endpoint, _engineCallback, _pollThread, this); _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; return(_debuggedProcess.Initialize()); }); EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process)); return(VSConstants.S_OK); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, reportOnlyCorrupting: true)) { // If we just return the exception as an HRESULT, we will loose our message, so we instead send up an error event, and then // return E_ABORT. SendStartDebuggingError(e); } Dispose(); return(VSConstants.E_ABORT); }
public int LaunchSuspended(string server, IDebugPort2 port, string exe, string args, string directory, string environment, string options, enum_LAUNCH_FLAGS launchFlags, uint standardInput, uint standardOutput, uint standardError, IDebugEventCallback2 callback, out IDebugProcess2 process) { processId = new AD_PROCESS_ID(); processId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; processId.guidProcessId = Guid.NewGuid(); EngineUtils.CheckOk(port.GetProcess(processId, out process)); this.Callback = callback; Session = new SoftDebuggerSession(); Session.TargetReady += (sender, eventArgs) => { var activeThread = Session.ActiveThread; threadManager.Add(activeThread, new MonoThread(this, activeThread)); /* * Session.Stop(); * var location = activeThread.Location; * var backtrace = activeThread.Backtrace; * var locations = Session.VirtualMachine.RootDomain.GetAssemblies().Select(x => x.Location).ToArray(); * Session.Continue(); */ MonoEngineCreateEvent.Send(this); MonoProgramCreateEvent.Send(this); }; Session.ExceptionHandler = exception => true; Session.TargetExceptionThrown += (sender, x) => Console.WriteLine(x.Type); Session.TargetExited += (sender, x) => Send(new MonoProgramDestroyEvent((uint?)x.ExitCode ?? 0), MonoProgramDestroyEvent.IID, null); Session.TargetUnhandledException += (sender, x) => Console.WriteLine(x.Type); Session.LogWriter = (stderr, text) => Console.WriteLine(text); Session.OutputWriter = (stderr, text) => Console.WriteLine(text); Session.TargetThreadStarted += (sender, x) => threadManager.Add(x.Thread, new MonoThread(this, x.Thread)); Session.TargetThreadStopped += (sender, x) => threadManager.Remove(x.Thread); Session.TargetStopped += (sender, x) => Console.WriteLine(x.Type); Session.TargetStarted += (sender, x) => Console.WriteLine(); Session.TargetSignaled += (sender, x) => Console.WriteLine(x.Type); Session.TargetInterrupted += (sender, x) => Console.WriteLine(x.Type); Session.TargetHitBreakpoint += (sender, x) => { var breakpoint = x.BreakEvent as Breakpoint; var pendingBreakpoint = breakpointManager[breakpoint]; Send(new MonoBreakpointEvent(new MonoBoundBreakpointsEnum(pendingBreakpoint.BoundBreakpoints)), MonoBreakpointEvent.IID, threadManager[x.Thread]); }; return(VSConstants.S_OK); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(m_debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { string commandLine = EngineUtils.BuildCommandLine(exe, args); ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.LaunchProcess(m_engineCallback, processLaunchInfo); })); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)m_debuggedProcess.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); return(Constants.S_OK); } catch (ComponentException e) { return(e.HResult); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); _events = ad7Callback; List <string[]> dirMapping = null; Guid processId; if (Guid.TryParse(exe, out processId)) { _process = DebugConnectionListener.GetProcess(processId); _attached = true; _pseudoAttach = true; } else { _process = new NodeProcess(exe, args, dir, BreakOnAllExceptions, dirMapping); } _programCreated = false; AttachProcessEvents(_process); _process.Start(); var adProcessId = new AD_PROCESS_ID { ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, dwProcessId = (uint)_process.Id }; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); Debug.WriteLine("NodeEngine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return(VSConstants.S_OK); }
// After engine initialization, SDM calls LaunchSuspended to start the debuggee in a suspended state. // ResumeProcess and Attach are invoked next. public int LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_program == null); var sourceFile = new SourceFile(Path.Combine(dir, exe)); var runner = new BasmRunner(sourceFile, OnProgramStop); var bpBackend = new BasmBreakpointBackend(runner, OnProgramStepComplete, OnProgramBreakComplete); _program = new Program(runner, bpBackend, sourceFile); var processId = _program.StartBasmProcess(); EngineUtils.RequireOk(port.GetProcess(processId, out process)); _callbacks = new EngineCallbacks(this, _program, process, ad7Callback); _breakpointManager = new BreakpointManager(_program, bpBackend, sourceFile, _callbacks); Debug.WriteLine("IDebugEngineLaunch2.LaunchSuspended: returning S_OK"); return(VSConstants.S_OK); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_pollThread == null); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); Debug.Assert(_ad7ProgramId == Guid.Empty); // Check if the logger was enabled late. Logger.LoadMIDebugLogger(_configStore); process = null; _engineCallback = new EngineCallback(this, ad7Callback); Exception exception; try { bool noDebug = launchFlags.HasFlag(enum_LAUNCH_FLAGS.LAUNCH_NODEBUG); // Note: LaunchOptions.GetInstance can be an expensive operation and may push a wait message loop LaunchOptions launchOptions = LaunchOptions.GetInstance(_configStore, exe, args, dir, options, noDebug, _engineCallback, TargetEngine.Native, Logger); StartDebugging(launchOptions); EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process)); return(Constants.S_OK); } catch (Exception e) when(ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { exception = e; // Return from the catch block so that we can let the exception unwind - the stack can get kind of big } // If we just return the exception as an HRESULT, we will lose our message, so we instead send up an error event, and then // return E_ABORT. OnStartDebuggingFailed(exception); return(Constants.E_ABORT); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_pollThread == null); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); Debug.Assert(_ad7ProgramId == Guid.Empty); // Check if the logger was enabled late. Logger.LoadMIDebugLogger(_configStore); process = null; _engineCallback = new EngineCallback(this, ad7Callback); Exception exception; try { // Note: LaunchOptions.GetInstance can be an expensive operation and may push a wait message loop LaunchOptions launchOptions = LaunchOptions.GetInstance(_configStore, exe, args, dir, options, _engineCallback, TargetEngine.Native, Logger); // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(Logger); var cancellationTokenSource = new CancellationTokenSource(); using (cancellationTokenSource) { _pollThread.RunOperation(ResourceStrings.InitializingDebugger, cancellationTokenSource, (HostWaitLoop waitLoop) => { try { _debuggedProcess = new DebuggedProcess(true, launchOptions, _engineCallback, _pollThread, _breakpointManager, this, _configStore); } finally { // If there is an exception from the DebuggeedProcess constructor, it is our responsibility to dispose the DeviceAppLauncher, // otherwise the DebuggedProcess object takes ownership. if (_debuggedProcess == null && launchOptions.DeviceAppLauncher != null) { launchOptions.DeviceAppLauncher.Dispose(); } } _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; return _debuggedProcess.Initialize(waitLoop, cancellationTokenSource.Token); }); } EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process)); return Constants.S_OK; } catch (Exception e) when (ExceptionHelper.BeforeCatch(e, Logger, reportOnlyCorrupting: true)) { exception = e; // Return from the catch block so that we can let the exception unwind - the stack can get kind of big } // If we just return the exception as an HRESULT, we will loose our message, so we instead send up an error event, and then // return E_ABORT. Logger.Flush(); SendStartDebuggingError(exception); Dispose(); return Constants.E_ABORT; }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.WriteLine("--------------------------------------------------------------------------------"); Debug.WriteLine("JEngine LaunchSuspended Begin " + launchFlags + " " + GetHashCode()); AssertMainThread(); Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); process = null; _events = ad7Callback; JLanguageVersion version = DefaultVersion; JDebugOptions debugOptions = JDebugOptions.None; bool attachRunning = false; List<string[]> dirMapping = null; string interpreterOptions = null; if (options != null) { var splitOptions = SplitOptions(options); foreach (var optionSetting in splitOptions) { var setting = optionSetting.Split(new[] { '=' }, 2); if (setting.Length == 2) { switch (setting[0]) { case VersionSetting: version = GetLanguageVersion(setting[1]); break; case WaitOnAbnormalExitSetting: bool value; if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.WaitOnAbnormalExit; } break; case WaitOnNormalExitSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.WaitOnNormalExit; } break; case RedirectOutputSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.RedirectOutput; } break; case BreakSystemExitZero: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.BreakOnSystemExitZero; } break; case DebugStdLib: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.DebugStdLib; } break; case DirMappingSetting: string[] dirs = setting[1].Split('|'); if (dirs.Length == 2) { if (dirMapping == null) { dirMapping = new List<string[]>(); } Debug.WriteLine(String.Format("Mapping dir {0} to {1}", dirs[0], dirs[1])); dirMapping.Add(dirs); } break; case InterpreterOptions: interpreterOptions = setting[1]; break; case AttachRunning: attachRunning = Convert.ToBoolean(setting[1]); break; case EnableDjangoDebugging: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= JDebugOptions.DjangoDebugging; } break; } } } } Guid processId; if (attachRunning && Guid.TryParse(exe, out processId)) { _process = DebugConnectionListener.GetProcess(processId); _attached = true; _pseudoAttach = true; } else { _process = new JProcess(version, exe, args, dir, env, interpreterOptions, debugOptions, dirMapping); } _programCreated = false; _loadComplete.Reset(); if (!attachRunning) { _process.Start(false); } AttachEvents(_process); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)_process.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); Debug.WriteLine("JEngine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return VSConstants.S_OK; }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { process = null; if (_mixedMode) { return VSConstants.E_NOTIMPL; } Debug.WriteLine("--------------------------------------------------------------------------------"); Debug.WriteLine("PythonEngine LaunchSuspended Begin " + launchFlags + " " + GetHashCode()); AssertMainThread(); Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); _events = ad7Callback; _engineCreated = _programCreated = false; _loadComplete.Reset(); if (options != null) { ParseOptions(options); } Send(new AD7CustomEvent(VsPackageMessage.SetDebugOptions, this), AD7CustomEvent.IID, null, null); // If this is a windowed application, there's no console to wait on, so disable those flags if they were set. if (_debugOptions.HasFlag(PythonDebugOptions.IsWindowsApplication)) { _debugOptions &= ~(PythonDebugOptions.WaitOnNormalExit | PythonDebugOptions.WaitOnAbnormalExit); } Guid processId; if (_debugOptions.HasFlag(PythonDebugOptions.AttachRunning)) { if (!Guid.TryParse(exe, out processId)) { Debug.Fail("When PythonDebugOptions.AttachRunning is used, the 'exe' parameter must be a debug session GUID."); return VSConstants.E_INVALIDARG; } _process = DebugConnectionListener.GetProcess(processId); _attached = true; _pseudoAttach = true; } else { _process = new PythonProcess(_languageVersion, exe, args, dir, env, _interpreterOptions, _debugOptions, _dirMapping); } if (!_debugOptions.HasFlag(PythonDebugOptions.AttachRunning)) { _process.Start(false); } AttachEvents(_process); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)_process.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); Debug.WriteLine("PythonEngine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return VSConstants.S_OK; }
public int LaunchSuspended(string server, IDebugPort2 port, string exe, string args, string directory, string environment, string options, enum_LAUNCH_FLAGS launchFlags, uint standardInput, uint standardOutput, uint standardError, IDebugEventCallback2 callback, out IDebugProcess2 process) { waiter = new AutoResetEvent(false); settings = MonoDebuggerSettings.Parse(options); Task.Run(() => { var outputWindow = (IVsOutputWindow)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsOutputWindow)); var generalPaneGuid = VSConstants.GUID_OutWindowDebugPane; outputWindow.GetPane(ref generalPaneGuid, out this.outputWindow); // Upload the contents of the output folder to the target directory if (connection == null) { connection = ConnectionManager.Get(settings); if (!connection.IsConnected) { Log("Connecting SSH and SFTP..."); // Debugger.Launch(); connection.Connect(); Log("Connected"); } } Log("Uploading program..."); // Ensure target directory exists: var targetDirectories = directory.Split('/'); foreach (var part in targetDirectories) { if (!connection.Sftp.Exists(part)) { connection.Sftp.CreateDirectory(part); } connection.Sftp.ChangeDirectory(part); } foreach (var _ in targetDirectories) { connection.Sftp.ChangeDirectory(".."); } var outputDirectory = new DirectoryInfo(Path.GetDirectoryName(exe)); foreach (var file in outputDirectory.EnumerateFiles().Where(x => x.Extension == ".dll" || x.Extension == ".mdb" || x.Extension == ".exe")) { using (var stream = file.OpenRead()) { connection.Sftp.UploadFile(stream, $"{directory}/{file.Name}", true); } Log($"Uploaded {file.FullName}"); } Log("Done"); var targetExe = directory + "/" + Path.GetFileName(exe); connection.Ssh.RunCommand("cd ~"); Log("Launching application"); var commandText = $"mono --debug=mdb-optimizations --debugger-agent=transport=dt_socket,address=0.0.0.0:6438,server=y {targetExe}"; connection.Ssh.RunCommand("kill $(ps auxww | grep '" + commandText + "' | awk '{print $2}')", this.outputWindow, null); runCommand = connection.Ssh.BeginCommand(commandText, this.outputWindow, out runCommandAsyncResult); // Trigger that the app is now running for whomever might be waiting for that signal waiter.Set(); }); Session = new SoftDebuggerSession(); Session.TargetReady += (sender, eventArgs) => { var activeThread = Session.ActiveThread; ThreadManager.Add(activeThread, new MonoThread(this, activeThread)); // Session.Stop(); }; Session.ExceptionHandler = exception => true; Session.TargetExited += (sender, x) => { // runCommand.EndExecute(runCommandAsyncResult); Send(new MonoProgramDestroyEvent((uint?)x.ExitCode ?? 0), MonoProgramDestroyEvent.IID, null); }; Session.TargetUnhandledException += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)) { IsUnhandled = true }, MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.LogWriter = (stderr, text) => Console.WriteLine(text); Session.OutputWriter = (stderr, text) => Console.WriteLine(text); Session.TargetThreadStarted += (sender, x) => ThreadManager.Add(x.Thread, new MonoThread(this, x.Thread)); Session.TargetThreadStopped += (sender, x) => { ThreadManager.Remove(x.Thread); }; Session.TargetStopped += (sender, x) => Console.WriteLine(x.Type); Session.TargetStarted += (sender, x) => Console.WriteLine(); Session.TargetSignaled += (sender, x) => Console.WriteLine(x.Type); Session.TargetInterrupted += (sender, x) => Console.WriteLine(x.Type); Session.TargetExceptionThrown += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)), MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.TargetHitBreakpoint += (sender, x) => { var breakpoint = x.BreakEvent as Breakpoint; var pendingBreakpoint = breakpointManager[breakpoint]; Send(new MonoBreakpointEvent(new MonoBoundBreakpointsEnum(pendingBreakpoint.BoundBreakpoints)), MonoBreakpointEvent.IID, ThreadManager[x.Thread]); }; processId = new AD_PROCESS_ID(); processId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; processId.guidProcessId = Guid.NewGuid(); EngineUtils.CheckOk(port.GetProcess(processId, out process)); Callback = callback; return(VSConstants.S_OK); }
public int LaunchSuspended(string server, IDebugPort2 port, string exe, string args, string directory, string environment, string options, enum_LAUNCH_FLAGS launchFlags, uint standardInput, uint standardOutput, uint standardError, IDebugEventCallback2 callback, out IDebugProcess2 process) { waiter = new AutoResetEvent(false); settings = MonoDebuggerSettings.Load(options); Task.Run(() => { var outputWindow = (IVsOutputWindow)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(SVsOutputWindow)); var generalPaneGuid = VSConstants.GUID_OutWindowDebugPane; outputWindow.GetPane(ref generalPaneGuid, out this.outputWindow); settings.Launcher.Launch(); // Trigger that the app is now running for whomever might be waiting for that signal waiter.Set(); }); Session = new SoftDebuggerSession(); Session.TargetReady += (sender, eventArgs) => { var activeThread = Session.ActiveThread; ThreadManager.Add(activeThread, new MonoThread(this, activeThread)); // Session.Stop(); }; Session.ExceptionHandler = exception => true; Session.TargetExited += (sender, x) => { // runCommand.EndExecute(runCommandAsyncResult); Send(new MonoProgramDestroyEvent((uint?)x.ExitCode ?? 0), MonoProgramDestroyEvent.IID, null); }; Session.TargetUnhandledException += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)) { IsUnhandled = true }, MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.LogWriter = (stderr, text) => Console.WriteLine(text); Session.OutputWriter = (stderr, text) => Console.WriteLine(text); Session.TargetThreadStarted += (sender, x) => ThreadManager.Add(x.Thread, new MonoThread(this, x.Thread)); Session.TargetThreadStopped += (sender, x) => { ThreadManager.Remove(x.Thread); }; Session.TargetStopped += (sender, x) => Console.WriteLine(x.Type); Session.TargetStarted += (sender, x) => Console.WriteLine(); Session.TargetSignaled += (sender, x) => Console.WriteLine(x.Type); Session.TargetInterrupted += (sender, x) => Console.WriteLine(x.Type); Session.TargetExceptionThrown += (sender, x) => { Send(new MonoExceptionEvent(x.Backtrace.GetFrame(0)), MonoExceptionEvent.IID, ThreadManager[x.Thread]); }; Session.TargetHitBreakpoint += (sender, x) => { var breakpoint = x.BreakEvent as Breakpoint; var pendingBreakpoint = breakpointManager[breakpoint]; Send(new MonoBreakpointEvent(new MonoBoundBreakpointsEnum(pendingBreakpoint.BoundBreakpoints)), MonoBreakpointEvent.IID, ThreadManager[x.Thread]); }; processId = new AD_PROCESS_ID(); processId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; processId.guidProcessId = Guid.NewGuid(); EngineUtils.CheckOk(port.GetProcess(processId, out process)); Callback = callback; return(VSConstants.S_OK); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(m_ad7ProgramId == Guid.Empty); m_ad7ProgramId = Guid.NewGuid(); STARTUPINFO si = new STARTUPINFO(); pi = new PROCESS_INFORMATION(); // try/finally free bool procOK = NativeMethods.CreateProcess(exe, args, IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED, IntPtr.Zero, null, ref si, out pi); pID = pi.dwProcessId; Task writepipeOK = WriteNamedPipeAsync(); Task readpipeOK = ReadNamedPipeAsync(); threadHandle = pi.hThread; IntPtr processHandle = pi.hProcess; // Inject LuaDebug into host IntPtr loadLibAddr = DLLInjector.GetProcAddress(DLLInjector.GetModuleHandle("kernel32.dll"), "LoadLibraryA"); string VS140ExtensionPath = Path.Combine(Path.GetDirectoryName(typeof(EngineConstants).Assembly.Location), "LuaDetour"); string luaDetoursDllName = Path.Combine(VS140ExtensionPath, "LuaDetours.dll"); if(!File.Exists(luaDetoursDllName)) { process = null; return VSConstants.E_FAIL; } IntPtr allocMemAddress1 = DLLInjector.VirtualAllocEx(processHandle, IntPtr.Zero, (uint)((luaDetoursDllName.Length + 1) * Marshal.SizeOf(typeof(char))), DLLInjector.MEM_COMMIT | DLLInjector.MEM_RESERVE, DLLInjector.PAGE_READWRITE); UIntPtr bytesWritten1; DLLInjector.WriteProcessMemory(processHandle, allocMemAddress1, Encoding.Default.GetBytes(luaDetoursDllName), (uint)((luaDetoursDllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten1); IntPtr hRemoteThread1 = DLLInjector.CreateRemoteThread(processHandle, IntPtr.Zero, 0, loadLibAddr, allocMemAddress1, 0, IntPtr.Zero); IntPtr[] handles1 = new IntPtr[] { hRemoteThread1 }; uint index1; NativeMethods.CoWaitForMultipleHandles(0, -1, handles1.Length, handles1, out index1); string debugDllName = Path.Combine(VS140ExtensionPath, "LuaDebug32.dll"); IntPtr allocMemAddress2 = DLLInjector.VirtualAllocEx(processHandle, IntPtr.Zero, (uint)((debugDllName.Length + 1) * Marshal.SizeOf(typeof(char))), DLLInjector.MEM_COMMIT | DLLInjector.MEM_RESERVE, DLLInjector.PAGE_READWRITE); UIntPtr bytesWritten2; DLLInjector.WriteProcessMemory(processHandle, allocMemAddress2, Encoding.Default.GetBytes(debugDllName), (uint)((debugDllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten2); IntPtr hRemoteThread2 = DLLInjector.CreateRemoteThread(processHandle, IntPtr.Zero, 0, loadLibAddr, allocMemAddress2, 0, IntPtr.Zero); IntPtr[] handles = new IntPtr[] { hRemoteThread2 }; uint index2; NativeMethods.CoWaitForMultipleHandles(0, -1, handles.Length, handles, out index2); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = pi.dwProcessId; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); debugProcess = process; return VSConstants.S_OK; }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(m_ad7ProgramId == Guid.Empty); m_ad7ProgramId = Guid.NewGuid(); STARTUPINFO si = new STARTUPINFO(); pi = new PROCESS_INFORMATION(); // try/finally free bool procOK = NativeMethods.CreateProcess(exe, args, IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CREATE_SUSPENDED, IntPtr.Zero, null, ref si, out pi); pID = pi.dwProcessId; Task writepipeOK = WriteNamedPipeAsync(); Task readpipeOK = ReadNamedPipeAsync(); threadHandle = pi.hThread; IntPtr processHandle = pi.hProcess; // Inject LuaDebug into host IntPtr loadLibAddr = DLLInjector.GetProcAddress(DLLInjector.GetModuleHandle("kernel32.dll"), "LoadLibraryA"); string VS140ExtensionPath = Path.Combine(Path.GetDirectoryName(typeof(EngineConstants).Assembly.Location), "LuaDetour"); string luaDetoursDllName = Path.Combine(VS140ExtensionPath, "LuaDetours.dll"); if (!File.Exists(luaDetoursDllName)) { process = null; return(VSConstants.E_FAIL); } IntPtr allocMemAddress1 = DLLInjector.VirtualAllocEx(processHandle, IntPtr.Zero, (uint)((luaDetoursDllName.Length + 1) * Marshal.SizeOf(typeof(char))), DLLInjector.MEM_COMMIT | DLLInjector.MEM_RESERVE, DLLInjector.PAGE_READWRITE); UIntPtr bytesWritten1; DLLInjector.WriteProcessMemory(processHandle, allocMemAddress1, Encoding.Default.GetBytes(luaDetoursDllName), (uint)((luaDetoursDllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten1); IntPtr hRemoteThread1 = DLLInjector.CreateRemoteThread(processHandle, IntPtr.Zero, 0, loadLibAddr, allocMemAddress1, 0, IntPtr.Zero); IntPtr[] handles1 = new IntPtr[] { hRemoteThread1 }; uint index1; NativeMethods.CoWaitForMultipleHandles(0, -1, handles1.Length, handles1, out index1); string debugDllName = Path.Combine(VS140ExtensionPath, "LuaDebug32.dll"); IntPtr allocMemAddress2 = DLLInjector.VirtualAllocEx(processHandle, IntPtr.Zero, (uint)((debugDllName.Length + 1) * Marshal.SizeOf(typeof(char))), DLLInjector.MEM_COMMIT | DLLInjector.MEM_RESERVE, DLLInjector.PAGE_READWRITE); UIntPtr bytesWritten2; DLLInjector.WriteProcessMemory(processHandle, allocMemAddress2, Encoding.Default.GetBytes(debugDllName), (uint)((debugDllName.Length + 1) * Marshal.SizeOf(typeof(char))), out bytesWritten2); IntPtr hRemoteThread2 = DLLInjector.CreateRemoteThread(processHandle, IntPtr.Zero, 0, loadLibAddr, allocMemAddress2, 0, IntPtr.Zero); IntPtr[] handles = new IntPtr[] { hRemoteThread2 }; uint index2; NativeMethods.CoWaitForMultipleHandles(0, -1, handles.Length, handles, out index2); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = pi.dwProcessId; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); debugProcess = process; return(VSConstants.S_OK); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { //Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(m_debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(() => m_debuggedProcess = new DebuggedProcess(exe, args, m_pollThread, Callback)); var adProcessId = new AD_PROCESS_ID { ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, dwProcessId = (uint)m_debuggedProcess.Id }; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); return Constants.S_OK; } catch (Exception e) { return EngineUtils.UnexpectedException(e); } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { LiveLogger.WriteLine("AD7Engine LaunchSuspended Called with flags '{0}' ({1})", launchFlags, GetHashCode()); AssertMainThread(); Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); _events = ad7Callback; var debugOptions = NodeDebugOptions.None; List<string[]> dirMapping = null; string interpreterOptions = null; ushort? debugPort = null; if (options != null) { var splitOptions = SplitOptions(options); foreach (var optionSetting in splitOptions) { var setting = optionSetting.Split(new[] { '=' }, 2); if (setting.Length == 2) { setting[1] = HttpUtility.UrlDecode(setting[1]); switch (setting[0]) { case WaitOnAbnormalExitSetting: bool value; if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.WaitOnAbnormalExit; } break; case WaitOnNormalExitSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.WaitOnNormalExit; } break; case RedirectOutputSetting: if (Boolean.TryParse(setting[1], out value) && value) { debugOptions |= NodeDebugOptions.RedirectOutput; } break; case DirMappingSetting: string[] dirs = setting[1].Split('|'); if (dirs.Length == 2) { if (dirMapping == null) { dirMapping = new List<string[]>(); } LiveLogger.WriteLine(String.Format("Mapping dir {0} to {1}", dirs[0], dirs[1])); dirMapping.Add(dirs); } break; case InterpreterOptions: interpreterOptions = setting[1]; break; case WebBrowserUrl: _webBrowserUrl = setting[1]; break; case DebuggerPort: ushort dbgPortTmp; if (ushort.TryParse(setting[1], out dbgPortTmp)) { debugPort = dbgPortTmp; } break; } } } } _process = new NodeDebugger( exe, args, dir, env, interpreterOptions, debugOptions, debugPort ); _process.Start(false); AttachEvents(_process); var adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)_process.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); LiveLogger.WriteLine("AD7Engine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return VSConstants.S_OK; }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { //Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); //Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { //string commandLine = EngineUtils.BuildCommandLine(exe, args); //ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything //m_pollThread = new WorkerThread(); string portname; port.GetPortName(out portname); m_engineCallback = new EngineCallback(this, ad7Callback); XmlDocument doc = new XmlDocument(); doc.LoadXml(options); XmlElement root = (XmlElement)doc.ChildNodes[0]; string ipaddress = root.GetAttribute("targetaddress"); int ipport = Int32.Parse(root.GetAttribute("port")); int connectiontries = Int32.Parse(root.GetAttribute("connectiontries")); int connectiondelay = Int32.Parse(root.GetAttribute("connectiondelay")); bool autoruninterpreter = Boolean.Parse(root.GetAttribute("autoruninterpreter")); bool suspendonstartup = Boolean.Parse(root.GetAttribute("suspendonstartup")); List <SquirrelDebugFileContext> ctxs = new List <SquirrelDebugFileContext>(); foreach (XmlElement e in doc.GetElementsByTagName("context")) { string rootpath = e.GetAttribute("rootpath"); string pathfixup = e.GetAttribute("pathfixup"); SquirrelDebugFileContext sdfc = new SquirrelDebugFileContext(rootpath, pathfixup); ctxs.Add(sdfc); } // Complete the win32 attach on the poll thread //THIS IS A MASSIVE HACK //the 'options' parameter is formatted this way "targetaddress,port,autorunintepreter,suspendonstartup,projectfolder,pathfixup" //I should find a better way to pass this params //fix working dir) dir = dir.Replace('/', '\\'); Process proc = null; if (autoruninterpreter) { proc = new Process(); proc.EnableRaisingEvents = false; proc.StartInfo.UseShellExecute = false; baseDir = proc.StartInfo.WorkingDirectory = dir; proc.StartInfo.FileName = exe; proc.StartInfo.Arguments = args; proc.StartInfo.RedirectStandardOutput = false; proc.StartInfo.RedirectStandardError = false; proc.Start(); } AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); if (proc != null) { adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)proc.Id; } else { adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_GUID; adProcessId.guidProcessId = Guid.NewGuid(); } EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); debuggedProcess = (SquirrelProcess)process; debuggedProcess.Engine = this; debuggedProcess.Process = proc; debuggedProcess.Name = proc != null? proc.StartInfo.FileName : "remoteprocess"; debuggedProcess.EngineCallback = m_engineCallback; debuggedProcess.IpAddress = ipaddress; debuggedProcess.IpPort = ipport; debuggedProcess.SuspendOnStartup = suspendonstartup; debuggedProcess.FileContexts = ctxs.ToArray(); //debuggedProcess.ConnectionTries = connectiontries; //debuggedProcess.ConnectionDelay = connectiondelay; //debuggedProcess.PathFixup = pathfixup; //debuggedProcess.ProjectFolder = projectfolder; /*DebuggedThread thread = new DebuggedThread(1); * DebuggedModule module = new DebuggedModule("the module"); * * m_engineCallback.OnModuleLoad(module); * m_engineCallback.OnSymbolSearch(module, "nothing", 0); * m_engineCallback.OnThreadStart(thread); * m_engineCallback.OnLoadComplete(thread);*/ return(EngineConstants.S_OK); } catch (ComponentException e) { return(e.HRESULT); } catch (Exception e) { return(EngineUtils.UnexpectedException(e)); } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_pollThread == null); Debug.Assert(_engineCallback == null); Debug.Assert(_debuggedProcess == null); Debug.Assert(_ad7ProgramId == Guid.Empty); process = null; _engineCallback = new EngineCallback(this, ad7Callback); Exception exception; try { // Note: LaunchOptions.GetInstance can be an expensive operation and may push a wait message loop LaunchOptions launchOptions = LaunchOptions.GetInstance(_registryRoot, exe, args, dir, options, _engineCallback); // We are being asked to debug a process when we currently aren't debugging anything _pollThread = new WorkerThread(); var cancellationTokenSource = new CancellationTokenSource(); using (cancellationTokenSource) { _pollThread.RunOperation(ResourceStrings.InitializingDebugger, cancellationTokenSource, (MICore.WaitLoop waitLoop) => { try { _debuggedProcess = new DebuggedProcess(true, launchOptions, _engineCallback, _pollThread, _breakpointManager, this); } finally { // If there is an exception from the DebuggeedProcess constructor, it is our responsibility to dispose the DeviceAppLauncher, // otherwise the DebuggedProcess object takes ownership. if (_debuggedProcess == null && launchOptions.DeviceAppLauncher != null) { launchOptions.DeviceAppLauncher.Dispose(); } } _pollThread.PostedOperationErrorEvent += _debuggedProcess.OnPostedOperationError; return(_debuggedProcess.Initialize(waitLoop, cancellationTokenSource.Token)); }); } EngineUtils.RequireOk(port.GetProcess(_debuggedProcess.Id, out process)); return(Constants.S_OK); } catch (Exception e) { exception = e; // Return from the catch block so that we can let the exception unwind - the stack can get kind of big } // If we just return the exception as an HRESULT, we will loose our message, so we instead send up an error event, and then // return E_ABORT. Logger.Flush(); SendStartDebuggingError(exception); Dispose(); return(Constants.E_ABORT); }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); _events = ad7Callback; List<string[]> dirMapping = null; Guid processId; if (Guid.TryParse(exe, out processId)) { _process = DebugConnectionListener.GetProcess(processId); _attached = true; _pseudoAttach = true; } else { _process = new NodeProcess(exe, args, dir, BreakOnAllExceptions, dirMapping); } _programCreated = false; AttachProcessEvents(_process); _process.Start(); var adProcessId = new AD_PROCESS_ID { ProcessIdType = (uint) enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, dwProcessId = (uint) _process.Id }; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); Debug.WriteLine("NodeEngine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return VSConstants.S_OK; }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.Assert(Worker.MainThreadId == Worker.CurrentThreadId); Debug.Assert(m_pollThread == null); Debug.Assert(m_engineCallback == null); Debug.Assert(m_debuggedProcess == null); Debug.Assert(m_ad7ProgramId == Guid.Empty); process = null; try { string commandLine = EngineUtils.BuildCommandLine(exe, args); ProcessLaunchInfo processLaunchInfo = new ProcessLaunchInfo(exe, commandLine, dir, env, options, (uint)launchFlags, hStdInput, hStdOutput, hStdError); // We are being asked to debug a process when we currently aren't debugging anything m_pollThread = new WorkerThread(); m_engineCallback = new EngineCallback(this, ad7Callback); // Complete the win32 attach on the poll thread m_pollThread.RunOperation(new Operation(delegate { m_debuggedProcess = Worker.LaunchProcess(m_engineCallback, processLaunchInfo); })); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)m_debuggedProcess.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); return Constants.S_OK; } catch (ComponentException e) { return e.HResult; } catch (Exception e) { return EngineUtils.UnexpectedException(e); } }
int IDebugRemoteCorDebug.DebugActiveProcessEx( IDebugPort2 pPort, uint id, int win32Attach, out object ppProcess ) { ppProcess = null; try { VsPackage.MessageCentre.DeploymentMsg(DiagnosticStrings.Attach); AD_PROCESS_ID pid = new AD_PROCESS_ID(); pid.ProcessIdType = (uint) AD_PROCESS_ID_TYPE.AD_PROCESS_ID_SYSTEM; pid.dwProcessId = id; IDebugProcess2 iDebugProcess; pPort.GetProcess(pid, out iDebugProcess); CorDebugProcess process = (CorDebugProcess) iDebugProcess; // StartDebugging() will either get a connected device into a debuggable state and start the dispatch thread, or throw. process.StartDebugging(this, false); ppProcess = process; return Utility.COM_HResults.S_OK; } catch (ProcessExitException) { VsPackage.MessageCentre.DeploymentMsg(DiagnosticStrings.AttachFailedProcessDied); return Utility.COM_HResults.S_FALSE; } catch (Exception ex) { VsPackage.MessageCentre.DeploymentMsg(DiagnosticStrings.AttachFailed); VsPackage.MessageCentre.InternalErrorMsg(false, ex.Message); return Utility.COM_HResults.S_FALSE; } }
// Launches a process by means of the debug engine. // Normally, Visual Studio launches a program using the IDebugPortEx2::LaunchSuspended method and then attaches the debugger // to the suspended program. However, there are circumstances in which the debug engine may need to launch a program // (for example, if the debug engine is part of an interpreter and the program being debugged is an interpreted language), // in which case Visual Studio uses the IDebugEngineLaunch2::LaunchSuspended method // The IDebugEngineLaunch2::ResumeProcess method is called to start the process after the process has been successfully launched in a suspended state. int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, string exe, string args, string dir, string env, string options, enum_LAUNCH_FLAGS launchFlags, uint hStdInput, uint hStdOutput, uint hStdError, IDebugEventCallback2 ad7Callback, out IDebugProcess2 process) { Debug.WriteLine("PythonEngine LaunchSuspended Begin " + launchFlags + " " + GetHashCode()); AssertMainThread(); Debug.Assert(_events == null); Debug.Assert(_process == null); Debug.Assert(_ad7ProgramId == Guid.Empty); process = null; _events = ad7Callback; PythonLanguageVersion version = DefaultVersion; bool waitOnAbnormalExit = false; bool redirectOutput = false; List <string[]> dirMapping = null; if (options != null) { var splitOptions = options.Split(new[] { ';' }, 2); foreach (var optionSetting in splitOptions) { var setting = optionSetting.Split(new[] { '=' }, 2); if (setting.Length == 2) { switch (setting[0]) { case VersionSetting: version = GetLanguageVersion(setting[1]); break; case WaitOnAbnormalExitSetting: bool value; if (Boolean.TryParse(setting[1], out value)) { waitOnAbnormalExit = value; } break; case RedirectOutputSetting: if (Boolean.TryParse(setting[1], out value)) { redirectOutput = value; } break; case DirMappingSetting: string[] dirs = setting[1].Split('|'); if (dirs.Length == 2) { if (dirMapping == null) { dirMapping = new List <string[]>(); } Debug.WriteLine(String.Format("Mapping dir {0} to {1}", dirs[0], dirs[1])); dirMapping.Add(dirs); } break; } } } } _process = new PythonProcess(version, exe, args, dir, env, waitOnAbnormalExit, redirectOutput, dirMapping); AttachEvents(_process); _programCreated = false; _loadComplete.Reset(); _process.Start(); AD_PROCESS_ID adProcessId = new AD_PROCESS_ID(); adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; adProcessId.dwProcessId = (uint)_process.Id; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); Debug.WriteLine("PythonEngine LaunchSuspended returning S_OK"); Debug.Assert(process != null); Debug.Assert(!_process.HasExited); return(VSConstants.S_OK); }