1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 335528: [multi-process] Move startOrRestart to the Processes service

This commit is contained in:
Marc Khouzam 2011-02-02 21:39:37 +00:00
parent 6a815d839a
commit 4881bba10c
11 changed files with 666 additions and 435 deletions

View file

@ -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 <V> 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> V getAttribute(Map<String, ?> attributes, String key, V defaultValue) {
Object value = attributes.get(key);
if (defaultValue.getClass().isInstance(value)) {
return (V)value;
}
return defaultValue;
}
}

View file

@ -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<Boolean>(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<String, Object> 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;

View file

@ -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<String, Object> 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();
}

View file

@ -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<String, String>());
@ -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<IProcessDMContext[]> 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<Boolean> 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<String, Object> 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<String, Object> 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<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(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<MIInfo> 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<MIBreakInsertInfo>(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
*/

View file

@ -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<Boolean> 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<String, Object> attributes, RequestMonitor rm) {
ImmediateExecutor.getInstance().execute(
new StartOrRestartProcessSequence_7_0(
getExecutor(), containerDmc, attributes, true,
new DataRequestMonitor<IContainerDMContext>(ImmediateExecutor.getInstance(), rm)));
}
@DsfServiceEventHandler
public void eventDispatched(final MIThreadGroupCreatedEvent e) {
IProcessDMContext procDmc = e.getDMContext();

View file

@ -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<Boolean> 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<String, Object> attributes, RequestMonitor rm);
}

View file

@ -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<String, Object> 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<IContainerDMContext> 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<String, Object> attributes,
boolean restart, DataRequestMonitor<IContainerDMContext> 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<String, Object>();
}
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<MIBreakInsertInfo>(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<MIBreakInsertInfo>(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<MIInfo> command;
if (useContinueCommand()) {
command = fCommandFactory.createMIExecContinue(fContainerDmc);
} else {
command = fCommandFactory.createMIExecRun(fContainerDmc);
}
fCommandControl.queueCommand(command, new DataRequestMonitor<MIInfo>(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<MIInfo>(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;
}
}

View file

@ -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<MIInfo> 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<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(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<MIBreakInsertInfo>(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.
*/

View file

@ -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<MIBreakInsertInfo>(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<MIBreakInsertInfo>(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<MIInfo> command;
if (useContinueCommand(launch, restart)) {
command = getCommandFactory().createMIExecContinue(fContainerDmc);
} else {
command = getCommandFactory().createMIExecRun(fContainerDmc);
}
queueCommand(command, new DataRequestMonitor<MIInfo>(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<MIInfo>(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.
*/

View file

@ -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();

View file

@ -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<Boolean> query = new Query<Boolean>() {
@Override
protected void execute(DataRequestMonitor<Boolean> rm) {
rm.setData(fGdbControl.canRestart());
rm.done();
protected void execute(final DataRequestMonitor<Boolean> rm) {
fProcessesService.canRestart(
containerDmc,
new DataRequestMonitor<Boolean>(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<Boolean> query2 = new Query<Boolean>() {
Query<Object> query2 = new Query<Object>() {
@Override
protected void execute(final DataRequestMonitor<Boolean> rm) {
protected void execute(final DataRequestMonitor<Object> rm) {
fGdbControl.initInferiorInputOutput(new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
@Override
@SuppressWarnings("unchecked")
@Override
protected void handleSuccess() {
fGdbControl.createInferiorProcess();
fGdbControl.restart(launch, rm);
Map<String, Object> attributes = null;
try {
attributes = launch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {}
fProcessesService.restart(containerDmc, attributes, rm);
}
});
}