From 65956e57785a4d8af3061760061104c545fb277d Mon Sep 17 00:00:00 2001
From: Uwe Stieber
Date: Mon, 25 May 2015 16:27:00 +0200
Subject: Target Explorer: Add auto-port capability for gdbserver launch for
CDT based launches
---
.../IGdbserverLaunchHandlerDelegate.java | 31 +++
.../cdt/launching/TEGdbAbstractLaunchDelegate.java | 302 ++++++++++++++-------
.../te/tcf/launch/cdt/launching/TEGdbLaunch.java | 69 +++++
.../tcf/te/tcf/launch/cdt/nls/Messages.java | 1 +
.../tcf/te/tcf/launch/cdt/nls/Messages.properties | 4 +
.../tcf/te/tcf/launch/cdt/utils/TEHelper.java | 90 ++----
.../processes/core/launcher/ProcessLauncher.java | 7 +-
7 files changed, 347 insertions(+), 157 deletions(-)
create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/interfaces/IGdbserverLaunchHandlerDelegate.java
create mode 100644 target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbLaunch.java
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/interfaces/IGdbserverLaunchHandlerDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/interfaces/IGdbserverLaunchHandlerDelegate.java
new file mode 100644
index 000000000..e5419dfc6
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/interfaces/IGdbserverLaunchHandlerDelegate.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.launch.cdt.interfaces;
+
+import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Gdbserver launch delegate interface.
+ */
+public interface IGdbserverLaunchHandlerDelegate {
+
+ /**
+ * Normalize the gdbserver launch failure details message.
+ *
+ * @param launch The launch. Must not be null
+ * @param details The details message or null
.
+ *
+ * @return The normalized details message or null
.
+ *
+ * @throws CoreException In case of an failure accessing any launch configuration attribute or similar.
+ */
+ public String normalizeGdbserverLaunchFailureDetailsMessage( GdbLaunch launch, String details) throws CoreException;
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbAbstractLaunchDelegate.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbAbstractLaunchDelegate.java
index 674aec519..4f7818731 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbAbstractLaunchDelegate.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbAbstractLaunchDelegate.java
@@ -10,9 +10,12 @@
package org.eclipse.tcf.te.tcf.launch.cdt.launching;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
@@ -37,14 +40,18 @@ import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.model.ISourceLocator;
import org.eclipse.osgi.util.NLS;
import org.eclipse.tcf.protocol.IPeer;
import org.eclipse.tcf.te.runtime.callback.Callback;
+import org.eclipse.tcf.te.runtime.services.ServiceUtils;
import org.eclipse.tcf.te.tcf.core.streams.StreamsDataReceiver;
import org.eclipse.tcf.te.tcf.launch.cdt.activator.Activator;
+import org.eclipse.tcf.te.tcf.launch.cdt.interfaces.IGdbserverLaunchHandlerDelegate;
import org.eclipse.tcf.te.tcf.launch.cdt.interfaces.IRemoteTEConfigurationConstants;
import org.eclipse.tcf.te.tcf.launch.cdt.nls.Messages;
import org.eclipse.tcf.te.tcf.launch.cdt.utils.TEHelper;
+import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode;
import org.eclipse.tcf.te.tcf.processes.core.launcher.ProcessLauncher;
/**
@@ -69,6 +76,14 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
super(requireCProject);
}
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate#createGdbLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.model.ISourceLocator)
+ */
+ @Override
+ protected GdbLaunch createGdbLaunch(ILaunchConfiguration configuration, String mode, ISourceLocator locator) throws CoreException {
+ return new TEGdbLaunch(configuration, mode, locator);
+ }
+
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
*/
@@ -119,113 +134,182 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
}
// Launch gdbserver on target
- String gdbserverPortNumber = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT, IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_DEFAULT);
- String gdbserverPortNumberMappedTo = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_MAPPED_TO, (String) null);
- String gdbserverCommand = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_COMMAND, IRemoteTEConfigurationConstants.ATTR_GDBSERVER_COMMAND_DEFAULT);
-
- String commandArguments = ""; //$NON-NLS-1$
- if (isAttachLaunch) {
- commandArguments = "--attach :" + gdbserverPortNumber + " " + remotePID; //$NON-NLS-1$ //$NON-NLS-2$
- monitor.setTaskName(Messages.TEGdbAbstractLaunchDelegate_attaching_program);
- } else {
- commandArguments = ":" + gdbserverPortNumber + " " + TEHelper.spaceEscapify(remoteExePath); //$NON-NLS-1$ //$NON-NLS-2$
-
- String arguments = getProgramArguments(config);
- String prelaunchCmd = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_PRERUN_COMMANDS, ""); //$NON-NLS-1$
-
- TEHelper.launchCmd(peer, prelaunchCmd, null, new SubProgressMonitor(monitor, 2), new Callback());
-
- if (arguments != null && !arguments.equals("")) { //$NON-NLS-1$
- commandArguments += " " + arguments; //$NON-NLS-1$
+ final AtomicReference gdbserverPortNumber = new AtomicReference(config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT, IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_DEFAULT));
+ final AtomicReference gdbserverPortNumberMappedTo = new AtomicReference(config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_MAPPED_TO, (String) null));
+ final String gdbserverCommand = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_COMMAND, IRemoteTEConfigurationConstants.ATTR_GDBSERVER_COMMAND_DEFAULT);
+ final List gdbserverPortNumberAlternatives = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_ALTERNATIVES, (List) null);
+ final List gdbserverPortNumberMappedToAlternatives = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_MAPPED_TO_ALTERNATIVES, (List) null);
+
+// For quick testing.
+// final List gdbserverPortNumberAlternatives = new ArrayList(Arrays.asList(new String[] { "49152", "49153", "49154", "49155", "49156" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+// final List gdbserverPortNumberMappedToAlternatives = new ArrayList(Arrays.asList(new String[] { "49652", "49653", "49654", "49655", "49656" })); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+
+ // Remember the originally configured port number and mapped to port number
+ final String origGdbserverPortNumber = gdbserverPortNumber.get();
+ final String origGdbserverPortNumberMappedTo = gdbserverPortNumberMappedTo.get();
+ final AtomicReference origGdbserverOutput = new AtomicReference(null);
+
+ ProcessLauncher launcher = null;
+
+ final AtomicBoolean gdbserverLaunchRetry = new AtomicBoolean(false);
+// final AtomicBoolean portRangeExceeded = new AtomicBoolean(false);
+ final AtomicInteger indexAlternatives = new AtomicInteger(0);
+
+ do {
+ gdbserverLaunchRetry.set(false);
+
+ final AtomicBoolean gdbServerStarted = new AtomicBoolean(false);
+ final AtomicBoolean gdbServerReady = new AtomicBoolean(false);
+ final AtomicBoolean gdbServerExited = new AtomicBoolean(false);
+ final StringBuilder gdbServerOutput = new StringBuilder();
+ final Object lock = new Object();
+
+ String commandArguments = ""; //$NON-NLS-1$
+ if (isAttachLaunch) {
+ commandArguments = "--attach :" + gdbserverPortNumber.get() + " " + remotePID; //$NON-NLS-1$ //$NON-NLS-2$
+ monitor.setTaskName(Messages.TEGdbAbstractLaunchDelegate_attaching_program);
+ } else {
+ commandArguments = ":" + gdbserverPortNumber.get() + " " + TEHelper.spaceEscapify(remoteExePath); //$NON-NLS-1$ //$NON-NLS-2$
+
+ String arguments = getProgramArguments(config);
+ String prelaunchCmd = config.getAttribute(IRemoteTEConfigurationConstants.ATTR_PRERUN_COMMANDS, ""); //$NON-NLS-1$
+
+ TEHelper.launchCmd(peer, prelaunchCmd, null, new SubProgressMonitor(monitor, 2), new Callback());
+
+ if (arguments != null && !arguments.equals("")) { //$NON-NLS-1$
+ commandArguments += " " + arguments; //$NON-NLS-1$
+ }
+ monitor.setTaskName(Messages.TEGdbAbstractLaunchDelegate_starting_program);
}
- monitor.setTaskName(Messages.TEGdbAbstractLaunchDelegate_starting_program);
- }
- final AtomicBoolean gdbServerStarted = new AtomicBoolean(false);
- final AtomicBoolean gdbServerReady = new AtomicBoolean(false);
- final AtomicBoolean gdbServerExited = new AtomicBoolean(false);
- final StringBuffer gdbServerOutput = new StringBuffer();
- final Object lock = new Object();
-
- final GdbLaunch l = (GdbLaunch) launch;
- final Callback callback = new Callback() {
- @Override
- protected void internalDone(Object caller, IStatus status) {
- if (!status.isOK()) {
- gdbServerOutput.append(status.getMessage());
- gdbServerExited.set(true);
- synchronized (lock) {
- lock.notifyAll();
+ final GdbLaunch l = (GdbLaunch) launch;
+ final Callback callback = new Callback() {
+ @Override
+ protected void internalDone(Object caller, IStatus status) {
+ if (!status.isOK()) {
+ gdbServerOutput.append(status.getMessage());
+ gdbServerExited.set(true);
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ else {
+ gdbServerStarted.set(true);
}
+ super.internalDone(caller, status);
}
- else {
- gdbServerStarted.set(true);
+ };
+
+ StreamsDataReceiver.Listener listener = new StreamsDataReceiver.Listener() {
+
+ @Override
+ public void dataReceived(String data) {
+ gdbServerOutput.append(data);
+ if (data.contains("Listening on port")) { //$NON-NLS-1$
+ gdbServerReady.set(true);
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ else if (data.contains("GDBserver exiting") || data.contains("Exiting")) { //$NON-NLS-1$ //$NON-NLS-2$
+ // Check if the gdbserver exited because the port is already in use
+ if (gdbServerOutput.toString().contains("Address already in use.")) { //$NON-NLS-1$
+ // If we have still alternatives, then retry the gdbserver launch
+ // with an alternative port
+ if (!gdbserverPortNumberAlternatives.isEmpty()) {
+ String newPort = null;
+ String newPortMappedTo = null;
+
+ do {
+ newPort = gdbserverPortNumberAlternatives.get(indexAlternatives.get());
+ if (gdbserverPortNumber.get().equals(newPort)) {
+ newPort = null;
+ } else {
+ newPortMappedTo = gdbserverPortNumberMappedToAlternatives != null && !gdbserverPortNumberMappedToAlternatives.isEmpty() ? gdbserverPortNumberMappedToAlternatives.get(indexAlternatives.get()) : null;
+ }
+ indexAlternatives.getAndIncrement();
+ } while (newPort == null && indexAlternatives.get() < gdbserverPortNumberAlternatives.size());
+
+ if (newPort != null) {
+ // Remember the original error
+ if (origGdbserverOutput.get() == null) origGdbserverOutput.set(gdbServerOutput.toString());
+ // Set the flag to retry the gdbserver launch
+ gdbserverLaunchRetry.set(true);
+ // Update the ports
+ gdbserverPortNumber.set(newPort);
+ gdbserverPortNumberMappedTo.set(newPortMappedTo);
+ }
+ }
+ }
+ gdbServerExited.set(true);
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
}
- super.internalDone(caller, status);
- }
- };
+ };
- StreamsDataReceiver.Listener listener = new StreamsDataReceiver.Listener() {
+ launcher = TEHelper.launchCmd(peer, gdbserverCommand, commandArguments, listener, new SubProgressMonitor(monitor, 3), callback);
- @Override
- public void dataReceived(String data) {
- gdbServerOutput.append(data);
- if (data.contains("Listening on port")) { //$NON-NLS-1$
- gdbServerReady.set(true);
+ // Now wait until gdbserver is up and running on the remote host
+ while (!gdbServerReady.get() && !gdbServerExited.get()) {
+ if (monitor.isCanceled()) {
+ // gdbserver launch failed
+ // Need to shutdown the DSF launch session because it is
+ // partially started already.
+ shutdownSession(l, Messages.TEGdbAbstractLaunchDelegate_canceledMsg, launcher);
+ }
+ if (gdbServerStarted.get() && launcher.getChannel() == null) {
+ // gdbserver died or exited. Wait a little bit to process
+ // possible gdbserver output before shutting down the session.
synchronized (lock) {
- lock.notifyAll();
+ try {
+ lock.wait(500);
+ }
+ catch (InterruptedException e) { /* ignored on purpose */ }
+ }
+ if (!gdbserverLaunchRetry.get()) {
+ shutdownSession(l, origGdbserverOutput.get() != null ? origGdbserverOutput.get() : gdbServerOutput.toString(), launcher);
}
}
- else if (data.contains("GDBserver exiting") || data.contains("Exiting")) { //$NON-NLS-1$ //$NON-NLS-2$
- gdbServerExited.set(true);
- synchronized (lock) {
- lock.notifyAll();
+ synchronized (lock) {
+ try {
+ lock.wait(300);
}
+ catch (InterruptedException e) { /* ignored on purpose */ }
}
-
}
- };
-
- ProcessLauncher launcher = TEHelper.launchCmd(peer, gdbserverCommand, commandArguments, listener, new SubProgressMonitor(monitor, 3), callback);
- // Now wait until gdbserver is up and running on the remote host
- while (!gdbServerReady.get() && !gdbServerExited.get()) {
- if (monitor.isCanceled()) {
- // gdbserver launch failed
- // Need to shutdown the DSF launch session because it is
- // partially started already.
- shutdownSession(l, Messages.TEGdbAbstractLaunchDelegate_canceledMsg);
+ // If the gdbserver exited, also shutdown the DSF launch session
+ if (!gdbserverLaunchRetry.get() && gdbServerExited.get()) {
+ shutdownSession(l, origGdbserverOutput.get() != null ? origGdbserverOutput.get() : gdbServerOutput.toString(), launcher);
}
- if (gdbServerStarted.get() && launcher.getChannel() == null) {
- // gdbserver died
- shutdownSession(l, gdbServerOutput.toString());
- }
- synchronized (lock) {
- try {
- lock.wait(300);
- }
- catch (InterruptedException e) {
- }
- }
- }
+ } while (gdbserverLaunchRetry.get());
- // If the gdbserver exited, also shutdown the DSF launch session
- if (gdbServerExited.get()) {
- shutdownSession(l, gdbServerOutput.toString());
+ // Set the launcher to the launch
+ if (launch instanceof TEGdbLaunch) {
+ ((TEGdbLaunch)launch).setLauncher(launcher);
}
// Let debugger know how gdbserver was started on the remote
ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
+ if (!origGdbserverPortNumber.equals(gdbserverPortNumber.get())) {
+ wc.setAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT, gdbserverPortNumber.get());
+ }
+ if (origGdbserverPortNumberMappedTo != null && !origGdbserverPortNumberMappedTo.equals(gdbserverPortNumberMappedTo.get())) {
+ wc.setAttribute(IRemoteTEConfigurationConstants.ATTR_GDBSERVER_PORT_MAPPED_TO, gdbserverPortNumberMappedTo.get());
+ }
wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, true);
wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_HOST, TEHelper.getCurrentConnection(config).getPeer().getAttributes().get(IPeer.ATTR_IP_HOST));
- wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_PORT, gdbserverPortNumberMappedTo == null || "".equals(gdbserverPortNumberMappedTo) ? gdbserverPortNumber : gdbserverPortNumberMappedTo); //$NON-NLS-1$
+ wc.setAttribute(IGDBLaunchConfigurationConstants.ATTR_PORT, gdbserverPortNumberMappedTo.get() == null || "".equals(gdbserverPortNumberMappedTo.get()) ? gdbserverPortNumber.get() : gdbserverPortNumberMappedTo.get()); //$NON-NLS-1$
wc.doSave();
try {
super.launch(config, mode, launch, monitor);
}
catch (CoreException ex) {
// Launch failed, need to kill gdbserver
- launcher.terminate();
+ if (launcher != null) launcher.terminate();
// report failure further
throw ex;
}
@@ -234,7 +318,6 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
}
}
-
/* (non-Javadoc)
* @see org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate#launchDebugSession(org.eclipse.debug.core.ILaunchConfiguration, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
*/
@@ -273,16 +356,6 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
}
}
- /**
- * Shutdown the GDB debug session.
- *
- * @param launch The GDB launch. Must not be null
.
- * @throws CoreException If the GDB debug session shutdown failed.
- */
- protected void shutdownSession(final GdbLaunch launch) throws CoreException {
- shutdownSession(launch, null);
- }
-
/**
* Shutdown the GDB debug session.
*
@@ -290,7 +363,7 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
* @param details Error message, may be null
* @throws CoreException If the GDB debug session shutdown failed.
*/
- protected void shutdownSession(final GdbLaunch launch, String details) throws CoreException {
+ protected void shutdownSession(final GdbLaunch launch, final String details, final ProcessLauncher launcher) throws CoreException {
Assert.isNotNull(launch);
try {
launch.getSession().getExecutor().submit(new DsfRunnable() {
@@ -300,6 +373,8 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
if (launch.getDsfExecutor() != null) {
launch.shutdownSession(new ImmediateRequestMonitor());
}
+ // Make sure that the gdbserver is killed and the launcher resources gets disposed
+ if (launcher != null) launcher.terminate();
}
}).get(1000, TimeUnit.MILLISECONDS);
}
@@ -310,11 +385,54 @@ public abstract class TEGdbAbstractLaunchDelegate extends GdbLaunchDelegate {
// Ignore exceptions during shutdown.
}
+ // Normalize the gdbserver start failure details
+ String details2 = normalizeDetails(launch, details);
+
String msg = Messages.TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorMessage;
- if (details != null && details.length() > 0) msg = NLS.bind(Messages.TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorWithDetails, details);
+ if (details2 != null && details2.length() > 0) msg = NLS.bind(Messages.TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorWithDetails, details2);
abort(msg, null, ICDTLaunchConfigurationConstants.ERR_DEBUGGER_NOT_INSTALLED);
}
+ /**
+ * Normalize the gdbserver launch failure details message.
+ *
+ * @param launch The launch. Must not be null
+ * @param details The details message or null
.
+ *
+ * @return The normalized details message or null
.
+ *
+ * @throws CoreException In case of an failure accessing any launch configuration attribute or similar.
+ */
+ protected String normalizeDetails(final GdbLaunch launch, final String details) throws CoreException {
+ Assert.isNotNull(launch);
+
+ // Get the launch configuration from the launch
+ final ILaunchConfiguration lc = launch.getLaunchConfiguration();
+
+ String d = details;
+ if (d != null && !"".equals(d)) { //$NON-NLS-1$
+ // Try the delegate first if available
+ IPeerNode peerNode = TEHelper.getCurrentConnection(lc);
+ Assert.isNotNull(peerNode);
+ IGdbserverLaunchHandlerDelegate delegate = ServiceUtils.getDelegateServiceDelegate(peerNode, peerNode, IGdbserverLaunchHandlerDelegate.class);
+ if (delegate != null) {
+ d = delegate.normalizeGdbserverLaunchFailureDetailsMessage(launch, details);
+ } else {
+ // Rewrite "Address in use" error.
+ if (d.contains("Address already in use.")) { //$NON-NLS-1$
+ // Get host and port
+ String host = lc.getAttribute(IGDBLaunchConfigurationConstants.ATTR_HOST, (String)null);
+ String port = lc.getAttribute(IGDBLaunchConfigurationConstants.ATTR_PORT, (String)null);
+
+ String address = host + (port != null ? ":" + port : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ d = NLS.bind(Messages.TEGdbAbstractLaunchDelegate_error_addressInUse, address);
+ }
+ }
+ }
+
+ return d;
+ }
+
protected String getProgramArguments(ILaunchConfiguration config) throws CoreException {
String args = config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, (String) null);
if (args != null) {
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbLaunch.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbLaunch.java
new file mode 100644
index 000000000..909b0c14b
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/launching/TEGdbLaunch.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.launch.cdt.launching;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.tcf.te.tcf.processes.core.launcher.ProcessLauncher;
+
+/**
+ * GDB launch implementation handling also the gdbserver life cycle.
+ */
+public class TEGdbLaunch extends GdbLaunch {
+ // The process launcher used to launch the gdbserver process
+ private ProcessLauncher launcher = null;
+
+ /**
+ * Constructor
+ *
+ * @param launchConfiguration The launch configuration. Must not be null
.
+ * @param mode The launch mode. Must not be null
.
+ * @param locator The source locator to use for this debug session, or null
if not supported
+ */
+ public TEGdbLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) {
+ super(launchConfiguration, mode, locator);
+ }
+
+ /**
+ * Sets the process launcher.
+ *
+ * @param launcher The process launcher or null
.
+ */
+ public final void setLauncher(ProcessLauncher launcher) {
+ this.launcher = launcher;
+ }
+
+ /**
+ * Returns the process launcher.
+ *
+ * @return The process launcher or null
.
+ */
+ public final ProcessLauncher getLauncher() {
+ return launcher;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.gdb.launching.GdbLaunch#shutdownSession(org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ @Override
+ public void shutdownSession(RequestMonitor rm) {
+ RequestMonitor r = new RequestMonitor(getDsfExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ ProcessLauncher launcher = getLauncher();
+ if (launcher != null) launcher.terminate();
+ super.handleCompleted();
+ }
+ };
+ super.shutdownSession(r);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.java
index 08617f0e2..c06c4cf43 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.java
@@ -53,6 +53,7 @@ public class Messages extends NLS {
public static String TEGdbAbstractLaunchDelegate_filetransferFailed;
public static String TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorMessage;
public static String TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorWithDetails;
+ public static String TEGdbAbstractLaunchDelegate_error_addressInUse;
static {
// initialize resource bundle
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.properties
index 71fc685ff..032d824c2 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.properties
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/nls/Messages.properties
@@ -47,6 +47,10 @@ TEGdbAbstractLaunchDelegate_starting_debugger=Starting Debugger
TEGdbAbstractLaunchDelegate_filetransferFailed=Failed to download application image to target. Possibly caused by: {0}
TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorMessage=Could not start gdbserver on the remote host. See console output for more details.
TEGdbAbstractLaunchDelegate_gdbserverFailedToStartErrorWithDetails=Could not start gdbserver on the remote host. Possibly caused by:\n{0}
+TEGdbAbstractLaunchDelegate_error_addressInUse=The address {0} is already in use on the remote host. Possibly another gdbserver process is already \
+running using the same port to listen for connections.\n\nPlease configure another port to use within the launch configuration. Do do so, open the \
+launch configuration dialog, select the launch configuration and switch to the "Debugger" tab. On the "Debugger" tab, configure the port to use on \
+the "gdbserver" tab.
TCFPeerSelector_0=Connection:
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/utils/TEHelper.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/utils/TEHelper.java
index ae2c0f42a..f225d140b 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/utils/TEHelper.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.launch.cdt/src/org/eclipse/tcf/te/tcf/launch/cdt/utils/TEHelper.java
@@ -39,7 +39,6 @@ import org.eclipse.tcf.te.runtime.callback.Callback;
import org.eclipse.tcf.te.runtime.concurrent.util.ExecutorsUtil;
import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback;
import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer;
-import org.eclipse.tcf.te.runtime.processes.ProcessOutputReaderThread;
import org.eclipse.tcf.te.runtime.properties.PropertiesContainer;
import org.eclipse.tcf.te.runtime.services.filetransfer.FileTransferItem;
import org.eclipse.tcf.te.runtime.services.interfaces.filetransfer.IFileTransferItem;
@@ -198,6 +197,33 @@ public class TEHelper {
Map launchAttributes = new HashMap();
+ // Compute the terminal title if possible
+ if (args != null && args.length > 0) {
+ StringBuilder title = new StringBuilder();
+ IPath p = new Path(remoteCommandPath);
+ // Avoid very long terminal title's by shortening the path if it has more than 3 segments
+ if (p.segmentCount() > 3) {
+ title.append(".../"); //$NON-NLS-1$
+ title.append(p.lastSegment());
+ } else {
+ title.append(p.toString());
+ }
+
+ for (String arg : args) {
+ if (arg.matches(":[0-9]+")) { //$NON-NLS-1$
+ title.append(arg);
+ break;
+ }
+ }
+
+ String name = peer.getName();
+ if (name != null && !"".equals(name)) { //$NON-NLS-1$
+ title.append(" [" + name + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ if (title.length() > 0) launchAttributes.put(ITerminalsConnectorConstants.PROP_TITLE, title.toString());
+ }
+
launchAttributes.put(IProcessLauncher.PROP_PROCESS_PATH, spaceEscapify(remoteCommandPath));
launchAttributes.put(IProcessLauncher.PROP_PROCESS_ARGS, args);
@@ -222,10 +248,8 @@ public class TEHelper {
Runnable runnable = new Runnable() {
@Override
public void run() {
- if (ITransportTypes.TRANSPORT_TYPE_TCP.equals(peer.getTransportName()) || ITransportTypes.TRANSPORT_TYPE_SSL
- .equals(peer.getTransportName())) {
- isLocalhost.set(IPAddressUtil.getInstance().isLocalHost(peer
- .getAttributes().get(IPeer.ATTR_IP_HOST)));
+ if (ITransportTypes.TRANSPORT_TYPE_TCP.equals(peer.getTransportName()) || ITransportTypes.TRANSPORT_TYPE_SSL.equals(peer.getTransportName())) {
+ isLocalhost.set(IPAddressUtil.getInstance().isLocalHost(peer.getAttributes().get(IPeer.ATTR_IP_HOST)));
}
}
};
@@ -257,62 +281,6 @@ public class TEHelper {
return null;
}
- public static String launchCmdReadOutput(final IPeer peer, String remoteCommandPath, String[] args, final SubProgressMonitor monitor, ICallback callback) throws CoreException {
- String output = null;
- if (remoteCommandPath != null && !remoteCommandPath.trim().equals("")) { //$NON-NLS-1$
- monitor.beginTask(NLS.bind(Messages.TEHelper_executing, remoteCommandPath, args), 10);
-
- // Construct the launcher object
- final ProcessStreamsProxy proxy = new ProcessStreamsProxy();
- ProcessLauncher launcher = new ProcessLauncher(proxy);
-
- Map launchAttributes = new HashMap();
-
- launchAttributes.put(IProcessLauncher.PROP_PROCESS_PATH, spaceEscapify(remoteCommandPath));
- launchAttributes.put(IProcessLauncher.PROP_PROCESS_ARGS, args);
-
- launchAttributes.put(ITerminalsConnectorConstants.PROP_LOCAL_ECHO, Boolean.FALSE);
- launchAttributes.put(IProcessLauncher.PROP_PROCESS_ASSOCIATE_CONSOLE, Boolean.TRUE);
-
- // Fill in the launch attributes
- IPropertiesContainer container = new PropertiesContainer();
- container.setProperties(launchAttributes);
- final boolean processDone[] = new boolean[1];
- processDone[0] = false;
-
- // Launch the process
- launcher.launch(peer, container, new Callback(callback) {
- @Override
- protected void internalDone(Object caller, IStatus status) {
- super.internalDone(caller, status);
- processDone[0] = true;
- }
- });
-
- final Object lock = new Object();
-
- synchronized (lock) {
- while (processDone[0] == false) {
- if (monitor.isCanceled()) {
- break;
- }
- }
- try {
- lock.wait(300);
- }
- catch (InterruptedException e) {
- }
- }
- ProcessOutputReaderThread reader = proxy.getOutputReader();
- while (!reader.isFinished()) {
- reader.waitForFinish();
- }
- output = reader.getOutput();
- }
- monitor.done();
- return output;
- }
-
/**
* Throws a core exception with an error status object built from the given message, lower level
* exception, and error code.
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.processes.core/src/org/eclipse/tcf/te/tcf/processes/core/launcher/ProcessLauncher.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.processes.core/src/org/eclipse/tcf/te/tcf/processes/core/launcher/ProcessLauncher.java
index 7ffd71e5c..bde2d8206 100644
--- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.processes.core/src/org/eclipse/tcf/te/tcf/processes/core/launcher/ProcessLauncher.java
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.processes.core/src/org/eclipse/tcf/te/tcf/processes/core/launcher/ProcessLauncher.java
@@ -597,10 +597,9 @@ public class ProcessLauncher extends PlatformObject implements IProcessLauncher
props.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, "org.eclipse.tm.terminal.connector.streams.launcher.streams"); //$NON-NLS-1$
props.put(ITerminalsConnectorConstants.PROP_ID, "org.eclipse.tm.terminal.view.ui.TerminalsView"); //$NON-NLS-1$
// Set the terminal tab title
- String terminalTitle = getTerminalTitle();
- if (terminalTitle != null) {
- props.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle);
- }
+ String terminalTitle = properties.getStringProperty(ITerminalsConnectorConstants.PROP_TITLE);
+ if (terminalTitle == null) terminalTitle = getTerminalTitle();
+ if (terminalTitle != null) props.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle);
// Get the process output listener list from the properties
Object value = properties.getProperty(PROP_PROCESS_OUTPUT_LISTENER);
--
cgit v1.2.3