public void Init(ITransportCallback transportCallback, LaunchOptions options, Logger logger, HostWaitLoop waitLoop = null) { _launchOptions = (UnixShellPortLaunchOptions)options; _callback = transportCallback; _logger = logger; _startRemoteDebuggerCommand = _launchOptions.StartRemoteDebuggerCommand; if (_launchOptions.DebuggerMIMode == MIMode.Clrdbg) { if (!UnixShellPortLaunchOptions.HasSuccessfulPreviousLaunch(_launchOptions)) { waitLoop?.SetText(MICoreResources.Info_InstallingDebuggerOnRemote); try { Task.Run(() => DownloadAndCopyFileToRemote(_launchOptions.DebuggerInstallationDirectory, _launchOptions.GetClrDbgUrl)).Wait(); } catch (Exception e) { // Even if downloading & copying to remote fails, we will still try to invoke the script as it might already exist. string message = String.Format(CultureInfo.CurrentUICulture, MICoreResources.Warning_DownloadingClrDbgToRemote, e.Message); _callback.AppendToInitializationLog(message); } } } _callback.AppendToInitializationLog(string.Format(CultureInfo.CurrentUICulture, MICoreResources.Info_StartingUnixCommand, _startRemoteDebuggerCommand)); _launchOptions.UnixPort.BeginExecuteAsyncCommand(_startRemoteDebuggerCommand, this, out _asyncCommand); }
void IPlatformAppLauncher.SetupForDebugging(out LaunchOptions debuggerLaunchOptions) { if (_launchOptions == null) { Debug.Fail("Why is SetupForDebugging being called before ParseLaunchOptions?"); throw new InvalidOperationException(); } string targetMachineName = LaunchOptions.RequireAttribute(_launchOptions.TargetMachine, "TargetMachine"); var port = new AD7Port(new AD7PortSupplier(), targetMachineName, isInAddPort: false); // NOTE: this may put up a dialog and/or throw an AD7ConnectCanceledException port.EnsureConnected(); debuggerLaunchOptions = new UnixShellPortLaunchOptions(_launchOptions.StartRemoteDebuggerCommand, port, LaunchOptions.ConvertMIModeAttribute(_launchOptions.MIMode), _launchOptions); }
/// <summary> /// Returns true if the previous launch was ever successful on the same session false otherwise. /// </summary> /// <param name="launchOptions">launch options</param> public static bool HasSuccessfulPreviousLaunch(UnixShellPortLaunchOptions launchOptions) { IDebugPort2 debugPort = launchOptions.UnixPort as IDebugPort2; if (debugPort != null) { string portName = null; debugPort.GetPortName(out portName); if (!string.IsNullOrWhiteSpace(portName)) { lock (s_LaunchSuccessSet) { // If it is successful once, we expect the clrdbg launch to be successful atleast till the end of the current VS session. // The portname will not be removed from the list. return s_LaunchSuccessSet.Contains(portName); } } } return false; }
public static UnixShellPortLaunchOptions CreateForAttachRequest(Microsoft.VisualStudio.Debugger.Interop.UnixPortSupplier.IDebugUnixShellPort unixPort, int processId, MIMode miMode, string getClrDbgUrl, string remoteDebuggingDirectory, string remoteDebuggingSubDirectory, string debuggerVersion) { var @this = new UnixShellPortLaunchOptions(startRemoteDebuggerCommand: null, unixPort: unixPort, miMode: miMode, baseLaunchOptions: null, getClrDbgUrl: getClrDbgUrl, remoteDebuggerInstallationDirectory: remoteDebuggingDirectory, remoteDebuggerInstallationSubDirectory: remoteDebuggingSubDirectory, clrdbgVersion: debuggerVersion); @this.ProcessId = processId; @this.SetupCommands = new ReadOnlyCollection<LaunchCommand>(new LaunchCommand[] { }); @this.SetInitializationComplete(); return @this; }
private void DetermineAndAddExecutablePathCommand(IList<LaunchCommand> commands, UnixShellPortLaunchOptions launchOptions) { // TODO: rajkumar42, connecting to OSX via SSH doesn't work yet. Show error after connection manager dialog gets dismissed. // Runs a shell command to get the full path of the exe. // /proc file system does not exist on OSX. And querying lsof on privilaged process fails with no output on Mac, while on Linux the command succeedes with // embedded error text in lsof output like "(readlink error)". string absoluteExePath; if (launchOptions.UnixPort.IsOSX()) { // Usually the first FD=txt in the output of lsof points to the executable. absoluteExePath = string.Format(CultureInfo.InvariantCulture, "shell lsof -p {0} | awk '$4 == \"txt\" {{ print $9 }}'|awk 'NR==1 {{print $1}}'", _launchOptions.ProcessId); } else if (launchOptions.UnixPort.IsLinux()) { absoluteExePath = string.Format(CultureInfo.InvariantCulture, @"shell readlink -f /proc/{0}/exe", _launchOptions.ProcessId); } else { throw new LaunchErrorException(ResourceStrings.Error_UnsupportedPlatform); } Action<string> failureHandler = (string miError) => { string message = string.Format(CultureInfo.CurrentUICulture, ResourceStrings.Error_FailedToGetExePath, miError); throw new LaunchErrorException(message); }; Action<string> successHandler = async (string exePath) => { string trimmedExePath = exePath.Trim(); try { await CmdAsync("-file-exec-and-symbols " + trimmedExePath, ResultClass.done); } catch (UnexpectedMIResultException miException) { string message = string.Format(CultureInfo.CurrentUICulture, ResourceStrings.Error_ExePathInvalid, trimmedExePath, MICommandFactory.Name, miException.MIError); throw new LaunchErrorException(message); } }; commands.Add(new LaunchCommand(absoluteExePath, ignoreFailures: false, failureHandler: failureHandler, successHandler: successHandler)); }