diff --git a/plugins/org.eclipse.dd.gdb.launch/.classpath b/plugins/org.eclipse.dd.gdb.launch/.classpath new file mode 100644 index 00000000000..304e86186aa --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/plugins/org.eclipse.dd.gdb.launch/.project b/plugins/org.eclipse.dd.gdb.launch/.project new file mode 100644 index 00000000000..116145f8919 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/.project @@ -0,0 +1,28 @@ + + + org.eclipse.dd.gdb.launch + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/plugins/org.eclipse.dd.gdb.launch/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.gdb.launch/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..8af0c69cefb --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +#Mon Mar 03 11:58:56 EST 2008 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/plugins/org.eclipse.dd.gdb.launch/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.gdb.launch/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..d63b2e1a771 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Debug Services Framework GDB Launch Plug-in +Bundle-Vendor: Eclipse.org +Bundle-SymbolicName: org.eclipse.dd.gdb.launch; singleton:=true +Bundle-Version: 1.0.0 +Bundle-Activator: org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.dd.dsf, + org.eclipse.dd.dsf.debug, + org.eclipse.dd.mi, + org.eclipse.dd.gdb, + org.eclipse.debug.core, + org.eclipse.cdt.core, + org.eclipse.cdt.launch, + org.eclipse.cdt.debug.core, + org.eclipse.cdt.debug.mi.core +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Export-Package: org.eclipse.dd.gdb.launch.launching diff --git a/plugins/org.eclipse.dd.gdb.launch/about.html b/plugins/org.eclipse.dd.gdb.launch/about.html new file mode 100644 index 00000000000..cb740ae8bc8 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/about.html @@ -0,0 +1,24 @@ + + + + +About +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available +at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + \ No newline at end of file diff --git a/plugins/org.eclipse.dd.gdb.launch/build.properties b/plugins/org.eclipse.dd.gdb.launch/build.properties new file mode 100644 index 00000000000..cf2d90c8779 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + icons/,\ + about.html diff --git a/plugins/org.eclipse.dd.gdb.launch/plugin.xml b/plugins/org.eclipse.dd.gdb.launch/plugin.xml new file mode 100644 index 00000000000..4b4a09485e8 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/plugin.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/internal/GdbLaunchPlugin.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/internal/GdbLaunchPlugin.java new file mode 100644 index 00000000000..3e2a6d9e678 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/internal/GdbLaunchPlugin.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.launch.internal; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Query; +import org.eclipse.dd.gdb.launch.launching.GdbLaunch; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class GdbLaunchPlugin extends Plugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.dd.gdb"; //$NON-NLS-1$ + + // The shared instance + private static GdbLaunchPlugin plugin; + + private static BundleContext fgBundleContext; + + /** + * The constructor + */ + public GdbLaunchPlugin() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + fgBundleContext = context; + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + shutdownActiveLaunches(); + plugin = null; + super.stop(context); + fgBundleContext = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static GdbLaunchPlugin getDefault() { + return plugin; + } + + public static BundleContext getBundleContext() { + return fgBundleContext; + } + + /** + * Shuts down any active launches. We must shutdown any active sessions + * and services associated with this plugin before this plugin is stopped. + * Any attempts to use the plugins {@link BundleContext} after the plugin + * is shut down will result in exceptions. + */ + private void shutdownActiveLaunches() { + for (ILaunch launch : DebugPlugin.getDefault().getLaunchManager().getLaunches()) { + if (launch instanceof GdbLaunch && ((GdbLaunch)launch).getSession().isActive()) { + final GdbLaunch gdbLaunch = (GdbLaunch)launch; + + Query launchShutdownQuery = new Query() { + @Override + protected void execute(DataRequestMonitor rm) { + gdbLaunch.shutdownSession(rm); + } + }; + + try { + gdbLaunch.getSession().getExecutor().execute(launchShutdownQuery); + } catch (RejectedExecutionException e) { + // We can get this exception if the session is shutdown concurrently + // to this method running. + break; + } + + // The Query.get() method is a synchronous call which blocks until the + // query completes. + try { + launchShutdownQuery.get(); + } catch (InterruptedException e) { + getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, "InterruptedException while shutting down PDA debugger launch " + gdbLaunch, e.getCause())); //$NON-NLS-1$ + } catch (ExecutionException e) { + getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, "Exception while shutting down PDA debugger launch " + gdbLaunch, e.getCause())); //$NON-NLS-1$ + } + } + } + } + +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLaunch.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLaunch.java new file mode 100644 index 00000000000..b98cd3783a2 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLaunch.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems 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.dd.gdb.launch.launching; + +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.ImmediateExecutor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.Launch; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.model.ITerminate; + +/** + * The only object in the model that implements the traditional interfaces. + */ +@ThreadSafe +public class GdbLaunch extends Launch + implements ITerminate +{ + private DefaultDsfExecutor fExecutor; + private DsfSession fSession; + private DsfServicesTracker fTracker; + private boolean fInitialized = false; + private boolean fShutDown = false; + + + public GdbLaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) { + super(launchConfiguration, mode, locator); + + // Create the dispatch queue to be used by debugger control and services + // that belong to this launch + final DefaultDsfExecutor dsfExecutor = new DefaultDsfExecutor(GdbLocalLaunchDelegate.GDB_DEBUG_MODEL_ID); + dsfExecutor.prestartCoreThread(); + fExecutor = dsfExecutor; + fSession = DsfSession.startSession(fExecutor, GdbLocalLaunchDelegate.GDB_DEBUG_MODEL_ID); + } + + public DsfExecutor getDsfExecutor() { return fExecutor; } + + @ConfinedToDsfExecutor("getExecutor") + public void initializeControl() + throws CoreException + { + + Runnable initRunnable = new DsfRunnable() { + public void run() { + fTracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), fSession.getId()); + fSession.addServiceEventListener(GdbLaunch.this, null); + + fInitialized = true; + fireChanged(); + } + }; + + // Invoke the execution code and block waiting for the result. + try { + fExecutor.submit(initRunnable).get(); + } catch (InterruptedException e) { + new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Error initializing launch", e); //$NON-NLS-1$ + } catch (ExecutionException e) { + new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, "Error initializing launch", e); //$NON-NLS-1$ + } + } + + public DsfSession getSession() { return fSession; } + + /////////////////////////////////////////////////////////////////////////// + // IServiceEventListener + @DsfServiceEventHandler public void eventDispatched(GDBControl.ExitedEvent event) { + shutdownSession(new RequestMonitor(ImmediateExecutor.getInstance(), null)); + } + + /////////////////////////////////////////////////////////////////////////// + // ITerminate + @Override + public boolean canTerminate() { + return super.canTerminate() && fInitialized && !fShutDown; + } + + @Override + public boolean isTerminated() { + return super.isTerminated() || fShutDown; + } + + + @Override + public void terminate() throws DebugException { + if (fShutDown) return; + super.terminate(); + } + // ITerminate + /////////////////////////////////////////////////////////////////////////// + + /** + * Shuts down the services, the session and the executor associated with + * this launch. + *

