diff options
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java')
-rw-r--r-- | dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java | 2404 |
1 files changed, 1221 insertions, 1183 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java index c4ac020b57b..82288507b27 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java @@ -7,12 +7,12 @@ * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: * Ericsson - initial API and implementation * Onur Akdemir (TUBITAK BILGEM-ITI) - Multi-process debugging (Bug 237306) * John Dallaway - GDB 7.x MI thread details field ignored (Bug 325556) - * Marc Khouzam (Ericsson) - Make each thread an IDisassemblyDMContext (bug 352748) + * Marc Khouzam (Ericsson) - Make each thread an IDisassemblyDMContext (bug 352748) * Andy Jin (QNX) - Not output thread osId as a string when it is null (Bug 397039) * Marc Khouzam (Ericsson) - Move IBreakpointsTargetDMContext from MIContainerDMC * to GDBContainerDMC to ease inheritance (Bug 389945) @@ -119,38 +119,36 @@ import org.osgi.framework.BundleContext; * This class implements the IProcesses interface for GDB 7.0 * which supports the new -list-thread-groups command. */ -public class GDBProcesses_7_0 extends AbstractDsfService - implements IGDBProcesses, ICachingService, IEventListener { +public class GDBProcesses_7_0 extends AbstractDsfService implements IGDBProcesses, ICachingService, IEventListener { /** * The maximum amount of exited processes we can show. * Each one is shown in the debug view. */ private final static int MAX_NUMBER_EXITED_PROCESS = 5; - + // Below is the context hierarchy that is implemented between the - // MIProcesses service and the MIRunControl service for the MI + // MIProcesses service and the MIRunControl service for the MI // implementation of DSF: // // MIControlDMContext (ICommandControlDMContext) // | // MIProcessDMC (IProcess) // / \ - // / \ + // / \ // MIContainerDMC MIThreadDMC (IThread) // (IContainer) / // \ / // MIExecutionDMC // (IExecution) // - + /** * Context representing a thread in GDB/MI */ @Immutable - private static class MIExecutionDMC extends AbstractDMContext - implements IMIExecutionDMContext, IDisassemblyDMContext - { + private static class MIExecutionDMC extends AbstractDMContext + implements IMIExecutionDMContext, IDisassemblyDMContext { /** * String ID that is used to identify the thread in the GDB/MI protocol. */ @@ -161,29 +159,30 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Instead clients should call {@link IMIProcesses#createExecutionContext()} * to create instances of this context based on the thread ID. * <p/> - * + * * @param sessionId Session that this context belongs to. * @param containerDmc The container that this context belongs to. * @param threadDmc The thread context parents of this context. * @param threadId GDB/MI thread identifier. */ - protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, IThreadDMContext threadDmc, String threadId) { - super(sessionId, - containerDmc == null && threadDmc == null ? new IDMContext[0] : - containerDmc == null ? new IDMContext[] { threadDmc } : - threadDmc == null ? new IDMContext[] { containerDmc } : - new IDMContext[] { containerDmc, threadDmc }); - fThreadId = threadId; - } + protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, IThreadDMContext threadDmc, + String threadId) { + super(sessionId, + containerDmc == null && threadDmc == null ? new IDMContext[0] + : containerDmc == null ? new IDMContext[] { threadDmc } + : threadDmc == null ? new IDMContext[] { containerDmc } + : new IDMContext[] { containerDmc, threadDmc }); + fThreadId = threadId; + } /** * Returns the GDB/MI thread identifier of this context. * @return */ - @Override - public String getThreadId() { - return fThreadId; - } + @Override + public String getThreadId() { + return fThreadId; + } /* Unused; reintroduce if needed public String getId(){ @@ -192,24 +191,26 @@ public class GDBProcesses_7_0 extends AbstractDsfService */ @Override - public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + public String toString() { + return baseToString() + ".thread[" + fThreadId + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } @Override public boolean equals(Object obj) { - return baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId.equals(fThreadId); + return baseEquals(obj) && ((MIExecutionDMC) obj).fThreadId.equals(fThreadId); } @Override - public int hashCode() { return baseHashCode() ^ fThreadId.hashCode(); } + public int hashCode() { + return baseHashCode() ^ fThreadId.hashCode(); + } } /** - * Context representing a thread group of GDB/MI. + * Context representing a thread group of GDB/MI. */ - @Immutable - static class MIContainerDMC extends AbstractDMContext - implements IMIContainerDMContext, IDisassemblyDMContext - { + @Immutable + static class MIContainerDMC extends AbstractDMContext implements IMIContainerDMContext, IDisassemblyDMContext { /** * String ID that is used to identify the thread group in the GDB/MI protocol. */ @@ -219,7 +220,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Constructor for the context. It should not be called directly by clients. * Instead clients should call {@link IMIProcesses#createContainerContext * to create instances of this context based on the group name. - * + * * @param sessionId Session that this context belongs to. * @param processDmc The process context that is the parent of this context. * @param groupId GDB/MI thread group identifier. @@ -233,118 +234,129 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Returns the GDB/MI thread group identifier of this context. */ @Override - public String getGroupId(){ return fId; } + public String getGroupId() { + return fId; + } @Override - public String toString() { return baseToString() + ".threadGroup[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + public String toString() { + return baseToString() + ".threadGroup[" + fId + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } @Override public boolean equals(Object obj) { - return baseEquals(obj) && - (((MIContainerDMC)obj).fId == null ? fId == null : ((MIContainerDMC)obj).fId.equals(fId)); + return baseEquals(obj) + && (((MIContainerDMC) obj).fId == null ? fId == null : ((MIContainerDMC) obj).fId.equals(fId)); } @Override - public int hashCode() { return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); } + public int hashCode() { + return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); + } } - private static class GDBContainerDMC extends MIContainerDMC - implements IMemoryDMContext, IBreakpointsTargetDMContext - { + private static class GDBContainerDMC extends MIContainerDMC + implements IMemoryDMContext, IBreakpointsTargetDMContext { public GDBContainerDMC(String sessionId, IProcessDMContext processDmc, String groupId) { super(sessionId, processDmc, groupId); } } - + /** - * Context representing a thread. + * Context representing a thread. * @since 4.0 */ - @Immutable - protected static class MIThreadDMC extends AbstractDMContext - implements IThreadDMContext - { - /** - * ID used by GDB to refer to threads. - */ - private final String fId; - - /** - * Constructor for the context. It should not be called directly by clients. - * Instead clients should call {@link IMIProcesses#createThreadContext} - * to create instances of this context based on the thread ID. - * <p/> - * - * @param sessionId Session that this context belongs to. - * @param processDmc The process that this thread belongs to. - * @param id thread identifier. - */ - public MIThreadDMC(String sessionId, IProcessDMContext processDmc, String id) { + @Immutable + protected static class MIThreadDMC extends AbstractDMContext implements IThreadDMContext { + /** + * ID used by GDB to refer to threads. + */ + private final String fId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link IMIProcesses#createThreadContext} + * to create instances of this context based on the thread ID. + * <p/> + * + * @param sessionId Session that this context belongs to. + * @param processDmc The process that this thread belongs to. + * @param id thread identifier. + */ + public MIThreadDMC(String sessionId, IProcessDMContext processDmc, String id) { super(sessionId, processDmc == null ? new IDMContext[0] : new IDMContext[] { processDmc }); - fId = id; - } + fId = id; + } - /** - * Returns the thread identifier of this context. - * @return - */ - public String getId(){ return fId; } + /** + * Returns the thread identifier of this context. + * @return + */ + public String getId() { + return fId; + } - @Override - public String toString() { return baseToString() + ".OSthread[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + @Override + public String toString() { + return baseToString() + ".OSthread[" + fId + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } @Override public boolean equals(Object obj) { - return baseEquals(obj) && - (((MIThreadDMC)obj).fId == null ? fId == null : ((MIThreadDMC)obj).fId.equals(fId)); + return baseEquals(obj) + && (((MIThreadDMC) obj).fId == null ? fId == null : ((MIThreadDMC) obj).fId.equals(fId)); } @Override - public int hashCode() { return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); } - } - - @Immutable - private static class MIProcessDMC extends AbstractDMContext - implements IMIProcessDMContext - { - /** - * ID given by the OS. - */ - private final String fId; - - /** - * Constructor for the context. It should not be called directly by clients. - * Instead clients should call {@link IMIProcesses#createProcessContext} - * to create instances of this context based on the PID. - * <p/> - * - * @param sessionId Session that this context belongs to. - * @param controlDmc The control context parent of this process. - * @param id process identifier. - */ - public MIProcessDMC(String sessionId, ICommandControlDMContext controlDmc, String id) { + public int hashCode() { + return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); + } + } + + @Immutable + private static class MIProcessDMC extends AbstractDMContext implements IMIProcessDMContext { + /** + * ID given by the OS. + */ + private final String fId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link IMIProcesses#createProcessContext} + * to create instances of this context based on the PID. + * <p/> + * + * @param sessionId Session that this context belongs to. + * @param controlDmc The control context parent of this process. + * @param id process identifier. + */ + public MIProcessDMC(String sessionId, ICommandControlDMContext controlDmc, String id) { super(sessionId, controlDmc == null ? new IDMContext[0] : new IDMContext[] { controlDmc }); - fId = id; - } - - @Override - public String getProcId() { return fId; } + fId = id; + } + + @Override + public String getProcId() { + return fId; + } - @Override - public String toString() { return baseToString() + ".proc[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + @Override + public String toString() { + return baseToString() + ".proc[" + fId + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } @Override public boolean equals(Object obj) { // We treat the UNKNOWN_PROCESS_ID as a wildcard. Any processId (except null) will be considered // equal to the UNKNOWN_PROCESS_ID. This is important because before starting a process, we don't // have a pid yet, but we still need to create a process context, and we must use UNKNOWN_PROCESS_ID. - // Bug 336890 + // Bug 336890 if (!baseEquals(obj)) { return false; } - MIProcessDMC other = (MIProcessDMC)obj; + MIProcessDMC other = (MIProcessDMC) obj; if (fId == null || other.fId == null) { return fId == null && other.fId == null; } @@ -353,48 +365,51 @@ public class GDBProcesses_7_0 extends AbstractDsfService if (fId.equals(MIProcesses.UNKNOWN_PROCESS_ID) || other.fId.equals(MIProcesses.UNKNOWN_PROCESS_ID)) { return true; } - + return fId.equals(other.fId); } @Override - public int hashCode() { + public int hashCode() { // We cannot use fId in the hashCode. This is because we support // the wildCard MIProcesses.UNKNOWN_PROCESS_ID which is equal to any other fId. // But we also need the hashCode of the wildCard to be the same // as the one of all other fIds, which is why we need a constant hashCode // See bug 336890 - return baseHashCode(); - } - } - - /** - * A process context representing a process that has exited. - * Since an exited process no longer has a pid, we need another way - * of characterizing it. We use the groupId instead. - * Note that with GDB 7.0 and 7.1, the groupId is the pid, so that - * does not help us, but since we only handle single-process debugging - * for those versions of GDB, we don't need any id to know we are - * dealing with our single process. - * Starting with GDB 7.2, we handle multi-process, but then we - * can use the groupId as a persistent identifier of each process, - * even an exited one. - * @since 4.7 - */ - @Immutable - protected static class MIExitedProcessDMC extends MIProcessDMC - { - private final String fGroupId; - - public MIExitedProcessDMC(String sessionId, ICommandControlDMContext controlDmc, String pid, String groupId) { + return baseHashCode(); + } + } + + /** + * A process context representing a process that has exited. + * Since an exited process no longer has a pid, we need another way + * of characterizing it. We use the groupId instead. + * Note that with GDB 7.0 and 7.1, the groupId is the pid, so that + * does not help us, but since we only handle single-process debugging + * for those versions of GDB, we don't need any id to know we are + * dealing with our single process. + * Starting with GDB 7.2, we handle multi-process, but then we + * can use the groupId as a persistent identifier of each process, + * even an exited one. + * @since 4.7 + */ + @Immutable + protected static class MIExitedProcessDMC extends MIProcessDMC { + private final String fGroupId; + + public MIExitedProcessDMC(String sessionId, ICommandControlDMContext controlDmc, String pid, String groupId) { super(sessionId, controlDmc, pid); - fGroupId = groupId; - } - - public String getGroupId() { return fGroupId; } + fGroupId = groupId; + } + + public String getGroupId() { + return fGroupId; + } - @Override - public String toString() { return super.toString() + ".group[" + getGroupId() + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + @Override + public String toString() { + return super.toString() + ".group[" + getGroupId() + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } @Override public boolean equals(Object obj) { @@ -402,7 +417,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService return false; } - MIExitedProcessDMC other = (MIExitedProcessDMC)obj; + MIExitedProcessDMC other = (MIExitedProcessDMC) obj; if (fGroupId == null || other.fGroupId == null) { return fGroupId == null && other.fGroupId == null; } @@ -411,59 +426,67 @@ public class GDBProcesses_7_0 extends AbstractDsfService } @Override - public int hashCode() { + public int hashCode() { return super.hashCode() ^ (fGroupId == null ? 0 : fGroupId.hashCode()); } - } - - /** - * The data of a corresponding thread or process. - */ - @Immutable - protected static class MIThreadDMData implements IThreadDMData { - final String fName; - final String fId; - - public MIThreadDMData(String name, String id) { - fName = name; - fId = id; - } - - @Override - public String getId() { return fId; } - - @Override - public String getName() { return fName; } - - @Override + } + + /** + * The data of a corresponding thread or process. + */ + @Immutable + protected static class MIThreadDMData implements IThreadDMData { + final String fName; + final String fId; + + public MIThreadDMData(String name, String id) { + fName = name; + fId = id; + } + + @Override + public String getId() { + return fId; + } + + @Override + public String getName() { + return fName; + } + + @Override public boolean isDebuggerAttached() { return true; } - } - - /** - * The data corresponding to an exited process. - * @since 4.7 - */ - @Immutable - protected static class MIExitedProcessDMData implements IGdbThreadExitedDMData { - final String fName; - final String fId; - final Integer fExitCode; - - public MIExitedProcessDMData(String name, String id, Integer exitCode) { - fName = name; - fId = id; - fExitCode = exitCode; - } - - @Override - public String getId() { return fId; } - - @Override - public String getName() { return fName; } - - @Override + } + + /** + * The data corresponding to an exited process. + * @since 4.7 + */ + @Immutable + protected static class MIExitedProcessDMData implements IGdbThreadExitedDMData { + final String fName; + final String fId; + final Integer fExitCode; + + public MIExitedProcessDMData(String name, String id, Integer exitCode) { + fName = name; + fId = id; + fExitCode = exitCode; + } + + @Override + public String getId() { + return fId; + } + + @Override + public String getName() { + return fName; + } + + @Override public boolean isDebuggerAttached() { return false; } @@ -472,268 +495,277 @@ public class GDBProcesses_7_0 extends AbstractDsfService public Integer getExitCode() { return fExitCode; } - } - - /** - * This class provides an implementation of both a process context and process data. - * It is used to be able to return a list of processes including their data all at once. - * @since 4.0 - */ - @Immutable - protected static class MIProcessDMCAndData extends MIProcessDMC implements IGdbThreadDMData2 { - final String fName; - // Note that cores are only available from GDB 7.1. - final String[] fCores; - final String fOwner; - final String fDescription; - - public MIProcessDMCAndData(String sessionId, ICommandControlDMContext controlDmc, - String id, String name, String[] cores, String owner) { - this(sessionId, controlDmc, id, name, cores, owner, null); - } - - /** + } + + /** + * This class provides an implementation of both a process context and process data. + * It is used to be able to return a list of processes including their data all at once. + * @since 4.0 + */ + @Immutable + protected static class MIProcessDMCAndData extends MIProcessDMC implements IGdbThreadDMData2 { + final String fName; + // Note that cores are only available from GDB 7.1. + final String[] fCores; + final String fOwner; + final String fDescription; + + public MIProcessDMCAndData(String sessionId, ICommandControlDMContext controlDmc, String id, String name, + String[] cores, String owner) { + this(sessionId, controlDmc, id, name, cores, owner, null); + } + + /** * @since 5.6 */ - public MIProcessDMCAndData(String sessionId, ICommandControlDMContext controlDmc, - String id, String name, String[] cores, String owner, String description) { - super(sessionId, controlDmc, id); - fName = name; - fCores = cores; - fOwner = owner; - fDescription = description; - } - - @Override - public String getId() { return getProcId(); } - - @Override - public String getName() { return fName; } - - @Override - public String getDescription() { return fDescription; } - - @Override - public boolean isDebuggerAttached() { + public MIProcessDMCAndData(String sessionId, ICommandControlDMContext controlDmc, String id, String name, + String[] cores, String owner, String description) { + super(sessionId, controlDmc, id); + fName = name; + fCores = cores; + fOwner = owner; + fDescription = description; + } + + @Override + public String getId() { + return getProcId(); + } + + @Override + public String getName() { + return fName; + } + + @Override + public String getDescription() { + return fDescription; + } + + @Override + public boolean isDebuggerAttached() { return true; } - @Override - public String[] getCores() { return fCores; } + @Override + public String[] getCores() { + return fCores; + } - @Override - public String getOwner() { return fOwner; } + @Override + public String getOwner() { + return fOwner; + } @Override - public String toString() { return baseToString() + - ".proc[" + getId() + "," + getName() + "," + getOwner() + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ + public String toString() { + return baseToString() + ".proc[" + getId() + "," + getName() + "," + getOwner() + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ + } @Override public boolean equals(Object obj) { - return super.equals(obj) && - (((MIProcessDMCAndData)obj).fName == null ? fName == null : ((MIProcessDMCAndData)obj).fName.equals(fName)) && - (((MIProcessDMCAndData)obj).fOwner == null ? fOwner == null : ((MIProcessDMCAndData)obj).fOwner.equals(fOwner)); + return super.equals(obj) + && (((MIProcessDMCAndData) obj).fName == null ? fName == null + : ((MIProcessDMCAndData) obj).fName.equals(fName)) + && (((MIProcessDMCAndData) obj).fOwner == null ? fOwner == null + : ((MIProcessDMCAndData) obj).fOwner.equals(fOwner)); } @Override - public int hashCode() { return super.hashCode() ^ - (fName == null ? 0 : fName.hashCode()) ^ - (fOwner == null ? 0 : fOwner.hashCode()) ; } - } - - /** - * Event indicating that an container (debugged process) has started. This event - * implements the {@link IStartedMDEvent} from the IRunControl service. - */ - public static class ContainerStartedDMEvent extends AbstractDMEvent<IExecutionDMContext> - implements IStartedDMEvent - { - public ContainerStartedDMEvent(IContainerDMContext context) { - super(context); - } - } - - /** - * Event indicating that an container is no longer being debugged. This event - * implements the {@link IExitedMDEvent} from the IRunControl service. - */ - public static class ContainerExitedDMEvent extends AbstractDMEvent<IExecutionDMContext> - implements IExitedDMEvent - { - public ContainerExitedDMEvent(IContainerDMContext context) { - super(context); - } - } - - /** + public int hashCode() { + return super.hashCode() ^ (fName == null ? 0 : fName.hashCode()) ^ (fOwner == null ? 0 : fOwner.hashCode()); + } + } + + /** + * Event indicating that an container (debugged process) has started. This event + * implements the {@link IStartedMDEvent} from the IRunControl service. + */ + public static class ContainerStartedDMEvent extends AbstractDMEvent<IExecutionDMContext> + implements IStartedDMEvent { + public ContainerStartedDMEvent(IContainerDMContext context) { + super(context); + } + } + + /** + * Event indicating that an container is no longer being debugged. This event + * implements the {@link IExitedMDEvent} from the IRunControl service. + */ + public static class ContainerExitedDMEvent extends AbstractDMEvent<IExecutionDMContext> implements IExitedDMEvent { + public ContainerExitedDMEvent(IContainerDMContext context) { + super(context); + } + } + + /** * @since 4.7 */ - protected static class ProcessRemovedDMEvent extends AbstractDMEvent<IThreadDMContext> - implements IThreadRemovedDMEvent - { - public ProcessRemovedDMEvent(IProcessDMContext context) { - super(context); - } - } - - /** - * A map of thread id to thread group id. We use this to find out to which threadGroup a thread belongs. - */ - private Map<String, String> fThreadToGroupMap = new HashMap<String, String>(); - /** - * A map of thread group id to process id. We use this to find out to which pid a group refers. - */ - private Map<String, String> fGroupToPidMap = new HashMap<String, String>(); - - private IGDBControl fCommandControl; - private IGDBBackend fBackend; - private CommandFactory fCommandFactory; - - // A cache for commands about the threadGroups + protected static class ProcessRemovedDMEvent extends AbstractDMEvent<IThreadDMContext> + implements IThreadRemovedDMEvent { + public ProcessRemovedDMEvent(IProcessDMContext context) { + super(context); + } + } + + /** + * A map of thread id to thread group id. We use this to find out to which threadGroup a thread belongs. + */ + private Map<String, String> fThreadToGroupMap = new HashMap<String, String>(); + /** + * A map of thread group id to process id. We use this to find out to which pid a group refers. + */ + private Map<String, String> fGroupToPidMap = new HashMap<String, String>(); + + private IGDBControl fCommandControl; + private IGDBBackend fBackend; + private CommandFactory fCommandFactory; + + // A cache for commands about the threadGroups private CommandCache fContainerCommandCache; //A cache for commands about the threads private CommandCache fThreadCommandCache; - + // A temporary cache to avoid using -list-thread-groups --available more than once at the same time. // We cannot cache this command because it lists all available processes, which can // change at any time. However, it is inefficient to send more than one of this command at // the same time. This cache will help us avoid that. The idea is that we cache the command, - // but as soon as it returns, we clear the cache. So the cache will only trigger for those + // but as soon as it returns, we clear the cache. So the cache will only trigger for those // overlapping situations. Using this cache also allows to handle the all-stop case // when the target can be unavailable and instead of hanging, the cache will return an error. private CommandCache fListThreadGroupsAvailableCache; - // A map of process id to process names. A name is fetched whenever we start + // A map of process id to process names. A name is fetched whenever we start // debugging a process, and removed when we stop. // This allows us to make sure that if a pid is re-used, we will not use an // old name for it. Bug 275497 // This map also serves as a list of processes we are currently debugging. // This is important because we cannot always ask GDB for the list, since it may // be running at the time. Bug 303503 - private Map<String, String> fDebuggedProcessesAndNames = new HashMap<>(); - - /** - * A map that keeps track of the PTY associated with an inferior (groupId) - */ - private Map<String, PTY> fGroupIdToPTYMap = new HashMap<>(); - /** - * A list of groupIds that have exited. - */ - private List<String> fExitedGroupId = new ArrayList<>(); - - /** - * Information about an exited process - * @since 4.7 - */ - protected class ExitedProcInfo { - private String pid; - private String name; - private Integer exitCode; - - public ExitedProcInfo(String aPid, String aName) { - pid = aPid; - name = aName; - } - - protected String getPid() { - return pid; - } - - protected String getName() { - return name; - } - - protected Integer getExitCode() { + private Map<String, String> fDebuggedProcessesAndNames = new HashMap<>(); + + /** + * A map that keeps track of the PTY associated with an inferior (groupId) + */ + private Map<String, PTY> fGroupIdToPTYMap = new HashMap<>(); + /** + * A list of groupIds that have exited. + */ + private List<String> fExitedGroupId = new ArrayList<>(); + + /** + * Information about an exited process + * @since 4.7 + */ + protected class ExitedProcInfo { + private String pid; + private String name; + private Integer exitCode; + + public ExitedProcInfo(String aPid, String aName) { + pid = aPid; + name = aName; + } + + protected String getPid() { + return pid; + } + + protected String getName() { + return name; + } + + protected Integer getExitCode() { return exitCode; } - - protected void setExitCode(Integer code) { + + protected void setExitCode(Integer code) { exitCode = code; } - } - - /** - * A LRU (least-recently-used) map that limits the amount of exited process list. - * Once the limit is reached, oldest exited processes are automatically removed - * when new ones are inserted. This avoids the risk of growing the list - * of exited processes too much and showing too many in the debug view. - */ - private class LRUExitedProcessMap extends LinkedHashMap<String, ExitedProcInfo> { - public static final long serialVersionUID = 0; - - @Override - protected boolean removeEldestEntry(Entry<String, ExitedProcInfo> eldest) { - return size() > MAX_NUMBER_EXITED_PROCESS; - } - } - - /** - * Map of groupId to ExitedProcInfo. - * This map contains the information of each process that has exited. - * Note that we must maintain this information ourselves since GDB - * sometimes prunes its list of inferiors, which implies we cannot - * count on GDB to keep track of exited processes. - */ - private Map<String, ExitedProcInfo> fProcExitedMap = new LRUExitedProcessMap(); - - /** - * Set of groupId of processes that we detached from. - * The content is very short-lived as it is only kept until - * we receive the =thread-group-exited event from GDB - * and need to know if the process in question was detached from. - * Using this set, we can know if we should store the process - * in the fExitedProcesses map or not. - */ - private Set<String> fProcDetachedSet = new HashSet<>(); - - private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$ - - /** - * Keeps track of how many processes we are currently connected to - */ - private int fNumConnected; - - /** - * Keeps track if we are dealing with the very first process of GDB. - */ - private boolean fInitialProcess = true; - - public GDBProcesses_7_0(DsfSession session) { - super(session); - } - - /** - * This method initializes this service. - * - * @param requestMonitor - * The request monitor indicating the operation is finished - */ - @Override - public void initialize(final RequestMonitor requestMonitor) { - super.initialize(new ImmediateRequestMonitor(requestMonitor) { - @Override - protected void handleSuccess() { - doInitialize(requestMonitor); + } + + /** + * A LRU (least-recently-used) map that limits the amount of exited process list. + * Once the limit is reached, oldest exited processes are automatically removed + * when new ones are inserted. This avoids the risk of growing the list + * of exited processes too much and showing too many in the debug view. + */ + private class LRUExitedProcessMap extends LinkedHashMap<String, ExitedProcInfo> { + public static final long serialVersionUID = 0; + + @Override + protected boolean removeEldestEntry(Entry<String, ExitedProcInfo> eldest) { + return size() > MAX_NUMBER_EXITED_PROCESS; + } + } + + /** + * Map of groupId to ExitedProcInfo. + * This map contains the information of each process that has exited. + * Note that we must maintain this information ourselves since GDB + * sometimes prunes its list of inferiors, which implies we cannot + * count on GDB to keep track of exited processes. + */ + private Map<String, ExitedProcInfo> fProcExitedMap = new LRUExitedProcessMap(); + + /** + * Set of groupId of processes that we detached from. + * The content is very short-lived as it is only kept until + * we receive the =thread-group-exited event from GDB + * and need to know if the process in question was detached from. + * Using this set, we can know if we should store the process + * in the fExitedProcesses map or not. + */ + private Set<String> fProcDetachedSet = new HashSet<>(); + + private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$ + + /** + * Keeps track of how many processes we are currently connected to + */ + private int fNumConnected; + + /** + * Keeps track if we are dealing with the very first process of GDB. + */ + private boolean fInitialProcess = true; + + public GDBProcesses_7_0(DsfSession session) { + super(session); + } + + /** + * This method initializes this service. + * + * @param requestMonitor + * The request monitor indicating the operation is finished + */ + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new ImmediateRequestMonitor(requestMonitor) { + @Override + protected void handleSuccess() { + doInitialize(requestMonitor); } }); } - + /** * This method initializes this service after our superclass's initialize() * method succeeds. - * + * * @param requestMonitor * The call-back object to notify when this service's * initialization is done. */ private void doInitialize(RequestMonitor requestMonitor) { - + fCommandControl = getServicesTracker().getService(IGDBControl.class); - fBackend = getServicesTracker().getService(IGDBBackend.class); - BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fCommandControl, getExecutor(), 2); + fBackend = getServicesTracker().getService(IGDBBackend.class); + BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fCommandControl, getExecutor(), 2); - fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); + fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); // These caches store the result of a command when received; also, these caches // are manipulated when receiving events. Currently, events are received after @@ -743,45 +775,41 @@ public class GDBProcesses_7_0 extends AbstractDsfService // To solve this, we use a bufferedCommandControl that will delay the command // result by two scheduling of the executor. // See bug 280461 - fContainerCommandCache = new CommandCache(getSession(), bufferedCommandControl); - fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); - fThreadCommandCache = new CommandCache(getSession(), bufferedCommandControl); - fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true); - - // No need to use the bufferedCommandControl for the listThreadGroups cache - // because it is not being affected by events. - fListThreadGroupsAvailableCache = new CommandCache(getSession(), fCommandControl); - fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true); - - getSession().addServiceEventListener(this, null); - fCommandControl.addEventListener(this); + fContainerCommandCache = new CommandCache(getSession(), bufferedCommandControl); + fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); + fThreadCommandCache = new CommandCache(getSession(), bufferedCommandControl); + fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true); + + // No need to use the bufferedCommandControl for the listThreadGroups cache + // because it is not being affected by events. + fListThreadGroupsAvailableCache = new CommandCache(getSession(), fCommandControl); + fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true); + + getSession().addServiceEventListener(this, null); + fCommandControl.addEventListener(this); // Register this service. - register(new String[] { IProcesses.class.getName(), - IMIProcesses.class.getName(), - IGDBProcesses.class.getName(), - GDBProcesses_7_0.class.getName() }, - new Hashtable<String, String>()); - + register(new String[] { IProcesses.class.getName(), IMIProcesses.class.getName(), IGDBProcesses.class.getName(), + GDBProcesses_7_0.class.getName() }, new Hashtable<String, String>()); + requestMonitor.done(); } - /** * This method shuts down this service. It unregisters the service, stops * receiving service events, and calls the superclass shutdown() method to * finish the shutdown process. - * + * * @return void */ @Override public void shutdown(RequestMonitor requestMonitor) { unregister(); - getSession().removeServiceEventListener(this); - fCommandControl.removeEventListener(this); + getSession().removeServiceEventListener(this); + fCommandControl.removeEventListener(this); super.shutdown(requestMonitor); } - + /** * @return The bundle context of the plug-in to which this service belongs. */ @@ -789,12 +817,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService protected BundleContext getBundleContext() { return GdbPlugin.getBundleContext(); } - + /** @since 4.0 */ protected Map<String, String> getThreadToGroupMap() { return fThreadToGroupMap; } - + /** @since 4.0 */ protected Map<String, String> getGroupToPidMap() { return fGroupToPidMap; @@ -819,7 +847,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService protected void setIsInitialProcess(boolean isInitial) { fInitialProcess = isInitial; } - + /**@since 4.7 */ protected Map<String, ExitedProcInfo> getExitedProcesses() { return fProcExitedMap; @@ -829,14 +857,15 @@ public class GDBProcesses_7_0 extends AbstractDsfService protected Set<String> getDetachedProcesses() { return fProcDetachedSet; } - - /** + + /** * Returns the groupId that is associated with the provided pId - * @since 4.0 + * @since 4.0 */ protected String getGroupFromPid(String pid) { - if (pid == null) return null; - + if (pid == null) + return null; + for (Map.Entry<String, String> entry : getGroupToPidMap().entrySet()) { if (pid.equals(entry.getValue())) { return entry.getKey(); @@ -844,135 +873,136 @@ public class GDBProcesses_7_0 extends AbstractDsfService } return null; } - + @Override - public IThreadDMContext createThreadContext(IProcessDMContext processDmc, String threadId) { - return new MIThreadDMC(getSession().getId(), processDmc, threadId); - } + public IThreadDMContext createThreadContext(IProcessDMContext processDmc, String threadId) { + return new MIThreadDMC(getSession().getId(), processDmc, threadId); + } @Override - public IProcessDMContext createProcessContext(ICommandControlDMContext controlDmc, String pid) { - return new MIProcessDMC(getSession().getId(), controlDmc, pid); - } - + public IProcessDMContext createProcessContext(ICommandControlDMContext controlDmc, String pid) { + return new MIProcessDMC(getSession().getId(), controlDmc, pid); + } + /** * Create a special context describing a process that has exited. * @param controlDmc Its parent context. * @param groupId The GDB groupId to which this process refers to. Since an exited process no longer * has a pid, we use this id to characterize it uniquely. - * Note that with GDB 7.0 and 7.1, the groupId is the pid, so that - * does not help us, but since we only handle single-process debugging - * for those versions of GDB, we don't need any id to know we are - * dealing with our single process. - * Starting with GDB 7.2, we handle multi-process, but then we - * can use the groupId as a persistent identifier of each process, - * even an exited one. + * Note that with GDB 7.0 and 7.1, the groupId is the pid, so that + * does not help us, but since we only handle single-process debugging + * for those versions of GDB, we don't need any id to know we are + * dealing with our single process. + * Starting with GDB 7.2, we handle multi-process, but then we + * can use the groupId as a persistent identifier of each process, + * even an exited one. */ - private IProcessDMContext createExitedProcessContext(ICommandControlDMContext controlDmc, String pid, String groupId) { - return new MIExitedProcessDMC(getSession().getId(), controlDmc, pid, groupId); - } - + private IProcessDMContext createExitedProcessContext(ICommandControlDMContext controlDmc, String pid, + String groupId) { + return new MIExitedProcessDMC(getSession().getId(), controlDmc, pid, groupId); + } + @Override - public IMIExecutionDMContext createExecutionContext(IContainerDMContext containerDmc, - IThreadDMContext threadDmc, - String threadId) { - return new MIExecutionDMC(getSession().getId(), containerDmc, threadDmc, threadId); - } + public IMIExecutionDMContext createExecutionContext(IContainerDMContext containerDmc, IThreadDMContext threadDmc, + String threadId) { + return new MIExecutionDMC(getSession().getId(), containerDmc, threadDmc, threadId); + } @Override - public IMIContainerDMContext createContainerContext(IProcessDMContext processDmc, - String groupId) { - return new GDBContainerDMC(getSession().getId(), processDmc, groupId); - } + public IMIContainerDMContext createContainerContext(IProcessDMContext processDmc, String groupId) { + return new GDBContainerDMC(getSession().getId(), processDmc, groupId); + } @Override - public IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, String threadId) { - String groupId = getThreadToGroupMap().get(threadId); - if (groupId == null) { - // this can happen if the threadId was 'all' - // In such a case, we choose the first process we find - // This works when we run a single process - // but will break for multi-process!!! - if (getThreadToGroupMap().isEmpty()) { - groupId = MIProcesses.UNIQUE_GROUP_ID; - } else { - Collection<String> values = getThreadToGroupMap().values(); - for (String value : values) { - groupId = value; - break; - } - } - } - - return createContainerContextFromGroupId(controlDmc, groupId); - } - - /** @since 4.0 */ + public IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, + String threadId) { + String groupId = getThreadToGroupMap().get(threadId); + if (groupId == null) { + // this can happen if the threadId was 'all' + // In such a case, we choose the first process we find + // This works when we run a single process + // but will break for multi-process!!! + if (getThreadToGroupMap().isEmpty()) { + groupId = MIProcesses.UNIQUE_GROUP_ID; + } else { + Collection<String> values = getThreadToGroupMap().values(); + for (String value : values) { + groupId = value; + break; + } + } + } + + return createContainerContextFromGroupId(controlDmc, groupId); + } + + /** @since 4.0 */ @Override - public IMIContainerDMContext createContainerContextFromGroupId(ICommandControlDMContext controlDmc, String groupId) { - if (groupId == null || groupId.length() == 0) { - // This happens when we are doing non-attach, so for GDB < 7.2, we know that in that case - // we are single process, so lets see if we have the group in our map. - assert getGroupToPidMap().size() <= 1 : "More than one process in our map"; //$NON-NLS-1$ - if (getGroupToPidMap().size() == 1) { - for (String key : getGroupToPidMap().keySet()) { - groupId = key; - break; - } - } - } - - String pid = getGroupToPidMap().get(groupId); - if (pid == null) { - // For GDB 7.0 and 7.1, the groupId is the pid, so we can use it directly - pid = groupId; - } - IProcessDMContext processDmc = createProcessContext(controlDmc, pid); - return createContainerContext(processDmc, groupId); - } - + public IMIContainerDMContext createContainerContextFromGroupId(ICommandControlDMContext controlDmc, + String groupId) { + if (groupId == null || groupId.length() == 0) { + // This happens when we are doing non-attach, so for GDB < 7.2, we know that in that case + // we are single process, so lets see if we have the group in our map. + assert getGroupToPidMap().size() <= 1 : "More than one process in our map"; //$NON-NLS-1$ + if (getGroupToPidMap().size() == 1) { + for (String key : getGroupToPidMap().keySet()) { + groupId = key; + break; + } + } + } + + String pid = getGroupToPidMap().get(groupId); + if (pid == null) { + // For GDB 7.0 and 7.1, the groupId is the pid, so we can use it directly + pid = groupId; + } + IProcessDMContext processDmc = createProcessContext(controlDmc, pid); + return createContainerContext(processDmc, groupId); + } + @Override - public IMIExecutionDMContext[] getExecutionContexts(IMIContainerDMContext containerDmc) { + public IMIExecutionDMContext[] getExecutionContexts(IMIContainerDMContext containerDmc) { if (isExitedProcess(containerDmc)) { // No threads for an exited process return new IMIExecutionDMContext[0]; } - - String groupId = containerDmc.getGroupId(); - List<IMIExecutionDMContext> execDmcList = new ArrayList<IMIExecutionDMContext>(); - Iterator<Map.Entry<String, String>> iterator = getThreadToGroupMap().entrySet().iterator(); - while (iterator.hasNext()){ - Map.Entry<String, String> entry = iterator.next(); - if (entry.getValue().equals(groupId)) { - String threadId = entry.getKey(); - IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class); - IMIExecutionDMContext execDmc = createExecutionContext(containerDmc, - createThreadContext(procDmc, threadId), - threadId); - execDmcList.add(execDmc); - } - } - return execDmcList.toArray(new IMIExecutionDMContext[0]); - } + + String groupId = containerDmc.getGroupId(); + List<IMIExecutionDMContext> execDmcList = new ArrayList<IMIExecutionDMContext>(); + Iterator<Map.Entry<String, String>> iterator = getThreadToGroupMap().entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry<String, String> entry = iterator.next(); + if (entry.getValue().equals(groupId)) { + String threadId = entry.getKey(); + IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class); + IMIExecutionDMContext execDmc = createExecutionContext(containerDmc, + createThreadContext(procDmc, threadId), threadId); + execDmcList.add(execDmc); + } + } + return execDmcList.toArray(new IMIExecutionDMContext[0]); + } @Override public void getExecutionData(IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) { if (dmc instanceof MIExitedProcessDMC) { - ExitedProcInfo info = getExitedProcesses().get(((MIExitedProcessDMC)dmc).getGroupId()); + ExitedProcInfo info = getExitedProcesses().get(((MIExitedProcessDMC) dmc).getGroupId()); if (info != null) { rm.done(new MIExitedProcessDMData(info.getName(), info.getPid(), info.getExitCode())); } else { // This can happen for example, when restarting an exited process, // where we've deleted the process from our table, but it has // yet to be cleaned up from the view - rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Unavailable info about exited process", null)); //$NON-NLS-1$ + rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, + "Unavailable info about exited process", null)); //$NON-NLS-1$ } - + return; } - + if (dmc instanceof IMIProcessDMContext) { - String id = ((IMIProcessDMContext)dmc).getProcId(); + String id = ((IMIProcessDMContext) dmc).getProcId(); String name = null; if (fBackend.getSessionType() == SessionType.CORE || "42000".equals(id)) { //$NON-NLS-1$ // For the Core session, the process is no longer running. @@ -1001,273 +1031,285 @@ public class GDBProcesses_7_0 extends AbstractDsfService // GDB is debugging a new process. Let's fetch its // name and remember it. In order to get the name, // we have to request all running processes, not - // just the ones being debugged. We got a lot more + // just the ones being debugged. We got a lot more // information when we request all processes. - final String finalPId = id; + final String finalPId = id; fListThreadGroupsAvailableCache.execute( - fCommandFactory.createMIListThreadGroups(fCommandControl.getContext(), true), - new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), null) { - @Override - protected void handleCompleted() { - // We cannot actually cache this command since the process - // list may change. But this cache allows to avoid overlapping - // sending of this command and proper handling if the target is - // unavailable. - fListThreadGroupsAvailableCache.reset(); - - // Note that the output of the "-list-thread-groups --available" command - // still shows the pid as a groupId, even for GDB 7.2. - String name = null; - if (isSuccess()) { - for (IThreadGroupInfo groupInfo : getData().getGroupList()) { - if (groupInfo.getPid().equals(finalPId)) { - name = groupInfo.getName(); - fDebuggedProcessesAndNames.put(finalPId, name); - break; + fCommandFactory.createMIListThreadGroups(fCommandControl.getContext(), true), + new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), null) { + @Override + protected void handleCompleted() { + // We cannot actually cache this command since the process + // list may change. But this cache allows to avoid overlapping + // sending of this command and proper handling if the target is + // unavailable. + fListThreadGroupsAvailableCache.reset(); + + // Note that the output of the "-list-thread-groups --available" command + // still shows the pid as a groupId, even for GDB 7.2. + String name = null; + if (isSuccess()) { + for (IThreadGroupInfo groupInfo : getData().getGroupList()) { + if (groupInfo.getPid().equals(finalPId)) { + name = groupInfo.getName(); + fDebuggedProcessesAndNames.put(finalPId, name); + break; + } + } + } else { + // Looks like this gdb doesn't truly support + // "-list-thread-groups --available". Get the + // process list natively if we're debugging locally + if (fBackend.getSessionType() == SessionType.LOCAL) { + try { + IProcessList list = CCorePlugin.getDefault().getProcessList(); + if (list != null) { + int pId_int = Integer.parseInt(finalPId); + for (IProcessInfo procInfo : list.getProcessList()) { + if (procInfo.getPid() == pId_int) { + name = procInfo.getName(); + fDebuggedProcessesAndNames.put(finalPId, name); + break; + } + } + } + } catch (Exception e) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + REQUEST_FAILED, "Could not get process name", e)); //$NON-NLS-1$ + } } } - } else { - // Looks like this gdb doesn't truly support - // "-list-thread-groups --available". Get the - // process list natively if we're debugging locally - if (fBackend.getSessionType() == SessionType.LOCAL) { - try { - IProcessList list = CCorePlugin.getDefault().getProcessList(); - if (list != null) { - int pId_int = Integer.parseInt(finalPId); - for (IProcessInfo procInfo : list.getProcessList()) { - if (procInfo.getPid() == pId_int) { - name = procInfo.getName(); - fDebuggedProcessesAndNames.put(finalPId, name); - break; - } - } - } - } catch (Exception e) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Could not get process name", e)); //$NON-NLS-1$ - } - } - } - - if (name == null) { - // No way to get the name right now, so use the binary file name (absolute path) - name = fBackend.getProgramPath().toOSString(); - fDebuggedProcessesAndNames.put(finalPId, name); + + if (name == null) { + // No way to get the name right now, so use the binary file name (absolute path) + name = fBackend.getProgramPath().toOSString(); + fDebuggedProcessesAndNames.put(finalPId, name); + } + rm.done(new MIThreadDMData(name, finalPId)); } - rm.done(new MIThreadDMData(name, finalPId)); - } - }); + }); return; } } else { // We don't have the name in our map. This could happen - // if a process has terminated but the + // if a process has terminated but the // debug session is not terminated because the preference // to keep GDB running has been selected or because there // are other processes part of that session. - name = "Unknown name"; //$NON-NLS-1$ + name = "Unknown name"; //$NON-NLS-1$ } } rm.setData(new MIThreadDMData(name, id)); - rm.done(); + rm.done(); } else if (dmc instanceof MIThreadDMC) { - final MIThreadDMC threadDmc = (MIThreadDMC)dmc; - + final MIThreadDMC threadDmc = (MIThreadDMC) dmc; + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); - fThreadCommandCache.execute(fCommandFactory.createMIThreadInfo(controlDmc, threadDmc.getId()), - new DataRequestMonitor<MIThreadInfoInfo>(getExecutor(), rm) { - @Override - protected void handleSuccess() { - IThreadDMData threadData = null; - if (getData().getThreadList().length != 0) { - MIThread thread = getData().getThreadList()[0]; - if (thread.getThreadId().equals(threadDmc.getId())) { - String id = ""; //$NON-NLS-1$ - if (thread.getOsId() != null) { - id = thread.getOsId(); - } - // append thread details (if any) to the thread ID - // as for GDB 6.x with CLIInfoThreadsInfo#getOsId() - final String details = thread.getDetails(); - if (details != null && !details.isEmpty()) { - if (!id.isEmpty()) id += " "; //$NON-NLS-1$ - id += "(" + details + ")"; //$NON-NLS-1$ //$NON-NLS-2$ - } - // We must indicate and empty id by using null - if (id.isEmpty()) id = null; - - threadData = new MIThreadDMData("", id); //$NON-NLS-1$ - } - } - - if (threadData != null) { - rm.setData(threadData); - } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Could not get thread info", null)); //$NON-NLS-1$ - } - rm.done(); - } - }); + fThreadCommandCache.execute(fCommandFactory.createMIThreadInfo(controlDmc, threadDmc.getId()), + new DataRequestMonitor<MIThreadInfoInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + IThreadDMData threadData = null; + if (getData().getThreadList().length != 0) { + MIThread thread = getData().getThreadList()[0]; + if (thread.getThreadId().equals(threadDmc.getId())) { + String id = ""; //$NON-NLS-1$ + if (thread.getOsId() != null) { + id = thread.getOsId(); + } + // append thread details (if any) to the thread ID + // as for GDB 6.x with CLIInfoThreadsInfo#getOsId() + final String details = thread.getDetails(); + if (details != null && !details.isEmpty()) { + if (!id.isEmpty()) + id += " "; //$NON-NLS-1$ + id += "(" + details + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + // We must indicate and empty id by using null + if (id.isEmpty()) + id = null; + + threadData = new MIThreadDMData("", id); //$NON-NLS-1$ + } + } + + if (threadData != null) { + rm.setData(threadData); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Could not get thread info", null)); //$NON-NLS-1$ + } + rm.done(); + } + }); } else { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DMC type", null)); //$NON-NLS-1$ rm.done(); } } - + @Override - public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor<IDMContext> rm) { - if (dmc instanceof MIExitedProcessDMC) { - MIExitedProcessDMC exitedProc = (MIExitedProcessDMC)dmc; + public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor<IDMContext> rm) { + if (dmc instanceof MIExitedProcessDMC) { + MIExitedProcessDMC exitedProc = (MIExitedProcessDMC) dmc; IMIContainerDMContext containerDmc = createContainerContext(exitedProc, exitedProc.getGroupId()); - rm.setData(containerDmc); - } else if (dmc instanceof MIProcessDMC) { - MIProcessDMC procDmc = (MIProcessDMC)dmc; + rm.setData(containerDmc); + } else if (dmc instanceof MIProcessDMC) { + MIProcessDMC procDmc = (MIProcessDMC) dmc; IMIContainerDMContext containerDmc = createContainerContext(procDmc, getGroupFromPid(procDmc.getProcId())); - rm.setData(containerDmc); - } else if (dmc instanceof MIThreadDMC) { - MIThreadDMC threadDmc = (MIThreadDMC)dmc; - IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); + rm.setData(containerDmc); + } else if (dmc instanceof MIThreadDMC) { + MIThreadDMC threadDmc = (MIThreadDMC) dmc; + IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); IMIContainerDMContext containerDmc = createContainerContext(procDmc, getGroupFromPid(procDmc.getProcId())); - rm.setData(createExecutionContext(containerDmc, threadDmc, threadDmc.getId())); - } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid thread context.", null)); //$NON-NLS-1$ - } - - rm.done(); - } - - /** @since 4.0 */ - protected boolean doIsDebuggerAttachSupported() { - return fBackend.getIsAttachSession() && fNumConnected == 0; - } - + rm.setData(createExecutionContext(containerDmc, threadDmc, threadDmc.getId())); + } else { + rm.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid thread context.", null)); //$NON-NLS-1$ + } + + rm.done(); + } + + /** @since 4.0 */ + protected boolean doIsDebuggerAttachSupported() { + return fBackend.getIsAttachSession() && fNumConnected == 0; + } + @Override - public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) { - rm.setData(doIsDebuggerAttachSupported()); - rm.done(); - } + public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) { + rm.setData(doIsDebuggerAttachSupported()); + rm.done(); + } @Override - public void attachDebuggerToProcess(IProcessDMContext procCtx, DataRequestMonitor<IDMContext> rm) { + public void attachDebuggerToProcess(IProcessDMContext procCtx, DataRequestMonitor<IDMContext> rm) { attachDebuggerToProcess(procCtx, null, rm); } - - /** + + /** * @since 4.0 */ @Override - public void attachDebuggerToProcess(final IProcessDMContext procCtx, final String binaryPath, final DataRequestMonitor<IDMContext> dataRm) { + public void attachDebuggerToProcess(final IProcessDMContext procCtx, final String binaryPath, + final DataRequestMonitor<IDMContext> dataRm) { if (procCtx instanceof IMIProcessDMContext) { - if (!doIsDebuggerAttachSupported()) { - dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$ - dataRm.done(); - return; - } - - // 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) { - - 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); - - if (binaryPath != null) { - fCommandControl.queueCommand( - fCommandFactory.createMIFileExecAndSymbols(fContainerDmc, binaryPath), - new ImmediateDataRequestMonitor<MIInfo>(rm)); - return; - } - - rm.done(); - } - }, - // Attach to the process - new Step() { - @Override - public void execute(RequestMonitor rm) { - // For non-stop mode, we do a non-interrupting attach - // Bug 333284 - boolean shouldInterrupt = true; + if (!doIsDebuggerAttachSupported()) { + dataRm.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$ + dataRm.done(); + return; + } + + // 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) { + + 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); + + if (binaryPath != null) { + fCommandControl.queueCommand( + fCommandFactory.createMIFileExecAndSymbols(fContainerDmc, binaryPath), + new ImmediateDataRequestMonitor<MIInfo>(rm)); + return; + } + + rm.done(); + } + }, + // Attach to the process + new Step() { + @Override + public void execute(RequestMonitor rm) { + // For non-stop mode, we do a non-interrupting attach + // Bug 333284 + boolean shouldInterrupt = true; IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class); if (runControl != null && runControl.getRunMode() == MIRunMode.NON_STOP) { shouldInterrupt = false; } - fCommandControl.queueCommand( - fCommandFactory.createMITargetAttach(fContainerDmc, ((IMIProcessDMContext)procCtx).getProcId(), shouldInterrupt), - new DataRequestMonitor<MIInfo>(getExecutor(), rm)); - } - }, - new Step() { - @Override - public void execute(RequestMonitor rm) { + fCommandControl.queueCommand( + fCommandFactory.createMITargetAttach(fContainerDmc, + ((IMIProcessDMContext) procCtx).getProcId(), shouldInterrupt), + 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); + fContainerDmc = createContainerContext(procCtx, + getGroupFromPid(((IMIProcessDMContext) procCtx).getProcId())); + + // Store the fully formed container context so it can be returned to the caller. + dataRm.setData(fContainerDmc); // Initialize memory data for this process. IGDBMemory memory = getServicesTracker().getService(IGDBMemory.class); - IMemoryDMContext memContext = DMContexts.getAncestorOfType(fContainerDmc, IMemoryDMContext.class); + IMemoryDMContext memContext = DMContexts.getAncestorOfType(fContainerDmc, + IMemoryDMContext.class); if (memory == null || memContext == null) { rm.done(); return; } memory.initializeMemoryData(memContext, rm); - } - }, - new Step() { - @Override - public void execute(RequestMonitor rm) { + } + }, new Step() { + @Override + public void execute(RequestMonitor rm) { // Start tracking breakpoints. - MIBreakpointsManager bpmService = getServicesTracker().getService(MIBreakpointsManager.class); + MIBreakpointsManager bpmService = getServicesTracker() + .getService(MIBreakpointsManager.class); bpmService.startTrackingBpForProcess(fContainerDmc, rm); - } - }, - // Turn on reverse debugging if it was enabled as a launch option - new Step() { - @Override - public void execute(RequestMonitor rm) { + } + }, + // Turn on reverse debugging if it was enabled as a launch option + new Step() { + @Override + public void execute(RequestMonitor rm) { doReverseDebugStep(procCtx, rm); - } - }, - }; + } + }, }; - @Override public Step[] getSteps() { return steps; } - }); - } else { - dataRm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ - dataRm.done(); - } + @Override + public Step[] getSteps() { + return steps; + } + }); + } else { + dataRm.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ + dataRm.done(); + } } /** @since 5.0 */ protected void doReverseDebugStep(final IProcessDMContext procCtx, RequestMonitor rm) { - // Turn on reverse debugging if it was enabled as a launch option + // Turn on reverse debugging if it was enabled as a launch option IReverseRunControl reverseService = getServicesTracker().getService(IReverseRunControl.class); if (reverseService != null) { ILaunch launch = procCtx.getAdapter(ILaunch.class); if (launch != null) { try { - boolean reverseEnabled = - launch.getLaunchConfiguration().getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, - IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); + boolean reverseEnabled = launch.getLaunchConfiguration().getAttribute( + IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_REVERSE, + IGDBLaunchConfigurationConstants.DEBUGGER_REVERSE_DEFAULT); if (reverseEnabled) { reverseService.enableReverseMode(fCommandControl.getContext(), true, rm); return; @@ -1280,29 +1322,29 @@ public class GDBProcesses_7_0 extends AbstractDsfService rm.done(); } - /** @since 4.0 */ - protected boolean doCanDetachDebuggerFromProcess() { - return fNumConnected > 0; - } - - private boolean isExitedProcess(IDMContext dmc) { - return DMContexts.getAncestorOfType(dmc, MIExitedProcessDMC.class) != null; - } - + /** @since 4.0 */ + protected boolean doCanDetachDebuggerFromProcess() { + return fNumConnected > 0; + } + + private boolean isExitedProcess(IDMContext dmc) { + return DMContexts.getAncestorOfType(dmc, MIExitedProcessDMC.class) != null; + } + @Override - public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) { + public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) { MIExitedProcessDMC exitedProc = DMContexts.getAncestorOfType(dmc, MIExitedProcessDMC.class); if (exitedProc != null) { // Allow to use the disconnect button to remove an exited process rm.done(true); return; } - rm.done(doCanDetachDebuggerFromProcess()); - } + rm.done(doCanDetachDebuggerFromProcess()); + } @Override - public void detachDebuggerFromProcess(final IDMContext dmc, final RequestMonitor rm) { - MIExitedProcessDMC exitedProc = DMContexts.getAncestorOfType(dmc, MIExitedProcessDMC.class); + public void detachDebuggerFromProcess(final IDMContext dmc, final RequestMonitor rm) { + MIExitedProcessDMC exitedProc = DMContexts.getAncestorOfType(dmc, MIExitedProcessDMC.class); if (exitedProc != null) { // For an exited process, remove the entry from our table to stop showing it, and // remove the entry from the launch itself to remove the process's console @@ -1312,16 +1354,17 @@ public class GDBProcesses_7_0 extends AbstractDsfService getSession().dispatchEvent(new ProcessRemovedDMEvent(exitedProc), null); return; } - - ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); - final IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); - if (controlDmc != null && procDmc != null) { - if (!doCanDetachDebuggerFromProcess()) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Detach not supported.", null)); //$NON-NLS-1$ - rm.done(); - return; - } + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); + final IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); + + if (controlDmc != null && procDmc != null) { + if (!doCanDetachDebuggerFromProcess()) { + rm.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Detach not supported.", null)); //$NON-NLS-1$ + rm.done(); + return; + } IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class); if (runControl != null && !runControl.isTargetAcceptingCommands()) { @@ -1334,22 +1377,21 @@ public class GDBProcesses_7_0 extends AbstractDsfService if (containerDmc != null) { getDetachedProcesses().add(containerDmc.getGroupId()); } - fCommandControl.queueCommand( - fCommandFactory.createMITargetDetach(controlDmc, procDmc.getProcId()), - new DataRequestMonitor<MIInfo>(getExecutor(), rm) { - @Override - protected void handleFailure() { - // The detach failed - if (containerDmc != null) { - getDetachedProcesses().remove(containerDmc.getGroupId()); - } - super.handleFailure(); - } - }); - } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ - rm.done(); - } + fCommandControl.queueCommand(fCommandFactory.createMITargetDetach(controlDmc, procDmc.getProcId()), + new DataRequestMonitor<MIInfo>(getExecutor(), rm) { + @Override + protected void handleFailure() { + // The detach failed + if (containerDmc != null) { + getDetachedProcesses().remove(containerDmc.getGroupId()); + } + super.handleFailure(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ + rm.done(); + } } @Override @@ -1366,17 +1408,17 @@ public class GDBProcesses_7_0 extends AbstractDsfService @Override public void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) { rm.setData(doIsDebugNewProcessSupported()); - rm.done(); + rm.done(); } /** @since 4.0 */ protected boolean doIsDebugNewProcessSupported() { return false; } - + @Override - public void debugNewProcess(IDMContext dmc, String file, - Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) { + public void debugNewProcess(IDMContext dmc, String file, Map<String, Object> attributes, + DataRequestMonitor<IDMContext> rm) { // Store the current value of the initialProcess variable because we will use it later // and we are about to change it. @@ -1386,26 +1428,27 @@ public class GDBProcesses_7_0 extends AbstractDsfService } 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; + 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( - getDebugNewProcessSequence(getExecutor(), isInitial, dmc, file, attributes, rm)); + ImmediateExecutor.getInstance() + .execute(getDebugNewProcessSequence(getExecutor(), isInitial, dmc, file, attributes, rm)); } - + /** * Return the sequence that is to be used to create a new process the specified process. * Allows others to extend more easily. * @since 4.0 */ - protected Sequence getDebugNewProcessSequence(DsfExecutor executor, boolean isInitial, IDMContext dmc, String file, - Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) { + protected Sequence getDebugNewProcessSequence(DsfExecutor executor, boolean isInitial, IDMContext dmc, String file, + Map<String, Object> attributes, DataRequestMonitor<IDMContext> rm) { return new DebugNewProcessSequence(executor, isInitial, dmc, file, attributes, rm); } - + @Override public void getProcessesBeingDebugged(final IDMContext dmc, final DataRequestMonitor<IDMContext[]> rm) { final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); @@ -1416,9 +1459,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService rm.done(new IMIExecutionDMContext[0]); return; } - - fThreadCommandCache.execute( - fCommandFactory.createMIListThreadGroups(controlDmc, containerDmc.getGroupId()), + + fThreadCommandCache.execute(fCommandFactory.createMIListThreadGroups(controlDmc, containerDmc.getGroupId()), new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) { @Override protected void handleSuccess() { @@ -1427,39 +1469,40 @@ public class GDBProcesses_7_0 extends AbstractDsfService } }); } else { - - final DataRequestMonitor<IMIContainerDMContext[]> addExitedDRM = - new ImmediateDataRequestMonitor<IMIContainerDMContext[]>(rm) { + + final DataRequestMonitor<IMIContainerDMContext[]> addExitedDRM = new ImmediateDataRequestMonitor<IMIContainerDMContext[]>( + rm) { @Override protected void handleCompleted() { List<IMIContainerDMContext> containerDmcs = new ArrayList<>(Arrays.asList(getData())); - + // Add the exited processes to our list in reverse order of insertion so that // the latest exited process is at the top List<Entry<String, ExitedProcInfo>> entries = new ArrayList<>(getExitedProcesses().entrySet()); - for (int i = entries.size() - 1; i >= 0 ; i--) { - Entry<String, ExitedProcInfo> entry = entries.get(i); - String groupId = entry.getKey(); + for (int i = entries.size() - 1; i >= 0; i--) { + Entry<String, ExitedProcInfo> entry = entries.get(i); + String groupId = entry.getKey(); String pid = entry.getValue().getPid(); IProcessDMContext processDmc = createExitedProcessContext(controlDmc, pid, groupId); containerDmcs.add(createContainerContext(processDmc, groupId)); } - + rm.done(containerDmcs.toArray(new IMIContainerDMContext[containerDmcs.size()])); }; }; - fContainerCommandCache.execute( - fCommandFactory.createMIListThreadGroups(controlDmc), + fContainerCommandCache.execute(fCommandFactory.createMIListThreadGroups(controlDmc), new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), addExitedDRM) { @Override protected void handleSuccess() { addExitedDRM.done(makeContainerDMCs(controlDmc, getData().getGroupList())); } + @Override protected void handleFailure() { // If the target is not available, generate the list ourselves - IMIContainerDMContext[] containerDmcs = new IMIContainerDMContext[getGroupToPidMap().size()]; + IMIContainerDMContext[] containerDmcs = new IMIContainerDMContext[getGroupToPidMap() + .size()]; int i = 0; for (String groupId : getGroupToPidMap().keySet()) { containerDmcs[i++] = createContainerContextFromGroupId(controlDmc, groupId); @@ -1478,16 +1521,14 @@ public class GDBProcesses_7_0 extends AbstractDsfService // So create thread-id = 0 when no thread is reported. // This hack is necessary to prevent AbstractMIControl from issuing a thread-select // because it doesn't work if the application was not compiled with pthread. - return new IMIExecutionDMContext[]{createExecutionContext(containerDmc, - createThreadContext(procDmc, FAKE_THREAD_ID), - FAKE_THREAD_ID)}; + return new IMIExecutionDMContext[] { createExecutionContext(containerDmc, + createThreadContext(procDmc, FAKE_THREAD_ID), FAKE_THREAD_ID) }; } else { IExecutionDMContext[] executionDmcs = new IMIExecutionDMContext[threadInfos.length]; for (int i = 0; i < threadInfos.length; i++) { String threadId = threadInfos[i].getThreadId(); - executionDmcs[i] = createExecutionContext(containerDmc, - createThreadContext(procDmc, threadId), - threadId); + executionDmcs[i] = createExecutionContext(containerDmc, createThreadContext(procDmc, threadId), + threadId); } return executionDmcs; } @@ -1500,21 +1541,21 @@ public class GDBProcesses_7_0 extends AbstractDsfService // code can be removed when GDB 7.2 is released // START OF WORKAROUND if (groups.length == 0 && fBackend.getSessionType() == SessionType.CORE) { - return new IMIContainerDMContext[] {createContainerContextFromGroupId(controlDmc, MIProcesses.UNIQUE_GROUP_ID)}; + return new IMIContainerDMContext[] { + createContainerContextFromGroupId(controlDmc, MIProcesses.UNIQUE_GROUP_ID) }; } // END OF WORKAROUND to be removed when GDB 7.2 is available - + // With GDB 7.1, we can receive a bogus process when we are not debugging anything - // -list-thread-groups - // ^done,groups=[{id="0",type="process",pid="0"}] + // -list-thread-groups + // ^done,groups=[{id="0",type="process",pid="0"}] // As for GDB 7.2, the pid field is missing altogether in this case // -list-thread-groups // ^done,groups=[{id="i1",type="process"}] // Just ignore that entry List<IMIContainerDMContext> containerDmcs = new ArrayList<IMIContainerDMContext>(groups.length); for (IThreadGroupInfo group : groups) { - if (group.getPid() == null || - group.getPid().isEmpty() || group.getPid().equals("0")) { //$NON-NLS-1$ + if (group.getPid() == null || group.getPid().isEmpty() || group.getPid().equals("0")) { //$NON-NLS-1$ continue; } String groupId = group.getGroupId(); @@ -1527,65 +1568,61 @@ public class GDBProcesses_7_0 extends AbstractDsfService public void getRunningProcesses(final IDMContext dmc, final DataRequestMonitor<IProcessDMContext[]> rm) { final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); if (controlDmc != null) { - fListThreadGroupsAvailableCache.execute( - fCommandFactory.createMIListThreadGroups(controlDmc, true), - new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) { - @Override - protected void handleCompleted() { - // We cannot actually cache this command since the process - // list may change. But this cache allows to avoid overlapping - // sending of this command. - fListThreadGroupsAvailableCache.reset(); - - if (isSuccess()) { - rm.setData(makeProcessDMCAndData(controlDmc, getData().getGroupList())); - } else { - // Looks like this gdb doesn't truly support - // "-list-thread-groups --available". If we're - // debugging locally, resort to getting the - // list natively (as we do with gdb 6.8). If - // we're debugging remotely, the user is out - // of luck - if (fBackend.getSessionType() == SessionType.LOCAL) { - IProcessList list = null; - try { - list = CCorePlugin.getDefault().getProcessList(); - } catch (CoreException e) { - } - - if (list == null) { - rm.setData(new IProcessDMContext[0]); + fListThreadGroupsAvailableCache.execute(fCommandFactory.createMIListThreadGroups(controlDmc, true), + new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) { + @Override + protected void handleCompleted() { + // We cannot actually cache this command since the process + // list may change. But this cache allows to avoid overlapping + // sending of this command. + fListThreadGroupsAvailableCache.reset(); + + if (isSuccess()) { + rm.setData(makeProcessDMCAndData(controlDmc, getData().getGroupList())); + } else { + // Looks like this gdb doesn't truly support + // "-list-thread-groups --available". If we're + // debugging locally, resort to getting the + // list natively (as we do with gdb 6.8). If + // we're debugging remotely, the user is out + // of luck + if (fBackend.getSessionType() == SessionType.LOCAL) { + IProcessList list = null; + try { + list = CCorePlugin.getDefault().getProcessList(); + } catch (CoreException e) { + } + + if (list == null) { + rm.setData(new IProcessDMContext[0]); + } else { + IProcessInfo[] procInfos = list.getProcessList(); + rm.setData(makeProcessDMCAndData(controlDmc, procInfos)); + } } else { - IProcessInfo[] procInfos = list.getProcessList(); - rm.setData(makeProcessDMCAndData(controlDmc, procInfos)); + rm.setData(new IProcessDMContext[0]); } } - else { - rm.setData(new IProcessDMContext[0]); - } + rm.done(); } - rm.done(); - } - }); + }); } else { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ rm.done(); } } - + /** * Create the joint process DMC and data based on IProcessInfo, which is a local listing. * @since 4.0 */ - protected MIProcessDMCAndData[] makeProcessDMCAndData(ICommandControlDMContext controlDmc, IProcessInfo[] processes) { + protected MIProcessDMCAndData[] makeProcessDMCAndData(ICommandControlDMContext controlDmc, + IProcessInfo[] processes) { MIProcessDMCAndData[] procDmcs = new MIProcessDMCAndData[processes.length]; - for (int i=0; i<procDmcs.length; i++) { - procDmcs[i] = new MIProcessDMCAndData(controlDmc.getSessionId(), - controlDmc, - Integer.toString(processes[i].getPid()), - processes[i].getName(), - null, null); + for (int i = 0; i < procDmcs.length; i++) { + procDmcs[i] = new MIProcessDMCAndData(controlDmc.getSessionId(), controlDmc, + Integer.toString(processes[i].getPid()), processes[i].getName(), null, null); } return procDmcs; } @@ -1594,17 +1631,13 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Create the joint process DMC and data based on IThreadGroupInfo, which is obtained from GDB. * @since 4.0 */ - protected MIProcessDMCAndData[] makeProcessDMCAndData(ICommandControlDMContext controlDmc, IThreadGroupInfo[] processes) { + protected MIProcessDMCAndData[] makeProcessDMCAndData(ICommandControlDMContext controlDmc, + IThreadGroupInfo[] processes) { MIProcessDMCAndData[] procDmcs = new MIProcessDMCAndData[processes.length]; - int i=0; + int i = 0; for (IThreadGroupInfo process : processes) { - procDmcs[i++] = new MIProcessDMCAndData(controlDmc.getSessionId(), - controlDmc, - process.getGroupId(), - process.getName(), - process.getCores(), - process.getUser(), - process.getDesciption()); + procDmcs[i++] = new MIProcessDMCAndData(controlDmc.getSessionId(), controlDmc, process.getGroupId(), + process.getName(), process.getCores(), process.getUser(), process.getDesciption()); } return procDmcs; } @@ -1612,14 +1645,13 @@ public class GDBProcesses_7_0 extends AbstractDsfService @Override public void isRunNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) { rm.setData(false); - rm.done(); + rm.done(); } - + @Override - public void runNewProcess(IDMContext dmc, String file, - Map<String, Object> attributes, DataRequestMonitor<IProcessDMContext> rm) { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, - NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + public void runNewProcess(IDMContext dmc, String file, Map<String, Object> attributes, + DataRequestMonitor<IProcessDMContext> rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ rm.done(); } @@ -1628,85 +1660,87 @@ public class GDBProcesses_7_0 extends AbstractDsfService if (thread instanceof MIExitedProcessDMC) { // For an exited process, remove the entry from our table to stop showing it, and // remove the entry from the launch itself to remove the process's console - String groupId = ((MIExitedProcessDMC)thread).getGroupId(); + String groupId = ((MIExitedProcessDMC) thread).getGroupId(); getExitedProcesses().remove(groupId); removeProcessFromLaunch(groupId); - getSession().dispatchEvent(new ProcessRemovedDMEvent((IProcessDMContext)thread), null); + getSession().dispatchEvent(new ProcessRemovedDMEvent((IProcessDMContext) thread), null); } else if (fBackend.getSessionType() == SessionType.CORE) { - // For a core session, there is no concept of killing the inferior, - // so lets kill GDB - fCommandControl.terminate(rm); - } else if (thread instanceof IMIProcessDMContext) { - getDebuggingContext( - thread, - new ImmediateDataRequestMonitor<IDMContext>(rm) { - @Override - protected void handleSuccess() { - if (getData() instanceof IMIContainerDMContext) { - IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class); - if (runControl != null && !runControl.isTargetAcceptingCommands()) { - fBackend.interrupt(); - } - - fCommandControl.queueCommand( - fCommandFactory.createMIInterpreterExecConsoleKill((IMIContainerDMContext)getData()), - new ImmediateDataRequestMonitor<MIInfo>(rm)); - } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ - rm.done(); - } + // For a core session, there is no concept of killing the inferior, + // so lets kill GDB + fCommandControl.terminate(rm); + } else if (thread instanceof IMIProcessDMContext) { + getDebuggingContext(thread, new ImmediateDataRequestMonitor<IDMContext>(rm) { + @Override + protected void handleSuccess() { + if (getData() instanceof IMIContainerDMContext) { + IMIRunControl runControl = getServicesTracker().getService(IMIRunControl.class); + if (runControl != null && !runControl.isTargetAcceptingCommands()) { + fBackend.interrupt(); } - }); - } else { - rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ - rm.done(); - } + + fCommandControl.queueCommand( + fCommandFactory.createMIInterpreterExecConsoleKill((IMIContainerDMContext) getData()), + new ImmediateDataRequestMonitor<MIInfo>(rm)); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, + "Invalid process context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + }); + } else { + rm.setStatus( + new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ + rm.done(); + } } - + /** @since 4.0 */ @Override - public void canRestart(IContainerDMContext containerDmc, DataRequestMonitor<Boolean> rm) { - if (fBackend.getIsAttachSession() || fBackend.getSessionType() == SessionType.CORE) { - rm.setData(false); - rm.done(); - return; - } - - // Before GDB6.8, the Linux gdbserver would restart a new - // process when getting a -exec-run but the communication - // with GDB had a bug and everything hung. - // with GDB6.8 the program restarts properly one time, - // but on a second attempt, gdbserver crashes. - // So, lets just turn off the Restart for Remote debugging - if (fBackend.getSessionType() == SessionType.REMOTE) { - rm.setData(false); - rm.done(); - return; - } - - rm.setData(true); - rm.done(); - } - - /** + public void canRestart(IContainerDMContext containerDmc, DataRequestMonitor<Boolean> rm) { + if (fBackend.getIsAttachSession() || fBackend.getSessionType() == SessionType.CORE) { + rm.setData(false); + rm.done(); + return; + } + + // Before GDB6.8, the Linux gdbserver would restart a new + // process when getting a -exec-run but the communication + // with GDB had a bug and everything hung. + // with GDB6.8 the program restarts properly one time, + // but on a second attempt, gdbserver crashes. + // So, lets just turn off the Restart for Remote debugging + if (fBackend.getSessionType() == SessionType.REMOTE) { + rm.setData(false); + rm.done(); + return; + } + + rm.setData(true); + rm.done(); + } + + /** * Creates the container context that is to be used for the new process that will * be created by the restart operation. * This container does not have its pid yet, while the container of the process * that is being restarted does have its pid. * Also, for GDB 7.0 and 7.1, the groupId being the pid, we cannot use the old * container's groupId, but must use the default groupId until the pid is created. - * + * * @since 4.0 */ protected IMIContainerDMContext createContainerContextForRestart(String groupId) { - IProcessDMContext processDmc = createProcessContext(fCommandControl.getContext(), MIProcesses.UNKNOWN_PROCESS_ID); - // Don't use the groupId passed in, since it is the old pid. + IProcessDMContext processDmc = createProcessContext(fCommandControl.getContext(), + MIProcesses.UNKNOWN_PROCESS_ID); + // Don't use the groupId passed in, since it is the old pid. return createContainerContext(processDmc, MIProcesses.UNIQUE_GROUP_ID); } - + /** @since 4.0 */ @Override - public void restart(IContainerDMContext containerDmc, final Map<String, Object> attributes, final DataRequestMonitor<IContainerDMContext> rm) { + public void restart(IContainerDMContext containerDmc, final Map<String, Object> attributes, + final DataRequestMonitor<IContainerDMContext> rm) { // Before performing the restart, check if the process is properly suspended. // For such a case, we usually use IMIRunControl.isTargetAcceptingCommands(). // However, in non-stop, although the target is accepting command, a restart @@ -1719,8 +1753,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService // just yet. // Bug 246740 - final String groupId = ((IMIContainerDMContext)containerDmc).getGroupId(); - + final String groupId = ((IMIContainerDMContext) containerDmc).getGroupId(); + // This request monitor actually performs the restart RequestMonitor restartRm = new ImmediateRequestMonitor(rm) { @Override @@ -1730,19 +1764,20 @@ public class GDBProcesses_7_0 extends AbstractDsfService // Pass in the groupId because starting with GDB 7.2, we must re-use the same groupId. IContainerDMContext newContainerDmc = createContainerContextForRestart(groupId); - startOrRestart(newContainerDmc, attributes, true, new ImmediateDataRequestMonitor<IContainerDMContext>(rm) { - @Override - protected void handleCompleted() { - // In case the process we restarted was already exited, remove it from our list - // We do this here for GDB 7.1, because we know the proper groupId here which - // will change when the new restarted process will start. For GDB >= 7.2 - // the groupId is fixed so we don't have to do this right away, but it won't hurt. - getExitedProcesses().remove(groupId); - - setData(getData()); - super.handleCompleted(); - }; - }); + startOrRestart(newContainerDmc, attributes, true, + new ImmediateDataRequestMonitor<IContainerDMContext>(rm) { + @Override + protected void handleCompleted() { + // In case the process we restarted was already exited, remove it from our list + // We do this here for GDB 7.1, because we know the proper groupId here which + // will change when the new restarted process will start. For GDB >= 7.2 + // the groupId is fixed so we don't have to do this right away, but it won't hurt. + getExitedProcesses().remove(groupId); + + setData(getData()); + super.handleCompleted(); + }; + }); }; }; @@ -1755,19 +1790,19 @@ public class GDBProcesses_7_0 extends AbstractDsfService restartRm.done(); } } - + /** @since 4.0 */ @Override - public void start(IContainerDMContext containerDmc, Map<String, Object> attributes, DataRequestMonitor<IContainerDMContext> rm) { + public void start(IContainerDMContext containerDmc, Map<String, Object> attributes, + DataRequestMonitor<IContainerDMContext> rm) { startOrRestart(containerDmc, attributes, false, rm); } - + /** @since 4.0 */ - protected void startOrRestart(IContainerDMContext containerDmc, Map<String, Object> attributes, - boolean restart, DataRequestMonitor<IContainerDMContext> rm) { - ImmediateExecutor.getInstance().execute( - getStartOrRestartProcessSequence( - getExecutor(), containerDmc, attributes, restart, rm)); + protected void startOrRestart(IContainerDMContext containerDmc, Map<String, Object> attributes, boolean restart, + DataRequestMonitor<IContainerDMContext> rm) { + ImmediateExecutor.getInstance() + .execute(getStartOrRestartProcessSequence(getExecutor(), containerDmc, attributes, restart, rm)); } /** @@ -1775,19 +1810,18 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Allows others to extend more easily. * @since 4.0 */ - protected Sequence getStartOrRestartProcessSequence(DsfExecutor executor, IContainerDMContext containerDmc, - Map<String, Object> attributes, boolean restart, - DataRequestMonitor<IContainerDMContext> rm) { + protected Sequence getStartOrRestartProcessSequence(DsfExecutor executor, IContainerDMContext containerDmc, + Map<String, Object> attributes, boolean restart, DataRequestMonitor<IContainerDMContext> rm) { return new StartOrRestartProcessSequence_7_0(executor, containerDmc, attributes, restart, rm); } - + /** * Removes the process with the specified groupId from the launch. - * + * * @return The label used for the console of that process. */ private String removeProcessFromLaunch(String groupId) { - ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class); + ILaunch launch = (ILaunch) getSession().getModelAdapter(ILaunch.class); IProcess[] launchProcesses = launch.getProcesses(); for (IProcess process : launchProcesses) { if (process instanceof InferiorRuntimeProcess) { @@ -1796,8 +1830,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService // if the groupAttribute is not set in the process we know we are dealing // with single process debugging so the one process is the one we want. // If the groupAttribute is set, then we must make sure it is the proper inferior - if (groupAttribute == null || groupAttribute.equals(MIProcesses.UNIQUE_GROUP_ID) || - groupAttribute.equals(groupId)) { + if (groupAttribute == null || groupAttribute.equals(MIProcesses.UNIQUE_GROUP_ID) + || groupAttribute.equals(groupId)) { launch.removeProcess(process); return process.getLabel(); } @@ -1810,34 +1844,35 @@ public class GDBProcesses_7_0 extends AbstractDsfService * Add the specified process to the launch. */ private void addProcessToLaunch(Process inferior, String groupId, String label) { - // Add the inferior to the launch. + // Add the inferior to the launch. // This cannot be done on the executor or things deadlock. DebugPlugin.getDefault().asyncExec(new Runnable() { @Override public void run() { // Add the inferior - // Need to go through DebugPlugin.newProcess so that we can use + // Need to go through DebugPlugin.newProcess so that we can use // the overrideable process factory to allow others to override. // First set attribute to specify we want to create an inferior process. // Bug 210366 - ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class); + ILaunch launch = (ILaunch) getSession().getModelAdapter(ILaunch.class); Map<String, String> attributes = new HashMap<String, String>(); - attributes.put(IGdbDebugConstants.PROCESS_TYPE_CREATION_ATTR, + attributes.put(IGdbDebugConstants.PROCESS_TYPE_CREATION_ATTR, IGdbDebugConstants.INFERIOR_PROCESS_CREATION_VALUE); - IProcess runtimeInferior = DebugPlugin.newProcess(launch, inferior, label != null ? label : "", attributes); //$NON-NLS-1$ + IProcess runtimeInferior = DebugPlugin.newProcess(launch, inferior, label != null ? label : "", //$NON-NLS-1$ + attributes); // Now set the inferior groupId runtimeInferior.setAttribute(IGdbDebugConstants.INFERIOR_GROUPID_ATTR, groupId); } }); } - - /** + + /** * @since 5.2 */ @Override public void addInferiorToLaunch(IContainerDMContext containerDmc, String label, PTY pty, RequestMonitor rm) { if (containerDmc instanceof IMIContainerDMContext) { - String groupId = ((IMIContainerDMContext)containerDmc).getGroupId(); + String groupId = ((IMIContainerDMContext) containerDmc).getGroupId(); // Create an MIInferiorProcess to track the new instance of the process, // remove the old one from the launch, and add the new one to the launch. Process inferiorProcess; @@ -1850,34 +1885,36 @@ public class GDBProcesses_7_0 extends AbstractDsfService addProcessToLaunch(inferiorProcess, groupId, label); } rm.done(); - } - - @DsfServiceEventHandler - public void eventDispatched(final MIThreadGroupCreatedEvent e) { - IProcessDMContext procDmc = e.getDMContext(); - IMIContainerDMContext containerDmc = e.getGroupId() != null ? createContainerContext(procDmc, e.getGroupId()) : null; - getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties()); - } - - @DsfServiceEventHandler - public void eventDispatched(final MIThreadGroupExitedEvent e) { - IProcessDMContext procDmc = e.getDMContext(); - IMIContainerDMContext containerDmc = e.getGroupId() != null ? createContainerContext(procDmc, e.getGroupId()) : null; + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadGroupCreatedEvent e) { + IProcessDMContext procDmc = e.getDMContext(); + IMIContainerDMContext containerDmc = e.getGroupId() != null ? createContainerContext(procDmc, e.getGroupId()) + : null; + getSession().dispatchEvent(new ContainerStartedDMEvent(containerDmc), getProperties()); + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadGroupExitedEvent e) { + IProcessDMContext procDmc = e.getDMContext(); + IMIContainerDMContext containerDmc = e.getGroupId() != null ? createContainerContext(procDmc, e.getGroupId()) + : null; getSession().dispatchEvent(new ContainerExitedDMEvent(containerDmc), getProperties()); - } - - @DsfServiceEventHandler - public void eventDispatched(IResumedDMEvent e) { - if (e instanceof IContainerResumedDMEvent) { - // This will happen in all-stop mode - fContainerCommandCache.setContextAvailable(e.getDMContext(), false); - fThreadCommandCache.setContextAvailable(e.getDMContext(), false); - fListThreadGroupsAvailableCache.setContextAvailable(e.getDMContext(), false); - } else { - // This will happen in non-stop mode - // Keep target available for Container commands - } - } + } + + @DsfServiceEventHandler + public void eventDispatched(IResumedDMEvent e) { + if (e instanceof IContainerResumedDMEvent) { + // This will happen in all-stop mode + fContainerCommandCache.setContextAvailable(e.getDMContext(), false); + fThreadCommandCache.setContextAvailable(e.getDMContext(), false); + fListThreadGroupsAvailableCache.setContextAvailable(e.getDMContext(), false); + } else { + // This will happen in non-stop mode + // Keep target available for Container commands + } + } /** @since 5.2 */ protected MIInferiorProcess createInferiorProcess(IContainerDMContext container, OutputStream outputStream) { @@ -1889,113 +1926,114 @@ public class GDBProcesses_7_0 extends AbstractDsfService return new MIInferiorProcess(container, pty); } - private void handleRestartingProcess(IMIContainerDMContext containerDmc) { + private void handleRestartingProcess(IMIContainerDMContext containerDmc) { String label = removeProcessFromLaunch(containerDmc.getGroupId()); if (label != null) { // We only add the process to the launch if the original process was part of the launch. // For example, in the attach case, there is no process added to the launch // We re-use the same PTY as the one used before the restart. - addInferiorToLaunch(containerDmc, label, fGroupIdToPTYMap.get(containerDmc.getGroupId()), new ImmediateRequestMonitor()); - } - } - - @DsfServiceEventHandler - public void eventDispatched(ISuspendedDMEvent e) { - if (e instanceof IContainerSuspendedDMEvent) { - // This will happen in all-stop mode - fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); - fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true); - fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true); - } else { - // This will happen in non-stop mode - } - - // If user is debugging a gdb target that doesn't send thread + addInferiorToLaunch(containerDmc, label, fGroupIdToPTYMap.get(containerDmc.getGroupId()), + new ImmediateRequestMonitor()); + } + } + + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent e) { + if (e instanceof IContainerSuspendedDMEvent) { + // This will happen in all-stop mode + fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); + fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true); + fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true); + } else { + // This will happen in non-stop mode + } + + // If user is debugging a gdb target that doesn't send thread // creation events, make sure we don't use cached thread // information. Reset the cache after every suspend. See bugzilla // 280631 - try { + try { if (fBackend.getUpdateThreadListOnSuspend()) { // We need to clear the cache for the context that we use to fill the cache, // and it is the controDMC in this case. - ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(e.getDMContext(), ICommandControlDMContext.class); + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(e.getDMContext(), + ICommandControlDMContext.class); fThreadCommandCache.reset(controlDmc); } - } catch (CoreException exc) {} - } - - // Event handler when a thread or threadGroup starts - @DsfServiceEventHandler - public void eventDispatched(IStartedDMEvent e) { - if (e.getDMContext() instanceof IMIContainerDMContext) { - String groupId = ((IMIContainerDMContext)e.getDMContext()).getGroupId(); + } catch (CoreException exc) { + } + } + + // Event handler when a thread or threadGroup starts + @DsfServiceEventHandler + public void eventDispatched(IStartedDMEvent e) { + if (e.getDMContext() instanceof IMIContainerDMContext) { + String groupId = ((IMIContainerDMContext) e.getDMContext()).getGroupId(); if (fExitedGroupId.remove(groupId)) { - // The process in question is restarting. - handleRestartingProcess((IMIContainerDMContext)e.getDMContext()); - } - - fContainerCommandCache.reset(); - fNumConnected++; - } else { - fThreadCommandCache.reset(); - } - } - - // Event handler when a thread or a threadGroup exits - @DsfServiceEventHandler - public void eventDispatched(IExitedDMEvent e) { - if (e.getDMContext() instanceof IMIContainerDMContext) { - fExitedGroupId.add(((IMIContainerDMContext)e.getDMContext()).getGroupId()); - - fContainerCommandCache.reset(); - - assert fNumConnected > 0; - fNumConnected--; - - if (fNumConnected == 0 && - Platform.getPreferencesService().getBoolean(GdbPlugin.PLUGIN_ID, - IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, - true, null)) { - // If the last process we are debugging finishes and does not restart - // let's terminate GDB. We wait a small delay to see if the process will restart. - // We also do this for a remote attach session, since the 'auto terminate' preference - // is enabled. If users want to keep the session alive to attach to another process, - // they can simply disable that preference - getExecutor().schedule(new DsfRunnable() { - @Override - public void run() { - // Verify the process didn't restart by checking that we still have nothing connected - if (fNumConnected == 0) { - fCommandControl.terminate(new ImmediateRequestMonitor()); - } - } - }, 500, TimeUnit.MILLISECONDS); - } - } else { - fThreadCommandCache.reset(); - } - } - - /** + // The process in question is restarting. + handleRestartingProcess((IMIContainerDMContext) e.getDMContext()); + } + + fContainerCommandCache.reset(); + fNumConnected++; + } else { + fThreadCommandCache.reset(); + } + } + + // Event handler when a thread or a threadGroup exits + @DsfServiceEventHandler + public void eventDispatched(IExitedDMEvent e) { + if (e.getDMContext() instanceof IMIContainerDMContext) { + fExitedGroupId.add(((IMIContainerDMContext) e.getDMContext()).getGroupId()); + + fContainerCommandCache.reset(); + + assert fNumConnected > 0; + fNumConnected--; + + if (fNumConnected == 0 && Platform.getPreferencesService().getBoolean(GdbPlugin.PLUGIN_ID, + IGdbDebugPreferenceConstants.PREF_AUTO_TERMINATE_GDB, true, null)) { + // If the last process we are debugging finishes and does not restart + // let's terminate GDB. We wait a small delay to see if the process will restart. + // We also do this for a remote attach session, since the 'auto terminate' preference + // is enabled. If users want to keep the session alive to attach to another process, + // they can simply disable that preference + getExecutor().schedule(new DsfRunnable() { + @Override + public void run() { + // Verify the process didn't restart by checking that we still have nothing connected + if (fNumConnected == 0) { + fCommandControl.terminate(new ImmediateRequestMonitor()); + } + } + }, 500, TimeUnit.MILLISECONDS); + } + } else { + fThreadCommandCache.reset(); + } + } + + /** * @since 5.2 */ - @DsfServiceEventHandler - public void eventDispatched(ICommandControlShutdownDMEvent e) { - // Now that the debug session is over, close the persistent PTY streams - for (PTY pty : fGroupIdToPTYMap.values()) { - if (pty instanceof PersistentPTY) { - try { - ((PersistentPTY)pty).closeStreams(); + @DsfServiceEventHandler + public void eventDispatched(ICommandControlShutdownDMEvent e) { + // Now that the debug session is over, close the persistent PTY streams + for (PTY pty : fGroupIdToPTYMap.values()) { + if (pty instanceof PersistentPTY) { + try { + ((PersistentPTY) pty).closeStreams(); } catch (IOException e1) { } - } - } - fGroupIdToPTYMap.clear(); - - fExitedGroupId.clear(); - } - - @Override + } + } + fGroupIdToPTYMap.clear(); + + fExitedGroupId.clear(); + } + + @Override public void flushCache(IDMContext context) { fContainerCommandCache.reset(context); fThreadCommandCache.reset(context); @@ -2008,69 +2046,69 @@ public class GDBProcesses_7_0 extends AbstractDsfService /* * Catch =thread-created/exited and =thread-group-exited events to update our - * groupId to threadId map. + * groupId to threadId map. */ @Override public void eventReceived(Object output) { - for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + for (MIOOBRecord oobr : ((MIOutput) output).getMIOOBRecords()) { if (oobr instanceof MINotifyAsyncOutput) { - MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr; - String miEvent = exec.getAsyncClass(); - if ("thread-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ - String threadId = null; - String groupId = null; - - MIResult[] results = exec.getMIResults(); - for (int i = 0; i < results.length; i++) { - String var = results[i].getVariable(); - MIValue val = results[i].getMIValue(); - if (var.equals("group-id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - groupId = ((MIConst) val).getString(); - } - } else if (var.equals("id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - threadId = ((MIConst) val).getString(); - } - } - } - - if ("thread-created".equals(miEvent)) { //$NON-NLS-1$ - // Update the thread to groupId map with the new groupId - getThreadToGroupMap().put(threadId, groupId); - } else { - getThreadToGroupMap().remove(threadId); - } - // "thread-group-created" was used before GDB 7.2, while "thread-group-started" is used with GDB 7.2 - } else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ - String groupId = null; - String pId = null; - - MIResult[] results = exec.getMIResults(); - for (int i = 0; i < results.length; i++) { - String var = results[i].getVariable(); - MIValue val = results[i].getMIValue(); - if (var.equals("id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - groupId = ((MIConst) val).getString().trim(); - } - } else if (var.equals("pid")) { //$NON-NLS-1$ - // Available starting with GDB 7.2 - if (val instanceof MIConst) { - pId = ((MIConst) val).getString().trim(); - } - } - } - - if (pId == null) { - // Before GDB 7.2, the groupId was the pid of the process - pId = groupId; - } - - if (groupId != null) { + MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr; + String miEvent = exec.getAsyncClass(); + if ("thread-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ + String threadId = null; + String groupId = null; + + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("group-id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + groupId = ((MIConst) val).getString(); + } + } else if (var.equals("id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + threadId = ((MIConst) val).getString(); + } + } + } + + if ("thread-created".equals(miEvent)) { //$NON-NLS-1$ + // Update the thread to groupId map with the new groupId + getThreadToGroupMap().put(threadId, groupId); + } else { + getThreadToGroupMap().remove(threadId); + } + // "thread-group-created" was used before GDB 7.2, while "thread-group-started" is used with GDB 7.2 + } else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ + String groupId = null; + String pId = null; + + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + groupId = ((MIConst) val).getString().trim(); + } + } else if (var.equals("pid")) { //$NON-NLS-1$ + // Available starting with GDB 7.2 + if (val instanceof MIConst) { + pId = ((MIConst) val).getString().trim(); + } + } + } + + if (pId == null) { + // Before GDB 7.2, the groupId was the pid of the process + pId = groupId; + } + + if (groupId != null) { // In case the process that just started was already exited (so we are dealing - // with a restart), remove it from our list. - // Do this here to handle the restart case triggered by GDB itself + // with a restart), remove it from our list. + // Do this here to handle the restart case triggered by GDB itself // (user typing 'run' from the GDB console). In this case, we don't know yet // we are dealing with a restart, but when we see the process come back, we // know to remove it from the exited list. Note that this won't work @@ -2078,51 +2116,51 @@ public class GDBProcesses_7_0 extends AbstractDsfService // one. Not worth fixing for such an old version. getExitedProcesses().remove(groupId); - getGroupToPidMap().put(groupId, pId); - - // Mark that we know this new process, but don't fetch its - // name until it is requested. - fDebuggedProcessesAndNames.put(pId, ""); //$NON-NLS-1$ - } - } else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ - String groupId = null; - - MIResult[] results = exec.getMIResults(); - for (int i = 0; i < results.length; i++) { - String var = results[i].getVariable(); - MIValue val = results[i].getMIValue(); - if (var.equals("id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - groupId = ((MIConst) val).getString().trim(); - } - } - } - - if (groupId != null) { - String pId = getGroupToPidMap().remove(groupId); - - // GDB is no longer debugging this process. Remove it from our list - String name = fDebuggedProcessesAndNames.remove(pId); - if (!getDetachedProcesses().remove(groupId)) { - // If the process was not detached, - // store it in the list of exited processes. - getExitedProcesses().put(groupId, new ExitedProcInfo(pId, name)); - } - - // Remove any entries for that group from our thread to group map - // When detaching from a group, we won't have received any thread-exited event - // but we don't want to keep those entries. - if (getThreadToGroupMap().containsValue(groupId)) { - Iterator<Map.Entry<String, String>> iterator = getThreadToGroupMap().entrySet().iterator(); - while (iterator.hasNext()){ - if (iterator.next().getValue().equals(groupId)) { - iterator.remove(); - } - } - } - } - } - } - } + getGroupToPidMap().put(groupId, pId); + + // Mark that we know this new process, but don't fetch its + // name until it is requested. + fDebuggedProcessesAndNames.put(pId, ""); //$NON-NLS-1$ + } + } else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ + String groupId = null; + + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + groupId = ((MIConst) val).getString().trim(); + } + } + } + + if (groupId != null) { + String pId = getGroupToPidMap().remove(groupId); + + // GDB is no longer debugging this process. Remove it from our list + String name = fDebuggedProcessesAndNames.remove(pId); + if (!getDetachedProcesses().remove(groupId)) { + // If the process was not detached, + // store it in the list of exited processes. + getExitedProcesses().put(groupId, new ExitedProcInfo(pId, name)); + } + + // Remove any entries for that group from our thread to group map + // When detaching from a group, we won't have received any thread-exited event + // but we don't want to keep those entries. + if (getThreadToGroupMap().containsValue(groupId)) { + Iterator<Map.Entry<String, String>> iterator = getThreadToGroupMap().entrySet().iterator(); + while (iterator.hasNext()) { + if (iterator.next().getValue().equals(groupId)) { + iterator.remove(); + } + } + } + } + } + } + } } } |