1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

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

This commit is contained in:
Marc Khouzam 2011-02-11 01:32:07 +00:00
parent 58a312b4ed
commit 8bec791d32
6 changed files with 875 additions and 324 deletions

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2011 Ericsson and others.
* Copyright (c) 2008, 2010 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
@ -15,35 +15,30 @@ 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.CDebugUtils;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
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.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;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.CSourceLookup;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
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;
@ -62,6 +57,9 @@ public class FinalLaunchSequence extends ReflectionSequence {
private GdbLaunch fLaunch;
private SessionType fSessionType;
private boolean fAttach;
// The launchConfiguration attributes
private Map<String, Object> fAttributes;
private IGDBControl fCommandControl;
private IGDBBackend fGDBBackend;
@ -82,22 +80,24 @@ public class FinalLaunchSequence extends ReflectionSequence {
if (GROUP_TOP_LEVEL.equals(group)) {
return new String[] {
"stepInitializeFinalLaunchSequence", //$NON-NLS-1$
// Global GDB settings
"stepSetEnvironmentDirectory", //$NON-NLS-1$
"stepSetBreakpointPending", //$NON-NLS-1$
"stepEnablePrettyPrinting", //$NON-NLS-1$
"stepSourceGDBInitFile", //$NON-NLS-1$
"stepSetEnvironmentVariables", //$NON-NLS-1$
"stepSetExecutable", //$NON-NLS-1$
"stepSetArguments", //$NON-NLS-1$
"stepSetNonStop", //$NON-NLS-1$
"stepSetAutoLoadSharedLibrarySymbols", //$NON-NLS-1$
"stepSetSharedLibraryPaths", //$NON-NLS-1$
"stepSetSourceLookupPath", //$NON-NLS-1$
// For post-mortem launch only
"stepSpecifyCoreFile", //$NON-NLS-1$
// For remote-attach launch only
"stepRemoteConnection", //$NON-NLS-1$
// For all launches except attach ones
"stepNewProcess", //$NON-NLS-1$
// For local attach launch only
"stepAttachToProcess", //$NON-NLS-1$
"stepStartTrackingBreakpoints", //$NON-NLS-1$
"stepStartExecution", //$NON-NLS-1$
// Global
"stepDataModelInitializationComplete", //$NON-NLS-1$
"stepCleanup", //$NON-NLS-1$
};
@ -110,6 +110,7 @@ public class FinalLaunchSequence extends ReflectionSequence {
* This step is mandatory for the rest fo the sequence to complete.
* @since 4.0
*/
@SuppressWarnings("unchecked")
@Execute
public void stepInitializeFinalLaunchSequence(RequestMonitor requestMonitor) {
fTracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fLaunch.getSession().getId());
@ -136,6 +137,14 @@ public class FinalLaunchSequence extends ReflectionSequence {
return;
}
try {
fAttributes = fLaunch.getLaunchConfiguration().getAttributes();
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain launch configuration attributes", null)); //$NON-NLS-1$
requestMonitor.done();
return;
}
requestMonitor.done();
}
@ -247,91 +256,16 @@ public class FinalLaunchSequence extends ReflectionSequence {
}
}
/**
* Specify environment variables if needed
* @since 4.0
*/
@Execute
public void stepSetEnvironmentVariables(final RequestMonitor requestMonitor) {
boolean clear = false;
Properties properties = new Properties();
try {
clear = fGDBBackend.getClearEnvironment();
properties = fGDBBackend.getEnvironmentVariables();
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get environment information", e)); //$NON-NLS-1$
requestMonitor.done();
return;
}
if (clear == true || properties.size() > 0) {
fCommandControl.setEnvironment(properties, clear, requestMonitor);
} else {
requestMonitor.done();
}
}
/**
* Specify the executable file to be debugged and read the symbol table.
* @since 4.0
*/
@Execute
public void stepSetExecutable(final RequestMonitor requestMonitor) {
boolean noFileCommand = IGDBLaunchConfigurationConstants.DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP_DEFAULT;
try {
noFileCommand = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP,
IGDBLaunchConfigurationConstants.DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP_DEFAULT);
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot read use solib symbols for app options", e)); //$NON-NLS-1$
requestMonitor.done();
return;
}
final IPath execPath = fGDBBackend.getProgramPath();
if (!noFileCommand && execPath != null && !execPath.isEmpty()) {
fCommandControl.queueCommand(
fCommandFactory.createMIFileExecAndSymbols(fCommandControl.getContext(),
execPath.toPortableString()),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
} else {
requestMonitor.done();
}
}
/**
* Specify the arguments to the executable file.
* @since 4.0
*/
@Execute
public void stepSetArguments(final RequestMonitor requestMonitor) {
try {
String args = fGDBBackend.getProgramArguments();
if (args != null) {
fCommandControl.queueCommand(
fCommandFactory.createMIGDBSetArgs(fCommandControl.getContext(), args),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
} else {
requestMonitor.done();
}
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get inferior arguments", e)); //$NON-NLS-1$
requestMonitor.done();
}
}
/**
* Enable non-stop mode if requested.
* @since 4.0
*/
@Execute
public void stepSetNonStop(final RequestMonitor requestMonitor) {
boolean isNonStop = false;
try {
isNonStop = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
} catch (CoreException e) {
}
boolean isNonStop = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP,
IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT);
// GDBs that don't support non-stop don't allow you to set it to false.
// We really should set it to false when GDB supports it though.
@ -365,16 +299,14 @@ public class FinalLaunchSequence extends ReflectionSequence {
*/
@Execute
public void stepSetAutoLoadSharedLibrarySymbols(RequestMonitor requestMonitor) {
try {
boolean autolib = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_AUTO_SOLIB,
IGDBLaunchConfigurationConstants.DEBUGGER_AUTO_SOLIB_DEFAULT);
fCommandControl.queueCommand(
fCommandFactory.createMIGDBSetAutoSolib(fCommandControl.getContext(), autolib),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot set shared library option", e)); //$NON-NLS-1$
requestMonitor.done();
}
boolean autolib = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_AUTO_SOLIB,
IGDBLaunchConfigurationConstants.DEBUGGER_AUTO_SOLIB_DEFAULT);
fCommandControl.queueCommand(
fCommandFactory.createMIGDBSetAutoSolib(fCommandControl.getContext(), autolib),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
}
/**
@ -476,10 +408,14 @@ public class FinalLaunchSequence extends ReflectionSequence {
@Execute
public void stepSpecifyCoreFile(final RequestMonitor requestMonitor) {
if (fSessionType == SessionType.CORE) {
try {
String coreFile = fLaunch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, ""); //$NON-NLS-1$
final String coreType = fLaunch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE,
IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT);
String coreFile = CDebugUtils.getAttribute(
fAttributes,
ICDTLaunchConfigurationConstants.ATTR_COREFILE_PATH, ""); //$NON-NLS-1$
final String coreType = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_POST_MORTEM_TYPE,
IGDBLaunchConfigurationConstants.DEBUGGER_POST_MORTEM_TYPE_DEFAULT);
if (coreFile.length() == 0) {
new PromptForCoreJob(
"Prompt for post mortem file", //$NON-NLS-1$
@ -530,124 +466,93 @@ public class FinalLaunchSequence extends ReflectionSequence {
requestMonitor.done();
}
}
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot get post mortem file path", e));
requestMonitor.done();
}
} else {
requestMonitor.done();
}
}
private boolean fTcpConnection;
private String fRemoteTcpHost;
private String fRemoteTcpPort;
private String fSerialDevice;
private boolean checkConnectionType(RequestMonitor requestMonitor) {
try {
fTcpConnection = fLaunch.getLaunchConfiguration().getAttribute(
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
false);
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve connection mode", e)); //$NON-NLS-1$
requestMonitor.done();
return false;
}
return true;
}
private boolean getSerialDevice(RequestMonitor requestMonitor) {
try {
fSerialDevice = fLaunch.getLaunchConfiguration().getAttribute(
IGDBLaunchConfigurationConstants.ATTR_DEV, "invalid"); //$NON-NLS-1$
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve serial device", e)); //$NON-NLS-1$
requestMonitor.done();
return false;
}
return true;
}
private boolean getTcpHost(RequestMonitor requestMonitor) {
try {
fRemoteTcpHost = fLaunch.getLaunchConfiguration().getAttribute(
IGDBLaunchConfigurationConstants.ATTR_HOST, "invalid"); //$NON-NLS-1$
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve remote TCP host", e)); //$NON-NLS-1$
requestMonitor.done();
return false;
}
return true;
}
private boolean getTcpPort(RequestMonitor requestMonitor) {
try {
fRemoteTcpPort = fLaunch.getLaunchConfiguration().getAttribute(
IGDBLaunchConfigurationConstants.ATTR_PORT, "invalid"); //$NON-NLS-1$
} catch (CoreException e) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve remote TCP port", e)); //$NON-NLS-1$
requestMonitor.done();
return false;
}
return true;
}
private final static String INVALID = "invalid"; //$NON-NLS-1$
/**
* If we are dealing with a remote debugging session, connect to the target.
* If we are dealing with a remote-attach debugging session, connect to the target.
* @since 4.0
*/
@Execute
public void stepRemoteConnection(final RequestMonitor requestMonitor) {
if (fSessionType == SessionType.REMOTE) {
if (!checkConnectionType(requestMonitor)) return;
public void stepRemoteConnection(final RequestMonitor rm) {
if (fSessionType == SessionType.REMOTE && fAttach) {
boolean isTcpConnection = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
false);
if (fTcpConnection) {
if (!getTcpHost(requestMonitor)) return;
if (!getTcpPort(requestMonitor)) return;
if (isTcpConnection) {
String remoteTcpHost = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_HOST, INVALID);
String remoteTcpPort = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_PORT, INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
fRemoteTcpHost, fRemoteTcpPort, fAttach),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
remoteTcpHost, remoteTcpPort, true),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
} else {
if (!getSerialDevice(requestMonitor)) return;
String serialDevice = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEV, INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
fSerialDevice, fAttach),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
serialDevice, true),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
}
} else {
requestMonitor.done();
rm.done();
}
}
/**
* If we are dealing with an attach debugging session, perform the attach.
* Start a new process if we are not dealing with an attach session
* i.e., a local session, a remote session or a post-mortem (core) session.
* @since 4.0
*/
@Execute
public void stepNewProcess(final RequestMonitor rm) {
if (!fAttach) {
boolean noBinarySpecified = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP,
IGDBLaunchConfigurationConstants.DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP_DEFAULT);
String binary = null;
final IPath execPath = fGDBBackend.getProgramPath();
if (!noBinarySpecified && execPath != null && !execPath.isEmpty()) {
binary = execPath.toPortableString();
}
// Even if binary is null, we must call this to do all the other steps
// necessary to create a process. It is possible that the binary is not needed
fProcService.debugNewProcess(fCommandControl.getContext(), binary, fAttributes,
new DataRequestMonitor<IDMContext>(getExecutor(), rm));
} else {
rm.done();
}
}
/**
* If we are dealing with an local attach session, perform the attach.
* For a remote attach session, we don't attach during the launch; instead
* we wait for the user to manually do the attach.
* @since 4.0
*/
@Execute
public void stepAttachToProcess(final RequestMonitor requestMonitor) {
// A local attach can figure out the binary from the attach
// command. This allows the user not to specify the binary
// in the launch. But for breakpoints to work, we must do the
// attach before we set the breakpoints, i.e., here.
// On the other hand, for a remote attach, we need to specify
// the binary anyway, or use the solib command. In both cases,
// breakpoints can be set before we attach. Therefore, we don't
// force an attach here, but wait for the user to decide to connect
// using the connect action.
if (fAttach && fSessionType != SessionType.REMOTE) {
// If we are attaching, get the process id.
int pid = -1;
try {
// have we already been given the pid (maybe from a JUnit test launch or something)
pid = fLaunch.getLaunchConfiguration().getAttribute(ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, -1);
} catch (CoreException e) {
// do nothing and fall to below
}
// Is the process id already stored in the launch?
int pid = CDebugUtils.getAttribute(
fAttributes,
ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID, -1);
if (pid != -1) {
fProcService.attachDebuggerToProcess(
@ -666,48 +571,6 @@ public class FinalLaunchSequence extends ReflectionSequence {
}
}
/**
* Start tracking the breakpoints. Note that for remote debugging
* we should first connect to the target.
* @since 4.0
*/
@Execute
public void stepStartTrackingBreakpoints(final RequestMonitor requestMonitor) {
if (fSessionType != SessionType.CORE) {
MIBreakpointsManager bpmService = fTracker.getService(MIBreakpointsManager.class);
IMIContainerDMContext containerDmc = fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), null);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, requestMonitor);
} else {
requestMonitor.done();
}
}
/**
* Start executing the program.
* @since 4.0
*/
@SuppressWarnings("unchecked")
@Execute
public void stepStartExecution(final RequestMonitor requestMonitor) {
if (fSessionType != SessionType.CORE) {
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();
}
}
/**
* Indicate that the Data Model has been filled. This will trigger the Debug view to expand.
* @since 4.0

View file

@ -0,0 +1,302 @@
/*******************************************************************************
* 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.Map;
import java.util.Properties;
import org.eclipse.cdt.debug.core.CDebugUtils;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.ReflectionSequence;
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.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
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.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;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* @since 4.0
*/
public class DebugNewProcessSequence extends ReflectionSequence {
private final static String INVALID = "invalid"; //$NON-NLS-1$
private IGDBControl fCommandControl;
private CommandFactory fCommandFactory;
private IGDBBackend fBackend;
private IGDBProcesses fProcService;
private DsfServicesTracker fTracker;
private IDMContext fContext;
private String fBinaryName;
private Map<String, Object> fAttributes;
private IMIContainerDMContext fContainerCtx;
// Store the dataRM so that we can fill it with the container context that we will be creating
private DataRequestMonitor<IDMContext> fDataRequestMonitor;
protected IMIContainerDMContext getContainerContext() {
return fContainerCtx;
}
protected void setContainerContext(IMIContainerDMContext ctx) {
fContainerCtx = ctx;
}
public DebugNewProcessSequence(DsfExecutor executor, IDMContext dmc, String file, Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
super(executor, rm);
fContext = dmc;
fBinaryName = file;
fAttributes = attributes;
fDataRequestMonitor = rm;
}
@Override
protected String[] getExecutionOrder(String group) {
if (GROUP_TOP_LEVEL.equals(group)) {
return new String[] {
"stepInitializeBaseSequence", //$NON-NLS-1$
"stepSetEnvironmentVariables", //$NON-NLS-1$
"stepSetExecutable", //$NON-NLS-1$
"stepSetArguments", //$NON-NLS-1$
"stepRemoteConnection", //$NON-NLS-1$
"stepStartTrackingBreakpoints", //$NON-NLS-1$
"stepStartExecution", //$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(), fContext.getSessionId());
fBackend = fTracker.getService(IGDBBackend.class);
fCommandControl = fTracker.getService(IGDBControl.class);
fCommandFactory = fTracker.getService(IMICommandControl.class).getCommandFactory();
fProcService = fTracker.getService(IGDBProcesses.class);
if (fBackend == null || 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;
}
// When we are starting to debug a new process, the container is the default process used by GDB.
// We don't have a pid yet, so we can simply create the container with the UNIQUE_GROUP_ID
setContainerContext(fProcService.createContainerContextFromGroupId(fCommandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID));
rm.done();
}
/**
* Rollback method for {@link #stepInitializeBaseSequence()}
* @since 4.0
*/
@RollBack("stepInitializeBaseSequence")
public void rollBackInitializeBaseSequence(RequestMonitor rm) {
if (fTracker != null) fTracker.dispose();
fTracker = null;
rm.done();
}
/**
* Specify environment variables if needed
*/
@Execute
public void stepSetEnvironmentVariables(RequestMonitor rm) {
boolean clear = false;
Properties properties = new Properties();
try {
// here we need to pass the proper container context
clear = fBackend.getClearEnvironment();
properties = fBackend.getEnvironmentVariables();
} catch (CoreException e) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Cannot get environment information", e)); //$NON-NLS-1$
rm.done();
return;
}
if (clear == true || properties.size() > 0) {
// here we need to pass the proper container context
fCommandControl.setEnvironment(properties, clear, rm);
} else {
rm.done();
}
}
/**
* Specify the executable file to be debugged and read the symbol table.
*/
@Execute
public void stepSetExecutable(RequestMonitor rm) {
boolean noFileCommand = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP,
IGDBLaunchConfigurationConstants.DEBUGGER_USE_SOLIB_SYMBOLS_FOR_APP_DEFAULT);
if (!noFileCommand && fBinaryName != null && fBinaryName.length() > 0) {
fCommandControl.queueCommand(
fCommandFactory.createMIFileExecAndSymbols(getContainerContext(), fBinaryName),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
} else {
rm.done();
}
}
/**
* Specify the arguments to the program that will be run.
*/
@Execute
public void stepSetArguments(RequestMonitor rm) {
try {
String args = fBackend.getProgramArguments();
if (args != null) {
fCommandControl.queueCommand(
// here we need to pass the proper container context
fCommandFactory.createMIGDBSetArgs(fCommandControl.getContext(), args),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
} else {
rm.done();
}
} catch (CoreException e) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Cannot get inferior arguments", e)); //$NON-NLS-1$
rm.done();
}
}
/**
* If we are dealing with a remote debugging session, connect to the target.
* @since 4.0
*/
@Execute
public void stepRemoteConnection(RequestMonitor rm) {
// If we are dealing with a remote session, it is now time to connect
// to the remote side. Note that this is the 'target remote' case
// and not the 'target extended-remote' case (remote attach session)
// We know this because a remote attach session does not start a new
// process, so we wouldn't be in this sequence
// This step is actually global for GDB. However, we have to do it after
// we have specified the executable, so we have to do it here.
// It is safe to do it here because a 'target remote' does not support
// multi-process so this step will not be executed more than once.
assert fBackend.getIsAttachSession() == false;
if (fBackend.getSessionType() == SessionType.REMOTE) {
boolean isTcpConnection = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
false);
if (isTcpConnection) {
String remoteTcpHost = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_HOST, INVALID);
String remoteTcpPort = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_PORT, INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
remoteTcpHost, remoteTcpPort, false),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
} else {
String serialDevice = CDebugUtils.getAttribute(
fAttributes,
IGDBLaunchConfigurationConstants.ATTR_DEV, INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
serialDevice, false),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
}
} else {
rm.done();
}
}
/**
* Start tracking the breakpoints. Note that for remote debugging
* we should first connect to the target.
*/
@Execute
public void stepStartTrackingBreakpoints(RequestMonitor rm) {
if (fBackend.getSessionType() != SessionType.CORE) {
MIBreakpointsManager bpmService = fTracker.getService(MIBreakpointsManager.class);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(getContainerContext(), IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
} else {
rm.done();
}
}
/**
* Start executing the program.
*/
@Execute
public void stepStartExecution(final RequestMonitor rm) {
if (fBackend.getSessionType() != SessionType.CORE) {
ImmediateExecutor.getInstance().execute(
new StartOrRestartProcessSequence_7_0(
getExecutor(), getContainerContext(), fAttributes, false,
new DataRequestMonitor<IContainerDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
assert getData() instanceof IMIContainerDMContext;
// Set the container that we created
setContainerContext(DMContexts.getAncestorOfType(getData(), IMIContainerDMContext.class));
fDataRequestMonitor.setData(getContainerContext());
// Don't call fDataRequestMonitor.done(), the sequence will
// automatically do that when we call rm.done();
rm.done();
}
}));
} else {
fDataRequestMonitor.setData(getContainerContext());
rm.done();
}
}
/**
* Cleanup now that the sequence has been run.
* @since 4.0
*/
@Execute
public void stepCleanupBaseSequence(RequestMonitor rm) {
fTracker.dispose();
fTracker = null;
rm.done();
}
}

