diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IDebugNewExecutableHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IDebugNewExecutableHandler.java
new file mode 100644
index 00000000000..ecde45f0427
--- /dev/null
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IDebugNewExecutableHandler.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Mentor Graphics 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:
+ * Mentor Graphics - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.debug.core.model;
+
+import org.eclipse.debug.core.commands.IDebugCommandHandler;
+
+/**
+ * Command handler for the "Debug New Executable" command.
+ *
+ * @since 7.3
+ */
+public interface IDebugNewExecutableHandler extends IDebugCommandHandler {
+}
diff --git a/debug/org.eclipse.cdt.debug.ui/icons/obj16/new_exec.gif b/debug/org.eclipse.cdt.debug.ui/icons/obj16/new_exec.gif
new file mode 100755
index 00000000000..78ca91c6dab
Binary files /dev/null and b/debug/org.eclipse.cdt.debug.ui/icons/obj16/new_exec.gif differ
diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.properties b/debug/org.eclipse.cdt.debug.ui/plugin.properties
index 34cbb7d2d35..2266d66e86e 100644
--- a/debug/org.eclipse.cdt.debug.ui/plugin.properties
+++ b/debug/org.eclipse.cdt.debug.ui/plugin.properties
@@ -242,3 +242,9 @@ OpenNewView.name = Open New View
# Disassembly Ruler Column extension point
extPoint.disassemblyRulerColumn=Disassembly Ruler Column
+
+# Debug New Executable Command
+DebugNewExecutable.name=Debug New Executable
+DebugNewExecutable.description=Debug a new executable
+DebugNewExecutable.label=Debug New Executable...
+DebugNewExecutable.tooltip=Debug a new executable
diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.xml b/debug/org.eclipse.cdt.debug.ui/plugin.xml
index 0188aa81f49..d2b3fc1b6f1 100644
--- a/debug/org.eclipse.cdt.debug.ui/plugin.xml
+++ b/debug/org.eclipse.cdt.debug.ui/plugin.xml
@@ -2012,7 +2012,12 @@
id="org.eclipse.cdt.debug.ui.command.connect"
name="%Connect.name">
-
+
+
@@ -2079,6 +2084,10 @@
class="org.eclipse.cdt.debug.internal.ui.commands.ConnectCommandHandler"
commandId="org.eclipse.cdt.debug.ui.command.connect">
+
+
@@ -2520,6 +2529,28 @@
+
+
+
+
+
getCommandType() {
+ return IDebugNewExecutableHandler.class;
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
index a35c0913306..ac16701c062 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
@@ -19,6 +19,7 @@ import java.util.WeakHashMap;
import org.eclipse.cdt.debug.core.model.ICBreakpoint;
import org.eclipse.cdt.debug.core.model.IConnectHandler;
+import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
import org.eclipse.cdt.debug.core.model.IResumeWithoutSignalHandler;
import org.eclipse.cdt.debug.core.model.IReverseResumeHandler;
import org.eclipse.cdt.debug.core.model.IReverseStepIntoHandler;
@@ -49,6 +50,7 @@ import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbDisconnectCommand;
import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbRestartCommand;
import org.eclipse.cdt.dsf.gdb.internal.ui.actions.GdbSteppingModeTarget;
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbConnectCommand;
+import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbDebugNewExecutableCommand;
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbResumeWithoutSignalCommand;
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbReverseResumeCommand;
import org.eclipse.cdt.dsf.gdb.internal.ui.commands.GdbReverseStepIntoCommand;
@@ -114,6 +116,7 @@ public class GdbAdapterFactory
final GdbResumeWithoutSignalCommand fResumeWithoutSignalCommand;
final GdbRestartCommand fRestartCommand;
final DsfTerminateCommand fTerminateCommand;
+ final GdbDebugNewExecutableCommand fDebugNewExecutableCommand;
final GdbConnectCommand fConnectCommand;
final GdbDisconnectCommand fDisconnectCommand;
final IDebugModelProvider fDebugModelProvider;
@@ -162,6 +165,7 @@ public class GdbAdapterFactory
fResumeWithoutSignalCommand = new GdbResumeWithoutSignalCommand(session);
fRestartCommand = new GdbRestartCommand(session, fLaunch);
fTerminateCommand = new DsfTerminateCommand(session);
+ fDebugNewExecutableCommand = new GdbDebugNewExecutableCommand(session, fLaunch);
fConnectCommand = new GdbConnectCommand(session);
fDisconnectCommand = new GdbDisconnectCommand(session);
fSuspendTrigger = new GdbSuspendTrigger(session, fLaunch);
@@ -189,6 +193,7 @@ public class GdbAdapterFactory
session.registerModelAdapter(IRestartHandler.class, fRestartCommand);
session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand);
session.registerModelAdapter(IConnectHandler.class, fConnectCommand);
+ session.registerModelAdapter(IDebugNewExecutableHandler.class, fDebugNewExecutableCommand);
session.registerModelAdapter(IDisconnectHandler.class, fDisconnectCommand);
session.registerModelAdapter(IModelSelectionPolicyFactory.class, fModelSelectionPolicyFactory);
session.registerModelAdapter(IRefreshAllTarget.class, fRefreshAllTarget);
@@ -249,6 +254,7 @@ public class GdbAdapterFactory
session.unregisterModelAdapter(IRestartHandler.class);
session.unregisterModelAdapter(ITerminateHandler.class);
session.unregisterModelAdapter(IConnectHandler.class);
+ session.unregisterModelAdapter(IDebugNewExecutableHandler.class);
session.unregisterModelAdapter(IDisconnectHandler.class);
session.unregisterModelAdapter(IModelSelectionPolicyFactory.class);
session.unregisterModelAdapter(IRefreshAllTarget.class);
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbDebugNewExecutableCommand.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbDebugNewExecutableCommand.java
new file mode 100644
index 00000000000..b4a366cca9f
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/GdbDebugNewExecutableCommand.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Mentor Graphics 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:
+ * Mentor Graphics - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.internal.ui.commands;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
+import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
+import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
+import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
+import org.eclipse.cdt.dsf.gdb.service.SessionType;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.debug.core.commands.AbstractDebugCommand;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.progress.UIJob;
+
+public class GdbDebugNewExecutableCommand extends AbstractDebugCommand implements IDebugNewExecutableHandler {
+
+ private class PromptJob extends UIJob {
+
+ private DataRequestMonitor fRequestMonitor;
+ private boolean fRemote = false;
+
+ private PromptJob( boolean remote, DataRequestMonitor rm ) {
+ super( "New Executable Prompt Job" ); //$NON-NLS-1$
+ fRemote = remote;
+ fRequestMonitor = rm;
+ }
+
+ @Override
+ public IStatus runInUIThread( IProgressMonitor monitor ) {
+ int flags = ( fRemote ) ? NewExecutableDialog.REMOTE : 0;
+ NewExecutableDialog dialog = new NewExecutableDialog( GdbUIPlugin.getShell(), flags );
+ final boolean canceled = dialog.open() == Window.CANCEL;
+ final PromptInfo info = dialog.getInfo();
+ fExecutor.execute( new DsfRunnable() {
+
+ @Override
+ public void run() {
+ if ( canceled )
+ fRequestMonitor.cancel();
+ else
+ fRequestMonitor.setData( info );
+ fRequestMonitor.done();
+ }
+ } );
+ return Status.OK_STATUS;
+ }
+ }
+
+ private class NewExecutableDialog extends TitleAreaDialog {
+
+ private static final int REMOTE = 0x1;
+
+ private int fFlags = 0;
+ private PromptInfo fInfo = null;
+
+ private Text fHostBinaryText;
+ private Text fTargetBinaryText;
+ private Text fArgumentsText;
+
+ private NewExecutableDialog( Shell parentShell, int flags ) {
+ super( parentShell );
+ setShellStyle( getShellStyle() | SWT.RESIZE );
+ fFlags = flags;
+ }
+
+ @Override
+ protected Control createContents( Composite parent ) {
+ Control control = super.createContents( parent );
+ validate();
+ return control;
+ }
+
+ @Override
+ protected Control createDialogArea( Composite parent ) {
+ boolean remote = (fFlags & REMOTE) > 0;
+
+ getShell().setText( Messages.GdbDebugNewExecutableCommand_Debug_New_Executable );
+ setTitle( Messages.GdbDebugNewExecutableCommand_Select_Binary );
+ String message = ( remote ) ?
+ Messages.GdbDebugNewExecutableCommand_Select_binaries_on_host_and_target :
+ Messages.GdbDebugNewExecutableCommand_Select_binary_and_specify_arguments;
+ setMessage( message );
+
+ Composite control = (Composite)super.createDialogArea( parent );
+ Composite comp = new Composite( control, SWT.NONE );
+ GridData gd = new GridData( SWT.FILL, SWT.FILL, true, true );
+ GridLayout layout = new GridLayout( 3, false );
+ comp.setLayout( layout );
+ comp.setLayoutData( gd );
+
+ new Label( comp, SWT.None ).setText( remote ? Messages.GdbDebugNewExecutableCommand_Binary_on_host : Messages.GdbDebugNewExecutableCommand_Binary );
+ fHostBinaryText = new Text( comp, SWT.BORDER );
+ fHostBinaryText.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false ) );
+ fHostBinaryText.addModifyListener( new ModifyListener() {
+
+ @Override
+ public void modifyText( ModifyEvent e ) {
+ validate();
+ }
+ } );
+ Button browseButton = new Button( comp, SWT.PUSH );
+ browseButton.setText( Messages.GdbDebugNewExecutableCommand_Browse );
+ browseButton.setFont( JFaceResources.getDialogFont() );
+ setButtonLayoutData( browseButton );
+ browseButton.addSelectionListener( new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected( SelectionEvent e ) {
+ FileDialog dialog = new FileDialog( getShell() );
+ dialog.setFileName( fHostBinaryText.getText() );
+ String result = dialog.open();
+ if ( result != null ) {
+ fHostBinaryText.setText( result );
+ }
+ }
+ } );
+
+ if ( remote ) {
+ new Label( comp, SWT.None ).setText( Messages.GdbDebugNewExecutableCommand_Binary_on_target );
+ fTargetBinaryText = new Text( comp, SWT.BORDER );
+ fTargetBinaryText.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 2, 1 ) );
+ fTargetBinaryText.addModifyListener( new ModifyListener() {
+
+ @Override
+ public void modifyText( ModifyEvent e ) {
+ validate();
+ }
+ } );
+ }
+
+ new Label( comp, SWT.None ).setText( Messages.GdbDebugNewExecutableCommand_Arguments );
+ fArgumentsText = new Text( comp, SWT.BORDER );
+ fArgumentsText.setLayoutData( new GridData( SWT.FILL, SWT.CENTER, true, false, 2, 1 ) );
+
+ return control;
+ }
+
+ @Override
+ protected void okPressed() {
+ String targetPath = ( fTargetBinaryText != null ) ? fTargetBinaryText.getText().trim() : null;
+ String args = fArgumentsText.getText().trim();
+ fInfo = new PromptInfo( fHostBinaryText.getText().trim(), targetPath, args );
+ super.okPressed();
+ }
+
+ private PromptInfo getInfo() {
+ return fInfo;
+ }
+
+ private void validate() {
+ String message = null;
+ String hostBinary = fHostBinaryText.getText().trim();
+ File file = new File( hostBinary );
+ if ( !file.exists() )
+ message = Messages.GdbDebugNewExecutableCommand_Binary_file_does_not_exist;
+ else if ( file.isDirectory() )
+ message = Messages.GdbDebugNewExecutableCommand_Invalid_binary;
+ if ( fTargetBinaryText != null ) {
+ if ( fTargetBinaryText.getText().trim().length() == 0 )
+ message = Messages.GdbDebugNewExecutableCommand_Binary_on_target_must_be_specified;
+ }
+ setErrorMessage( message );
+ getButton( IDialogConstants.OK_ID ).setEnabled( message == null );
+ }
+ }
+
+ private class PromptInfo {
+ private String fHostPath;
+ private String fTargetPath;
+ private String fArguments;
+
+ private PromptInfo( String hostPath, String targetPath, String args ) {
+ super();
+ fHostPath = hostPath;
+ fTargetPath = targetPath;
+ fArguments = args;
+ }
+
+ String getHostPath() {
+ return fHostPath;
+ }
+
+ String getTargetPath() {
+ return fTargetPath;
+ }
+
+ String getArguments() {
+ return fArguments;
+ }
+ }
+
+ private final GdbLaunch fLaunch;
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+
+ public GdbDebugNewExecutableCommand( DsfSession session, GdbLaunch launch ) {
+ super();
+ fLaunch = launch;
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker( GdbUIPlugin.getBundleContext(), session.getId() );
+ }
+
+ public boolean canDebugNewExecutable() {
+
+ Query canDebugQuery = new Query() {
+ @Override
+ public void execute( DataRequestMonitor rm ) {
+ IProcesses procService = fTracker.getService( IProcesses.class );
+ IGDBBackend backend = fTracker.getService( IGDBBackend.class );
+ ICommandControlService commandControl = fTracker.getService( ICommandControlService.class );
+
+ if ( procService == null || commandControl == null || backend == null ) {
+ rm.setData( false );
+ rm.done();
+ return;
+ }
+ procService.isDebugNewProcessSupported( commandControl.getContext(), rm );
+ }
+ };
+ try {
+ fExecutor.execute( canDebugQuery );
+ return canDebugQuery.get();
+ }
+ catch( InterruptedException e ) {
+ }
+ catch( ExecutionException e ) {
+ }
+ catch( RejectedExecutionException e ) {
+ // Can be thrown if the session is shutdown
+ }
+ return false;
+ }
+
+ public void debugNewExecutable( final RequestMonitor rm ) {
+ IGDBBackend backend = fTracker.getService( IGDBBackend.class );
+ final IProcesses procService = fTracker.getService( IProcesses.class );
+ final ICommandControlService commandControl = fTracker.getService( ICommandControlService.class );
+ if ( backend == null || procService == null || commandControl == null ) {
+ rm.setStatus( new Status( IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, "Service is not available" ) ); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ PromptJob job = new PromptJob(
+ backend.getSessionType() == SessionType.REMOTE,
+ new DataRequestMonitor( fExecutor, rm ){
+
+ @Override
+ protected void handleCancel() {
+ rm.cancel();
+ rm.done();
+ };
+
+ @Override
+ protected void handleSuccess() {
+ try {
+ @SuppressWarnings( "unchecked" )
+ final Map attributes =
+ new HashMap( getLaunchConfiguration().getAttributes() );
+ attributes.put( IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY, getData().getTargetPath() );
+ attributes.put( ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, getData().getArguments() );
+ procService.debugNewProcess(
+ commandControl.getContext(),
+ getData().getHostPath(),
+ attributes,
+ new ImmediateDataRequestMonitor( rm ) );
+ }
+ catch( CoreException e ) {
+ rm.setStatus( e.getStatus() );
+ rm.done();
+ }
+ };
+ } );
+ job.schedule();
+ }
+
+ @Override
+ protected void doExecute( Object[] targets, IProgressMonitor monitor, IRequest request ) throws CoreException {
+ Query query = new Query() {
+
+ @Override
+ protected void execute( DataRequestMonitor rm ) {
+ debugNewExecutable( rm );
+ }
+ };
+ try {
+ fExecutor.execute( query );
+ query.get();
+ }
+ catch( InterruptedException e ) {
+ }
+ catch( ExecutionException e ) {
+ }
+ catch( CancellationException e ) {
+ // Nothing to do, just ignore the command since the user
+ // cancelled it.
+ }
+ catch( RejectedExecutionException e ) {
+ // Can be thrown if the session is shutdown
+ }
+ }
+
+ @Override
+ protected boolean isExecutable( Object[] targets, IProgressMonitor monitor, IEnabledStateRequest request ) throws CoreException {
+ return canDebugNewExecutable();
+ }
+
+ @Override
+ protected Object getTarget( Object element ) {
+ if ( element instanceof GdbLaunch || element instanceof IDMVMContext )
+ return element;
+ return null;
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ private ILaunchConfiguration getLaunchConfiguration() {
+ return fLaunch.getLaunchConfiguration();
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.java
new file mode 100644
index 00000000000..b5c9461dd53
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Mentor Graphics 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:
+ * Mentor Graphics - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.internal.ui.commands;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+ public static String GdbDebugNewExecutableCommand_Arguments;
+
+ public static String GdbDebugNewExecutableCommand_Binary;
+
+ public static String GdbDebugNewExecutableCommand_Binary_file_does_not_exist;
+
+ public static String GdbDebugNewExecutableCommand_Binary_on_host;
+
+ public static String GdbDebugNewExecutableCommand_Binary_on_target;
+
+ public static String GdbDebugNewExecutableCommand_Binary_on_target_must_be_specified;
+
+ public static String GdbDebugNewExecutableCommand_Browse;
+
+ public static String GdbDebugNewExecutableCommand_Debug_New_Executable;
+
+ public static String GdbDebugNewExecutableCommand_Invalid_binary;
+
+ public static String GdbDebugNewExecutableCommand_Select_binaries_on_host_and_target;
+
+ public static String GdbDebugNewExecutableCommand_Select_Binary;
+
+ public static String GdbDebugNewExecutableCommand_Select_binary_and_specify_arguments;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages( Messages.class.getName(), Messages.class );
+ }
+
+ private Messages() {
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.properties
new file mode 100644
index 00000000000..bc56895950e
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/commands/Messages.properties
@@ -0,0 +1,12 @@
+GdbDebugNewExecutableCommand_Arguments=Arguments:
+GdbDebugNewExecutableCommand_Binary=Binary:
+GdbDebugNewExecutableCommand_Binary_file_does_not_exist=Binary file does not exist
+GdbDebugNewExecutableCommand_Binary_on_host=Binary on host:
+GdbDebugNewExecutableCommand_Binary_on_target=Binary on target:
+GdbDebugNewExecutableCommand_Binary_on_target_must_be_specified=Binary on target must be specified
+GdbDebugNewExecutableCommand_Browse=Browse...
+GdbDebugNewExecutableCommand_Debug_New_Executable=Debug New Executable
+GdbDebugNewExecutableCommand_Invalid_binary=Invalid binary
+GdbDebugNewExecutableCommand_Select_binaries_on_host_and_target=Select binaries on the host and the target and specify the arguments
+GdbDebugNewExecutableCommand_Select_Binary=Select Binary
+GdbDebugNewExecutableCommand_Select_binary_and_specify_arguments=Select a binary and specify the arguments
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java
index 0f1cf56d63b..74bdabda65e 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/IGDBLaunchConfigurationConstants.java
@@ -114,6 +114,13 @@ public class IGDBLaunchConfigurationConstants {
*/
public static final String ATTR_DEBUGGER_TRACEPOINT_MODE = GdbPlugin.PLUGIN_ID + ".TRACEPOINT_MODE"; //$NON-NLS-1$
+ /**
+ * Launch configuration attribute key. The value is a String specifying the path of the executable
+ * on the target.
+ * @since 4.2
+ */
+ public static final String ATTR_DEBUGGER_REMOTE_BINARY = GdbPlugin.PLUGIN_ID + ".REMOTE_BINARY"; //$NON-NLS-1$
+
/**
* Launch configuration attribute value. The key is ATTR_DEBUG_NAME.
*/
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
index 87c79a79e94..efaa5bdb475 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/GdbLaunch.java
@@ -19,6 +19,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.debug.core.model.IConnectHandler;
+import org.eclipse.cdt.debug.core.model.IDebugNewExecutableHandler;
import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
@@ -295,7 +296,10 @@ public class GdbLaunch extends DsfLaunch
if (adapter.equals(IConnectHandler.class))
return getSession().getModelAdapter(adapter);
- // Must force adapters to be loaded.
+ if (adapter.equals(IDebugNewExecutableHandler.class))
+ return getSession().getModelAdapter(adapter);
+
+ // Must force adapters to be loaded.
Platform.getAdapterManager().loadAdapter(this, adapter.getName());
return super.getAdapter(adapter);
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence.java
index ba0797d0f3b..acd2c10c2cc 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence.java
@@ -200,9 +200,13 @@ public class DebugNewProcessSequence extends ReflectionSequence {
@Execute
public void stepSetArguments(RequestMonitor rm) {
try {
- String args = fBackend.getProgramArguments();
+ String args = CDebugUtils.getAttribute(
+ fAttributes,
+ ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
+ ""); //$NON-NLS-1$
- if (args != null) {
+ if (args.length() != 0) {
+ args = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(args);
String[] argArray = CommandLineUtil.argumentsToArray(args);
fCommandControl.queueCommand(
fCommandFactory.createMIGDBSetArgs(getContainerContext(), argArray),
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence_7_2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence_7_2.java
index c7238712b59..0f6d5628df2 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence_7_2.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/DebugNewProcessSequence_7_2.java
@@ -15,15 +15,19 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import org.eclipse.cdt.debug.core.CDebugUtils;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
+import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIAddInferiorInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@@ -40,14 +44,37 @@ public class DebugNewProcessSequence_7_2 extends DebugNewProcessSequence {
private IGDBControl fGdbControl;
private IGDBProcesses fProcService;
+ private IGDBBackend fBackend;
+ private CommandFactory fCommandFactory;
private String fSessionId;
private final boolean fInitialProcess;
+ private final Map fAttributes;
- public DebugNewProcessSequence_7_2(DsfExecutor executor, boolean isInitial, IDMContext dmc, String file,
- Map attributes, DataRequestMonitor rm) {
- super(executor, isInitial, dmc, file, attributes, rm);
+ public DebugNewProcessSequence_7_2(
+ DsfExecutor executor,
+ boolean isInitial,
+ IDMContext dmc,
+ String file,
+ Map attributes,
+ DataRequestMonitor rm) {
+ this(executor, isInitial, dmc, file, null, attributes, rm);
+ }
+
+ /**
+ * @since 4.2
+ */
+ public DebugNewProcessSequence_7_2(
+ DsfExecutor executor,
+ boolean isInitial,
+ IDMContext dmc,
+ String fileOnHost,
+ String fileOnTarget,
+ Map attributes,
+ DataRequestMonitor rm) {
+ super(executor, isInitial, dmc, fileOnHost, attributes, rm);
fSessionId = dmc.getSessionId();
fInitialProcess = isInitial;
+ fAttributes = attributes;
}
@Override
@@ -60,13 +87,14 @@ public class DebugNewProcessSequence_7_2 extends DebugNewProcessSequence {
// Now insert our steps right after the initialization of the base class.
orderList.add(orderList.indexOf("stepInitializeBaseSequence") + 1, "stepInitializeSequence_7_2"); //$NON-NLS-1$ //$NON-NLS-2$
orderList.add(orderList.indexOf("stepInitializeSequence_7_2") + 1, "stepAddInferior"); //$NON-NLS-1$ //$NON-NLS-2$
+ orderList.add(orderList.indexOf("stepSetExecutable") + 1, "stepSetRemoteExecutable"); //$NON-NLS-1$ //$NON-NLS-2$
return orderList.toArray(new String[orderList.size()]);
}
return null;
}
-
+
/**
* Initialize the members of the DebugNewProcessSequence_7_2 class.
* This step is mandatory for the rest of the sequence to complete.
@@ -76,14 +104,17 @@ public class DebugNewProcessSequence_7_2 extends DebugNewProcessSequence {
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSessionId);
fGdbControl = tracker.getService(IGDBControl.class);
fProcService = tracker.getService(IGDBProcesses.class);
+ fBackend = tracker.getService(IGDBBackend.class);
tracker.dispose();
- if (fGdbControl == null || fProcService == null) {
+ if (fGdbControl == null || fProcService == null || fBackend == null) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$
rm.done();
return;
}
+ fCommandFactory = fGdbControl.getCommandFactory();
+
rm.done();
}
@@ -119,5 +150,37 @@ public class DebugNewProcessSequence_7_2 extends DebugNewProcessSequence {
rm.done();
}
});
+ }
+
+ /**
+ * Set remote executable.
+ * @since 4.2
+ */
+ @Execute
+ public void stepSetRemoteExecutable(final RequestMonitor rm) {
+ if (fBackend.getSessionType() == SessionType.REMOTE && fBackend.getIsAttachSession()) {
+ String remoteBinary = CDebugUtils.getAttribute(
+ fAttributes,
+ IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY,
+ ""); //$NON-NLS-1$
+ if (remoteBinary.length() == 0) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "Binary on host is not specified")); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ fGdbControl.queueCommand(
+ fCommandFactory.createMIGDBSet(
+ getContainerContext(),
+ new String[] {
+ "remote", //$NON-NLS-1$
+ "exec-file", //$NON-NLS-1$
+ remoteBinary,
+ }),
+ new ImmediateDataRequestMonitor(rm));
+ }
+ else {
+ rm.done();
}
}
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java
index d9ab8bc5851..3b1a28f160f 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_2.java
@@ -469,10 +469,13 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 {
return false;
}
- // We don't yet support starting a new process on a remote target
- // Bug 344890
- if (type == SessionType.REMOTE && fBackend.getIsAttachSession()) {
- return false;
+ // Multi-process does not work for all-stop right now
+ IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class);
+ if (runControl != null && runControl.getRunMode() == MIRunMode.ALL_STOP) {
+ // Only one process is allowed in all-stop (for now)
+ return getNumConnected() == 0;
+ // NOTE: when we support multi-process in all-stop mode,
+ // we will need to interrupt the target to when doing the attach.
}
return true;
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java
index 6f8a2fd69fd..43d5866263a 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java
@@ -296,11 +296,9 @@ public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence {
*/
@Execute
public void stepCreateConsole(final RequestMonitor rm) {
- if (fBackend.getSessionType() == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
- // Remote non-attach sessions don't support multi-process and therefore will not
- // start new processes. Those sessions will only start the one process, which should
- // not have a console, because it's output is handled by GDB server. Therefore,
- // no need to create an inferior process and add it to the launch
+ if (fBackend.getSessionType() == SessionType.REMOTE) {
+ // The program output for a remote session is handled by gdbserver. Therefore,
+ // no need to create an inferior process and add it to the launch.
rm.done();
return;
}