diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java index 695fc47fa03..befd0946a38 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java @@ -501,7 +501,6 @@ public class GdbThreadFilterEditor { if (procService != null) { IThreadDMContext threadDmc = DMContexts.getAncestorOfType(thread, IThreadDMContext.class); procService.getExecutionData(threadDmc, new DataRequestMonitor( - // Is it ok to use the ImmediateExecutor here? ImmediateExecutor.getInstance(), rm) { @Override protected void handleSuccess() { diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java index fa5b6d27274..77220ecfc2b 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java @@ -86,7 +86,7 @@ public class ContainerVMNode extends AbstractContainerVMNode protected void updateLabelInSessionThread(final ILabelUpdate update) { IProcesses processService = getServicesTracker().getService(IProcesses.class); IRunControl runControl = getServicesTracker().getService(IRunControl.class); - if (processService == null) { + if (processService == null || runControl == null) { handleFailedUpdate(update); return; } diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java index bc4a3ffcb83..1a7a405a74d 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/FinalLaunchSequence.java @@ -37,10 +37,10 @@ import org.eclipse.dd.dsf.service.DsfServicesTracker; import org.eclipse.dd.gdb.internal.GdbPlugin; import org.eclipse.dd.gdb.internal.provisional.IGDBLaunchConfigurationConstants; import org.eclipse.dd.gdb.internal.provisional.actions.IConnect; -import org.eclipse.dd.gdb.internal.provisional.service.GDBProcesses; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.SessionType; import org.eclipse.dd.mi.service.CSourceLookup; +import org.eclipse.dd.mi.service.IMIProcesses; import org.eclipse.dd.mi.service.MIBreakpointsManager; import org.eclipse.dd.mi.service.command.commands.CLISource; import org.eclipse.dd.mi.service.command.commands.MIEnvironmentCD; @@ -73,7 +73,7 @@ public class FinalLaunchSequence extends Sequence { new Step() { @Override public void execute(RequestMonitor requestMonitor) { fCommandControl = fTracker.getService(GDBControl.class); - fProcService = fTracker.getService(GDBProcesses.class); + fProcService = fTracker.getService(IMIProcesses.class); if (fCommandControl == null || fProcService == null) { requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain service", null)); //$NON-NLS-1$ } @@ -464,7 +464,7 @@ public class FinalLaunchSequence extends Sequence { boolean fAttach; GDBControl fCommandControl; - GDBProcesses fProcService; + IMIProcesses fProcService; DsfServicesTracker fTracker; public FinalLaunchSequence(DsfExecutor executor, GdbLaunch launch, SessionType sessionType, boolean attach) { diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBMultiProcesses.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBMultiProcesses.java new file mode 100644 index 00000000000..44104943eda --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBMultiProcesses.java @@ -0,0 +1,698 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.provisional.service; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IProcesses; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.internal.GdbPlugin; +import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionGroupDMContext; +import org.eclipse.dd.mi.service.IMIProcessDMContext; +import org.eclipse.dd.mi.service.IMIProcesses; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.commands.MIListThreadGroups; +import org.eclipse.dd.mi.service.command.commands.MITargetAttach; +import org.eclipse.dd.mi.service.command.commands.MITargetDetach; +import org.eclipse.dd.mi.service.command.events.MIThreadGroupCreatedEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadGroupExitedEvent; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo; +import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo.IThreadGroupInfo; +import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo.IThreadInfo; +import org.osgi.framework.BundleContext; + + +public class GDBMultiProcesses extends AbstractDsfService implements IMIProcesses { + + // Below is the context hierarchy that is implemented between the + // MIProcesses service and the MIRunControl service for the MI + // implementation of DSF: + // + // MIControlDMContext + // | + // MIProcessDMC (IProcess) + // MIExecutionGroupDMC __/ | + // (IContainer) | + // | MIThreadDMC (IThread) + // MIExecutionDMC _____/ + // (IExecution) + // + + /** + * Context representing a thread in GDB/MI + */ + @Immutable + private static class MIExecutionDMC extends AbstractDMContext + implements IMIExecutionDMContext + { + /** + * String ID that is used to identify the thread in the GDB/MI protocol. + */ + private final String fThreadId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link IMIProcesses#createExecutionContext()} + * to create instances of this context based on the thread ID. + *

+ * + * @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; + } + + /** + * Returns the GDB/MI thread identifier of this context. + * @return + */ + public int getThreadId(){ + try { + return Integer.parseInt(fThreadId); + } catch (NumberFormatException e) { + } + + return 0; + } + + public String getId(){ + return fThreadId; + } + + @Override + public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId.equals(fThreadId); + } + + @Override + public int hashCode() { return super.baseHashCode() ^ fThreadId.hashCode(); } + } + + /** + * Context representing a thread group of GDB/MI. + */ + @Immutable + private static class MIExecutionGroupDMC extends AbstractDMContext + implements IMIExecutionGroupDMContext + { + /** + * String ID that is used to identify the thread group in the GDB/MI protocol. + */ + private final String fId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link IMIProcesses#createExecutionGroupContext + * 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. + */ + public MIExecutionGroupDMC(String sessionId, IProcessDMContext processDmc, String groupId) { + super(sessionId, processDmc == null ? new IDMContext[0] : new IDMContext[] { processDmc }); + fId = groupId; + } + + /** + * Returns the GDB/MI thread group identifier of this context. + */ + public String getGroupId(){ return fId; } + + @Override + public String toString() { return baseToString() + ".threadGroup[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && + (((MIExecutionGroupDMC)obj).fId == null ? fId == null : ((MIExecutionGroupDMC)obj).fId.equals(fId)); + } + + @Override + public int hashCode() { return super.baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); } + } + + /** + * Context representing a thread. + */ + @Immutable + private 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. + *

+ * + * @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; + } + + /** + * 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 boolean equals(Object obj) { + return super.baseEquals(obj) && + (((MIThreadDMC)obj).fId == null ? fId == null : ((MIThreadDMC)obj).fId.equals(fId)); + } + + @Override + public int hashCode() { return super.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. + *

+ * + * @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, MIControlDMContext controlDmc, String id) { + super(sessionId, controlDmc == null ? new IDMContext[0] : new IDMContext[] { controlDmc }); + fId = id; + } + + public String getProcId() { return fId; } + + @Override + public String toString() { return baseToString() + ".proc[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && + (((MIProcessDMC)obj).fId == null ? fId == null : ((MIProcessDMC)obj).fId.equals(fId)); + } + + @Override + public int hashCode() { return super.baseHashCode() ^ (fId == null ? 0 : fId.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; + } + + public String getId() { return fId; } + public String getName() { return fName; } + public boolean isDebuggerAttached() { + return true; + } + } + + /** + * Event indicating that an execution group (debugged process) has started. This event + * implements the {@link IStartedMDEvent} from the IRunControl service. + */ + public static class ExecutionGroupStartedDMEvent extends AbstractDMEvent + implements IStartedDMEvent + { + public ExecutionGroupStartedDMEvent(IMIExecutionGroupDMContext context) { + super(context); + } + } + + /** + * Event indicating that an execution group is no longer being debugged. This event + * implements the {@link IExitedMDEvent} from the IRunControl service. + */ + public static class ExecutionGroupExitedDMEvent extends AbstractDMEvent + implements IExitedDMEvent + { + public ExecutionGroupExitedDMEvent(IContainerDMContext context) { + super(context); + } + } + + private GDBControl fCommandControl; + private CommandCache fCommandCache; + + // A map of process id to process names. It is filled when we get all the processes that are running + private Map fProcessNames = new HashMap(); + // A map of thread id to thread group id. We use this to find out to which threadGroup a thread belongs. + private Map fGroupIdMap = new HashMap(); + + private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$ + + public GDBMultiProcesses(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 RequestMonitor(getExecutor(), 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(GDBControl.class); + fCommandCache = new CommandCache(getSession(), fCommandControl); + fCommandCache.setContextAvailable(fCommandControl.getControlDMContext(), true); + getSession().addServiceEventListener(this, null); + + // Register this service. + register(new String[] { IProcesses.class.getName(), + IMIProcesses.class.getName(), + GDBMultiProcesses.class.getName() }, + new Hashtable()); + + 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); + super.shutdown(requestMonitor); + } + + /** + * @return The bundle context of the plug-in to which this service belongs. + */ + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } + + public IThreadDMContext createThreadContext(IProcessDMContext processDmc, String threadId) { + return new MIThreadDMC(getSession().getId(), processDmc, threadId); + } + + public IProcessDMContext createProcessContext(MIControlDMContext controlDmc, String pid) { + return new MIProcessDMC(getSession().getId(), controlDmc, pid); + } + + public IMIExecutionDMContext createExecutionContext(IContainerDMContext containerDmc, + IThreadDMContext threadDmc, + String threadId) { + return new MIExecutionDMC(getSession().getId(), containerDmc, threadDmc, threadId); + } + + public IMIExecutionGroupDMContext createExecutionGroupContext(IProcessDMContext processDmc, + String groupId) { + return new MIExecutionGroupDMC(getSession().getId(), processDmc, groupId); + } + + /** + * This method obtains the model data for a given IThreadDMContext object + * which can represent a thread or a process. + * + * @param dmc + * The context for which we are requesting the data + * @param rm + * The request monitor that will contain the requested data + */ + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof IThreadDMContext) { + getExecutionData((IThreadDMContext) dmc, + (DataRequestMonitor) rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getExecutionData(IThreadDMContext dmc, final DataRequestMonitor rm) { + if (dmc instanceof IMIProcessDMContext) { + String id = ((IMIProcessDMContext)dmc).getProcId(); + String name = fProcessNames.get(id); + if (name == null) name = "Unknown name"; //$NON-NLS-1$ + rm.setData(new MIThreadDMData(name, id)); + rm.done(); + } else if (dmc instanceof MIThreadDMC) { + final MIThreadDMC threadDmc = (MIThreadDMC)dmc; + + MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class); + IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); + fCommandCache.execute(new MIListThreadGroups(controlDmc, procDmc.getProcId()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + IThreadDMData threadData = new MIThreadDMData("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + for (IThreadInfo thread : getData().getThreadList()) { + if (thread.getThreadId().equals(threadDmc.getId())) { + threadData = new MIThreadDMData("", thread.getOSId()); //$NON-NLS-1$ + break; + } + } + rm.setData(threadData); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor rm) { + rm.setData(fCommandControl.getIsAttachSession()); + rm.done(); + } + + public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor rm) { + if (procCtx instanceof IMIProcessDMContext) { + MIControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, MIControlDMContext.class); + fCommandControl.queueCommand( + new MITargetAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + fCommandControl.setConnected(true); + + IMIExecutionGroupDMContext groupDmc = createExecutionGroupContext(procCtx, + ((IMIProcessDMContext)procCtx).getProcId()); + rm.setData(groupDmc); + rm.done(); + } + }); + + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor rm) { + rm.setData(fCommandControl.getIsAttachSession() && fCommandControl.isConnected()); + rm.done(); + } + + public void detachDebuggerFromProcess(final IDMContext dmc, final RequestMonitor rm) { + MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class); + IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class); + + if (controlDmc != null && procDmc != null) { + fCommandControl.queueCommand( + new MITargetDetach(controlDmc, procDmc.getProcId()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // only if it is the last detach + fCommandControl.setConnected(false); + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void canTerminate(IThreadDMContext thread, DataRequestMonitor rm) { + rm.setData(true); + rm.done(); + } + + public void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor rm) { + rm.setData(false); + rm.done(); + } + + public void debugNewProcess(String file, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + public void getProcessesBeingDebugged(final IDMContext dmc, final DataRequestMonitor rm) { +// MIInferiorProcess inferiorProcess = fCommandControl.getInferiorProcess(); +// if (fCommandControl.isConnected() && +// inferiorProcess != null && +// inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) { + + final MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class); + final IMIExecutionGroupDMContext groupDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionGroupDMContext.class); + if (groupDmc != null) { + fCommandCache.execute( + new MIListThreadGroups(controlDmc, groupDmc.getGroupId()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(makeExecutionDMCs(groupDmc, getData().getThreadList())); + rm.done(); + } + }); + } else { + fCommandCache.execute( + new MIListThreadGroups(controlDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(makeExecutionGroupDMCs(controlDmc, getData().getGroupList())); + rm.done(); + } + }); + } +// } else { +// rm.setData(new IDMContext[0]); +// rm.done(); +// } + } + + private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerDmc, IThreadInfo[] threadInfos) { + final IProcessDMContext procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class); + + if (threadInfos.length == 0) { + // Main thread always exist even if it is not reported by GDB. + // 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)}; + } 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); + } + return executionDmcs; + } + } + + private IMIExecutionGroupDMContext[] makeExecutionGroupDMCs(MIControlDMContext controlDmc, IThreadGroupInfo[] groups) { + IProcessDMContext[] procDmcs = makeProcessDMCs(controlDmc, groups); + + IMIExecutionGroupDMContext[] groupDmcs = new IMIExecutionGroupDMContext[groups.length]; + for (int i = 0; i < procDmcs.length; i++) { + String groupId = groups[i].getGroupId(); + IProcessDMContext procDmc = createProcessContext(controlDmc, groupId); + groupDmcs[i] = createExecutionGroupContext(procDmc, groupId); + } + return groupDmcs; + } + + public void getRunningProcesses(IDMContext dmc, final DataRequestMonitor rm) { + final MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class); + + if (controlDmc != null) { + fCommandCache.execute( + new MIListThreadGroups(controlDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + for (IThreadGroupInfo groupInfo : getData().getGroupList()) { + fProcessNames.put(groupInfo.getPid(), groupInfo.getName()); + } + rm.setData(makeProcessDMCs(controlDmc, getData().getGroupList())); + } else { + rm.setData(new IProcessDMContext[0]); + } + rm.done(); + } + }); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context.", null)); //$NON-NLS-1$ + rm.done(); + } + + } + + private IProcessDMContext[] makeProcessDMCs(MIControlDMContext controlDmc, IThreadGroupInfo[] processes) { + IProcessDMContext[] procDmcs = new IMIProcessDMContext[processes.length]; + for (int i=0; i rm) { + rm.setData(false); + rm.done(); + } + public void runNewProcess(String file, DataRequestMonitor rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + public void terminate(IThreadDMContext thread, RequestMonitor rm) { + if (thread instanceof IMIProcessDMContext) { + fCommandControl.terminate(rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public String getExecutionGroupIdFromThread(String threadId) { + String groupId = fGroupIdMap.get(threadId); + if (groupId == null) return "162"; //$NON-NLS-1$ + else return groupId; + } + + @DsfServiceEventHandler + public void eventDispatched(IResumedDMEvent e) { + fCommandCache.setContextAvailable(e.getDMContext(), false); + // I need to put this so that in non-stop mode, we can send the CLIInfo + // command while some threads are running. + // However, in all-stop, this line breaks a thread exiting, and threads running + // because it allows us to send the thread-list-ids although we don't have a prompt + // We need to find a proper solution for the cache. +// fCommandCache.setContextAvailable(fCommandControl.getControlDMContext(), true); + if (e.getReason() != StateChangeReason.STEP) { + fCommandCache.reset(); + } + } + + + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent e) { + fCommandCache.setContextAvailable(e.getDMContext(), true); + fCommandCache.setContextAvailable(fCommandControl.getControlDMContext(), true); + fCommandCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadGroupCreatedEvent e) { + IProcessDMContext procDmc = e.getDMContext(); + IMIExecutionGroupDMContext groupDmc = e.getGroupId() != null ? createExecutionGroupContext(procDmc, e.getGroupId()) : null; + getSession().dispatchEvent(new ExecutionGroupStartedDMEvent(groupDmc), getProperties()); + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadGroupExitedEvent e) { + IProcessDMContext procDmc = e.getDMContext(); + IMIExecutionGroupDMContext groupDmc = e.getGroupId() != null ? createExecutionGroupContext(procDmc, e.getGroupId()) : null; + getSession().dispatchEvent(new ExecutionGroupExitedDMEvent(groupDmc), getProperties()); + + } +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java index b14c6260253..cac53fbfb63 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactory.java @@ -98,6 +98,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { @Override protected IProcesses createProcessesService(DsfSession session) { +// if (fVersion.startsWith("6.8.50.20080730")) { //$NON-NLS-1$ +// return new GDBMultiProcesses(session); +// } return new GDBProcesses(session); } diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java index 354328b8298..6eb3734a327 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.gdb.internal.provisional.service; +import org.eclipse.dd.dsf.debug.service.IProcesses; import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IStack; import org.eclipse.dd.dsf.service.DsfSession; @@ -21,7 +22,15 @@ public class GdbDebugServicesFactoryNS extends GdbDebugServicesFactory { public GdbDebugServicesFactoryNS(String version) { super(version); } - + + @Override + protected IProcesses createProcessesService(DsfSession session) { +// if (getVersion().startsWith("6.8.50.20080730")) { //$NON-NLS-1$ +// return new GDBMultiProcesses(session); +// } + return new GDBProcesses(session); + } + @Override protected IStack createStackService(DsfSession session) { return new MIStackNS(session); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIProcesses.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIProcesses.java index 548f0c32214..e81951e7ad3 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIProcesses.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIProcesses.java @@ -53,5 +53,7 @@ public interface IMIProcesses extends IProcesses */ IMIExecutionGroupDMContext createExecutionGroupContext(IProcessDMContext processDmc, String groupId); + + String getExecutionGroupIdFromThread(String threadId); } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIProcesses.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIProcesses.java index a98e8ab3287..eb7370e7bc3 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIProcesses.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIProcesses.java @@ -297,6 +297,7 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses { private CommandCache fCommandCache; private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$ + private static final String UNIQUE_GROUP_ID = "0"; //$NON-NLS-1$ public MIProcesses(DsfSession session) { super(session); @@ -444,13 +445,15 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses { public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor rm) { if (procCtx instanceof IMIProcessDMContext) { + MIControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, MIControlDMContext.class); fCommandControl.queueCommand( new CLIAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()), new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { - IMIExecutionGroupDMContext groupDmc = createExecutionGroupContext(procCtx, ""); //$NON-NLS-1$ + IMIExecutionGroupDMContext groupDmc = createExecutionGroupContext(procCtx, + ((IMIProcessDMContext)procCtx).getProcId()); getSession().dispatchEvent(new ExecutionGroupStartedDMEvent(groupDmc), getProperties()); rm.setData(groupDmc); @@ -526,7 +529,8 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses { // This service version only handles a single process to debug, therefore, we can simply // create the context describing this process ourselves. MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class); - IMIExecutionGroupDMContext newGroupDmc = createExecutionGroupContext(createProcessContext(controlDmc, ""), "");//$NON-NLS-1$//$NON-NLS-2$ + IProcessDMContext procDmc = createProcessContext(controlDmc, UNIQUE_GROUP_ID); + IMIExecutionGroupDMContext newGroupDmc = createExecutionGroupContext(procDmc, UNIQUE_GROUP_ID); rm.setData(new IContainerDMContext[] {newGroupDmc}); rm.done(); } @@ -577,6 +581,10 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses { rm.done(); } + public String getExecutionGroupIdFromThread(String threadId) { + return UNIQUE_GROUP_ID; + } + @DsfServiceEventHandler public void eventDispatched(IResumedDMEvent e) { fCommandCache.setContextAvailable(e.getDMContext(), false); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java index 1fdab36eeb4..e64d7b19893 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java @@ -44,7 +44,6 @@ import org.eclipse.dd.mi.service.command.commands.MIExecNextInstruction; import org.eclipse.dd.mi.service.command.commands.MIExecStep; import org.eclipse.dd.mi.service.command.commands.MIExecStepInstruction; import org.eclipse.dd.mi.service.command.commands.MIExecUntil; -import org.eclipse.dd.mi.service.command.commands.MIThreadListIds; import org.eclipse.dd.mi.service.command.events.IMIDMEvent; import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; import org.eclipse.dd.mi.service.command.events.MIErrorEvent; @@ -58,7 +57,6 @@ import org.eclipse.dd.mi.service.command.events.MIThreadCreatedEvent; import org.eclipse.dd.mi.service.command.events.MIThreadExitEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.dd.mi.service.command.output.MIInfo; -import org.eclipse.dd.mi.service.command.output.MIThreadListIdsInfo; import org.osgi.framework.BundleContext; /** @@ -286,7 +284,6 @@ public class MIRunControlNS extends AbstractDsfService implements IRunControl public void shutdown(final RequestMonitor rm) { unregister(); getSession().removeServiceEventListener(this); - fMICommandCache.reset(); super.shutdown(rm); } @@ -647,24 +644,22 @@ public class MIRunControlNS extends AbstractDsfService implements IRunControl // ------------------------------------------------------------------------ public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor rm) { - fMICommandCache.execute(new MIThreadListIds(containerDmc), - new DataRequestMonitor(getExecutor(), rm) { + IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class); + procService.getProcessesBeingDebugged( + containerDmc, + new DataRequestMonitor(getExecutor(), rm) { @Override protected void handleSuccess() { - rm.setData(makeExecutionDMCs(containerDmc, getData())); + if (getData() instanceof IExecutionDMContext[]) { + rm.setData((IExecutionDMContext[])getData()); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid contexts", null)); //$NON-NLS-1$ + } rm.done(); } }); } - private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerCtx, MIThreadListIdsInfo info) { - IExecutionDMContext[] executionDmcs = new IMIExecutionDMContext[info.getStrThreadIds().length]; - for (int i = 0; i < info.getStrThreadIds().length; i++) { - executionDmcs[i] = createMIExecutionContext(containerCtx, info.getStrThreadIds()[i]); - } - return executionDmcs; - } - public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor rm) { MIThreadRunState threadState = fThreadRunStates.get(dmc); if (threadState == null) { diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java index 7e7b5aab8a9..d529da73948 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java @@ -123,10 +123,14 @@ public class CLIEventProcessor Pattern pattern = Pattern.compile("(^\\[New Thread.*LWP\\s*)(\\d*)", Pattern.MULTILINE); //$NON-NLS-1$ Matcher matcher = pattern.matcher(exec.getCString()); if (matcher.find()) { + String threadId = Integer.toString(++fLastThreadId); + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ - IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, ""); //$NON-NLS-1$ - MIEvent e = new MIThreadCreatedEvent(processContainerDmc, Integer.toString(++fLastThreadId)); + String groupId = procService.getExecutionGroupIdFromThread(threadId); + + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); + MIEvent e = new MIThreadCreatedEvent(processContainerDmc, threadId); fCommandControl.getSession().dispatchEvent(e, fCommandControl.getProperties()); } @@ -147,8 +151,10 @@ public class CLIEventProcessor if (fInferior.getState() == MIInferiorProcess.State.RUNNING) { fInferior.setState(MIInferiorProcess.State.STOPPED); IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ - IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, ""); //$NON-NLS-1$ + String groupId = procService.getExecutionGroupIdFromThread(null); + + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); fCommandControl.getSession().dispatchEvent( MIErrorEvent.parse(processContainerDmc, rr.getToken(), rr.getMIResults(), null), fCommandControl.getProperties()); @@ -191,8 +197,10 @@ public class CLIEventProcessor if (type != -1) { // if it was a step instruction set state running IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ - IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, ""); //$NON-NLS-1$ + String groupId = procService.getExecutionGroupIdFromThread(null); + + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); MIEvent event = new MIRunningEvent(processContainerDmc, token, type); fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java index 5a8b77fcde6..1f3c1b5b745 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java @@ -47,6 +47,8 @@ import org.eclipse.dd.mi.service.command.events.MISteppingRangeEvent; import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; import org.eclipse.dd.mi.service.command.events.MIThreadCreatedEvent; import org.eclipse.dd.mi.service.command.events.MIThreadExitEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadGroupCreatedEvent; +import org.eclipse.dd.mi.service.command.events.MIThreadGroupExitedEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointScopeEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.dd.mi.service.command.output.MIConst; @@ -157,9 +159,8 @@ public class MIRunControlEventProcessor MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr; String miEvent = exec.getAsyncClass(); if ("thread-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ - - // For now, since GDB does not support thread-groups, fake an empty one - String groupId = "";//null; //$NON-NLS-1$ + String threadId = null; + String groupId = null; MIResult[] results = exec.getMIResults(); for (int i = 0; i < results.length; i++) { @@ -169,33 +170,74 @@ public class MIRunControlEventProcessor if (val instanceof MIConst) { groupId = ((MIConst) val).getString(); } - } + } else if (var.equals("id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + threadId = ((MIConst) val).getString(); + } + } } IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ + + if (groupId == null) { + groupId = procService.getExecutionGroupIdFromThread(threadId); + } + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); MIEvent event = null; if ("thread-created".equals(miEvent)) { //$NON-NLS-1$ - event = MIThreadCreatedEvent.parse(processContainerDmc, exec.getToken(), exec.getMIResults()); + event = new MIThreadCreatedEvent(processContainerDmc, exec.getToken(), threadId); } else if ("thread-exited".equals(miEvent)) { //$NON-NLS-1$ - event = MIThreadExitEvent.parse(processContainerDmc, exec.getToken(), exec.getMIResults()); + event = new MIThreadExitEvent(processContainerDmc, exec.getToken(), threadId); } if (event != null) { fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); } } + } else if (oobr instanceof MINotifyAsyncOutput) { + // Parse the string and dispatch the corresponding event + MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr; + String miEvent = exec.getAsyncClass(); + if ("thread-group-created".equals(miEvent) || "thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ + + 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) { + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + + MIEvent event = null; + if ("thread-group-created".equals(miEvent)) { //$NON-NLS-1$ + event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId); + } else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ + event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId); + } + + if (event != null) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + } } } } protected MIEvent createEvent(String reason, MIExecAsyncOutput exec) { String threadId = null; - - // For now, since GDB does not support thread-groups, fake an empty one - String groupId = "";//null; //$NON-NLS-1$ + String groupId = null; MIResult[] results = exec.getMIResults(); for (int i = 0; i < results.length; i++) { @@ -215,7 +257,10 @@ public class MIRunControlEventProcessor IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ + if (groupId == null) { + groupId = procService.getExecutionGroupIdFromThread(threadId); + } + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); IExecutionDMContext execDmc = processContainerDmc; @@ -291,8 +336,9 @@ public class MIRunControlEventProcessor else { type = MIRunningEvent.CONTINUE; } IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, ""); //$NON-NLS-1$ - IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, ""); //$NON-NLS-1$ + String groupId = procService.getExecutionGroupIdFromThread(null); + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); fCommandControl.getSession().dispatchEvent( new MIRunningEvent(processContainerDmc, id, type), fCommandControl.getProperties()); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIListThreadGroups.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIListThreadGroups.java index 9e7feb4d071..66967531881 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIListThreadGroups.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIListThreadGroups.java @@ -12,23 +12,22 @@ package org.eclipse.dd.mi.service.command.commands; import java.util.ArrayList; -import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.dd.mi.service.IMIExecutionGroupDMContext; +import org.eclipse.dd.mi.service.command.MIControlDMContext; import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo; import org.eclipse.dd.mi.service.command.output.MIOutput; /** - * -list-thread-groups [--available] [GROUP] + * -list-thread-groups [--available | GROUP] * * When used without GROUP parameter, this will list top-level - * thread groups that are been debugged. When used with the GROUP + * thread groups that are being debugged. When used with the GROUP * parameter, the children of the specified group will be listed. * The children can be either threads, or other groups. At present, * GDB will not report both threads and groups as children at the * same time, but it may change in future. * * With the --available option, instead of reporting groups that are - * been debugged, GDB will report all thread groups available on the + * being debugged, GDB will report all thread groups available on the * target, not only the presently debugged ones. Using the --available * option together with explicit GROUP is not likely to work on all targets. * @@ -45,11 +44,24 @@ import org.eclipse.dd.mi.service.command.output.MIOutput; */ public class MIListThreadGroups extends MICommand { - public MIListThreadGroups(IContainerDMContext ctx) { + // List all groups being debugged + public MIListThreadGroups(MIControlDMContext ctx) { this(ctx, false); } - public MIListThreadGroups(IContainerDMContext ctx, boolean listAll) { + // List all groups or threads being debugged which are children of the specified group + public MIListThreadGroups(MIControlDMContext ctx, String groupId) { + this(ctx, groupId, false); + } + + // List all groups available on the target + public MIListThreadGroups(MIControlDMContext ctx, boolean listAll) { + this(ctx, null, listAll); + } + + // There should be no reason to have both listAll and groupId specified, + // so this constructor is private, and exists to avoid duplicating code. + private MIListThreadGroups(MIControlDMContext ctx, String groupId, boolean listAll) { super(ctx, "-list-thread-groups"); //$NON-NLS-1$ final ArrayList arguments = new ArrayList(); @@ -57,11 +69,8 @@ public class MIListThreadGroups extends MICommand { arguments.add("--available"); //$NON-NLS-1$ } - // If the context is a thread-group, use the thread-group name - // to list its children; if it is not, then we don't use any name to get - // the list of all thread-groups - if (ctx instanceof IMIExecutionGroupDMContext) { - arguments.add(((IMIExecutionGroupDMContext)ctx).getGroupId()); + if (groupId != null) { + arguments.add(groupId); } if (!arguments.isEmpty()) { diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetAttach.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetAttach.java index 7aabeb04b9f..d5b6645f57f 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetAttach.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetAttach.java @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.mi.service.command.commands; -import org.eclipse.dd.mi.service.IMIExecutionGroupDMContext; -import org.eclipse.dd.mi.service.IMIProcessDMContext; +import org.eclipse.dd.mi.service.command.MIControlDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** @@ -22,11 +21,7 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; */ public class MITargetAttach extends MICommand { - public MITargetAttach(IMIExecutionGroupDMContext ctx) { - super(ctx, "-target-attach", new String[] {ctx.getGroupId()}); //$NON-NLS-1$ - } - - public MITargetAttach(IMIProcessDMContext ctx) { - super(ctx, "-target-attach", new String[] {"--pid " + ctx.getProcId()}); //$NON-NLS-1$//$NON-NLS-2$ + public MITargetAttach(MIControlDMContext ctx, String groupId) { + super(ctx, "-target-attach", new String[] {groupId}); //$NON-NLS-1$ } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetDetach.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetDetach.java index 1681587f4fc..6141c0ee7f5 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetDetach.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MITargetDetach.java @@ -10,8 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.mi.service.command.commands; -import org.eclipse.dd.mi.service.IMIExecutionGroupDMContext; -import org.eclipse.dd.mi.service.IMIProcessDMContext; +import org.eclipse.dd.mi.service.command.MIControlDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** @@ -21,12 +20,8 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; * or THREAD_GROUP_ID */ public class MITargetDetach extends MICommand { - - public MITargetDetach(IMIExecutionGroupDMContext ctx) { - super(ctx, "-target-detach", new String[] {ctx.getGroupId()}); //$NON-NLS-1$ - } - public MITargetDetach(IMIProcessDMContext ctx) { - super(ctx, "-target-detach", new String[] {"--pid " + ctx.getProcId()}); //$NON-NLS-1$//$NON-NLS-2$ + public MITargetDetach(MIControlDMContext ctx, String groupId) { + super(ctx, "-target-detach", new String[] {groupId}); //$NON-NLS-1$ } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java index 17ed050a80b..bebd9071acd 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java @@ -14,13 +14,10 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.dd.mi.service.command.output.MIConst; -import org.eclipse.dd.mi.service.command.output.MIResult; -import org.eclipse.dd.mi.service.command.output.MIValue; /** - * This can not be detected yet by gdb/mi. + * This can only be detected by gdb/mi after GDB 6.8. * */ @Immutable @@ -58,19 +55,4 @@ public class MIThreadCreatedEvent extends MIEvent { public String getStrId() { return fThreadId; } - - public static MIThreadCreatedEvent parse(IContainerDMContext ctx, int token, MIResult[] results) - { - 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) { - return new MIThreadCreatedEvent(ctx, token, ((MIConst) val).getString().trim()); - } - } - } - - return null; - } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java index ef26491b1ce..b93b321f4b5 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java @@ -14,9 +14,6 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; -import org.eclipse.dd.mi.service.command.output.MIConst; -import org.eclipse.dd.mi.service.command.output.MIResult; -import org.eclipse.dd.mi.service.command.output.MIValue; /** @@ -58,19 +55,4 @@ public class MIThreadExitEvent extends MIEvent { public String getStrId() { return fThreadId; } - - public static MIThreadExitEvent parse(IContainerDMContext ctx, int token, MIResult[] results) - { - 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) { - return new MIThreadExitEvent(ctx, token, ((MIConst) val).getString().trim()); - } - } - } - - return null; - } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupCreatedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupCreatedEvent.java new file mode 100644 index 00000000000..2f480a07935 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupCreatedEvent.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext; + + +/** + * This can only be detected by gdb/mi after GDB 6.8. + * + */ +@Immutable +public class MIThreadGroupCreatedEvent extends MIEvent { + + final private String fGroupId; + + public MIThreadGroupCreatedEvent(IProcessDMContext ctx, int token, String groupId) { + super(ctx, token, null); + fGroupId = groupId; + } + + public String getGroupId() { return fGroupId; } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupExitedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupExitedEvent.java new file mode 100644 index 00000000000..80a00f55d56 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadGroupExitedEvent.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.events; + +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext; + + +/** + * This can only be detected by gdb/mi after GDB 6.8. + * + */ +@Immutable +public class MIThreadGroupExitedEvent extends MIEvent { + + final private String fGroupId; + + public MIThreadGroupExitedEvent(IProcessDMContext ctx, int token, String groupId) { + super(ctx, token, null); + fGroupId = groupId; + } + + public String getGroupId() { return fGroupId; } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIListThreadGroupsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIListThreadGroupsInfo.java index 8d190f6afcb..9d82582309b 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIListThreadGroupsInfo.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIListThreadGroupsInfo.java @@ -11,75 +11,105 @@ package org.eclipse.dd.mi.service.command.output; -import org.eclipse.cdt.core.IProcessInfo; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.dd.dsf.concurrent.Immutable; /** * GDB/MI thread group parsing. * - * ^done,groups=[{id="p133",type="process",pid="133"},{id="p162",type="process",pid="162"}] - * or - * ^done,threads=[{id="1",target-id="Thread 162.32942",details="JUnitProcess_PT (Ready) 1275938023 3473",frame={level="0",addr="0x00000000",func="??",args=[]}}] + * The description field can be different depending on the target we are connected to. + * + * This output is from -list-thread-groups --available: + * ^done,groups=[{id="160",description="name: JIM_InstallerProcess, type 555481, locked: N, system: N, state: Idle"}, + * {id="161",description="name: JIM_TcpSetupHandlerProcess, type 555505, locked: N, system: N, state: Idle"}, + * {id="162",description="name: JUnitProcess_PT, type 1094605, locked: N, system: N, state: Idle"}] + * + * This output is from -list-thread-groups: + * ^done,groups=[{id="162",type="process",pid="162"}] + * + * This output is from -list-thread-groups GROUPID, in the case of a running thread or a stopped thread: + * ^done,threads=[{id="1",target-id="Thread 162.32942",details="JUnitProcess_PT (Ready) 1030373359 44441",frame={level="0",addr="0x00000000",func="??",args=[]},state="stopped"}] + * ^done,threads=[{id="1",target-id="Thread 162.32942",details="JUnitProcess_PT Idle 981333916 42692",state="running"}] */ public class MIListThreadGroupsInfo extends MIInfo { - public class ThreadGroupInfo implements IProcessInfo { - int pid; - String name; + public interface IThreadGroupInfo { + String getGroupId(); + String getPid(); + String getName(); + String getDesciption(); + } + + @Immutable + private static class ThreadGroupInfo implements IThreadGroupInfo { + final String fGroupId; + final String fDescription; + final String fName; - public ThreadGroupInfo(String name, String pidStr) { - try { - this.pid = Integer.parseInt(pidStr); - } catch (NumberFormatException e) { - } - this.name = name; + public ThreadGroupInfo(String id, String description) { + fGroupId = id; + fDescription = description; + + fName = parseName(fDescription); } - public ThreadGroupInfo(String name, int pid) { - this.pid = pid; - this.name = name; - } - - /** - * @see org.eclipse.cdt.core.IProcessInfo#getName() - */ - public String getName() { + private static String parseName(String desc) { + String name = ""; //$NON-NLS-1$ + + // Find the string "name: " followed by the smallest set of characters that + // is followed by a comma, or by the end of the line. + Pattern pattern = Pattern.compile("name: (.*?)(, |$)", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(desc); + if (matcher.find()) { + name = matcher.group(1); + } + return name; } - - /** - * @see org.eclipse.cdt.core.IProcessInfo#getPid() - */ - public int getPid() { - return pid; - } - } - - public class ThreadId { - String fId; - public ThreadId(String id) { - fId = id; - } - public String getId() { - return fId; - } + public String getGroupId() { return fGroupId; } + public String getPid() { return fGroupId; } + + public String getName() { return fName; } + + public String getDesciption() { return fDescription; } } - IProcessInfo[] fProcessList; - ThreadId[] fThreadList; + public interface IThreadInfo { + String getThreadId(); + String getOSId(); + String getState(); + } + + @Immutable + private static class ThreadInfo implements IThreadInfo { + final String fThreadId; + final String fOSId; + final String fState; + + public ThreadInfo(String id, String osId, String state) { + fThreadId = id; + fOSId = osId; + fState = state; + } + + public String getThreadId() { return fThreadId; } + public String getOSId() { return fOSId; } + public String getState() { return fState; } + } + + IThreadGroupInfo[] fGroupList; + IThreadInfo[] fThreadList; public MIListThreadGroupsInfo(MIOutput out) { super(out); parse(); } - public IProcessInfo[] getGroupList() { - return fProcessList; - } - - public ThreadId[] getThreadList() { - return fThreadList; - } + public IThreadGroupInfo[] getGroupList() { return fGroupList; } + public IThreadInfo[] getThreadList() { return fThreadList; } private void parse() { if (isDone()) { @@ -104,20 +134,20 @@ public class MIListThreadGroupsInfo extends MIInfo { } } } - if (fProcessList == null) { - fProcessList = new ThreadGroupInfo[0]; + if (fGroupList == null) { + fGroupList = new IThreadGroupInfo[0]; } if (fThreadList == null) { - fThreadList = new ThreadId[0]; + fThreadList = new IThreadInfo[0]; } } private void parseGroups(MIList list) { MIValue[] values = list.getMIValues(); - fProcessList = new ThreadGroupInfo[values.length]; + fGroupList = new ThreadGroupInfo[values.length]; for (int i = 0; i < values.length; i++) { MIResult[] results = ((MITuple)values[i]).getMIResults(); - String name = "", pid = "";//$NON-NLS-1$//$NON-NLS-2$ + String id = "", desc = "";//$NON-NLS-1$//$NON-NLS-2$ for (MIResult result : results) { String var = result.getVariable(); @@ -125,27 +155,27 @@ public class MIListThreadGroupsInfo extends MIInfo { MIValue value = result.getMIValue(); if (value instanceof MIConst) { String str = ((MIConst)value).getCString(); - name = str.trim(); - + id = str.trim(); } - } else if (var.equals("pid")) { //$NON-NLS-1$ + } else if (var.equals("description")) { //$NON-NLS-1$ MIValue value = result.getMIValue(); if (value instanceof MIConst) { String str = ((MIConst)value).getCString(); - pid = str.trim(); + desc = str.trim(); } } } - fProcessList[i] = new ThreadGroupInfo(name, pid); + fGroupList[i] = new ThreadGroupInfo(id, desc); } } private void parseThreads(MIList list) { MIValue[] values = list.getMIValues(); - fThreadList = new ThreadId[values.length]; + fThreadList = new ThreadInfo[values.length]; for (int i = 0; i < values.length; i++) { MIResult[] results = ((MITuple)values[i]).getMIResults(); + String id = "", osId = "", state = "";//$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ for (MIResult result : results) { String var = result.getVariable(); @@ -153,11 +183,26 @@ public class MIListThreadGroupsInfo extends MIInfo { MIValue value = result.getMIValue(); if (value instanceof MIConst) { String str = ((MIConst)value).getCString(); - fThreadList[i] = new ThreadId(str.trim()); - break; + id = str.trim(); + } + } else if (var.equals("target-id")) { //$NON-NLS-1$ + MIValue value = result.getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getCString(); + osId = str.trim(); + + } + } else if (var.equals("state")) { //$NON-NLS-1$ + MIValue value = result.getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst)value).getCString(); + state = str.trim(); + } } } + fThreadList[i] = new ThreadInfo(id, osId, state); + } } }