+ * Note: The argument request monitor to this method should NOT use the + * executor that belongs to this launch. By the time the shutdown is + * complete, this executor will not be dispatching anymore and the + * request monitor will never be invoked. Instead callers should use + * the {@link ImmediateExecutor}. + *

+ * @param rm The request monitor invoked when the shutdown is complete. + */ + @ConfinedToDsfExecutor("getSession().getExecutor()") + public void shutdownSession(final RequestMonitor rm) { + if (fShutDown) { + rm.done(); + return; + } + fShutDown = true; + + Sequence shutdownSeq = new ShutdownSequence( + getDsfExecutor(), fSession.getId(), + new RequestMonitor(fSession.getExecutor(), rm) { + @Override + public void handleCompleted() { + fSession.removeServiceEventListener(GdbLaunch.this); + if (!getStatus().isOK()) { + GdbLaunchPlugin.getDefault().getLog().log(new MultiStatus( + GdbLaunchPlugin.PLUGIN_ID, -1, new IStatus[]{getStatus()}, "Session shutdown failed", null)); //$NON-NLS-1$ + } + // Last order of business, shutdown the dispatch queue. + fTracker.dispose(); + fTracker = null; + DsfSession.endSession(fSession); + // endSession takes a full dispatch to distribute the + // session-ended event, finish step only after the dispatch. + fExecutor.shutdown(); + fExecutor = null; + fireTerminate(); + + rm.setStatus(getStatus()); + rm.done(); + } + }); + fExecutor.execute(shutdownSeq); + } + + @SuppressWarnings("unchecked") + @Override + public Object getAdapter(Class adapter) { + // Must force adapters to be loaded. + Platform.getAdapterManager().loadAdapter(this, adapter.getName()); + return super.getAdapter(adapter); + } +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLocalLaunchDelegate.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLocalLaunchDelegate.java new file mode 100644 index 00000000000..d5e5c57f478 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbLocalLaunchDelegate.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright (c) 2004, 2006 QNX Software Systems 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: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.launch.launching; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.launch.AbstractCLaunchDelegate; +import org.eclipse.cdt.launch.internal.ui.LaunchMessages; +import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.model.DsfMemoryBlockRetrieval; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.command.AbstractCLIProcess; +import org.eclipse.dd.mi.service.command.MIInferiorProcess; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.core.model.IPersistableSourceLocator; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2; + +/** + * The launch configuration delegate for the CDI debugger session types. + */ +@ThreadSafe +public class GdbLocalLaunchDelegate extends AbstractCLaunchDelegate + implements ILaunchConfigurationDelegate2 +{ + public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.dd.gdb"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + if ( monitor == null ) { + monitor = new NullProgressMonitor(); + } + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + launchDebugger( config, launch, monitor ); + } + } + + private void launchDebugger( ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + monitor.beginTask("Launching debugger session", 10); //$NON-NLS-1$ + if ( monitor.isCanceled() ) { + return; + } + try { + String debugMode = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ); + if ( debugMode.equals( ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ) ) { + launchLocalDebugSession( config, launch, monitor ); + } + } + finally { + monitor.done(); + } + } + + private void launchLocalDebugSession( final ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { + if ( monitor.isCanceled() ) { + return; + } + final GdbLaunch launch = (GdbLaunch)l; + + monitor.subTask( "Debugging local C/C++ application" ); //$NON-NLS-1$ + IPath exePath = verifyProgramPath( config ); + ICProject project = verifyCProject( config ); + if ( exePath != null ) { + verifyBinary( project, exePath ); + } + + setDefaultSourceLocator(launch, config); + + monitor.worked( 1 ); + + + // Create and invoke the launch sequence to create the debug control and services + final LaunchSequence launchSequence = + new LaunchSequence(launch.getSession(), launch, exePath); + launch.getSession().getExecutor().execute(launchSequence); + try { + launchSequence.get(); + } catch (InterruptedException e1) { + throw new DebugException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Interrupted Exception in dispatch thread", e1)); //$NON-NLS-1$ + } catch (ExecutionException e1) { + throw new DebugException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Error in launch sequence", e1.getCause())); //$NON-NLS-1$ + } + + launch.initializeControl(); + + // Add the CLI and "inferior" process objects to the launch. + final AtomicReference cliProcessRef = new AtomicReference(); + final AtomicReference inferiorProcessRef = new AtomicReference(); + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdb = tracker.getService(GDBControl.class); + if (gdb != null) { + cliProcessRef.set(gdb.getCLIProcess()); + inferiorProcessRef.set(gdb.getInferiorProcess()); + } + tracker.dispose(); + return null; + } + }).get(); + launch.addProcess(DebugPlugin.newProcess(launch, cliProcessRef.get(), "gdb")); //$NON-NLS-1$ + launch.addProcess(DebugPlugin.newProcess(launch, inferiorProcessRef.get(), exePath.lastSegment())); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + + // Create a memory retrieval and register it with session + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdbControl = tracker.getService(GDBControl.class); + if (gdbControl != null) { + IMemoryBlockRetrieval memRetrieval = new DsfMemoryBlockRetrieval( + GDB_DEBUG_MODEL_ID, config, (IMemoryDMContext)gdbControl.getControlDMContext()); + launch.getSession().registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval); + ((DsfMemoryBlockRetrieval) memRetrieval).initialize(); + } + tracker.dispose(); + return null; + } + }).get(); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + } + + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#getPluginID() + */ + @Override + protected String getPluginID() { + return LaunchUIPlugin.getUniqueIdentifier(); + } + + /** + * Performs a runtime exec on the given command line in the context of the + * specified working directory, and returns the resulting process. If the + * current runtime does not support the specification of a working + * directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if + * the exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @return the resulting process or null if the exec is + * cancelled + * @see Runtime + */ + protected Process exec( String[] cmdLine, String[] environ, File workingDirectory, boolean usePty ) throws CoreException { + Process p = null; + try { + if ( workingDirectory == null ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ ); + } + else { + if ( usePty && PTY.isSupported() ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory, new PTY() ); + } + else { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory ); + } + } + } + catch( IOException e ) { + if ( p != null ) { + p.destroy(); + } + abort( "Error starting process.", e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR ); //$NON-NLS-1$ + } + catch( NoSuchMethodError e ) { + // attempting launches on 1.2.* - no ability to set working + // directory + IStatus status = new Status( IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_NOT_SUPPORTED, LaunchMessages.getString( "LocalDsfLaunchDelegate.9" ), e ); //$NON-NLS-1$ + IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler( status ); + if ( handler != null ) { + Object result = handler.handleStatus( status, this ); + if ( result instanceof Boolean && ((Boolean)result).booleanValue() ) { + p = exec( cmdLine, environ, null, usePty ); + } + } + } + return p; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public boolean preLaunchCheck( ILaunchConfiguration config, String mode, IProgressMonitor monitor ) throws CoreException { + // no pre launch check for core file + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + if ( ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE.equals( config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ) ) ) + return true; + } + return super.preLaunchCheck( config, mode, monitor ); + } + + /////////////////////////////////////////////////////////////////////////// + // ILaunchConfigurationDelegate2 + @Override + public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return false; + } + + @Override + public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return true; + } + + @Override + public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { + // Need to configure the source locator before creating the launch + // because once the launch is created and added to launch manager, + // the adapters will be created for the whole session, including + // the source lookup adapter. + ISourceLocator locator = getSourceLocator(configuration); + + return new GdbLaunch(configuration, mode, locator); + } + + private ISourceLocator getSourceLocator(ILaunchConfiguration configuration) throws CoreException { + String type = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null); + if (type == null) { + type = configuration.getType().getSourceLocatorId(); + } + if (type != null) { + IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type); + String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null); + if (memento == null) { + locator.initializeDefaults(configuration); + } else { + if(locator instanceof IPersistableSourceLocator2) + ((IPersistableSourceLocator2)locator).initializeFromMemento(memento, configuration); + else + locator.initializeFromMemento(memento); + } + return locator; + } + return null; + } +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbRemoteLaunchDelegate.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbRemoteLaunchDelegate.java new file mode 100644 index 00000000000..77f554e2b57 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/GdbRemoteLaunchDelegate.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - Initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.launch.launching; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.launch.AbstractCLaunchDelegate; +import org.eclipse.cdt.launch.internal.ui.LaunchMessages; +import org.eclipse.cdt.launch.internal.ui.LaunchUIPlugin; +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.debug.model.DsfMemoryBlockRetrieval; +import org.eclipse.dd.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.command.AbstractCLIProcess; +import org.eclipse.dd.mi.service.command.MIInferiorProcess; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2; +import org.eclipse.debug.core.model.IMemoryBlockRetrieval; +import org.eclipse.debug.core.model.IPersistableSourceLocator; +import org.eclipse.debug.core.model.ISourceLocator; +import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2; + +/** + * The launch configuration delegate for the CDI debugger session types. + */ +@ThreadSafe +public class GdbRemoteLaunchDelegate extends AbstractCLaunchDelegate +implements ILaunchConfigurationDelegate2 +{ + public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.dd.gdb"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + if ( monitor == null ) { + monitor = new NullProgressMonitor(); + } + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + launchDebugger( config, launch, monitor ); + } + } + + private void launchDebugger( ILaunchConfiguration config, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + monitor.beginTask("Launching debugger session", 10); //$NON-NLS-1$ + if ( monitor.isCanceled() ) { + return; + } + try { + // Hack until we fix the tabs + try { + ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); + wc.setAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE ); + wc.doSave(); + } + catch( CoreException e ) { + } + // END HACK + String debugMode = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE ); + if ( debugMode.equals( IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE ) ) { + launchRemoteDebugSession( config, launch, monitor ); + } + } + finally { + monitor.done(); + } + } + + private void launchRemoteDebugSession( final ILaunchConfiguration config, ILaunch l, IProgressMonitor monitor ) throws CoreException { + if ( monitor.isCanceled() ) { + return; + } + final GdbLaunch launch = (GdbLaunch)l; + + monitor.subTask( "Debugging remote C/C++ application" ); //$NON-NLS-1$ + IPath exePath = verifyProgramPath( config ); + ICProject project = verifyCProject( config ); + if ( exePath != null ) { + verifyBinary( project, exePath ); + } + + setDefaultSourceLocator(launch, config); + + monitor.worked( 1 ); + + + // Create and invoke the launch sequence to create the debug control and services + final LaunchSequence launchSequence = + new LaunchSequence(launch.getSession(), launch, exePath); + launch.getSession().getExecutor().execute(launchSequence); + try { + launchSequence.get(); + } catch (InterruptedException e1) { + throw new DebugException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Interrupted Exception in dispatch thread", e1)); //$NON-NLS-1$ + } catch (ExecutionException e1) { + throw new DebugException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Error in launch sequence", e1.getCause())); //$NON-NLS-1$ + } + + launch.initializeControl(); + + // Add the CLI and "inferior" process objects to the launch. + final AtomicReference cliProcessRef = new AtomicReference(); + final AtomicReference inferiorProcessRef = new AtomicReference(); + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdb = tracker.getService(GDBControl.class); + if (gdb != null) { + cliProcessRef.set(gdb.getCLIProcess()); + inferiorProcessRef.set(gdb.getInferiorProcess()); + } + tracker.dispose(); + return null; + } + }).get(); + launch.addProcess(DebugPlugin.newProcess(launch, cliProcessRef.get(), "gdb")); //$NON-NLS-1$ + launch.addProcess(DebugPlugin.newProcess(launch, inferiorProcessRef.get(), exePath.lastSegment())); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + + // Create a memory retrieval and register it with session + try { + launch.getDsfExecutor().submit( new Callable() { + public Object call() throws CoreException { + DsfServicesTracker tracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), launch.getSession().getId()); + GDBControl gdbControl = tracker.getService(GDBControl.class); + if (gdbControl != null) { + IMemoryBlockRetrieval memRetrieval = new DsfMemoryBlockRetrieval( + GDB_DEBUG_MODEL_ID, config, (IMemoryDMContext)gdbControl.getControlDMContext()); + launch.getSession().registerModelAdapter(IMemoryBlockRetrieval.class, memRetrieval); + ((DsfMemoryBlockRetrieval) memRetrieval).initialize(); + } + tracker.dispose(); + return null; + } + }).get(); + } catch (InterruptedException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Interrupted while waiting for get process callable.", e)); //$NON-NLS-1$ + } catch (ExecutionException e) { + throw (CoreException)e.getCause(); + } catch (RejectedExecutionException e) { + throw new CoreException(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, 0, "Debugger shut down before launch was completed.", e)); //$NON-NLS-1$ + } + } + + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#getPluginID() + */ + @Override + protected String getPluginID() { + return LaunchUIPlugin.getUniqueIdentifier(); + } + + /** + * Performs a runtime exec on the given command line in the context of the + * specified working directory, and returns the resulting process. If the + * current runtime does not support the specification of a working + * directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if + * the exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @return the resulting process or null if the exec is + * cancelled + * @see Runtime + */ + protected Process exec( String[] cmdLine, String[] environ, File workingDirectory, boolean usePty ) throws CoreException { + Process p = null; + try { + if ( workingDirectory == null ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ ); + } + else { + if ( usePty && PTY.isSupported() ) { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory, new PTY() ); + } + else { + p = ProcessFactory.getFactory().exec( cmdLine, environ, workingDirectory ); + } + } + } + catch( IOException e ) { + if ( p != null ) { + p.destroy(); + } + abort( "Error starting process.", e, ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR ); //$NON-NLS-1$ + } + catch( NoSuchMethodError e ) { + // attempting launches on 1.2.* - no ability to set working + // directory + IStatus status = new Status( IStatus.ERROR, LaunchUIPlugin.getUniqueIdentifier(), ICDTLaunchConfigurationConstants.ERR_WORKING_DIRECTORY_NOT_SUPPORTED, LaunchMessages.getString( "LocalDsfLaunchDelegate.9" ), e ); //$NON-NLS-1$ + IStatusHandler handler = DebugPlugin.getDefault().getStatusHandler( status ); + if ( handler != null ) { + Object result = handler.handleStatus( status, this ); + if ( result instanceof Boolean && ((Boolean)result).booleanValue() ) { + p = exec( cmdLine, environ, null, usePty ); + } + } + } + return p; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.launch.AbstractCLaunchDelegate#preLaunchCheck(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public boolean preLaunchCheck( ILaunchConfiguration config, String mode, IProgressMonitor monitor ) throws CoreException { + // no pre launch check for core file + if ( mode.equals( ILaunchManager.DEBUG_MODE ) ) { + if ( ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE.equals( config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ) ) ) + return true; + } + return super.preLaunchCheck( config, mode, monitor ); + } + + /////////////////////////////////////////////////////////////////////////// + // ILaunchConfigurationDelegate2 + @Override + public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return false; + } + + @Override + public boolean finalLaunchCheck(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException { + return true; + } + + @Override + public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException { + // Need to configure the source locator before creating the launch + // because once the launch is created and added to launch manager, + // the adapters will be created for the whole session, including + // the source lookup adapter. + ISourceLocator locator = getSourceLocator(configuration); + + return new GdbLaunch(configuration, mode, locator); + } + + private ISourceLocator getSourceLocator(ILaunchConfiguration configuration) throws CoreException { + String type = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null); + if (type == null) { + type = configuration.getType().getSourceLocatorId(); + } + if (type != null) { + IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type); + String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null); + if (memento == null) { + locator.initializeDefaults(configuration); + } else { + if(locator instanceof IPersistableSourceLocator2) + ((IPersistableSourceLocator2)locator).initializeFromMemento(memento, configuration); + else + locator.initializeFromMemento(memento); + } + return locator; + } + return null; + } +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/IGDBLaunchConfigurationConstants.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/IGDBLaunchConfigurationConstants.java new file mode 100644 index 00000000000..fff7667d916 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/IGDBLaunchConfigurationConstants.java @@ -0,0 +1,7 @@ +package org.eclipse.dd.gdb.launch.launching; + +public class IGDBLaunchConfigurationConstants { + + public static final String DEBUGGER_MODE_REMOTE = "remote"; + +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/LaunchSequence.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/LaunchSequence.java new file mode 100644 index 00000000000..624517fad07 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/LaunchSequence.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems 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.dd.gdb.launch.launching; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; +import org.eclipse.cdt.debug.mi.core.IMILaunchConfigurationConstants; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.debug.service.StepQueueManager; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.CSourceLookup; +import org.eclipse.dd.mi.service.ExpressionService; +import org.eclipse.dd.mi.service.MIBreakpoints; +import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; +import org.eclipse.dd.mi.service.MIMemory; +import org.eclipse.dd.mi.service.MIModules; +import org.eclipse.dd.mi.service.MIRegisters; +import org.eclipse.dd.mi.service.MIStack; +import org.eclipse.dd.mi.service.command.commands.MIBreakInsert; +import org.eclipse.dd.mi.service.command.commands.MIExecRun; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.debug.core.DebugException; + +public class LaunchSequence extends Sequence { + + Step[] fSteps = new Step[] { + // Create and initialize the Connection service. + new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + // + // Create the connection. + // + fCommandControl = new GDBControl( + fSession, getGDBPath(), fExecPath, GDBControl.SessionType.RUN, 30); + fCommandControl.initialize(requestMonitor); + } + }, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new GDBRunControl(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new StepQueueManager(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIMemory(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIModules(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIStack(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new ExpressionService(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + fSourceLookup = new CSourceLookup(fSession); + fSourceLookup.initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + fSourceLookup.setSourceLookupDirector( + fCommandControl.getGDBDMContext(), + ((CSourceLookupDirector)fLaunch.getSourceLocator())); + requestMonitor.done(); + }}, + new Step() { @Override + public void execute(final RequestMonitor requestMonitor) { + // Create the low-level breakpoint service + final MIBreakpoints bpService = new MIBreakpoints(fSession); + bpService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + requestMonitor.done(); + } + }); + }}, + new Step() { @Override + public void execute(final RequestMonitor requestMonitor) { + // Create high-level breakpoint service and install breakpoints + // for the GDB debug context. + final MIBreakpointsManager bpmService = new MIBreakpointsManager(fSession, CDebugCorePlugin.PLUGIN_ID); + bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + bpmService.startTrackingBreakpoints(fCommandControl.getGDBDMContext(), requestMonitor); + } + }); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIRegisters(fSession).initialize(requestMonitor); + }}, + new Step() { @Override + public void execute(RequestMonitor requestMonitor) { + new MIDisassembly(fSession).initialize(requestMonitor); + }}, + /* + * If needed, insert breakpoint at main and run to it. + */ + new Step() { + private boolean fStopInMain = false; + private String fStopSymbol = null; + + /** + * @return The return value actually indicates whether the get operation succeeded, + * not whether to stop. + */ + private boolean readStopAtMain(RequestMonitor requestMonitor) { + try { + fStopInMain = fLaunch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, -1, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ + requestMonitor.done(); + return false; + } + return true; + } + + private boolean readStopSymbol(RequestMonitor requestMonitor) { + try { + fStopSymbol = fLaunch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ + requestMonitor.done(); + return false; + } + return true; + } + + @Override + public void execute(final RequestMonitor requestMonitor) { + if (!readStopAtMain(requestMonitor)) return; + if (!fStopInMain) { + // Just start the program. + fCommandControl.queueCommand( + new MIExecRun((IContainerDMContext)fCommandControl.getControlDMContext(), new String[0]), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + requestMonitor.done(); + } + } + ); + } else { + if (!readStopSymbol(requestMonitor)) return; + + // Insert a breakpoint at the requested stop symbol. + fCommandControl.queueCommand( + new MIBreakInsert( + (IBreakpointsTargetDMContext)fCommandControl.getControlDMContext(), + true, false, null, 0, fStopSymbol, 0), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + + // After the break-insert is done, execute the -exec-run command. + fCommandControl.queueCommand( + new MIExecRun((IContainerDMContext)fCommandControl.getControlDMContext(), new String[0]), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleOK() { + requestMonitor.done(); + } + } + ); + } + }); + } + } + }, + }; + + DsfSession fSession; + GdbLaunch fLaunch; + IPath fExecPath; + + GDBControl fCommandControl; + CSourceLookup fSourceLookup; + + public LaunchSequence(DsfSession session, GdbLaunch launch, IPath execPath) { + super(session.getExecutor()); + fSession = session; + fLaunch = launch; + fExecPath = execPath; + } + + @Override + public Step[] getSteps() { + return fSteps; + } + + private IPath getGDBPath() { + IPath retVal = new Path("gdb.exe"); //$NON-NLS-1$ + try { + retVal = new Path( fLaunch.getLaunchConfiguration().getAttribute( IMILaunchConfigurationConstants.ATTR_DEBUG_NAME, IMILaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT ) ); + } catch (CoreException e) { + } + return retVal; + } + +} diff --git a/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/ShutdownSequence.java b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/ShutdownSequence.java new file mode 100644 index 00000000000..4ddab9e913f --- /dev/null +++ b/plugins/org.eclipse.dd.gdb.launch/src/org/eclipse/dd/gdb/launch/launching/ShutdownSequence.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2006 Wind River Systems 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.dd.gdb.launch.launching; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.dsf.service.IDsfService; +import org.eclipse.dd.gdb.launch.internal.GdbLaunchPlugin; +import org.eclipse.dd.gdb.service.GDBRunControl; +import org.eclipse.dd.gdb.service.command.GDBControl; +import org.eclipse.dd.mi.service.CSourceLookup; +import org.eclipse.dd.mi.service.ExpressionService; +import org.eclipse.dd.mi.service.MIBreakpoints; +import org.eclipse.dd.mi.service.MIBreakpointsManager; +import org.eclipse.dd.mi.service.MIDisassembly; +import org.eclipse.dd.mi.service.MIMemory; +import org.eclipse.dd.mi.service.MIModules; +import org.eclipse.dd.mi.service.MIRegisters; +import org.eclipse.dd.mi.service.MIStack; + +public class ShutdownSequence extends Sequence { + + String fSessionId; + + String fApplicationName; + + String fDebugModelId; + + DsfServicesTracker fTracker; + + public ShutdownSequence(DsfExecutor executor, String sessionId, RequestMonitor requestMonitor) { + super(executor, requestMonitor); + fSessionId = sessionId; + } + + @Override + public Step[] getSteps() { + return fSteps; + } + + private final Step[] fSteps = new Step[] { new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + assert GdbLaunchPlugin.getBundleContext() != null; + fTracker = new DsfServicesTracker(GdbLaunchPlugin.getBundleContext(), fSessionId); + requestMonitor.done(); + } + + @Override + public void rollBack(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIDisassembly.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIRegisters.class, requestMonitor); + } +// TODO: As Pawel about the necessity of this step +// Not clear on the purpose of this step since the next one does it also +// (stopTrackingBreakpoints() is called as part of the shutdown method) +// Besides, the run control is already gone so removing breakpoints from +// the back-end is bound to fail... +// }, new Step() { +// @Override +// public void execute(final RequestMonitor requestMonitor) { +// MIBreakpointsManager bpm = fTracker.getService(MIBreakpointsManager.class); +// GDBControl commandControl = fTracker.getService(GDBControl.class); +// if (bpm != null && commandControl != null) { +// bpm.stopTrackingBreakpoints( +// commandControl.getGDBDMContext(), +// new RequestMonitor(getExecutor(), requestMonitor) { +// @Override +// protected void handleCompleted() { +// // If un-installing breakpoints fails, log the error but continue shutting down. +// if (!getStatus().isOK()) { +// DsfGdbLaunchPlugin.getDefault().getLog().log(getStatus()); +// } +// requestMonitor.done(); +// } +// }); +// } else { +// requestMonitor.setStatus(new Status(IStatus.ERROR, DsfGdbLaunchPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, +// "Needed services not found.", null)); //$NON-NLS-1$ +// requestMonitor.done(); +// } +// } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIBreakpointsManager.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIBreakpoints.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(CSourceLookup.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(ExpressionService.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIStack.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIModules.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(MIMemory.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(GDBRunControl.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + shutdownService(GDBControl.class, requestMonitor); + } + }, new Step() { + @Override + public void execute(RequestMonitor requestMonitor) { + fTracker.dispose(); + fTracker = null; + requestMonitor.done(); + } + } }; + + @SuppressWarnings("unchecked") + private void shutdownService(Class clazz, final RequestMonitor requestMonitor) { + IDsfService service = fTracker.getService(clazz); + if (service != null) { + service.shutdown(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleCompleted() { + if (!getStatus().isOK()) { + GdbLaunchPlugin.getDefault().getLog().log(getStatus()); + } + requestMonitor.done(); + } + }); + } else { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbLaunchPlugin.PLUGIN_ID, IDsfService.INTERNAL_ERROR, + "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$ + requestMonitor.done(); + } + } +}