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; }