From 4881bba10c7d5f78d704cd8615527b7356a4a664 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Wed, 2 Feb 2011 21:39:37 +0000 Subject: [PATCH] Bug 335528: [multi-process] Move startOrRestart to the Processes service --- .../eclipse/cdt/debug/core/CDebugUtils.java | 23 ++ .../ui/actions/GdbRestartCommand.java | 80 ++-- .../gdb/launching/FinalLaunchSequence.java | 17 +- .../cdt/dsf/gdb/service/GDBProcesses.java | 138 ++++++- .../cdt/dsf/gdb/service/GDBProcesses_7_0.java | 35 +- .../cdt/dsf/gdb/service/IGDBProcesses.java | 30 +- .../StartOrRestartProcessSequence_7_0.java | 354 ++++++++++++++++++ .../dsf/gdb/service/command/GDBControl.java | 130 +------ .../gdb/service/command/GDBControl_7_0.java | 250 +------------ .../dsf/gdb/service/command/IGDBControl.java | 6 +- .../cdt/tests/dsf/gdb/framework/SyncUtil.java | 38 +- 11 files changed, 666 insertions(+), 435 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java index f9cdb805d60..ec7de3bb4ec 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugUtils.java @@ -19,6 +19,7 @@ import java.nio.charset.CharsetDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; @@ -673,4 +674,26 @@ public class CDebugUtils { private static void throwCoreException(String msg, Exception innerException, int code) throws CoreException { throw new CoreException(new Status(IStatus.ERROR, CDebugCorePlugin.getUniqueIdentifier(), code, msg, innerException)); } + + /** + * Generic method to fetch an attribute from a Map that has keys of type String. The defaultValue + * parameter will be returned if the map does not contain the key, or if the matching value is not + * of the correct type. + * + * @param The type of the value we are looking for. Specified by the type of defaultValue. + * @param attributes The map with keys of type String, and values of any type. Cannot be null. + * @param key They key for which we want the value. + * @param defaultValue The default value to return if the key is not found in the map, or if the value found + * is not of the same type as defaultValue. Cannot be null. + * @return The value, if found and of the same type as defaultValue. Else, returns defaultValue. + * @since 7.1 + */ + @SuppressWarnings("unchecked") + public static V getAttribute(Map attributes, String key, V defaultValue) { + Object value = attributes.get(key); + if (defaultValue.getClass().isInstance(value)) { + return (V)value; + } + return defaultValue; + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbRestartCommand.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbRestartCommand.java index 03d3bc5791a..f2a28e11bc4 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbRestartCommand.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbRestartCommand.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2011 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 @@ -11,12 +11,19 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.internal.ui.actions; +import java.util.Map; + +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.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.ui.actions.DsfCommandRunnable; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.launching.GDBProcess; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; +import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; @@ -51,19 +58,29 @@ public class GdbRestartCommand implements IRestartHandler { request.done(); return; } - - fExecutor.submit(new DsfRunnable() { - public void run() { - IGDBControl gdbControl = fTracker.getService(IGDBControl.class); - if (gdbControl != null) { - request.setEnabled(gdbControl.canRestart()); - } else { - request.setEnabled(false); - } - request.done(); + + fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) { + @Override public void doExecute() { + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(getContext(), IContainerDMContext.class); + IGDBProcesses procService = fTracker.getService(IGDBProcesses.class); + + if (procService != null) { + procService.canRestart( + containerDmc, + new DataRequestMonitor(fExecutor, null) { + @Override + protected void handleCompleted() { + request.setEnabled(isSuccess() && getData()); + request.done(); + } + }); + } else { + request.setEnabled(false); + request.done(); + } } - }); - } + }); + } private class UpdateLaunchJob extends Job { IDebugCommandRequest fRequest; @@ -106,20 +123,29 @@ public class GdbRestartCommand implements IRestartHandler { // Now that we have added the new inferior to the launch, // which creates its console, we can perform the restart safely. - fExecutor.submit(new DsfRunnable() { - public void run() { - final IGDBControl gdbControl = fTracker.getService(IGDBControl.class); - if (gdbControl != null) { - gdbControl.restart(fLaunch, new RequestMonitor(fExecutor, null) { - @Override - protected void handleCompleted() { - fRequest.done(); - }; - }); - } else { - fRequest.done(); - } - } + fExecutor.submit(new DsfCommandRunnable(fTracker, fRequest.getElements()[0], fRequest) { + @SuppressWarnings("unchecked") + @Override public void doExecute() { + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(getContext(), IContainerDMContext.class); + IGDBProcesses procService = fTracker.getService(IGDBProcesses.class); + + if (procService != null) { + Map attributes = null; + try { + attributes = fLaunch.getLaunchConfiguration().getAttributes(); + } catch (CoreException e) {} + + procService.restart(containerDmc, attributes, + new RequestMonitor(fExecutor, null) { + @Override + protected void handleCompleted() { + fRequest.done(); + }; + }); + } else { + fRequest.done(); + } + } }); return Status.OK_STATUS; diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java index f96fb0e68b4..9637859dbc3 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/launching/FinalLaunchSequence.java @@ -14,6 +14,7 @@ package org.eclipse.cdt.dsf.gdb.launching; import java.util.List; +import java.util.Map; import java.util.Properties; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; @@ -26,12 +27,14 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext; import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.actions.IConnect; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; +import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceTargetDMContext; import org.eclipse.cdt.dsf.gdb.service.SessionType; @@ -39,6 +42,7 @@ import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.CSourceLookup; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; +import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.service.DsfServicesTracker; @@ -682,10 +686,21 @@ public class FinalLaunchSequence extends ReflectionSequence { * Start executing the program. * @since 4.0 */ + @SuppressWarnings("unchecked") @Execute public void stepStartExecution(final RequestMonitor requestMonitor) { if (fSessionType != SessionType.CORE) { - fCommandControl.start(fLaunch, requestMonitor); + Map attributes = null; + try { + attributes = fLaunch.getLaunchConfiguration().getAttributes(); + } catch (CoreException e) {} + + IGDBProcesses procService = fTracker.getService(IGDBProcesses.class); + IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fCommandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID); + + // For now, call restart since it does the same as start + // but this is just temporary until procService.debugNewProcess is ready + procService.restart(containerDmc, attributes, requestMonitor); } else { requestMonitor.done(); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java index 4b81a9f6519..811506571f2 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Ericsson and others. + * Copyright (c) 2008, 2011 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 @@ -17,23 +17,32 @@ import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IProcessInfo; import org.eclipse.cdt.core.IProcessList; +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; -import org.eclipse.cdt.dsf.debug.service.IProcesses; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.MIProcesses; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.CoreException; @@ -42,7 +51,7 @@ import org.eclipse.core.runtime.Status; import org.osgi.framework.BundleContext; -public class GDBProcesses extends MIProcesses { +public class GDBProcesses extends MIProcesses implements IGDBProcesses { private class GDBContainerDMC extends MIContainerDMC implements IMemoryDMContext @@ -53,6 +62,8 @@ public class GDBProcesses extends MIProcesses { } private IGDBControl fGdb; + private IGDBBackend fBackend; + private CommandFactory fCommandFactory; // A map of pid to names. It is filled when we get all the // processes that are running @@ -83,10 +94,13 @@ public class GDBProcesses extends MIProcesses { private void doInitialize(RequestMonitor requestMonitor) { fGdb = getServicesTracker().getService(IGDBControl.class); - + fBackend = getServicesTracker().getService(IGDBBackend.class); + fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); + // Register this service. register(new String[] { IProcesses.class.getName(), IMIProcesses.class.getName(), + IGDBProcesses.class.getName(), MIProcesses.class.getName(), GDBProcesses.class.getName() }, new Hashtable()); @@ -148,8 +162,7 @@ public class GDBProcesses extends MIProcesses { if (inferior != null) { String inferiorPidStr = inferior.getPid(); if (inferiorPidStr != null && Integer.parseInt(inferiorPidStr) == pid) { - IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); - name = backend.getProgramPath().lastSegment(); + name = fBackend.getProgramPath().lastSegment(); } } } @@ -160,8 +173,7 @@ public class GDBProcesses extends MIProcesses { // Until bug 305385 is fixed, the above code will not work, so we assume we // are looking for our own process // assert false : "Don't have entry for process ID: " + pid; //$NON-NLS-1$ - IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); - name = backend.getProgramPath().lastSegment(); + name = fBackend.getProgramPath().lastSegment(); } @@ -248,8 +260,7 @@ public class GDBProcesses extends MIProcesses { @Override public void getRunningProcesses(IDMContext dmc, final DataRequestMonitor rm) { final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); - IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); - if (backend.getSessionType() == SessionType.LOCAL) { + if (fBackend.getSessionType() == SessionType.LOCAL) { IProcessList list = null; try { list = CCorePlugin.getDefault().getProcessList(); @@ -296,6 +307,113 @@ public class GDBProcesses extends MIProcesses { } } + /** @since 4.0 */ + public IMIExecutionDMContext[] getExecutionContexts(IMIContainerDMContext containerDmc) { + assert false; // This is not being used before GDB 7.0 + return null; + } + + /** @since 4.0 */ + public void canRestart(IContainerDMContext containerDmc, DataRequestMonitor rm) { + if (fBackend.getIsAttachSession() || fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + + // Before GDB6.8, the Linux gdbserver would restart a new + // process when getting a -exec-run but the communication + // with GDB had a bug and everything hung. + // with GDB6.8 the program restarts properly one time, + // but on a second attempt, gdbserver crashes. + // So, lets just turn off the Restart for Remote debugging + if (fBackend.getSessionType() == SessionType.REMOTE) { + rm.setData(false); + rm.done(); + return; + } + + rm.setData(true); + rm.done(); + } + + /** @since 4.0 */ + public void restart(IContainerDMContext containerDmc, Map attributes, RequestMonitor rm) { + startOrRestart(containerDmc, attributes, true, rm); + } + + /** + * Insert breakpoint at entry if set, and start or restart the program. + * + * @since 4.0 + */ + protected void startOrRestart(final IContainerDMContext containerDmc, Map attributes, + boolean restart, final RequestMonitor requestMonitor) { + if (fBackend.getIsAttachSession()) { + // When attaching to a running process, we do not need to set a breakpoint or + // start the program; it is left up to the user. + requestMonitor.done(); + return; + } + + final DataRequestMonitor execMonitor = new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + if (fBackend.getSessionType() != SessionType.REMOTE) { + // Don't send the ContainerStarted event for a remote session because + // it has already been done by MIRunControlEventProcessor when receiving + // the ^connect + getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties()); + } + super.handleSuccess(); + } + }; + + final ICommand execCommand; + if (useContinueCommand()) { + execCommand = fCommandFactory.createMIExecContinue(containerDmc); + } else { + execCommand = fCommandFactory.createMIExecRun(containerDmc); + } + + boolean stopInMain = CDebugUtils.getAttribute(attributes, + ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, + false); + + if (!stopInMain) { + // Just start the program. + fGdb.queueCommand(execCommand, execMonitor); + } else { + String stopSymbol = CDebugUtils.getAttribute(attributes, + ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, + ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT); + + // Insert a breakpoint at the requested stop symbol. + IBreakpointsTargetDMContext bpTarget = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class); + fGdb.queueCommand( + fCommandFactory.createMIBreakInsert(bpTarget, true, false, null, 0, stopSymbol, 0), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + // After the break-insert is done, execute the -exec-run or -exec-continue command. + fGdb.queueCommand(execCommand, execMonitor); + } + }); + } + } + + /** + * This method indicates if we should use the -exec-continue command + * instead of the -exec-run command. + * This method can be overridden to allow for customization. + * @since 4.0 + */ + protected boolean useContinueCommand() { + // When doing remote debugging, we use -exec-continue instead of -exec-run + // Restart does not apply to remote sessions + return fBackend.getSessionType() == SessionType.REMOTE; + } + /** * @since 3.0 */ diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java index 4fe9950005d..ed3b4397438 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Ericsson and others. + * Copyright (c) 2008, 2011 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 @@ -24,6 +24,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.IProcessInfo; import org.eclipse.cdt.core.IProcessList; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.Immutable; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; @@ -981,6 +982,38 @@ public class GDBProcesses_7_0 extends AbstractDsfService fCommandControl.terminate(rm); } + /** @since 4.0 */ + public void canRestart(IContainerDMContext containerDmc, DataRequestMonitor rm) { + if (fBackend.getIsAttachSession() || fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + + // Before GDB6.8, the Linux gdbserver would restart a new + // process when getting a -exec-run but the communication + // with GDB had a bug and everything hung. + // with GDB6.8 the program restarts properly one time, + // but on a second attempt, gdbserver crashes. + // So, lets just turn off the Restart for Remote debugging + if (fBackend.getSessionType() == SessionType.REMOTE) { + rm.setData(false); + rm.done(); + return; + } + + rm.setData(true); + rm.done(); + } + + /** @since 4.0 */ + public void restart(IContainerDMContext containerDmc, Map attributes, RequestMonitor rm) { + ImmediateExecutor.getInstance().execute( + new StartOrRestartProcessSequence_7_0( + getExecutor(), containerDmc, attributes, true, + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm))); + } + @DsfServiceEventHandler public void eventDispatched(final MIThreadGroupCreatedEvent e) { IProcessDMContext procDmc = e.getDMContext(); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBProcesses.java index 22bf1c11434..4769ce37170 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBProcesses.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/IGDBProcesses.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Ericsson and others. + * Copyright (c) 2008, 2011 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 @@ -11,6 +11,11 @@ *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; +import java.util.Map; + +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIProcesses; @@ -50,5 +55,26 @@ public interface IGDBProcesses extends IMIProcesses { * @param containerDmc The container for which we want to get the execution contexts */ IMIExecutionDMContext[] getExecutionContexts(IMIContainerDMContext containerDmc); - + + /** + * Returns whether the specified process can be restarted. + * + * @param containerDmc The process that should be restarted + * @param rm The requestMonitor that returns if a restart is allowed on the specified process. + * + * @since 4.0 + */ + void canRestart(IContainerDMContext containerDmc, DataRequestMonitor rm); + + /** + * Request that the specified process be restarted. + * + * @param containerDmc The process that should be restarted + * @param attributes Different attributes that affect the restart operation. This is + * usually the launch configuration attributes + * @param rm The requetMonitor that indicates that the restart request has been completed. + * + * @since 4.0 + */ + void restart(IContainerDMContext containerDmc, Map attributes, RequestMonitor rm); } 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 new file mode 100644 index 00000000000..faad1931c06 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/StartOrRestartProcessSequence_7_0.java @@ -0,0 +1,354 @@ +/******************************************************************************* + * Copyright (c) 2011 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.cdt.dsf.gdb.service; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.cdt.debug.core.CDebugUtils; +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +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.ImmediateExecutor; +import org.eclipse.cdt.dsf.concurrent.ReflectionSequence; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommand; +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.IMICommandControl; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; +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; + +/** + * This class causes a process to start (run for the first time), or to + * be restarted. The complexity is due to the handling of reverse debugging, + * which this class transparently enables if necessary. + * + * This sequence is used for GDB >= 7.0 which supports reverse debugging. + * + * @since 4.0 + */ +public class StartOrRestartProcessSequence_7_0 extends ReflectionSequence { + + private IGDBControl fCommandControl; + private CommandFactory fCommandFactory; + private IGDBProcesses fProcService; + private IReverseRunControl fReverseService; + + private DsfServicesTracker fTracker; + + // This variable will be used to store the original container context, + // but once the new process is start (restarted), it will contain the new + // container context. This new container context has for parent the process + // context, which holds the new pid. + private IContainerDMContext fContainerDmc; + + // If the user requested a stop_on_main, this variable will hold the breakpoint + private MIBreakpoint fUserBreakpoint; + // Since the stop_on_main option allows the user to set the breakpoint on any + // symbol, we use this variable to know if the stop_on_main breakpoint was really + // on the main() method. + private boolean fUserBreakpointIsOnMain; + + private boolean fReverseEnabled; + private final Map fAttributes; + + // Indicates if the sequence is being used for a restart or a start + private final boolean fRestart; + + // Store the dataRM so that we can fill it with the new container context, which we must return + // Although we can access this through Sequence.getRequestMonitor(), we would loose the type-checking. + // Therefore, doing it like this is more future-proof. + private final DataRequestMonitor fDataRequestMonitor; + + + protected IContainerDMContext getContainerContext() { + return fContainerDmc; + } + + protected MIBreakpoint getUserBreakpoint() { + return fUserBreakpoint; + } + + protected boolean getUserBreakpointIsOnMain() { + return fUserBreakpointIsOnMain; + } + + + public StartOrRestartProcessSequence_7_0(DsfExecutor executor, IContainerDMContext containerDmc, Map attributes, + boolean restart, DataRequestMonitor rm) { + super(executor, rm); + + assert executor != null; + assert containerDmc != null; + if (attributes == null) { + // If no attributes are specified, simply use an empty map. + attributes = new HashMap(); + } + + fContainerDmc = containerDmc; + fAttributes = attributes; + fRestart = restart; + fDataRequestMonitor = rm; + } + + @Override + protected String[] getExecutionOrder(String group) { + if (GROUP_TOP_LEVEL.equals(group)) { + + DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fContainerDmc.getSessionId()); + IGDBBackend backend = tracker.getService(IGDBBackend.class); + tracker.dispose(); + + if (backend.getIsAttachSession()) { + // Restart does not apply to attach sessions, so we are only dealing with the + // Start case. + // + // When attaching to a running process, we do not need to set a breakpoint or + // start the program; it is left up to the user. + // We only need to turn on Reverse Debugging if requested. + + return new String[] { + "stepInitializeBaseSequence", //$NON-NLS-1$ + "stepEnableReverse", //$NON-NLS-1$ + "stepCleanupBaseSequence", //$NON-NLS-1$ + }; + } else { + return new String[] { + "stepInitializeBaseSequence", //$NON-NLS-1$ + "stepInsertStopOnMainBreakpoint", //$NON-NLS-1$ + "stepSetBreakpointForReverse", //$NON-NLS-1$ + "stepRunProgram", //$NON-NLS-1$ + "stepSetReverseOff", //$NON-NLS-1$ + "stepEnableReverse", //$NON-NLS-1$ + "stepContinue", //$NON-NLS-1$ + "stepCleanupBaseSequence", //$NON-NLS-1$ + }; + } + } + return null; + } + + /** + * Initialize the members of the {@link StartOrRestartProcessSequence_7_0} class. + * This step is mandatory for the rest of the sequence to complete. + */ + @Execute + public void stepInitializeBaseSequence(RequestMonitor rm) { + fTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fContainerDmc.getSessionId()); + fCommandControl = fTracker.getService(IGDBControl.class); + fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory(); + fProcService = fTracker.getService(IGDBProcesses.class); + + if (fCommandControl == null || fCommandFactory == null || fProcService == null) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot obtain service", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + fReverseService = fTracker.getService(IReverseRunControl.class); + if (fReverseService != null) { + // Although the option to use reverse debugging could be on, we only check + // it if we actually have a reverse debugging service. There is no point + // in trying to handle reverse debugging if it is not available. + fReverseEnabled = CDebugUtils.getAttribute(fAttributes, + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, + IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); + } + + rm.done(); + } + + /** + * Rollback method for {@link #stepInitializeBaseSequence()} + */ + @RollBack("stepInitializeBaseSequence") + public void rollBackInitializeBaseSequence(RequestMonitor rm) { + if (fTracker != null) fTracker.dispose(); + fTracker = null; + rm.done(); + } + + /** + * If the user requested a 'stopOnMain', let's set the temporary breakpoint + * where the user specified. + */ + @Execute + public void stepInsertStopOnMainBreakpoint(final RequestMonitor rm) { + boolean userRequestedStop = CDebugUtils.getAttribute(fAttributes, + ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, + false); + + if (userRequestedStop) { + String userStopSymbol = CDebugUtils.getAttribute(fAttributes, + ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, + ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT); + + fCommandControl.queueCommand( + fCommandFactory.createMIBreakInsert((IBreakpointsTargetDMContext)fCommandControl.getContext(), + true, false, null, 0, userStopSymbol, 0), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + public void handleSuccess() { + if (getData() != null) { + MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); + if (breakpoints.length > 0) { + fUserBreakpoint = breakpoints[0]; + } + } + rm.done(); + } + }); + } else { + rm.done(); + } + } + + /** + * If reverse debugging, set a breakpoint on main to be able to enable reverse + * as early as possible. + * If the user has requested a stop at the same point, we could skip this breakpoint + * however, we have to first set it to find out! So, we just leave it. + */ + @Execute + public void stepSetBreakpointForReverse(final RequestMonitor rm) { + if (fReverseEnabled) { + fCommandControl.queueCommand( + fCommandFactory.createMIBreakInsert((IBreakpointsTargetDMContext)fCommandControl.getContext(), + true, false, null, 0, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT, 0), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + public void handleSuccess() { + if (getData() != null) { + MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); + if (breakpoints.length > 0 && fUserBreakpoint != null) { + fUserBreakpointIsOnMain = breakpoints[0].getAddress().equals(fUserBreakpoint.getAddress()); + } + } + rm.done(); + } + }); + } else { + rm.done(); + } + } + + /** + * Now, run the program. + */ + @Execute + public void stepRunProgram(final RequestMonitor rm) { + ICommand command; + if (useContinueCommand()) { + command = fCommandFactory.createMIExecContinue(fContainerDmc); + } else { + command = fCommandFactory.createMIExecRun(fContainerDmc); + } + fCommandControl.queueCommand(command, new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + protected void handleSuccess() { + // Now that the process is started, the pid has been allocated + // so we need to fetch the proper container context + // We replace our current context which does not have the pid, with one that has the pid. + + if (fContainerDmc instanceof IMIContainerDMContext) { + fContainerDmc = fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), ((IMIContainerDMContext)fContainerDmc).getGroupId()); + // This is the container context that this sequence is supposed to return: set the dataRm + fDataRequestMonitor.setData(fContainerDmc); + } else { + assert false : "Container context was not an IMIContainerDMContext"; //$NON-NLS-1$ + } + rm.done(); + } + }); + } + + /** + * In case of a restart, we must mark reverse debugging as disabled because + * GDB has turned it off. We may have to turn it back on after. + */ + @Execute + public void stepSetReverseOff(RequestMonitor rm) { + if (fRestart) { + GDBRunControl_7_0 reverseService = fTracker.getService(GDBRunControl_7_0.class); + if (reverseService != null) { + reverseService.setReverseModeEnabled(false); + } else { + assert false : "Missing reverse runControl service"; //$NON-NLS-1$ + } + } + rm.done(); + } + + /** + * Since we have started the program, we can turn on reverse debugging if needed. + * We know the program will stop since we set a breakpoint on main, to enable reverse. + */ + @Execute + public void stepEnableReverse(RequestMonitor rm) { + if (fReverseEnabled) { + fReverseService.enableReverseMode(fCommandControl.getContext(), true, rm); + } else { + rm.done(); + } + } + + /** + * Finally, if we are enabling reverse, and the userSymbolStop is not on main, + * we should do a continue because we are currently stopped on main but that + * is not what the user requested + */ + @Execute + public void stepContinue(RequestMonitor rm) { + if (fReverseEnabled && !fUserBreakpointIsOnMain) { + fCommandControl.queueCommand(fCommandFactory.createMIExecContinue(fContainerDmc), + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm)); + } else { + rm.done(); + } + } + + /** + * Cleanup now that the sequence has been run. + */ + @Execute + public void stepCleanupBaseSequence(final RequestMonitor rm) { + fTracker.dispose(); + fTracker = null; + rm.done(); + } + + /** + * This method indicates if we should use the -exec-continue command + * instead of the -exec-run command. + * This method can be overridden to allow for customization. + */ + protected boolean useContinueCommand() { + // When doing remote debugging, we use -exec-continue instead of -exec-run + // Restart does not apply to remote sessions + IGDBBackend backend = fTracker.getService(IGDBBackend.class); + if (backend == null) { + return false; + } + return backend.getSessionType() == SessionType.REMOTE; + } + +} \ No newline at end of file diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java index 061b34cc4ec..ab7978fba4d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2011 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 @@ -24,7 +24,6 @@ import java.util.Properties; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; @@ -33,22 +32,16 @@ import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.Sequence; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; -import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; -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.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; -import org.eclipse.cdt.dsf.mi.service.IMIProcesses; -import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerExitedDMEvent; -import org.eclipse.cdt.dsf.mi.service.MIProcesses.ContainerStartedDMEvent; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor; @@ -57,18 +50,13 @@ import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor; -import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; -import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.utils.pty.PTY; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.osgi.framework.BundleContext; @@ -273,122 +261,6 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { } } - - public boolean canRestart() { - if (fMIBackend.getIsAttachSession() || fMIBackend.getSessionType() == SessionType.CORE) { - return false; - } - - // Before GDB6.8, the Linux gdbserver would restart a new - // process when getting a -exec-run but the communication - // with GDB had a bug and everything hung. - // with GDB6.8 the program restarts properly one time, - // but on a second attempt, gdbserver crashes. - // So, lets just turn off the Restart for Remote debugging - if (fMIBackend.getSessionType() == SessionType.REMOTE) return false; - - return true; - } - - /* - * Start the program. - */ - public void start(GdbLaunch launch, final RequestMonitor requestMonitor) { - startOrRestart(launch, false, requestMonitor); - } - - /* - * Before restarting the inferior, we must re-initialize its input/output streams - * and create a new inferior process object. Then we can restart the inferior. - */ - public void restart(final GdbLaunch launch, final RequestMonitor requestMonitor) { - startOrRestart(launch, true, requestMonitor); - } - - /* - * Insert breakpoint at entry if set, and start or restart the program. - */ - protected void startOrRestart(final GdbLaunch launch, boolean restart, final RequestMonitor requestMonitor) { - if (fMIBackend.getIsAttachSession()) { - // When attaching to a running process, we do not need to set a breakpoint or - // start the program; it is left up to the user. - requestMonitor.done(); - return; - } - - DsfServicesTracker servicesTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), getSession().getId()); - IMIProcesses procService = servicesTracker.getService(IMIProcesses.class); - servicesTracker.dispose(); - final IContainerDMContext containerDmc = procService.createContainerContextFromGroupId(fControlDmc, MIProcesses.UNIQUE_GROUP_ID); - - final ICommand execCommand; - if (useContinueCommand(launch, restart)) { - execCommand = getCommandFactory().createMIExecContinue(containerDmc); - } else { - execCommand = getCommandFactory().createMIExecRun(containerDmc); - } - - boolean stopInMain = false; - try { - stopInMain = launch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false ); - } catch (CoreException e) { - requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve stop at entry point boolean", e)); //$NON-NLS-1$ - requestMonitor.done(); - return; - } - - final DataRequestMonitor execMonitor = new DataRequestMonitor(getExecutor(), requestMonitor) { - @Override - protected void handleSuccess() { - if (fMIBackend.getSessionType() != SessionType.REMOTE) { - // Don't send the ContainerStarted event for a remote session because - // it has already been done by MIRunControlEventProcessor when receiving - // the ^connect - getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties()); - } - super.handleSuccess(); - } - }; - - if (!stopInMain) { - // Just start the program. - queueCommand(execCommand, execMonitor); - } else { - String stopSymbol = null; - try { - stopSymbol = launch.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, GdbPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ - requestMonitor.done(); - return; - } - - // Insert a breakpoint at the requested stop symbol. - queueCommand( - getCommandFactory().createMIBreakInsert(fControlDmc, true, false, null, 0, stopSymbol, 0), - new DataRequestMonitor(getExecutor(), requestMonitor) { - @Override - protected void handleSuccess() { - // After the break-insert is done, execute the -exec-run or -exec-continue command. - queueCommand(execCommand, execMonitor); - } - }); - } - } - - /** - * This method indicates if we should use the -exec-continue method - * instead of the -exec-run method. - * This can be overridden to allow for customization. - * - * @since 4.0 - */ - protected boolean useContinueCommand(ILaunch launch, boolean restart) { - // When doing remote debugging, we use -exec-continue instead of -exec-run - // Restart does not apply to remote sessions - return fMIBackend.getSessionType() == SessionType.REMOTE; - } - /* * This method creates a new inferior process object based on the current Pty or output stream. */ diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java index cdfdc6958f4..e083f04ab1b 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl_7_0.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems and others. + * Copyright (c) 2006, 2011 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 @@ -24,7 +24,6 @@ import java.util.Properties; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; @@ -33,26 +32,18 @@ import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.concurrent.Sequence; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; -import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.cdt.dsf.debug.service.command.ICommand; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; -import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; -import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; import org.eclipse.cdt.dsf.gdb.service.GDBProcesses_7_0.ContainerExitedDMEvent; import org.eclipse.cdt.dsf.gdb.service.GDBProcesses_7_0.ContainerStartedDMEvent; -import org.eclipse.cdt.dsf.gdb.service.GDBRunControl_7_0; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent; -import org.eclipse.cdt.dsf.gdb.service.IReverseRunControl; import org.eclipse.cdt.dsf.gdb.service.SessionType; import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIBackend.BackendStateChangedEvent; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; -import org.eclipse.cdt.dsf.mi.service.IMIProcesses; -import org.eclipse.cdt.dsf.mi.service.MIProcesses; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor_7_0; @@ -61,19 +52,14 @@ import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess.State; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor_7_0; -import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; -import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIListFeaturesInfo; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.utils.pty.PTY; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.debug.core.DebugException; -import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.osgi.framework.BundleContext; @@ -292,240 +278,6 @@ public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { } } - - public boolean canRestart() { - if (fMIBackend.getIsAttachSession()|| fMIBackend.getSessionType() == SessionType.CORE) { - return false; - } - - // Before GDB6.8, the Linux gdbserver would restart a new - // process when getting a -exec-run but the communication - // with GDB had a bug and everything hung. - // with GDB6.8 the program restarts properly one time, - // but on a second attempt, gdbserver crashes. - // So, lets just turn off the Restart for Remote debugging - if (fMIBackend.getSessionType() == SessionType.REMOTE) return false; - - return true; - } - - /** - * Start the program. - */ - public void start(GdbLaunch launch, final RequestMonitor requestMonitor) { - startOrRestart(launch, false, requestMonitor); - } - - /** - * Before restarting the inferior, we must re-initialize its input/output streams - * and create a new inferior process object. Then we can restart the inferior. - */ - public void restart(final GdbLaunch launch, final RequestMonitor requestMonitor) { - startOrRestart(launch, true, requestMonitor); - } - - /** - * Insert breakpoint at entry if set, and start or restart the program. - * Note that restart does not apply to remote or attach sessions. - * - * If we want to enable Reverse debugging from the start of the program we do the following: - * attachSession => enable reverse - * else => set temp bp on main, run, enable reverse, continue if bp on main was not requested by user - */ - protected void startOrRestart(final GdbLaunch launch, final boolean restart, RequestMonitor requestMonitor) { - boolean tmpReverseEnabled = IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT; - try { - tmpReverseEnabled = launch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, - IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); - } catch (CoreException e) { - } - final boolean reverseEnabled = tmpReverseEnabled; - - if (fMIBackend.getIsAttachSession()) { - // Restart does not apply to attach sessions. - // - // When attaching to a running process, we do not need to set a breakpoint or - // start the program; it is left up to the user. - // We only need to turn on Reverse Debugging if requested. - if (reverseEnabled) { - IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class); - if (reverseService != null) { - reverseService.enableReverseMode(fControlDmc, true, requestMonitor); - return; - } - } - requestMonitor.done(); - return; - } - - // When it is not an attach session, it gets a little more complicated - // so let's use a sequence. - getExecutor().execute(new Sequence(getExecutor(), requestMonitor) { - IContainerDMContext fContainerDmc; - MIBreakpoint fUserBreakpoint = null; - boolean fUserBreakpointIsOnMain = false; - - Step[] fSteps = new Step[] { - /* - * If the user requested a 'stopOnMain', let's set the temporary breakpoint - * where the user specified. - */ - new Step() { - @Override - public void execute(final RequestMonitor rm) { - boolean userRequestedStop = false; - try { - userRequestedStop = launch.getLaunchConfiguration().getAttribute( - ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, - false); - } catch (CoreException e) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve stop at entry point boolean", e)); //$NON-NLS-1$ - rm.done(); - return; - } - - if (userRequestedStop) { - String userStopSymbol = null; - try { - userStopSymbol = launch.getLaunchConfiguration().getAttribute( - ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, - ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT); - } catch (CoreException e) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ - rm.done(); - return; - } - - queueCommand(getCommandFactory().createMIBreakInsert(fControlDmc, true, false, null, 0, userStopSymbol, 0), - new DataRequestMonitor(getExecutor(), rm) { - @Override - public void handleSuccess() { - if (getData() != null) { - MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); - if (breakpoints.length > 0) { - fUserBreakpoint = breakpoints[0]; - } - } - rm.done(); - } - }); - } else { - rm.done(); - } - }}, - /* - * If reverse debugging, set a breakpoint on main to be able to enable reverse - * as early as possible. - * If the user has requested a stop at the same point, we could skip this breakpoint - * however, we have to first set it to find out! So, we just leave it. - */ - new Step() { - @Override - public void execute(final RequestMonitor rm) { - if (reverseEnabled) { - queueCommand(getCommandFactory().createMIBreakInsert(fControlDmc, true, false, null, 0, - ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT, 0), - new DataRequestMonitor(getExecutor(), rm) { - @Override - public void handleSuccess() { - if (getData() != null) { - MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); - if (breakpoints.length > 0 && fUserBreakpoint != null) { - fUserBreakpointIsOnMain = breakpoints[0].getAddress().equals(fUserBreakpoint.getAddress()); - } - } - rm.done(); - } - }); - } else { - rm.done(); - } - }}, - /* - * Now, run the program. Use either -exec-run or -exec-continue depending - * on whether we have remote session or not. - */ - new Step() { - @Override - public void execute(RequestMonitor rm) { - IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class); - fContainerDmc = procService.createContainerContextFromGroupId(fControlDmc, MIProcesses.UNIQUE_GROUP_ID); - ICommand command; - - if (useContinueCommand(launch, restart)) { - command = getCommandFactory().createMIExecContinue(fContainerDmc); - } else { - command = getCommandFactory().createMIExecRun(fContainerDmc); - } - queueCommand(command, new DataRequestMonitor(getExecutor(), rm)); - }}, - /* - * In case of a restart, reverse debugging should be marked as off here because - * GDB will have turned it off. We may turn it back on after. - */ - new Step() { - @Override - public void execute(RequestMonitor rm) { - // Although it only makes sense for a restart, it doesn't hurt - // do to it all the time. - GDBRunControl_7_0 reverseService = getServicesTracker().getService(GDBRunControl_7_0.class); - if (reverseService != null) { - reverseService.setReverseModeEnabled(false); - } - rm.done(); - }}, - /* - * Since we have started the program, we can turn on reverse debugging if needed - */ - new Step() { - @Override - public void execute(RequestMonitor rm) { - if (reverseEnabled) { - IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class); - if (reverseService != null) { - reverseService.enableReverseMode(fControlDmc, true, rm); - return; - } - } - rm.done(); - }}, - /* - * Finally, if we are enabling reverse, and the userSymbolStop is not on main, - * we should do a continue because we are currently stopped on main but that - * is not what the user requested - */ - new Step() { - @Override - public void execute(RequestMonitor rm) { - if (reverseEnabled && !fUserBreakpointIsOnMain) { - queueCommand(getCommandFactory().createMIExecContinue(fContainerDmc), - new DataRequestMonitor(getExecutor(), rm)); - } else { - rm.done(); - } - }}, - }; - - @Override - public Step[] getSteps() { - return fSteps; - } - }); - } - - /** - * This method indicates if we should use the -exec-continue method - * instead of the -exec-run method. - * This can be overridden to allow for customization. - * - * @since 4.0 - */ - protected boolean useContinueCommand(ILaunch launch, boolean restart) { - // When doing remote debugging, we use -exec-continue instead of -exec-run - // Restart does not apply to remote sessions - return fMIBackend.getSessionType() == SessionType.REMOTE; - } - /** * This method creates a new inferior process object based on the current Pty or output stream. */ diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java index bccf575377d..575dda4c30a 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/IGDBControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008, 2010 Ericsson and others. + * Copyright (c) 2008, 2011 Ericsson and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse License v1.0 * which accompanies this distribution, and is available at @@ -17,7 +17,6 @@ import java.util.List; import java.util.Properties; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; -import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.command.AbstractCLIProcess; import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; @@ -27,9 +26,6 @@ public interface IGDBControl extends IMICommandControl { void terminate(final RequestMonitor rm); void initInferiorInputOutput(final RequestMonitor requestMonitor); - boolean canRestart(); - void start(GdbLaunch launch, final RequestMonitor requestMonitor); - void restart(final GdbLaunch launch, final RequestMonitor requestMonitor); void createInferiorProcess(); boolean isConnected(); diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java index 5fae58e0d1f..8ca0b72b483 100644 --- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java +++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/SyncUtil.java @@ -41,10 +41,10 @@ import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; +import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses; import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; -import org.eclipse.cdt.dsf.mi.service.IMIProcesses; import org.eclipse.cdt.dsf.mi.service.IMIRunControl; import org.eclipse.cdt.dsf.mi.service.MIStack; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; @@ -76,7 +76,7 @@ public class SyncUtil { private static CommandFactory fCommandFactory; private static IBreakpointsTargetDMContext fBreakpointsDmc; - private static IMIProcesses fProcessesService; + private static IGDBProcesses fProcessesService; // Initialize some common things, once the session has been established public static void initialize(DsfSession session) throws Exception { @@ -92,7 +92,7 @@ public class SyncUtil { fRunControl = tracker.getService(IMIRunControl.class); fStack = tracker.getService(MIStack.class); fExpressions = tracker.getService(IExpressions.class); - fProcessesService = tracker.getService(IMIProcesses.class); + fProcessesService = tracker.getService(IGDBProcesses.class); fCommandFactory = tracker.getService(IMICommandControl.class).getCommandFactory(); fBreakpointsDmc = (IBreakpointsTargetDMContext)fGdbControl.getContext(); @@ -606,12 +606,22 @@ public class SyncUtil { * Restart the program. */ public static void restart(final GdbLaunch launch) throws Throwable { - // Check if restart is allowed + final IContainerDMContext containerDmc = getContainerContext(); + + // Check if restart is allowed Query query = new Query() { @Override - protected void execute(DataRequestMonitor rm) { - rm.setData(fGdbControl.canRestart()); - rm.done(); + protected void execute(final DataRequestMonitor rm) { + fProcessesService.canRestart( + containerDmc, + new DataRequestMonitor(ImmediateExecutor.getInstance(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData()); + rm.done(); + } + }); + } }; @@ -628,14 +638,20 @@ public class SyncUtil { MIStoppedEvent.class); // Perform the restart - Query query2 = new Query() { + Query query2 = new Query() { @Override - protected void execute(final DataRequestMonitor rm) { + protected void execute(final DataRequestMonitor rm) { fGdbControl.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) { - @Override + @SuppressWarnings("unchecked") + @Override protected void handleSuccess() { fGdbControl.createInferiorProcess(); - fGdbControl.restart(launch, rm); + Map attributes = null; + try { + attributes = launch.getLaunchConfiguration().getAttributes(); + } catch (CoreException e) {} + + fProcessesService.restart(containerDmc, attributes, rm); } }); }