View file

@ -0,0 +1,123 @@
/*******************************************************************************
* 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.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
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.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.command.output.MIAddInferiorInfo;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* With GDB 7.2, to create a new process, we need to use the -add-inferior command first.
* This allows to create multiple processes, unlike previous versions of GDB.
* Note that GDB 7.1 does support multi-process but didn't have the MI commands (e.g., -add-inferior)
* so we only support multi-process starting with 7.2
*
* @since 4.0
*/
public class DebugNewProcessSequence_7_2 extends DebugNewProcessSequence {
private IGDBControl fGdbControl;
private IGDBProcesses fProcService;
private String fSessionId;
private boolean fInitialProcess;
public DebugNewProcessSequence_7_2(DsfExecutor executor, boolean initialProcess, IDMContext dmc, String file,
Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
super(executor, dmc, file, attributes, rm);
fSessionId = dmc.getSessionId();
fInitialProcess = initialProcess;
}
@Override
protected String[] getExecutionOrder(String group) {
if (GROUP_TOP_LEVEL.equals(group)) {
// Initialize the list with the base class' steps
// We need to create a list that we can modify, which is why we create our own ArrayList.
List<String> orderList = new ArrayList<String>(Arrays.asList(super.getExecutionOrder(GROUP_TOP_LEVEL)));
// Now insert our steps right after the initialization of the base class.
orderList.add(orderList.indexOf("stepInitializeBaseSequence") + 1, "stepInitializeSequence_7_2"); //$NON-NLS-1$ //$NON-NLS-2$
orderList.add(orderList.indexOf("stepInitializeSequence_7_2") + 1, "stepAddInferior"); //$NON-NLS-1$ //$NON-NLS-2$
return orderList.toArray(new String[orderList.size()]);
}
return null;
}
/**
* Initialize the members of the {@link DebugNewProcessSequence_7_2} class.
* This step is mandatory for the rest of the sequence to complete.
*/
@Execute
public void stepInitializeSequence_7_2(RequestMonitor rm) {
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fSessionId);
fGdbControl = tracker.getService(IGDBControl.class);
fProcService = tracker.getService(IGDBProcesses.class);
tracker.dispose();
if (fGdbControl == 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;
}
rm.done();
}
/**
* Add a new inferior.
*/
@Execute
public void stepAddInferior(final RequestMonitor rm) {
if (fInitialProcess) {
// The first process is automatically created by GDB. We actually want to use that first created process
// instead of ignoring it and creating a new one for a couple of reasons:
// 1- post-mortem and non-attach remote sessions don't support creating a new process
// 2- commands that were part of the .gdbinit file will affect the initial process, which is what the user expects,
// but would not affect a new process we created instead.
setContainerContext(fProcService.createContainerContextFromGroupId(fGdbControl.getContext(), "i1")); //$NON-NLS-1$
rm.done();
return;
}
fGdbControl.queueCommand(
fGdbControl.getCommandFactory().createMIAddInferior(fGdbControl.getContext()),
new DataRequestMonitor<MIAddInferiorInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
final String groupId = getData().getGroupId();
if (groupId == null || groupId.trim().length() == 0) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Invalid gdb group id.", null)); //$NON-NLS-1$
rm.done();
return;
}
setContainerContext(fProcService.createContainerContextFromGroupId(fGdbControl.getContext(), groupId));
rm.done();
}
});
}
}

