diff options
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java')
-rw-r--r-- | dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java new file mode 100644 index 00000000000..e23b06be894 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * 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.cdt.dsf.gdb.service; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.IProcessInfo; +import org.eclipse.cdt.core.IProcessList; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses; +import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; +import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; +import org.eclipse.cdt.dsf.mi.service.IMIProcesses; +import org.eclipse.cdt.dsf.mi.service.MIProcesses; +import org.eclipse.cdt.dsf.mi.service.command.MIInferiorProcess; +import org.eclipse.cdt.dsf.mi.service.command.commands.CLIMonitorListProcesses; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIMonitorListProcessesInfo; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.osgi.framework.BundleContext; + + +public class GDBProcesses extends MIProcesses { + + private class GDBContainerDMC extends MIContainerDMC + implements IMemoryDMContext + { + public GDBContainerDMC(String sessionId, IProcessDMContext processDmc, String groupId) { + super(sessionId, processDmc, groupId); + } + } + + private IGDBControl fGdb; + + // A map of pid to names. It is filled when we get all the + // processes that are running + private Map<Integer, String> fProcessNames = new HashMap<Integer, String>(); + + public GDBProcesses(DsfSession session) { + super(session); + } + + @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) { + + fGdb = getServicesTracker().getService(IGDBControl.class); + + // Register this service. + register(new String[] { IProcesses.class.getName(), + IMIProcesses.class.getName(), + MIProcesses.class.getName(), + GDBProcesses.class.getName() }, + new Hashtable<String, String>()); + + ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class); + IProcessDMContext procDmc = createProcessContext(commandControl.getContext(), MIProcesses.UNIQUE_GROUP_ID); + IContainerDMContext containerDmc = createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID); + fGdb.getInferiorProcess().setContainerContext(containerDmc); + + requestMonitor.done(); + } + + @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(); + } + + @Override + public IMIContainerDMContext createContainerContext(IProcessDMContext processDmc, + String groupId) { + return new GDBContainerDMC(getSession().getId(), processDmc, groupId); + } + + @Override + public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) { + if (dmc instanceof IMIProcessDMContext) { + String pidStr = ((IMIProcessDMContext)dmc).getProcId(); + // In our context hierarchy we don't actually use the pid in this version, because in this version, + // we only debug a single process. This means we will not have a proper pid in all cases + // inside the context, so must find it another way. Note that this method is also called to find the name + // of processes to attach to, and in this case, we do have the proper pid. + if (pidStr == null || pidStr.length() == 0) { + MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); + if (inferiorProcess != null) { + pidStr = inferiorProcess.getPid(); + } + } + int pid = -1; + try { + pid = Integer.parseInt(pidStr); + } catch (NumberFormatException e) { + } + + String name = fProcessNames.get(pid); + // If we still don't find the name in our list, return the default name of our program + if (name == null) { + IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); + name = backend.getProgramPath().lastSegment(); + } + rm.setData(new MIThreadDMData(name, pidStr)); + rm.done(); + } else { + super.getExecutionData(dmc, rm); + } + } + + @Override + public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) { + MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); + if (!fGdb.isConnected() && + inferiorProcess != null && + inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) { + + rm.setData(true); + } else { + rm.setData(false); + } + rm.done(); + } + + @Override + public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) { + super.attachDebuggerToProcess( + procCtx, + new DataRequestMonitor<IDMContext>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + fGdb.setConnected(true); + + MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); + if (inferiorProcess != null) { + inferiorProcess.setPid(((IMIProcessDMContext)procCtx).getProcId()); + } + + rm.setData(getData()); + rm.done(); + } + }); + } + + @Override + public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) { + rm.setData(false); // don't turn on yet, as we need to generate events to use this properly + rm.done(); + } + + @Override + public void detachDebuggerFromProcess(IDMContext dmc, final RequestMonitor rm) { + super.detachDebuggerFromProcess( + dmc, + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + fGdb.setConnected(false); + + MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); + if (inferiorProcess != null) { + inferiorProcess.setPid(null); + } + + rm.done(); + } + }); + } + + @Override + public void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm) { + MIInferiorProcess inferiorProcess = fGdb.getInferiorProcess(); + if (fGdb.isConnected() && + inferiorProcess != null && + inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) { + + final IMIContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IMIContainerDMContext.class); + if (containerDmc == null) { + // This service version only handles a single process to debug, therefore, we can simply + // create the context describing this process ourselves. + ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); + String groupId = MIProcesses.UNIQUE_GROUP_ID; + IProcessDMContext procDmc = createProcessContext(controlDmc, groupId); + IMIContainerDMContext newContainerDmc = createContainerContext(procDmc, groupId); + rm.setData(new IContainerDMContext[] {newContainerDmc}); + rm.done(); + } else { + // List of threads + super.getProcessesBeingDebugged(dmc, rm); + } + } else { + rm.setData(new IDMContext[0]); + rm.done(); + } + } + + @Override + public void getRunningProcesses(IDMContext dmc, final DataRequestMonitor<IProcessDMContext[]> rm) { + final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); + IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); + if (backend.getSessionType() == SessionType.LOCAL) { + IProcessList list = null; + try { + list = CCorePlugin.getDefault().getProcessList(); + } catch (CoreException e) { + } + + if (list == null) { + // If the list is null, the prompter will deal with it + fProcessNames.clear(); + rm.setData(null); + } else { + fProcessNames.clear(); + for (IProcessInfo procInfo : list.getProcessList()) { + fProcessNames.put(procInfo.getPid(), procInfo.getName()); + } + rm.setData(makeProcessDMCs(controlDmc, list.getProcessList())); + } + rm.done(); + } else { + // monitor list processes is only for remote session + fGdb.queueCommand( + new CLIMonitorListProcesses(dmc), + new DataRequestMonitor<CLIMonitorListProcessesInfo>(getExecutor(), rm) { + @Override + protected void handleCompleted() { + if (isSuccess()) { + for (IProcessInfo procInfo : getData().getProcessList()) { + fProcessNames.put(procInfo.getPid(), procInfo.getName()); + } + rm.setData(makeProcessDMCs(controlDmc, getData().getProcessList())); + } else { + // The monitor list command is not supported. + // Just return an empty list and let the caller deal with it. + fProcessNames.clear(); + rm.setData(new IProcessDMContext[0]); + } + rm.done(); + } + + }); + } + } + + private IProcessDMContext[] makeProcessDMCs(ICommandControlDMContext controlDmc, IProcessInfo[] processes) { + IProcessDMContext[] procDmcs = new IMIProcessDMContext[processes.length]; + for (int i=0; i<procDmcs.length; i++) { + procDmcs[i] = createProcessContext(controlDmc, Integer.toString(processes[i].getPid())); + } + return procDmcs; + } + + @Override + public void terminate(IThreadDMContext thread, RequestMonitor rm) { + if (thread instanceof IMIProcessDMContext) { + fGdb.terminate(rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ + rm.done(); + } + } +} |