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

Bug 240507

Adds a GDBMultiProcesses service which uses the new GDB -list-thread-group commands.  Also adds some support for =thread-group-created/exited events.

Since the public GDB is not ready yet, I have commented out the instantiation of this new service, for now.
This commit is contained in:
Marc Khouzam 2008-08-06 13:39:49 +00:00
parent 0d74c407e4
commit 55a4d47017
19 changed files with 1011 additions and 168 deletions

View file

@ -501,7 +501,6 @@ public class GdbThreadFilterEditor {
if (procService != null) {
IThreadDMContext threadDmc = DMContexts.getAncestorOfType(thread, IThreadDMContext.class);
procService.getExecutionData(threadDmc, new DataRequestMonitor<IThreadDMData>(
// Is it ok to use the ImmediateExecutor here?
ImmediateExecutor.getInstance(), rm) {
@Override
protected void handleSuccess() {

View file

@ -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;
}

View file

@ -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) {

View file

@ -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.
* <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;
}
/**
* 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.
* <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;
}
/**
* 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.
* <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, 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<IExecutionDMContext>
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<IExecutionDMContext>
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<String, String> fProcessNames = new HashMap<String, String>();
// 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> fGroupIdMap = new HashMap<String, String>();
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<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);
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<IThreadDMData>) 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<IThreadDMData> 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<MIListThreadGroupsInfo>(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<IDMContext> 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<Boolean> rm) {
rm.setData(fCommandControl.getIsAttachSession());
rm.done();
}
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) {
if (procCtx instanceof IMIProcessDMContext) {
MIControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, MIControlDMContext.class);
fCommandControl.queueCommand(
new MITargetAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(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<Boolean> 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<MIInfo>(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<Boolean> rm) {
rm.setData(true);
rm.done();
}
public void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(false);
rm.done();
}
public void debugNewProcess(String file, DataRequestMonitor<IProcessDMContext> 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<IDMContext[]> 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<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(makeExecutionDMCs(groupDmc, getData().getThreadList()));
rm.done();
}
});
} else {
fCommandCache.execute(
new MIListThreadGroups(controlDmc),
new DataRequestMonitor<MIListThreadGroupsInfo>(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<IProcessDMContext[]> rm) {
final MIControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, MIControlDMContext.class);
if (controlDmc != null) {
fCommandCache.execute(
new MIListThreadGroups(controlDmc, true),
new DataRequestMonitor<MIListThreadGroupsInfo>(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<procDmcs.length; i++) {
procDmcs[i] = createProcessContext(controlDmc, processes[i].getGroupId());
}
return procDmcs;
}
public void isRunNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(false);
rm.done();
}
public void runNewProcess(String file, DataRequestMonitor<IProcessDMContext> 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());
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -53,5 +53,7 @@ public interface IMIProcesses extends IProcesses
*/
IMIExecutionGroupDMContext createExecutionGroupContext(IProcessDMContext processDmc,
String groupId);
String getExecutionGroupIdFromThread(String threadId);
}

View file

@ -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<IDMContext> rm) {
if (procCtx instanceof IMIProcessDMContext) {
MIControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, MIControlDMContext.class);
fCommandControl.queueCommand(
new CLIAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(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);

View file

@ -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<IExecutionDMContext[]> rm) {
fMICommandCache.execute(new MIThreadListIds(containerDmc),
new DataRequestMonitor<MIThreadListIdsInfo>(getExecutor(), rm) {
IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class);
procService.getProcessesBeingDebugged(
containerDmc,
new DataRequestMonitor<IDMContext[]>(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<IExecutionDMData> rm) {
MIThreadRunState threadState = fThreadRunStates.get(dmc);
if (threadState == null) {

View file

@ -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());
}

View file

@ -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());

View file

@ -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<MIListThreadGroupsInfo> {
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<String> arguments = new ArrayList<String>();
@ -57,11 +69,8 @@ public class MIListThreadGroups extends MICommand<MIListThreadGroupsInfo> {
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()) {

View file

@ -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<MIInfo> {
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$
}
}

View file

@ -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<MIInfo> {
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$
}
}

View file

@ -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<IContainerDMContext> {
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;
}
}

View file

@ -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<IContainerDMContext> {
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;
}
}

View file

@ -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<IProcessDMContext> {
final private String fGroupId;
public MIThreadGroupCreatedEvent(IProcessDMContext ctx, int token, String groupId) {
super(ctx, token, null);
fGroupId = groupId;
}
public String getGroupId() { return fGroupId; }
}

View file

@ -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<IProcessDMContext> {
final private String fGroupId;
public MIThreadGroupExitedEvent(IProcessDMContext ctx, int token, String groupId) {
super(ctx, token, null);
fGroupId = groupId;
}
public String getGroupId() { return fGroupId; }
}

View file

@ -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);
}
}
}