View file

@ -20,6 +20,7 @@ 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.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
@ -37,6 +38,7 @@ 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.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.MIInferiorProcess;
@ -46,6 +48,7 @@ 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;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.osgi.framework.BundleContext;
@ -200,22 +203,51 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
@Override
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) {
super.attachDebuggerToProcess(
procCtx,
new DataRequestMonitor<IDMContext>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
fGdb.setConnected(true);
// For remote attach, we must set the binary first
// For a local attach, GDB can figure out the binary automatically,
// so we don't specify it.
IMIContainerDMContext containerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (inferiorProcess != null) {
inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId());
}
DataRequestMonitor<MIInfo> attachRm = new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
GDBProcesses.super.attachDebuggerToProcess(
procCtx,
new DataRequestMonitor<IDMContext>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
fGdb.setConnected(true);
rm.setData(getData());
rm.done();
}
});
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();
if (inferiorProcess != null) {
inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId());
}
IDMContext containerDmc = getData();
rm.setData(containerDmc);
// Start tracking breakpoints.
MIBreakpointsManager bpmService = getServicesTracker().getService(MIBreakpointsManager.class);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
}
});
}
};
if (fBackend.getSessionType() == SessionType.REMOTE) {
final IPath execPath = fBackend.getProgramPath();
if (execPath != null && !execPath.isEmpty()) {
fGdb.queueCommand(
fCommandFactory.createMIFileExecAndSymbols(containerDmc, execPath.toPortableString()),
attachRm);
return;
}
}
// If we get here, let's do the attach by completing the requestMonitor
attachRm.done();
}
@Override
@ -243,6 +275,13 @@ public class GDBProcesses extends MIProcesses implements IGDBProcesses {
});
}
@Override
public void debugNewProcess(IDMContext dmc, String file,
Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
ImmediateExecutor.getInstance().execute(
new DebugNewProcessSequence(getExecutor(), dmc, file, attributes, rm));
}
@Override
public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) {
MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess();

View file

@ -27,6 +27,7 @@ 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.concurrent.Sequence;
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
@ -47,6 +48,7 @@ import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
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;
@ -54,6 +56,7 @@ 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.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.events.MIThreadGroupCreatedEvent;
@ -73,8 +76,10 @@ import org.eclipse.cdt.dsf.service.AbstractDsfService;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.osgi.framework.BundleContext;
/**
@ -430,6 +435,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService
private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$
private boolean fInitialProcess = true;
public GDBProcesses_7_0(DsfSession session) {
super(session);
}
@ -639,8 +646,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
} else if (name.length() == 0) {
// Probably will not happen, but just in case...use the
// binary file name (absolute path)
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
name = backend.getProgramPath().toOSString();
name = fBackend.getProgramPath().toOSString();
fDebuggedProcessesAndNames.put(id, name);
}
}
@ -702,11 +708,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
/** @since 4.0 */
protected boolean doIsDebuggerAttachSupported() {
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
if (backend != null) {
return backend.getIsAttachSession();
}
return false;
return fBackend.getIsAttachSession() && !fCommandControl.isConnected();
}
public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
@ -714,39 +716,102 @@ public class GDBProcesses_7_0 extends AbstractDsfService
rm.done();
}
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) {
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> dataRm) {
if (procCtx instanceof IMIProcessDMContext) {
if (!doIsDebuggerAttachSupported()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$
rm.done();
dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$
dataRm.done();
return;
}
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class);
fCommandControl.queueCommand(
fCommandFactory.createMITargetAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
// By now, GDB has reported the groupId that was attached to this process
rm.setData(createContainerContext(procCtx, getGroupFromPid(((IMIProcessDMContext)procCtx).getProcId())));
rm.done();
}
});
// Use a sequence for better control of each step
ImmediateExecutor.getInstance().execute(new Sequence(getExecutor(), dataRm) {
private IMIContainerDMContext fContainerDmc;
private Step[] steps = new Step[] {
// For remote attach, we must set the binary first
// For a local attach, GDB can figure out the binary automatically,
// so we don't specify it.
new Step() {
@Override
public void execute(RequestMonitor rm) {
// There is no groupId until we attach, so we can use the default groupId
fContainerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
if (fBackend.getSessionType() == SessionType.REMOTE) {
final IPath execPath = fBackend.getProgramPath();
if (execPath != null && !execPath.isEmpty()) {
fCommandControl.queueCommand(
fCommandFactory.createMIFileExecAndSymbols(fContainerDmc, execPath.toPortableString()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
return;
}
}
rm.done();
}
},
// Attach to the process
new Step() {
@Override
public void execute(RequestMonitor rm) {
fCommandControl.queueCommand(
fCommandFactory.createMITargetAttach(fContainerDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
}
},
new Step() {
@Override
public void execute(RequestMonitor rm) {
// By now, GDB has reported the groupId that was created for this process
fContainerDmc = createContainerContext(procCtx, getGroupFromPid(((IMIProcessDMContext)procCtx).getProcId()));
// Store the fully formed container context so it can be returned to the caller.
dataRm.setData(fContainerDmc);
// Start tracking breakpoints.
MIBreakpointsManager bpmService = getServicesTracker().getService(MIBreakpointsManager.class);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(fContainerDmc, IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
}
},
// Turn on reverse debugging if it was enabled as a launch option
new Step() {
@Override
public void execute(RequestMonitor rm) {
IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class);
if (reverseService != null) {
ILaunch launch = (ILaunch)procCtx.getAdapter(ILaunch.class);
if (launch != null) {
try {
boolean reverseEnabled =
launch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
if (reverseEnabled) {
reverseService.enableReverseMode(fCommandControl.getContext(), true, rm);
return;
}
} catch (CoreException e) {
// Ignore, just don't set reverse
}
}
}
rm.done();
}
},
};
@Override public Step[] getSteps() { return steps; }
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
dataRm.done();
}
}
/** @since 4.0 */
protected boolean doCanDetachDebuggerFromProcess() {
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
if (backend != null) {
return backend.getIsAttachSession() && fCommandControl.isConnected();
}
return false;
return fBackend.getIsAttachSession() && fCommandControl.isConnected();
}
public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
@ -781,15 +846,29 @@ public class GDBProcesses_7_0 extends AbstractDsfService
}
public void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(false);
rm.done();
rm.setData(doIsDebugNewProcessSupported());
rm.done();
}
/** @since 4.0 */
protected boolean doIsDebugNewProcessSupported() {
return false;
}
public void debugNewProcess(IDMContext dmc, String file,
Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$
rm.done();
if (!fInitialProcess) {
// If we have already dealt with the initial process, check if we are allowed to create another one
if (!doIsDebugNewProcessSupported()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Cannot start a new process", null)); //$NON-NLS-1$
rm.done();
return;
}
}
fInitialProcess = false;
ImmediateExecutor.getInstance().execute(
new DebugNewProcessSequence(getExecutor(), dmc, file, attributes, rm));
}
public void getProcessesBeingDebugged(final IDMContext dmc, final DataRequestMonitor<IDMContext[]> rm) {
@ -904,8 +983,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
// list natively (as we do with gdb 6.8). If
// we're debugging remotely, the user is out
// of luck
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
if (backend.getSessionType() == SessionType.LOCAL) {
if (fBackend.getSessionType() == SessionType.LOCAL) {
IProcessList list = null;
try {
list = CCorePlugin.getDefault().getProcessList();
@ -1185,8 +1263,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
// Looks like this gdb doesn't truly support
// "-list-thread-groups --available". Get the
// process list natively if we're debugging locally
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
if (backend.getSessionType() == SessionType.LOCAL) {
if (fBackend.getSessionType() == SessionType.LOCAL) {
IProcessList list = null;
try {
list = CCorePlugin.getDefault().getProcessList();

View file

@ -10,12 +10,17 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.util.Map;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
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.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
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;
@ -26,8 +31,11 @@ import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIAddInferiorInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
/**
* Adding support for multi-process with GDB 7.2
@ -38,6 +46,14 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 {
private CommandFactory fCommandFactory;
private IGDBControl fCommandControl;
private IGDBBackend fBackend;
/**
* Keeps track if we are dealing with the very first
* process of GDB. In such a case, we should not create a new
* inferior, since GDB has already created one by default.
*/
private boolean fInitialProcess = true;
public GDBProcesses_7_2(DsfSession session) {
super(session);
@ -64,6 +80,8 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 {
private void doInitialize(RequestMonitor requestMonitor) {
fCommandControl = getServicesTracker().getService(IGDBControl.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
fBackend = getServicesTracker().getService(IGDBBackend.class);
requestMonitor.done();
}
@ -72,47 +90,140 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 {
super.shutdown(requestMonitor);
}
@Override
protected boolean doIsDebuggerAttachSupported() {
// Multi-process is not applicable to post-mortem sessions (core)
// or to non-attach remote sessions.
if (fBackend.getSessionType() == SessionType.CORE) {
return false;
}
if (fBackend.getSessionType() == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
return false;
}
return true;
}
@Override
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) {
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> dataRm) {
if (procCtx instanceof IMIProcessDMContext) {
if (!doIsDebuggerAttachSupported()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$
rm.done();
dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$
dataRm.done();
return;
}
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class);
fCommandControl.queueCommand(
fCommandFactory.createMIAddInferior(controlDmc),
new DataRequestMonitor<MIAddInferiorInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
final String groupId = getData().getGroupId();
if (groupId == null || groupId.trim().length() == 0) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid gdb group id.", null)); //$NON-NLS-1$
rm.done();
return;
}
final IMIContainerDMContext containerDmc = createContainerContext(procCtx, groupId);
fCommandControl.queueCommand(
fCommandFactory.createMITargetAttach(containerDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(containerDmc);
// Start tracking this process' breakpoints.
MIBreakpointsManager bpmService = getServicesTracker().getService(MIBreakpointsManager.class);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(containerDmc, IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
}
});
}
});
// Use a sequence for better control of each step
ImmediateExecutor.getInstance().execute(new Sequence(getExecutor(), dataRm) {
private IMIContainerDMContext fContainerDmc;
private Step[] steps = new Step[] {
// If this is not the very first inferior, we first need create the new inferior
new Step() {
@Override
public void execute(final RequestMonitor rm) {
if (fInitialProcess) {
fInitialProcess = false;
fContainerDmc = createContainerContext(procCtx, "i1"); //$NON-NLS-1$
rm.done();
return;
}
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class);
fCommandControl.queueCommand(
fCommandFactory.createMIAddInferior(controlDmc),
new DataRequestMonitor<MIAddInferiorInfo>(ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {
final String groupId = getData().getGroupId();
if (groupId == null || groupId.trim().length() == 0) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid gdb group id.", null)); //$NON-NLS-1$
} else {
fContainerDmc = createContainerContext(procCtx, groupId);
}
rm.done();
}
});
}
},
// For remote attach, we must set the binary first
// For a local attach, GDB can figure out the binary automatically,
// so we don't specify it.
new Step() {
@Override
public void execute(RequestMonitor rm) {
if (fBackend.getSessionType() == SessionType.REMOTE) {
final IPath execPath = fBackend.getProgramPath();
if (execPath != null && !execPath.isEmpty()) {
fCommandControl.queueCommand(
fCommandFactory.createMIFileExecAndSymbols(fContainerDmc, execPath.toPortableString()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
return;
}
}
rm.done();
}
},
// Now, actually do the attach
new Step() {
@Override
public void execute(RequestMonitor rm) {
fCommandControl.queueCommand(
fCommandFactory.createMITargetAttach(fContainerDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(ImmediateExecutor.getInstance(), rm));
}
},
// Start tracking this process' breakpoints.
new Step() {
@Override
public void execute(RequestMonitor rm) {
MIBreakpointsManager bpmService = getServicesTracker().getService(MIBreakpointsManager.class);
IBreakpointsTargetDMContext bpTargetDmc = DMContexts.getAncestorOfType(fContainerDmc, IBreakpointsTargetDMContext.class);
bpmService.startTrackingBreakpoints(bpTargetDmc, rm);
}
},
// Turn on reverse debugging if it was enabled as a launch option
new Step() {
@Override
public void execute(RequestMonitor rm) {
IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class);
if (reverseService != null) {
ILaunch launch = (ILaunch)procCtx.getAdapter(ILaunch.class);
if (launch != null) {
try {
boolean reverseEnabled =
launch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE,
IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT);
if (reverseEnabled) {
reverseService.enableReverseMode(fCommandControl.getContext(), true, rm);
return;
}
} catch (CoreException e) {
// Ignore, just don't set reverse
}
}
}
rm.done();
}
},
// Store the fully formed container context so it can be returned to the caller.
new Step() {
@Override
public void execute(RequestMonitor rm) {
dataRm.setData(fContainerDmc);
rm.done();
}
},
};
@Override public Step[] getSteps() { return steps; }
});
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
dataRm.done();
}
}
@ -156,5 +267,41 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 {
rm.done();
}
}
@Override
protected boolean doIsDebugNewProcessSupported() {
// Multi-process is not applicable to post-mortem sessions (core)
// or to non-attach remote sessions.
SessionType type = fBackend.getSessionType();
if (type == SessionType.CORE) {
return false;
}
if (type == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
return false;
}
return true;
}
@Override
public void debugNewProcess(IDMContext dmc, String file,
Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) {
boolean isInitial = fInitialProcess;
if (fInitialProcess) {
fInitialProcess = false;
} else {
// If we are trying to create another process than the initial one, see if we are allowed
if (!doIsDebugNewProcessSupported()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Not allowed to create a new process", null)); //$NON-NLS-1$
rm.done();
return;
}
}
ImmediateExecutor.getInstance().execute(
new DebugNewProcessSequence_7_2(getExecutor(), isInitial, dmc, file, attributes, rm));
}
}