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

Bug 528145 - Breakpoints are not working with remote attach launch (#336)

Looking at the logs, it seems that the regression is caused at 8bec791
where support for multi-process was added. We removed breakpoints
tracking support from final launch sequence and moved it to debug new
process and attach to process logic but none of these are run for remote
attach launch, hence breakpoint tracking is not started for remote
attach launch.

To fix the problem, IGDBProcesses.attachDebuggerToProcess(..) is updated
to handle remote attach launch as well instead of final launch sequence
handling it.

This commit is created after reverting 7bddb5f and 96839a0 which is the
older fix done to fix this issue and the other commit was to fix the
regression caused by the old fix.

The problem with older fix was that for non-stop mode, attach to process
was not working for remote launches when there is already a process
being debugged. Note that to use this feature, gdbserver should be
started with --multi option.

* Revert "Bug 580259: Not all remote session have a connected process"

This reverts commit 96839a029d.

* Revert "Bug 528145 - Attach debugger to a gdbserver remote session"

This reverts commit 7bddb5f4cb.
This commit is contained in:
Umair Sair 2023-04-11 03:32:11 +05:00 committed by GitHub
parent 2777c17784
commit e8f17beeb5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 459 additions and 136 deletions

View file

@ -37,6 +37,7 @@ jobs:
run: |
export DISPLAY=:99
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 &
echo 0| sudo tee /proc/sys/kernel/yama/ptrace_scope
mvn \
clean verify -B -V \
-Dmaven.test.failure.ignore=true \

View file

@ -12,6 +12,10 @@ This is the New & Noteworthy page for CDT 11.2 which is part of Eclipse 2023-06
Please see [CHANGELOG-API](CHANGELOG-API.md) for details on the breaking API changes in this release as well as future planned API changes.
## `FinalLaunchSequence.stepRemoteConnection()` and `FinalLaunchSequence.stepAttachRemoteToDebugger()` are deprecated
The remote connection for attach launch will be moved in the implementation of `IGDBProcesses.attachDebuggerToProcess()`
# Noteworthy Issues and Pull Requests
See [Noteworthy issues and PRs](https://github.com/eclipse-cdt/cdt/issues?q=is%3Aclosed+label%3Anoteworthy+milestone%3A11.2.0) for this release in the issue/PR tracker.

View file

@ -596,3 +596,11 @@ The class BuiltinDetctionArgsGeneric will be removed. Use the correctly
spelled BuiltinDetectionArgsGeneric instead.
- org.eclipse.cdt.jsoncdb.core.participant.Arglets.BuiltinDetctionArgsGeneric
## API Removals after June 2025
### FinalLaunchSequence.stepRemoteConnection() and FinalLaunchSequence.stepAttachRemoteToDebugger() will be removed
These APIs will be removed and remote connection for attach launch will be moved in the implementation of `IGDBProcesses.attachDebuggerToProcess()`.
See https://github.com/eclipse-cdt/cdt/pull/336

View file

@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-SymbolicName: org.eclipse.cdt.dsf.gdb;singleton:=true
Bundle-Version: 7.0.0.qualifier
Bundle-Version: 7.1.0.qualifier
Bundle-Activator: org.eclipse.cdt.dsf.gdb.internal.GdbPlugin
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime,

View file

@ -19,7 +19,6 @@
* Anton Gorenkov - A preference to use RTTI for variable types determination (Bug 377536)
* Xavier Raynaud (Kalray) - Avoid duplicating fields in sub-classes (add protected accessors)
* Marc Khouzam (Ericsson) - Output the version of GDB at startup (Bug 455408)
* Jonathan Tousignant (NordiaSoft) - Remote session breakpoint (Bug 528145)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.launching;
@ -39,7 +38,6 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitorWithProgress;
import org.eclipse.cdt.dsf.datamodel.DataModelInitializedEvent;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
@ -47,11 +45,11 @@ 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.IGDBSourceLookup;
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.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.output.MIGDBVersionInfo;
@ -77,7 +75,7 @@ public class FinalLaunchSequence extends ReflectionSequence {
private IGDBControl fCommandControl;
private IGDBBackend fGDBBackend;
private IMIProcesses fProcService;
private IGDBProcesses fProcService;
private CommandFactory fCommandFactory;
private DsfServicesTracker fTracker;
@ -136,13 +134,13 @@ public class FinalLaunchSequence extends ReflectionSequence {
//
// "stepSetSourceLookupPath", //$NON-NLS-1$
// For remote-attach launch only
// For remote-attach launch only (deprecated, see javadocs)
"stepRemoteConnection", //$NON-NLS-1$
// For all launches except attach ones
"stepNewProcess", //$NON-NLS-1$
// For local attach launch only
// For all attach launch only
"stepAttachToProcess", //$NON-NLS-1$
// For remote attach launch only
// For remote attach launch only (deprecated, see javadocs)
"stepAttachRemoteToDebugger", //$NON-NLS-1$
// Global
"stepDataModelInitializationComplete", //$NON-NLS-1$
@ -178,7 +176,7 @@ public class FinalLaunchSequence extends ReflectionSequence {
fCommandFactory = fCommandControl.getCommandFactory();
fProcService = fTracker.getService(IMIProcesses.class);
fProcService = fTracker.getService(IGDBProcesses.class);
if (fProcService == null) {
requestMonitor.setStatus(
new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain process service", null)); //$NON-NLS-1$
@ -552,13 +550,17 @@ public class FinalLaunchSequence extends ReflectionSequence {
rm.done();
}
@Deprecated(forRemoval = true)
private static final String INVALID = "invalid"; //$NON-NLS-1$
/**
* If we are dealing with a remote-attach debugging session, connect to the target.
* @since 4.0
*
* When removing, revive/uncomment code in implementations of IGDBProcesses.attachDebuggerToProcess()
*/
@Execute
@Deprecated(forRemoval = true)
public void stepRemoteConnection(final RequestMonitor rm) {
if (fGDBBackend.getSessionType() == SessionType.REMOTE && fGDBBackend.getIsAttachSession()) {
boolean isTcpConnection = CDebugUtils.getAttribute(fAttributes,
@ -593,19 +595,9 @@ public class FinalLaunchSequence extends ReflectionSequence {
@Execute
public void stepNewProcess(final RequestMonitor rm) {
if (!fGDBBackend.getIsAttachSession()) {
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.toString();
}
// 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,
fProcService.debugNewProcess(fCommandControl.getContext(), getBinary(), fAttributes,
new DataRequestMonitor<IDMContext>(getExecutor(), rm) {
@Override
protected void handleCancel() {
@ -623,14 +615,28 @@ public class FinalLaunchSequence extends ReflectionSequence {
}
/**
* 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 7.1
*/
protected String getBinary() {
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.toString();
}
return binary;
}
/**
* If we are dealing with an attach session, perform the attach.
* @since 4.0
*/
@Execute
public void stepAttachToProcess(final RequestMonitor requestMonitor) {
if (fGDBBackend.getIsAttachSession() && fGDBBackend.getSessionType() != SessionType.REMOTE) {
if (fGDBBackend.getIsAttachSession()) {
// Is the process id already stored in the launch?
int pid = CDebugUtils.getAttribute(fAttributes, ICDTLaunchConfigurationConstants.ATTR_ATTACH_PROCESS_ID,
-1);
@ -639,6 +645,10 @@ public class FinalLaunchSequence extends ReflectionSequence {
fProcService.attachDebuggerToProcess(
fProcService.createProcessContext(fCommandControl.getContext(), Integer.toString(pid)),
new DataRequestMonitor<IDMContext>(getExecutor(), requestMonitor));
} else if (fGDBBackend.getSessionType() == SessionType.REMOTE) {
// Inline following and remove requestMonitor.done() once FinalLaunchSequence.stepAttachRemoteToDebugger() is removed
// stepAttachRemoteToDebugger(requestMonitor);
requestMonitor.done();
} else {
IConnectHandler connectCommand = (IConnectHandler) fSession.getModelAdapter(IConnectHandler.class);
if (connectCommand instanceof IConnect) {
@ -656,22 +666,19 @@ public class FinalLaunchSequence extends ReflectionSequence {
* If we are dealing with an remote attach session, perform the attach to debugger.
* Bug 528145
* @since 6.6
*
* When removing, revive/uncomment code in implementations in FinalLaunchSequence.stepAttachToProcess(RequestMonitor)
*/
@Deprecated(forRemoval = true)
@Execute
public void stepAttachRemoteToDebugger(final RequestMonitor requestMonitor) {
if (fGDBBackend.getIsAttachSession() && fGDBBackend.getSessionType() == SessionType.REMOTE) {
DataRequestMonitor<Boolean> rm = new DataRequestMonitor<>(getExecutor(), null);
fProcService.canDetachDebuggerFromProcess(null, rm);
if (rm.getData()) {
IProcessDMContext processContext = fProcService.createProcessContext(fCommandControl.getContext(),
MIProcesses.UNKNOWN_PROCESS_ID);
fProcService.attachDebuggerToProcess(processContext,
new DataRequestMonitor<IDMContext>(getExecutor(), requestMonitor));
return;
}
fProcService.attachDebuggerToProcess(
fProcService.createProcessContext(fCommandControl.getContext(), MIProcesses.UNKNOWN_PROCESS_ID),
getBinary(), new DataRequestMonitor<IDMContext>(getExecutor(), requestMonitor));
} else {
requestMonitor.done();
}
requestMonitor.done();
}
/**

View file

@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit;
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.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
@ -75,6 +76,7 @@ import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.launching.GDBRemoteTCPLaunchTargetProvider;
import org.eclipse.cdt.dsf.gdb.launching.InferiorRuntimeProcess;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
@ -113,6 +115,8 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.launchbar.core.target.ILaunchTarget;
import org.eclipse.launchbar.core.target.launch.ITargetedLaunch;
import org.osgi.framework.BundleContext;
/**
@ -126,6 +130,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesse
* Each one is shown in the debug view.
*/
private final static int MAX_NUMBER_EXITED_PROCESS = 5;
private final static String INVALID = "invalid"; //$NON-NLS-1$
// Below is the context hierarchy that is implemented between the
// MIProcesses service and the MIRunControl service for the MI
@ -1216,13 +1221,6 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesse
new Step() {
@Override
public void execute(RequestMonitor rm) {
if (isInitialProcess()) {
// To be proper, set the initialProcess variable to false
// it may be necessary for a class that extends this class
setIsInitialProcess(false);
}
// There is no groupId until we attach, so we can use the default groupId
fContainerDmc = createContainerContext(procCtx, MIProcesses.UNIQUE_GROUP_ID);
@ -1240,6 +1238,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesse
new Step() {
@Override
public void execute(RequestMonitor rm) {
if (fBackend.getSessionType() == SessionType.REMOTE && isInitialProcess()) {
// Uncomment following and remove rm.done() once FinalLaunchSequence.stepRemoteConnection() is removed
// connectToTarget(procCtx, rm);
rm.done();
return;
}
// For non-stop mode, we do a non-interrupting attach
// Bug 333284
boolean shouldInterrupt = true;
@ -1262,6 +1266,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesse
// Store the fully formed container context so it can be returned to the caller.
dataRm.setData(fContainerDmc);
setIsInitialProcess(false);
// Initialize memory data for this process.
IGDBMemory memory = getServicesTracker().getService(IGDBMemory.class);
@ -1302,6 +1307,61 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesse
}
}
/**
* @since 7.1
*/
protected void connectToTarget(IProcessDMContext procCtx, RequestMonitor rm) {
ILaunch launch = procCtx.getAdapter(ILaunch.class);
assert launch != null;
if (launch != null) {
Map<String, Object> attributes = new HashMap<>();
try {
attributes.putAll(launch.getLaunchConfiguration().getAttributes());
} catch (CoreException e) {
rm.done(e.getStatus());
return;
}
if (launch instanceof ITargetedLaunch) {
ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
if (target != null) {
attributes.putAll(target.getAttributes());
String tcp = target.getAttribute(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, ""); //$NON-NLS-1$
if (!tcp.isEmpty()) {
attributes.put(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, Boolean.parseBoolean(tcp));
} else {
attributes.put(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
target.getTypeId().equals(GDBRemoteTCPLaunchTargetProvider.TYPE_ID));
}
}
}
boolean isTcpConnection = CDebugUtils.getAttribute(attributes,
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, false);
if (isTcpConnection) {
String remoteTcpHost = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_HOST,
INVALID);
String remoteTcpPort = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_PORT,
INVALID);
fCommandControl.queueCommand(fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
remoteTcpHost, remoteTcpPort, true), new ImmediateDataRequestMonitor<MIInfo>(rm));
} else {
String serialDevice = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_DEV,
INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(), serialDevice, true),
new ImmediateDataRequestMonitor<MIInfo>(rm));
}
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Cannot reconnect to target.", //$NON-NLS-1$
null));
rm.done();
}
}
/** @since 5.0 */
protected void doReverseDebugStep(final IProcessDMContext procCtx, RequestMonitor rm) {
// Turn on reverse debugging if it was enabled as a launch option

View file

@ -13,20 +13,17 @@
* Marc Khouzam (Ericsson) - Workaround for Bug 352998
* Marc Khouzam (Ericsson) - Update breakpoint handling for GDB >= 7.4 (Bug 389945)
* Alvaro Sanchez-Leon (Ericsson) - Breakpoint Enable does not work after restarting the application (Bug 456959)
* Jonathan Tousignant (NordiaSoft) - Remote session breakpoint (Bug 528145)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.debug.core.CDebugUtils;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
@ -48,9 +45,7 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.ICommand;
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.launching.GDBRemoteTCPLaunchTargetProvider;
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
@ -67,12 +62,8 @@ 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.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.launchbar.core.target.ILaunchTarget;
import org.eclipse.launchbar.core.target.launch.ITargetedLaunch;
/**
* Adding support for multi-process with GDB 7.2
@ -176,8 +167,6 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
private IGDBControl fCommandControl;
private IGDBBackend fBackend;
private final static String INVALID = "invalid"; //$NON-NLS-1$
/**
* Keep track if we need to reconnect to the target
* due to a workaround because of a GDB 7.2 bug.
@ -266,15 +255,13 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
@Override
protected boolean doIsDebuggerAttachSupported() {
SessionType sessionType = fBackend.getSessionType();
// Multi-process is not applicable to post-mortem sessions (core)
// or to non-attach remote sessions.
if (sessionType == SessionType.CORE) {
if (fBackend.getSessionType() == SessionType.CORE) {
return false;
}
if (sessionType == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
if (fBackend.getSessionType() == SessionType.REMOTE && !fBackend.getIsAttachSession()) {
return false;
}
@ -282,16 +269,9 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class);
if (runControl != null && runControl.getRunMode() == MIRunMode.ALL_STOP) {
// Only one process is allowed in all-stop (for now)
return getNumConnected() == 0;
// NOTE: when we support multi-process in all-stop mode,
// we will need to interrupt the target to when doing the attach.
int numConnected = getNumConnected();
if (numConnected == 1 && sessionType == SessionType.REMOTE) {
// Bug 528145: Special case for remote sessions with an existing connection.
return true;
}
return numConnected == 0;
}
return true;
@ -325,10 +305,8 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
new Step() {
@Override
public void execute(final RequestMonitor rm) {
// The remote session is already connected to the process
// Bug 528145
if (fBackend.getSessionType() == SessionType.REMOTE
&& doCanDetachDebuggerFromProcess()) {
if (procCtx instanceof IMIProcessDMContext ctx
&& MIProcesses.UNKNOWN_PROCESS_ID.equals(ctx.getProcId())) {
rm.done();
return;
}
@ -469,14 +447,12 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
new Step() {
@Override
public void execute(RequestMonitor rm) {
// This call end the current attach to the gdbserver in remote session
// Bug 528145
if (fBackend.getSessionType() == SessionType.REMOTE
&& doCanDetachDebuggerFromProcess()) {
if (fBackend.getSessionType() == SessionType.REMOTE && isInitialProcess()) {
// Uncomment following and remove rm.done() once FinalLaunchSequence.stepRemoteConnection() is removed
// connectToTarget(procCtx, rm);
rm.done();
return;
}
// For non-stop mode, we do a non-interrupting attach
// Bug 333284
boolean shouldInterrupt = true;
@ -560,58 +536,6 @@ public class GDBProcesses_7_2 extends GDBProcesses_7_1 implements IMultiTerminat
return false;
}
private void connectToTarget(IProcessDMContext procCtx, RequestMonitor rm) {
ILaunch launch = procCtx.getAdapter(ILaunch.class);
assert launch != null;
if (launch != null) {
Map<String, Object> attributes = new HashMap<>();
try {
attributes.putAll(launch.getLaunchConfiguration().getAttributes());
} catch (CoreException e) {
rm.done(e.getStatus());
return;
}
if (launch instanceof ITargetedLaunch) {
ILaunchTarget target = ((ITargetedLaunch) launch).getLaunchTarget();
if (target != null) {
attributes.putAll(target.getAttributes());
String tcp = target.getAttribute(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, ""); //$NON-NLS-1$
if (!tcp.isEmpty()) {
attributes.put(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, Boolean.parseBoolean(tcp));
} else {
attributes.put(IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP,
target.getTypeId().equals(GDBRemoteTCPLaunchTargetProvider.TYPE_ID));
}
}
}
boolean isTcpConnection = CDebugUtils.getAttribute(attributes,
IGDBLaunchConfigurationConstants.ATTR_REMOTE_TCP, false);
if (isTcpConnection) {
String remoteTcpHost = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_HOST,
INVALID);
String remoteTcpPort = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_PORT,
INVALID);
fCommandControl.queueCommand(fCommandFactory.createMITargetSelect(fCommandControl.getContext(),
remoteTcpHost, remoteTcpPort, true), new ImmediateDataRequestMonitor<MIInfo>(rm));
} else {
String serialDevice = CDebugUtils.getAttribute(attributes, IGDBLaunchConfigurationConstants.ATTR_DEV,
INVALID);
fCommandControl.queueCommand(
fCommandFactory.createMITargetSelect(fCommandControl.getContext(), serialDevice, true),
new ImmediateDataRequestMonitor<MIInfo>(rm));
}
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Cannot reconnect to target.", //$NON-NLS-1$
null));
rm.done();
}
}
@Override
public void detachDebuggerFromProcess(IDMContext dmc, final RequestMonitor rm) {

View file

@ -24,9 +24,11 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
@ -192,7 +194,9 @@ public class BaseTestCase {
*/
public boolean isRemoteSession() {
return launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE);
.equals(IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE)
|| launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE_ATTACH);
}
/**
@ -553,9 +557,6 @@ public class BaseTestCase {
protected GdbLaunch doLaunchInner() throws Exception {
assertNotNull("The launch configuration has not been created. Call doLaunch first.", fLaunchConfiguration);
boolean postMortemLaunch = launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE);
SessionEventListener sessionEventListener = new SessionEventListener(fLaunchConfiguration);
SessionStartedListener sessionStartedListener = new SessionStartedListener() {
@Override
@ -586,12 +587,10 @@ public class BaseTestCase {
// proceeding. All tests assume that stable initial state. Two
// seconds is plenty; we typically get to that state in a few
// hundred milliseconds with the tiny test programs we use.
if (!postMortemLaunch) {
if (isTargetExpectedToStopAfterLaunch()) {
sessionEventListener.waitUntilTargetSuspended();
}
// This should be a given if the above check passes
if (!postMortemLaunch) {
// This should be a given if the above check passes
synchronized (this) {
MIStoppedEvent initialStoppedEvent = sessionEventListener.getInitialStoppedEvent();
Assert.assertNotNull(initialStoppedEvent);
@ -617,6 +616,11 @@ public class BaseTestCase {
return launch;
}
protected boolean isTargetExpectedToStopAfterLaunch() {
return !launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE)
.equals(ICDTLaunchConfigurationConstants.DEBUGGER_MODE_CORE);
}
/**
* Assert that the launch terminates. Callers should have already
* terminated the launch in some way.
@ -680,7 +684,19 @@ public class BaseTestCase {
String server = (String) launchAttributes.get(ATTR_DEBUG_SERVER_NAME);
String port = (String) launchAttributes.get(IGDBLaunchConfigurationConstants.ATTR_PORT);
String program = (String) launchAttributes.get(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME);
String[] commandLine = { server, ":" + port, program };
boolean multi = Boolean.valueOf((String) launchAttributes.get(ITestConstants.LAUNCH_GDB_SERVER_MULTI));
boolean noprogram = Boolean
.valueOf((String) launchAttributes.get(ITestConstants.LAUNCH_GDB_SERVER_WITHOUT_PROGRAM));
List<String> commandArgs = new ArrayList<>();
commandArgs.add(server);
if (multi) {
commandArgs.add("--multi");
}
commandArgs.add(":" + port);
if (!noprogram) {
commandArgs.add(program);
}
String[] commandLine = commandArgs.toArray(new String[0]);
try {
if (GdbDebugOptions.DEBUG)
GdbDebugOptions

View file

@ -1111,6 +1111,43 @@ public class SyncUtil {
return query.get(TestsPlugin.massageTimeout(2000), TimeUnit.MILLISECONDS);
}
/**
* Utility method to return all the container DM contexts.
*
* <p>
* This must NOT be called from the DSF executor.
*
* @return the process context
* @throws InterruptedException
* @throws TimeoutException
* @throws ExecutionException
*/
@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
public static IContainerDMContext[] getAllContainerContexts()
throws InterruptedException, ExecutionException, TimeoutException {
assert !fProcessesService.getExecutor().isInExecutorThread();
Query<IContainerDMContext[]> query = new Query<>() {
@Override
protected void execute(final DataRequestMonitor<IContainerDMContext[]> rm) {
fProcessesService.getProcessesBeingDebugged(fGdbControl.getContext(),
new ImmediateDataRequestMonitor<IDMContext[]>() {
@Override
protected void handleCompleted() {
if (isSuccess()) {
rm.done((IContainerDMContext[]) getData());
} else {
rm.done(getStatus());
}
}
});
}
};
fGdbControl.getExecutor().execute(query);
return query.get(TestsPlugin.massageTimeout(2000), TimeUnit.MILLISECONDS);
}
/**
* Utility method to return all threads
*
@ -1126,6 +1163,22 @@ public class SyncUtil {
final IContainerDMContext containerDmc = SyncUtil.getContainerContext();
return getExecutionContexts(containerDmc);
}
/**
* Utility method to return all threads for given containerDmc
* @param containerDmc
* @return
* @throws InterruptedException
* @throws ExecutionException
* @throws TimeoutException
*/
@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
public static IMIExecutionDMContext[] getExecutionContexts(IContainerDMContext containerDmc)
throws InterruptedException, ExecutionException, TimeoutException {
assert !fProcessesService.getExecutor().isInExecutorThread();
Query<IMIExecutionDMContext[]> query = new Query<>() {
@Override
protected void execute(final DataRequestMonitor<IMIExecutionDMContext[]> rm) {

View file

@ -64,4 +64,9 @@ public class ITestConstants {
// Attribute that allows a test to request not to start gdbserver even if the session is a remote one
public static final String LAUNCH_GDB_SERVER = TestsPlugin.PLUGIN_ID + ".launchGdbServer";
// Attribute that tells whether gdbserver should be launched without program
public static final String LAUNCH_GDB_SERVER_WITHOUT_PROGRAM = TestsPlugin.PLUGIN_ID
+ ".launchGdbServerWithoutProgram";
// Attribute that tells whether gdbserver should be launched with --multi argument
public static final String LAUNCH_GDB_SERVER_MULTI = TestsPlugin.PLUGIN_ID + ".launchGdbServerMulti";
}

View file

@ -17,6 +17,7 @@ import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.GDBMultiNonStopRunControlTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.MIExpressionsNonStopTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.MIRunControlNonStopTargetAvailableTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.MultiProcessRemoteTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.OperationsWhileTargetIsRunningNonStopTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.StepIntoSelectionNonStopTest;
import org.eclipse.cdt.tests.dsf.gdb.tests.nonstop.ThreadStackFrameSyncTest;
@ -46,7 +47,8 @@ import org.junit.runners.Suite;
OperationsWhileTargetIsRunningNonStopTest.class, StepIntoSelectionNonStopTest.class,
GDBRemoteTracepointsTest.class, TraceFileTest.class, GDBConsoleSynchronizingTest.class, MIMemoryTest.class,
MIDisassemblyTest.class, GDBProcessesTest.class, PostMortemCoreTest.class, CommandTimeoutTest.class,
ThreadStackFrameSyncTest.class, CommandLineArgsTest.class, MIAsyncErrorProcessorTests.class
ThreadStackFrameSyncTest.class, CommandLineArgsTest.class, MIAsyncErrorProcessorTests.class,
MultiProcessRemoteTest.class
/* Add your test class here */
})
public class SuiteGdb {

View file

@ -0,0 +1,243 @@
package org.eclipse.cdt.tests.dsf.gdb.tests.nonstop;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil.DefaultTimeouts;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil.DefaultTimeouts.ETimeout;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
import org.eclipse.cdt.utils.spawner.ProcessFactory;
import org.eclipse.core.runtime.IPath;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
public class MultiProcessRemoteTest extends BaseParametrizedTestCase {
private static final String EXEC_NAME = "MultiThread.exe";
private DsfServicesTracker fServicesTracker;
private IGDBProcesses fGdbProcesses;
private ICommandControlService fCommandControl;
private IGDBBackend fGDBBackend;
private List<Process> appProcesses = new ArrayList<>();
@BeforeClass
public static void beforeClass() {
Assume.assumeTrue(supportsNonStop());
}
@Override
public void doBeforeTest() throws Exception {
assumeRemoteSession();
assumeGdbVersionAtLeast(ITestConstants.SUFFIX_GDB_7_0);
super.doBeforeTest();
final DsfSession session = getGDBLaunch().getSession();
Runnable runnable = () -> {
fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), session.getId());
fGdbProcesses = fServicesTracker.getService(IGDBProcesses.class);
fCommandControl = fServicesTracker.getService(ICommandControlService.class);
fGDBBackend = fServicesTracker.getService(IGDBBackend.class);
};
session.getExecutor().submit(runnable).get();
}
@Override
protected void setLaunchAttributes() {
super.setLaunchAttributes();
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, getBinary());
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false);
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE,
IGDBLaunchConfigurationConstants.DEBUGGER_MODE_REMOTE_ATTACH);
setLaunchAttribute(ITestConstants.LAUNCH_GDB_SERVER_MULTI, Boolean.TRUE.toString());
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REMOTE_BINARY,
getLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME));
if (testName.getMethodName().contains("_noProgram")) {
setLaunchAttribute(ITestConstants.LAUNCH_GDB_SERVER_WITHOUT_PROGRAM, Boolean.TRUE.toString());
}
}
@Override
public void doAfterTest() throws Exception {
if (fServicesTracker != null)
fServicesTracker.dispose();
super.doAfterTest();
for (Process p : appProcesses) {
if (p.isAlive())
p.destroyForcibly();
}
appProcesses.clear();
}
@Override
protected boolean isTargetExpectedToStopAfterLaunch() {
// For some tests, we'll get stop event but not for others. Checking stop event
// at start of launch is not required for this test class
return false;
}
@Test
public void launchGdbServerWithProgramAndStartMulipleNewExecutables() throws Throwable {
assertEquals("Wrong number of containers at the start of launch", SyncUtil.getAllContainerContexts().length,
getInitialProcessCount());
final IPath execPath = fGDBBackend.getProgramPath();
Map<String, Object> attributes = getLaunchConfiguration().getAttributes();
IMIExecutionDMContext[] ctx = debugNewProcess(fGDBBackend.getProgramPath(), attributes);
assertTrue("Process-1 is not started properly as no threads found for it", ctx != null && ctx.length > 0);
ctx = debugNewProcess(execPath, attributes);
assertTrue("Process-2 is not started properly as no threads found for it", ctx != null && ctx.length > 0);
ctx = debugNewProcess(execPath, attributes);
assertTrue("Process-3 is not started properly as no threads found for it", ctx != null && ctx.length > 0);
}
@Test
public void launchGdbServerWithoutProgramAndStartMulipleNewExecutables_noProgram() throws Throwable {
launchGdbServerWithProgramAndStartMulipleNewExecutables();
}
@Test
public void launchGdbServerWithProgramAndConnectMultipleExecutables() throws Throwable {
assertEquals("Wrong number of containers at the start of launch", SyncUtil.getAllContainerContexts().length,
getInitialProcessCount());
Process process = launchApplication();
IMIExecutionDMContext[] ctx = attachToProcess(Long.toString(process.pid()));
assertTrue("Process-1 is not attached properly as no threads found for it", ctx != null && ctx.length > 0);
process = launchApplication();
ctx = attachToProcess(Long.toString(process.pid()));
assertTrue("Process-2 is not attached properly as no threads found for it", ctx != null && ctx.length > 0);
process = launchApplication();
ctx = attachToProcess(Long.toString(process.pid()));
assertTrue("Process-3 is not attached properly as no threads found for it", ctx != null && ctx.length > 0);
}
@Test
public void launchGdbServerWithoutProgramAndConnectMultipleExecutables_noProgram() throws Throwable {
launchGdbServerWithProgramAndConnectMultipleExecutables();
}
@Test
public void launchGdbServerWithProgram_DebugNewExecutable_And_ConnectExecutable() throws Throwable {
assertEquals("Wrong number of containers at the start of launch", SyncUtil.getAllContainerContexts().length,
getInitialProcessCount());
final IPath execPath = fGDBBackend.getProgramPath();
Map<String, Object> attributes = getLaunchConfiguration().getAttributes();
IMIExecutionDMContext[] ctx = debugNewProcess(execPath, attributes);
assertTrue("Process-1 is not started properly as no threads found for it", ctx != null && ctx.length > 0);
Process process = launchApplication();
ctx = attachToProcess(Long.toString(process.pid()));
assertTrue("Process-2 is not attached properly as no threads found for it", ctx != null && ctx.length > 0);
}
@Test
public void launchGdbServerWithoutProgram_DebugNewExecutable_And_ConnectExecutable_noProgram() throws Throwable {
launchGdbServerWithProgram_DebugNewExecutable_And_ConnectExecutable();
}
@Test
public void launchGdbServerWithProgram_ConnectExecutable_And_DebugNewExecutable() throws Throwable {
assertEquals("Wrong number of containers at the start of launch", SyncUtil.getAllContainerContexts().length,
getInitialProcessCount());
Process process = launchApplication();
IMIExecutionDMContext[] ctx = attachToProcess(Long.toString(process.pid()));
assertTrue("Process-1 is not attached properly as no threads found for it", ctx != null && ctx.length > 0);
final IPath execPath = fGDBBackend.getProgramPath();
Map<String, Object> attributes = getLaunchConfiguration().getAttributes();
ctx = debugNewProcess(execPath, attributes);
assertTrue("Process-2 is not started properly as no threads found for it", ctx != null && ctx.length > 0);
}
@Test
public void launchGdbServerWithoutProgram_ConnectExecutable_And_DebugNewExecutable_noProgram() throws Throwable {
launchGdbServerWithProgram_ConnectExecutable_And_DebugNewExecutable();
}
private int getInitialProcessCount() {
return Boolean.valueOf((String) getLaunchAttribute(ITestConstants.LAUNCH_GDB_SERVER_WITHOUT_PROGRAM)) ? 0 : 1;
}
private Process launchApplication() throws IOException {
Process process = ProcessFactory.getFactory()
.exec(new String[] { Path.of(getBinary()).toAbsolutePath().toString() });
if (process.isAlive()) {
appProcesses.add(process);
return process;
}
throw new IOException("Unable to launch application");
}
private static String getBinary() {
return EXEC_PATH + EXEC_NAME;
}
private IMIExecutionDMContext[] debugNewProcess(final IPath execPath, Map<String, Object> attributes)
throws InterruptedException, ExecutionException, TimeoutException {
Query<IDMContext> query = new Query<>() {
@Override
protected void execute(DataRequestMonitor<IDMContext> rm) {
fGdbProcesses.debugNewProcess(fCommandControl.getContext(), execPath.toOSString(), attributes, rm);
}
};
fGDBBackend.getExecutor().execute(query);
IDMContext context = query.get(DefaultTimeouts.get(ETimeout.waitForStop), TimeUnit.MILLISECONDS);
return fGdbProcesses.getExecutionContexts(DMContexts.getAncestorOfType(context, IMIContainerDMContext.class));
}
private IMIExecutionDMContext[] attachToProcess(String pid)
throws InterruptedException, ExecutionException, TimeoutException {
Query<IDMContext> query = new Query<>() {
@Override
protected void execute(DataRequestMonitor<IDMContext> rm) {
IProcessDMContext procDmc = fGdbProcesses.createProcessContext(fCommandControl.getContext(), pid);
fGdbProcesses.attachDebuggerToProcess(procDmc, getBinary(), rm);
}
};
fGDBBackend.getExecutor().execute(query);
IDMContext context = query.get(DefaultTimeouts.get(ETimeout.waitForStop), TimeUnit.MILLISECONDS);
return fGdbProcesses.getExecutionContexts(DMContexts.getAncestorOfType(context, IMIContainerDMContext.class));
}
}