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

Bug 239050

New interface and service to provide access to the OS's process information, manipulation methods, and debugging methods.
This commit is contained in:
Marc Khouzam 2008-07-03 19:05:20 +00:00
parent dd61347700
commit e3eb35603d
7 changed files with 500 additions and 9 deletions

View file

@ -34,7 +34,9 @@ public abstract class AbstractDsfDebugServicesFactory implements IDsfDebugServic
return (V)createMemoryService(session);
} else if (IRunControl.class.isAssignableFrom(clazz)) {
return (V)createRunControlService(session);
}
} else if (IProcesses.class.isAssignableFrom(clazz)) {
return (V)createProcessesService(session);
}
return null;
}
@ -48,5 +50,6 @@ public abstract class AbstractDsfDebugServicesFactory implements IDsfDebugServic
protected abstract IModules createModulesService(DsfSession session);
protected abstract IMemory createMemoryService(DsfSession session);
protected abstract IRunControl createRunControlService(DsfSession session);
protected abstract IProcesses createProcessesService(DsfSession session);
}

View file

@ -0,0 +1,119 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 Wind River Systems 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:
* Wind River Systems - initial API and implementation
* Ericsson - Updated for latest DSF version
*******************************************************************************/
package org.eclipse.dd.dsf.debug.service;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.datamodel.IDMContext;
import org.eclipse.dd.dsf.datamodel.IDMData;
import org.eclipse.dd.dsf.datamodel.IDMEvent;
import org.eclipse.dd.dsf.datamodel.IDMService;
/**
* This interface provides access to the OS's process
* information, manipulation methods, and debugging methods.
* This service provides a relatively simple interface for
* manipulating processes as compared with a full-blown
* remote target debugger.
*/
public interface IProcesses extends IDMService {
/**
* A thread as known by the OS.
* This context is kept different than {@link IRunControl.IExecutionDMContext}
* because the OS id of a thread may not be the same as the thread id used by
* the debugger when doing run control operations.
*/
public interface IThreadDMContext extends IDMContext {}
/**
* A process as known by the OS.
* This context is kept different than {@link IRunControl.IContainerDMContext}
* because the OS id of a process may not be the same as the process id used by
* the debugger when doing run control operations.
*/
public interface IProcessDMContext extends IThreadDMContext {}
/**
* Interface for thread and process object data. This data provides a link
* to the lower level debugger services, in form of execution contexts.
*/
public interface IThreadDMData extends IDMData {
String getName();
String getId();
boolean isDebuggerAttached();
IDMContext getDebuggingContext();
}
/**
* Event indicating that process data has changed.
*/
public interface ProcessChangedDMEvent extends IDMEvent<IProcessDMContext> {}
/**
* Retrieves thread or process data for given context.
* @param dmc Context to retrieve data for.
* @param rm Request completion monitor.
*/
public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm);
/**
* Retrieves the current list of processes running on target.
* @param rm Request completion monitor, to be filled in with array of process contexts.
*/
void getRunningProcesses(DataRequestMonitor<IProcessDMContext[]> rm);
/**
* Attaches debugger to the given process.
*/
void attachDebuggerToProcess(IProcessDMContext procCtx, RequestMonitor requestMonitor);
/**
* Detaches debugger from the given process.
*/
void detachDebuggerFromProcess(IProcessDMContext procCtx, RequestMonitor requestMonitor);
/**
* Starts a new process.
* @param file Process image to use for the new process.
* @param rm Request completion monitor, to be filled in with the process context.
*/
void runNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm);
/**
* Starts a new process with debugger attached.
* @param file Process image to use for the new process.
* @param rm Request completion monitor, to be willed in with the process context.
*/
void debugNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm);
/**
* Retrieves the list of processes which are currently under
* debugger control.
* @param rm Request completion monitor.
*/
void getProcessesBeingDebugged(DataRequestMonitor<IProcessDMContext[]> rm);
/**
* Checks whether the given process or thread can be terminated.
* @param thread Thread or process to terminate.
* @param rm Return token.
*/
void canTerminate(IThreadDMContext thread, DataRequestMonitor<Boolean> rm);
/**
* Terminates the selected process or thread.
* @param thread Thread or process to terminate.
* @param rm Request completion monitor, indicates success or failure.
*/
void terminate(IThreadDMContext thread, RequestMonitor requestMonitor);
}

