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

Bug 487682 - refuse process selection for already connected process

- Extend query for already connected process to all sessions for local
session types

Change-Id: I36591ff96d28977b4670700a2a2eb92c34945c7a
Signed-off-by: Teodor Madan <teodor.madan@nxp.com>
This commit is contained in:
Teodor Madan 2016-02-09 22:47:35 +02:00 committed by Gerrit Code Review @ Eclipse.org
parent 70fe6cbbde
commit f29de7cedd
4 changed files with 182 additions and 39 deletions

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2015 Ericsson and others. * Copyright (c) 2008, 2016 Ericsson and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -14,10 +14,12 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.commands;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
@ -28,8 +30,11 @@ import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateInDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor; 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.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IProcesses;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
@ -50,6 +55,7 @@ import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages;
import org.eclipse.cdt.dsf.gdb.service.IGDBBackend; import org.eclipse.cdt.dsf.gdb.service.IGDBBackend;
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses; import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses;
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses.IGdbThreadDMData; import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses.IGdbThreadDMData;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
import org.eclipse.cdt.dsf.gdb.service.SessionType; import org.eclipse.cdt.dsf.gdb.service.SessionType;
import org.eclipse.cdt.dsf.service.DsfServicesTracker; import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.DsfSession;
@ -149,13 +155,15 @@ public class GdbConnectCommand extends RefreshableDebugCommand implements IConne
DataRequestMonitor<Object> fRequestMonitor; DataRequestMonitor<Object> fRequestMonitor;
boolean fNewProcessSupported; boolean fNewProcessSupported;
boolean fRemote; boolean fRemote;
private List<String> fDebuggedProcesses;
public PromptForPidJob(String name, boolean newProcessSupported, boolean remote, IProcessExtendedInfo[] procs, DataRequestMonitor<Object> rm) { public PromptForPidJob(String name, boolean newProcessSupported, boolean remote, IProcessExtendedInfo[] procs, List<String> debuggedProcesses, DataRequestMonitor<Object> rm) {
super(name); super(name);
fNewProcessSupported = newProcessSupported; fNewProcessSupported = newProcessSupported;
fRemote = remote; fRemote = remote;
fProcessList = procs; fProcessList = procs;
fRequestMonitor = rm; fRequestMonitor = rm;
fDebuggedProcesses = debuggedProcesses;
} }
@Override @Override
@ -165,7 +173,7 @@ public class GdbConnectCommand extends RefreshableDebugCommand implements IConne
null); null);
try { try {
PrompterInfo info = new PrompterInfo(fNewProcessSupported, fRemote, fProcessList); PrompterInfo info = new PrompterInfo(fNewProcessSupported, fRemote, fProcessList, fDebuggedProcesses);
Object result = new ProcessPrompter().handleStatus(null, info); Object result = new ProcessPrompter().handleStatus(null, info);
if (result == null) { if (result == null) {
fRequestMonitor.cancel(); fRequestMonitor.cancel();
@ -284,6 +292,81 @@ public class GdbConnectCommand extends RefreshableDebugCommand implements IConne
} }
} }
/**
* Get already debugged processes from all compatible sessions.
* "compatible" in current implementation means all sessions on local machine.
*
* @param currentCtx current session context
* @param allSessions true if all session to be queried, false to return result only for current execution session context
* @param drm where result to be returned
*/
private void getAllDebuggedProcesses(final IDMContext currentCtx, boolean allSessions, final DataRequestMonitor<List<String>> drm) {
SessionType sessionType = fTracker.getService(IGDBBackend.class).getSessionType();
final List<String> result = new LinkedList<>();
final List<DsfSession> sessions = new LinkedList<>();
// Only for local session types search in all debug sessions
if (allSessions && sessionType == SessionType.LOCAL) {
sessions.addAll(Arrays.asList(DsfSession.getActiveSessions()));
} else {
// For remote session just query current context.
//
// cannot reliably match two remote debug session that are connected to same target machine.
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=486408#c7
sessions.add(DsfSession.getSession(currentCtx.getSessionId()));
}
// Query each sessions for existing processes in a sequential fashion.
// We must do this as each session will require different executor.
final class ProcessRequestMonitor extends DataRequestMonitor<IDMContext[]> {
public ProcessRequestMonitor(Executor executor) { super(executor, null);}
public ProcessRequestMonitor(DsfExecutor executor) {
super(new ImmediateInDsfExecutor(executor), null);
}
@Override
protected void handleCompleted() {
// if succeeded and has data, add process ids to result,
// otherwise proceed to next debug session (aka DsfSession)
if (isSuccess() && getData() != null) {
for (IDMContext dmc : getData()) {
IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc,
IMIProcessDMContext.class);
if (procDmc != null) {
result.add(procDmc.getProcId());
}
}
}
if (!sessions.isEmpty()) {
final DsfSession nextSession = sessions.remove(0);
final boolean sameSession = currentCtx.getSessionId().equals(nextSession.getId());
nextSession.getExecutor().execute(new DsfRunnable() {
@Override
public void run() {
DsfServicesTracker nextTracker = new DsfServicesTracker(GdbUIPlugin.getBundleContext(), nextSession.getId());
IGDBBackend nextSessionBackend = nextTracker.getService(IGDBBackend.class);
if (sameSession || nextSessionBackend.getSessionType() == SessionType.LOCAL) {
ICommandControlService nextCommandControl = nextTracker.getService(ICommandControlService.class);
IProcesses nextProcService = nextTracker.getService(IProcesses.class);
nextProcService.getProcessesBeingDebugged(
nextCommandControl.getContext(), new ProcessRequestMonitor(nextSession.getExecutor()));
} else {
// proceed to next session context query passing an error (that will be ignored)
new ProcessRequestMonitor(nextSession.getExecutor()).done(
new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Only local session", null)); //$NON-NLS-1$
}
nextTracker.dispose();
}
});
} else {
// done with querying all session. Copy the result
drm.done(result);
}
}
};
// Trigger the first query
new ProcessRequestMonitor(ImmediateExecutor.getInstance()).done();
}
/* /*
* This method should not be called from the UI thread. * This method should not be called from the UI thread.
* (non-Javadoc) * (non-Javadoc)
@ -322,31 +405,39 @@ public class GdbConnectCommand extends RefreshableDebugCommand implements IConne
new CountingRequestMonitor(fExecutor, rm) { new CountingRequestMonitor(fExecutor, rm) {
@Override @Override
protected void handleSuccess() { protected void handleSuccess() {
// Prompt the user to choose one or more processes, or to start a new one getAllDebuggedProcesses(controlCtx, true, new ImmediateDataRequestMonitor<List<String>>(rm) {
new PromptForPidJob( @Override
LaunchUIMessages.getString("ProcessPrompter.PromptJob"), //$NON-NLS-1$ protected void handleSuccess() {
newProcessSupported, List<String> dbgPids = getData();
remote,
procInfoList.toArray(new IProcessExtendedInfo[procInfoList.size()]), // Prompt the user to choose one or more processes, or to start a new one
new DataRequestMonitor<Object>(fExecutor, rm) { new PromptForPidJob(
@Override LaunchUIMessages.getString("ProcessPrompter.PromptJob"), //$NON-NLS-1$
protected void handleCancel() { newProcessSupported,
rm.cancel(); remote,
rm.done(); procInfoList.toArray(new IProcessExtendedInfo[procInfoList.size()]),
} dbgPids,
@Override new DataRequestMonitor<Object>(fExecutor, rm) {
protected void handleSuccess() { @Override
Object data = getData(); protected void handleCancel() {
if (data instanceof NewExecutableInfo) { rm.cancel();
// User wants to start a new process rm.done();
startNewProcess(controlCtx, (NewExecutableInfo)data, rm); }
} else if (data instanceof IProcessExtendedInfo[]) { @Override
attachToProcesses(controlCtx, (IProcessExtendedInfo[])data, rm); protected void handleSuccess() {
} else { Object data = getData();
rm.done(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid return type for process prompter", null)); //$NON-NLS-1$ if (data instanceof NewExecutableInfo) {
} // User wants to start a new process
} startNewProcess(controlCtx, (NewExecutableInfo)data, rm);
}).schedule(); } else if (data instanceof IProcessExtendedInfo[]) {
attachToProcesses(controlCtx, (IProcessExtendedInfo[])data, rm);
} else {
rm.done(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid return type for process prompter", null)); //$NON-NLS-1$
}
}
}).schedule();
}
});
} }
}; };

View file

@ -1,5 +1,5 @@
############################################################################### ###############################################################################
# Copyright (c) 2003, 2015 QNX Software Systems and others. # Copyright (c) 2003, 2016 QNX Software Systems and others.
# All rights reserved. This program and the accompanying materials # All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0 # are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at # which accompanies this distribution, and is available at
@ -235,5 +235,7 @@ LocalCDILaunchDelegate.10=Failed to set program arguments, environment or workin
ProcessPrompter.Core=core ProcessPrompter.Core=core
ProcessPrompter.Cores=cores ProcessPrompter.Cores=cores
ProcessPrompter.PromptJob=Prompt for Process ProcessPrompter.PromptJob=Prompt for Process
ProcessPrompter.ErrProcessConected=Process {0} already connected
ProcessPrompterDialog.New=New... ProcessPrompterDialog.New=New...
ProcessPrompterDialog.TitlePrefix=Choose binary for process: ProcessPrompterDialog.TitlePrefix=Choose binary for process:

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2014 QNX Software Systems and others. * Copyright (c) 2008, 2016 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -12,6 +12,8 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui.launching; package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
import java.util.List;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin;
import org.eclipse.cdt.dsf.gdb.launching.IProcessExtendedInfo; import org.eclipse.cdt.dsf.gdb.launching.IProcessExtendedInfo;
@ -29,6 +31,9 @@ import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window; import org.eclipse.jface.window.Window;
import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import com.ibm.icu.text.MessageFormat;
public class ProcessPrompter implements IStatusHandler { public class ProcessPrompter implements IStatusHandler {
@ -36,11 +41,13 @@ public class ProcessPrompter implements IStatusHandler {
public boolean supportsNewProcess; public boolean supportsNewProcess;
public boolean remote; public boolean remote;
public IProcessExtendedInfo[] processList; public IProcessExtendedInfo[] processList;
public List<String> debuggedProcesses;
public PrompterInfo(boolean supportsNew, boolean remote, IProcessExtendedInfo[] list) { public PrompterInfo(boolean supportsNew, boolean remote, IProcessExtendedInfo[] list, List<String> debuggedProcs) {
supportsNewProcess = supportsNew; supportsNewProcess = supportsNew;
this.remote = remote; this.remote = remote;
processList = list; processList = list;
this.debuggedProcesses = debuggedProcs;
} }
} }
@ -60,7 +67,7 @@ public class ProcessPrompter implements IStatusHandler {
throw new CoreException(error); throw new CoreException(error);
} }
PrompterInfo prompterInfo = (PrompterInfo) info; final PrompterInfo prompterInfo = (PrompterInfo) info;
IProcessExtendedInfo[] plist = prompterInfo.processList; IProcessExtendedInfo[] plist = prompterInfo.processList;
if (plist == null) { if (plist == null) {
MessageDialog.openError( MessageDialog.openError(
@ -178,7 +185,21 @@ public class ProcessPrompter implements IStatusHandler {
// Allow for multiple selection // Allow for multiple selection
dialog.setMultipleSelection(true); dialog.setMultipleSelection(true);
dialog.setStatusLineAboveButtons(true);
dialog.setValidator(new ISelectionStatusValidator() {
@Override
public IStatus validate(Object[] selection) {
for (Object sel : selection) {
String pid = Integer.toString(((IProcessExtendedInfo)sel).getPid(), 10);
if (prompterInfo.debuggedProcesses.contains(pid)) {
return new Status(IStatus.ERROR, GdbUIPlugin.getUniqueIdentifier(),
MessageFormat.format(LaunchUIMessages.getString("ProcessPrompter.ErrProcessConected"), pid)); //$NON-NLS-1$
}
}
return new Status(IStatus.OK, GdbUIPlugin.getUniqueIdentifier(), ""); //$NON-NLS-1$
}
});
dialog.setElements(plist); dialog.setElements(plist);
if (dialog.open() == Window.OK) { if (dialog.open() == Window.OK) {
// First check if the user pressed the New button // First check if the user pressed the New button

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2011, 2013 Ericsson and others. * Copyright (c) 2011, 2016 Ericsson and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -13,6 +13,8 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.launching;
import java.util.Arrays; import java.util.Arrays;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
@ -22,6 +24,8 @@ import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.dialogs.TwoPaneElementSelector; import org.eclipse.ui.dialogs.TwoPaneElementSelector;
/** /**
@ -130,4 +134,29 @@ public class ProcessPrompterDialog extends TwoPaneElementSelector {
public NewExecutableInfo getExecutableInfo() { public NewExecutableInfo getExecutableInfo() {
return fExecInfo; return fExecInfo;
} }
/**
* Validate only upper selected elements. Lower list is always disabled.
*
* @see #createLowerList(Composite)
*/
@Override
protected boolean validateCurrentSelection() {
ISelectionStatusValidator validator = getValidator();
Object[] elements = getSelectedElements();
if (elements.length > 0) {
IStatus status;
if (validator != null) {
status = validator.validate(elements);
} else {
status = new Status(IStatus.OK, PlatformUI.PLUGIN_ID, IStatus.OK, "", //$NON-NLS-1$
null);
}
updateStatus(status);
return status.isOK();
}
return super.validateCurrentSelection();
}
} }