View file

@ -37,14 +37,15 @@ import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.concurrent.Sequence;
import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext;
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.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.MIBreakpointsManager;
import org.eclipse.dd.mi.service.command.commands.CLIAttach;
import org.eclipse.dd.mi.service.command.commands.CLIMonitorListProcesses;
import org.eclipse.dd.mi.service.command.commands.CLISource;
import org.eclipse.dd.mi.service.command.commands.MIEnvironmentCD;
@ -70,8 +71,9 @@ public class FinalLaunchSequence extends Sequence {
public void execute(RequestMonitor requestMonitor) {
DsfServicesTracker tracker = new DsfServicesTracker(GdbPlugin.getBundleContext(), fLaunch.getSession().getId());
fCommandControl = tracker.getService(GDBControl.class);
if (fCommandControl == null) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain GDBControl service", null)); //$NON-NLS-1$
fProcService = tracker.getService(GDBProcesses.class);
if (fCommandControl == null || fProcService == null) {
requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot obtain service", null)); //$NON-NLS-1$
}
tracker.dispose();
@ -437,17 +439,23 @@ public class FinalLaunchSequence extends Sequence {
}
if (pid != -1) {
fCommandControl.queueCommand(
new CLIAttach(fCommandControl.getControlDMContext(), pid),
IProcessDMContext procDmc =
fProcService.createProcessContext(Integer.toString(pid));
fProcService.attachDebuggerToProcess(
procDmc,
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
} else {
promptForProcessID(fLaunch.getLaunchConfiguration(),
new DataRequestMonitor<Integer>(getExecutor(), requestMonitor) {
@Override
protected void handleSuccess() {
fCommandControl.queueCommand(
new CLIAttach(fCommandControl.getControlDMContext(), getData()),
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
IProcessDMContext procDmc =
fProcService.createProcessContext(Integer.toString(getData()));
fProcService.attachDebuggerToProcess(
procDmc,
new DataRequestMonitor<MIInfo>(getExecutor(), requestMonitor));
}
});
}
@ -482,6 +490,8 @@ public class FinalLaunchSequence extends Sequence {
boolean fAttach;
GDBControl fCommandControl;
GDBProcesses fProcService;
// The list of processes used in the case of an ATTACH session
IProcessInfo[] fProcessList = null;

View file

@ -19,6 +19,7 @@ import org.eclipse.dd.dsf.debug.service.IDisassembly;
import org.eclipse.dd.dsf.debug.service.IExpressions;
import org.eclipse.dd.dsf.debug.service.IMemory;
import org.eclipse.dd.dsf.debug.service.IModules;
import org.eclipse.dd.dsf.debug.service.IProcesses;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.ISourceLookup;
@ -50,6 +51,10 @@ public class ServicesLaunchSequence extends Sequence {
fLaunch.getServiceFactory().createService(fSession, IRunControl.class).initialize(requestMonitor);
}},
new Step() { @Override
public void execute(RequestMonitor requestMonitor) {
fLaunch.getServiceFactory().createService(fSession, IProcesses.class).initialize(requestMonitor);
}},
new Step() { @Override
public void execute(RequestMonitor requestMonitor) {
new StepQueueManager(fSession).initialize(requestMonitor);
}},

View file

@ -21,6 +21,7 @@ import org.eclipse.dd.dsf.debug.service.IDisassembly;
import org.eclipse.dd.dsf.debug.service.IExpressions;
import org.eclipse.dd.dsf.debug.service.IMemory;
import org.eclipse.dd.dsf.debug.service.IModules;
import org.eclipse.dd.dsf.debug.service.IProcesses;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.ISourceLookup;
@ -110,6 +111,11 @@ public class ShutdownSequence extends Sequence {
public void execute(RequestMonitor requestMonitor) {
shutdownService(IMemory.class, requestMonitor);
}
}, new Step() {
@Override
public void execute(RequestMonitor requestMonitor) {
shutdownService(IProcesses.class, requestMonitor);
}
}, new Step() {
@Override
public void execute(RequestMonitor requestMonitor) {

View file

@ -0,0 +1,342 @@
/*******************************************************************************
* 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.Hashtable;
import org.eclipse.cdt.core.IProcessInfo;
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.IDMContext;
import org.eclipse.dd.dsf.debug.service.IProcesses;
import org.eclipse.dd.dsf.service.AbstractDsfService;
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.command.commands.CLIAttach;
import org.eclipse.dd.mi.service.command.commands.CLIMonitorListProcesses;
import org.eclipse.dd.mi.service.command.output.CLIMonitorListProcessesInfo;
import org.eclipse.dd.mi.service.command.output.MIInfo;
import org.osgi.framework.BundleContext;
public class GDBProcesses extends AbstractDsfService implements IProcesses {
@Immutable
protected class GdbThreadDMC extends AbstractDMContext
implements IThreadDMContext
{
/**
* ID given by the OS.
*/
private final String fOSId;
/**
* Constructor for the context. It should not be called directly by clients.
* Instead clients should call {@link GDBProcesses#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.
*/
protected GdbThreadDMC(String sessionId, IProcessDMContext processDmc, String id) {
super(sessionId, processDmc != null ? new IDMContext[] { processDmc } : new IDMContext[0]);
fOSId = id;
}
/**
* Returns the thread identifier of this context.
* @return
*/
public String getId(){ return fOSId; }
@Override
public String toString() { return baseToString() + ".thread[" + fOSId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
@Override
public boolean equals(Object obj) {
return super.baseEquals(obj) && ((GdbThreadDMC)obj).fOSId == fOSId;
}
@Override
public int hashCode() { return super.baseHashCode() ^ fOSId.hashCode(); }
}
@Immutable
protected class GdbProcessDMC extends GdbThreadDMC
implements IProcessDMContext
{
/**
* Constructor for the context. It should not be called directly by clients.
* Instead clients should call {@link GDBProcesses#createProcessContext}
* to create instances of this context based on the PID.
* <p/>
*
* @param sessionId Session that this context belongs to.
* @param name process name
* @param id process identifier.
*/
protected GdbProcessDMC(String sessionId, String id) {
super(sessionId, null, id);
}
@Override
public String toString() { return baseToString() + ".proc[" + getId() + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() { return super.hashCode(); }
}
/*
* The data of a corresponding thread or process.
*/
@Immutable
private static class GdbThreadDMData implements IThreadDMData {
final String fName;
final String fId;
GdbThreadDMData(String name, String id) {
fName = name;
fId = id;
}
public IDMContext getDebuggingContext() {
return null;
}
public String getId() { return fId; }
public String getName() { return fName; }
public boolean isDebuggerAttached() {
return true;
}
}
private GDBControl fCommandControl;
public GDBProcesses(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) {
// Register this service.
register(new String[] { IProcesses.class.getName(),
GDBProcesses.class.getName() },
new Hashtable<String, String>());
fCommandControl = getServicesTracker().getService(GDBControl.class);
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();
super.shutdown(requestMonitor);
}
/**
* @return The bundle context of the plug-in to which this service belongs.
*/
@Override
protected BundleContext getBundleContext() {
return GdbPlugin.getBundleContext();
}
/**
* Create a thread context.
*
* @param process The parent process context
* @param threadId The OS Id of the thread
*/
public IThreadDMContext createThreadContext(IProcessDMContext process, String threadId) {
return new GdbThreadDMC(getSession().getId(), process, threadId);
}
/**
* Create a process context.
*
* @param pid The OS Id of the process
*/
public IProcessDMContext createProcessContext(String pid) {
return new GdbProcessDMC(getSession().getId(), pid);
}
/**
* This method obtains the model data for a given GdbThreadDMC 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, "Unknown DMC type", null)); //$NON-NLS-1$
rm.done();
}
}
public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) {
// We must first check for GdbProcessDMC because it is also a GdbThreadDMC
if (dmc instanceof GdbProcessDMC) {
rm.setData(new GdbThreadDMData("", ((GdbProcessDMC)dmc).getId())); //$NON-NLS-1$
rm.done();
} else if (dmc instanceof GdbThreadDMC) {
rm.setData(new GdbThreadDMData("", ((GdbThreadDMC)dmc).getId())); //$NON-NLS-1$
rm.done();
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
rm.done();
}
}
public void attachDebuggerToProcess(IProcessDMContext procCtx, final RequestMonitor rm) {
if (procCtx instanceof GdbProcessDMC) {
int pid;
try {
pid = Integer.parseInt(((GdbProcessDMC)procCtx).getId());
} catch (NumberFormatException e) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid process id.", null)); //$NON-NLS-1$
rm.done();
return;
}
fCommandControl.queueCommand(
new CLIAttach(procCtx, pid),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
}
}
public void detachDebuggerFromProcess(IProcessDMContext procCtx, final RequestMonitor rm) {
// if (procCtx instanceof GdbProcessDMC) {
// int pid;
// try {
// pid = Integer.parseInt(((GdbProcessDMC)procCtx).getId());
// } catch (NumberFormatException e) {
// rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid process id.", null)); //$NON-NLS-1$
// rm.done();
// return;
// }
//
// fCommandControl.queueCommand(
// new CLIDetach(procCtx, pid),
// new DataRequestMonitor<MIInfo>(getExecutor(), rm));
// } else {
// rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
// rm.done();
// }
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$
rm.done();
}
public void canTerminate(IThreadDMContext thread, DataRequestMonitor<Boolean> rm) {
rm.setData(true);
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(DataRequestMonitor<IProcessDMContext[]> rm) {
// use -list-thread-groups
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID,
NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$
rm.done();
}
public void getRunningProcesses(DataRequestMonitor<IProcessDMContext[]> rm) {
// use -list-thread-groups for local session
// monitor list processes is only for remote session
fCommandControl.queueCommand(
new CLIMonitorListProcesses(fCommandControl.getControlDMContext()),
new DataRequestMonitor<CLIMonitorListProcessesInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
IProcessInfo[] processes = getData().getProcessList();
IProcessDMContext[] procDmcs = new GdbProcessDMC[processes.length];
for (int i=0; i<procDmcs.length; i++) {
procDmcs[i] = createProcessContext(Integer.toString(processes[i].getPid()));
}
}
});
}
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 GdbProcessDMC) {
fCommandControl.terminate(rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
}
}
}

View file

@ -17,6 +17,7 @@ import org.eclipse.dd.dsf.debug.service.IDisassembly;
import org.eclipse.dd.dsf.debug.service.IExpressions;
import org.eclipse.dd.dsf.debug.service.IMemory;
import org.eclipse.dd.dsf.debug.service.IModules;
import org.eclipse.dd.dsf.debug.service.IProcesses;
import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.ISourceLookup;
@ -93,6 +94,11 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
return new GDBRunControl(session);
}
@Override
protected IProcesses createProcessesService(DsfSession session) {
return new GDBProcesses(session);
}
protected MIBreakpointsManager createBreakpointManagerService(DsfSession session) {
return new MIBreakpointsManager(session, CDebugCorePlugin.PLUGIN_ID);
}