From fbb213521436471ca11109368b55548187787bfb Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 11 Sep 2008 19:36:56 +0000 Subject: [PATCH] Bug 242234 creates GDBControl_7_0, CLIEventProcessor_7_0 and MIRunControlEventProcessor_7_0. It also reverts CLIEventProcessor and MIRunControlEventProcessor to the logic needed for a GDB pre 7.0 (the way we released it in 1.0) MIThreadExited and MIThreadCreated events are now only issued once. Running events are also issued only once, however, it needed a little gymnastics to keep the same functionality. Before 7.0, what we did was trigger the event once a continue, step or next command was executed; this allowed to also know the type of command that caused the running event. With the new MI event "*running", we don't know the type of the command that caused it. What I did was, like before, when a continue, step, next command is issued, I store the type of the command, and once the *running event occurs, I use that type. I do this using a global MIRunControlEventProcessor_7_0.fLastRunningCmdType When issuing such a continue, etc command through the CLI, we still need to somehow remember the type of the command. This is under discussion in the bug. --- .../ui/actions/GdbRestartCommand.java | 2 +- .../service/GDBRunControl_7_0.java | 117 +++ .../service/GdbDebugServicesFactory.java | 10 +- .../service/GdbDebugServicesFactoryNS.java | 9 - .../service/command/GDBControl.java | 8 +- .../service/command/GDBControl_7_0.java | 761 ++++++++++++++++++ .../service/command/IGDBControl.java | 5 +- .../mi/service/command/CLIEventProcessor.java | 6 - .../command/CLIEventProcessor_7_0.java | 321 ++++++++ .../command/MIRunControlEventProcessor.java | 95 +-- .../MIRunControlEventProcessor_7_0.java | 340 ++++++++ 11 files changed, 1554 insertions(+), 120 deletions(-) create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor_7_0.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor_7_0.java diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/GdbRestartCommand.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/GdbRestartCommand.java index e7cea3014ee..bc5a65f2004 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/GdbRestartCommand.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/actions/GdbRestartCommand.java @@ -82,7 +82,7 @@ public class GdbRestartCommand implements IRestart { @Override protected void handleSuccess() { gdbControl.createInferiorProcess(); - gdbControl.getCLICommandProcessor().resetInferior(gdbControl.getInferiorProcess()); + gdbControl.resetInferior(gdbControl.getInferiorProcess()); gdbControl.restart(fLaunch, rm); } }); diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java new file mode 100644 index 00000000000..9bc5678a199 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl_7_0.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 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 - Modified for additional functionality + * Ericsson - Version 7.0 + *******************************************************************************/ + +package org.eclipse.dd.gdb.internal.provisional.service; + + +import java.util.Hashtable; + +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.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.dd.dsf.debug.service.IProcesses.IThreadDMContext; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.gdb.internal.GdbPlugin; +import org.eclipse.dd.gdb.internal.provisional.service.command.IGDBControl; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIProcesses; +import org.eclipse.dd.mi.service.MIRunControl; + +public class GDBRunControl_7_0 extends MIRunControl { + private IGDBControl fGdb; + private IMIProcesses fProcService; + + public GDBRunControl_7_0(DsfSession session) { + super(session); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( + new RequestMonitor(getExecutor(), requestMonitor) { + @Override + public void handleSuccess() { + doInitialize(requestMonitor); + }}); + } + + private void doInitialize(final RequestMonitor requestMonitor) { + + fGdb = getServicesTracker().getService(IGDBControl.class); + fProcService = getServicesTracker().getService(IMIProcesses.class); + + register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName()}, + new Hashtable()); + requestMonitor.done(); + } + + @Override + public void shutdown(final RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } + + @Override + public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId) { + IProcessDMContext procDmc = DMContexts.getAncestorOfType(container, IProcessDMContext.class); + + IThreadDMContext threadDmc = null; + if (procDmc != null) { + // For now, reuse the threadId as the OSThreadId + threadDmc = fProcService.createThreadContext(procDmc, Integer.toString(threadId)); + } + + return fProcService.createExecutionContext(container, threadDmc, Integer.toString(threadId)); + } + + @Override + public void suspend(IExecutionDMContext context, final RequestMonitor rm){ + canSuspend( + context, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (getData()) { + fGdb.interrupt(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Context cannot be suspended.", null)); //$NON-NLS-1$ + } + rm.done(); + } + }); + } + + @Override + public void getExecutionContexts(IContainerDMContext containerDmc, final DataRequestMonitor rm) { + fProcService.getProcessesBeingDebugged( + containerDmc, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + if (getData() instanceof IExecutionDMContext[]) { + IExecutionDMContext[] execDmcs = (IExecutionDMContext[])getData(); + rm.setData(execDmcs); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid contexts", null)); //$NON-NLS-1$ + } + rm.done(); + } + }); + } +} 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 42b834df88e..dbd3331d45e 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 @@ -25,6 +25,7 @@ import org.eclipse.dd.dsf.debug.service.IStack; import org.eclipse.dd.dsf.debug.service.command.ICommandControl; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; +import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl_7_0; import org.eclipse.dd.mi.service.CSourceLookup; import org.eclipse.dd.mi.service.ExpressionService; import org.eclipse.dd.mi.service.MIBreakpoints; @@ -73,12 +74,10 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { } protected ICommandControl createCommandControl(DsfSession session, ILaunchConfiguration config) { - boolean useThreadAndFrameOptions = false; if ("6.8".compareTo(fVersion) < 0) { //$NON-NLS-1$ - useThreadAndFrameOptions = true; + return new GDBControl_7_0(session, config); } - - return new GDBControl(session, config, useThreadAndFrameOptions); + return new GDBControl(session, config); } @Override @@ -116,6 +115,9 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { @Override protected IRunControl createRunControlService(DsfSession session) { + if ("6.8".compareTo(fVersion) < 0) { //$NON-NLS-1$ + return new GDBRunControl_7_0(session); + } return new GDBRunControl(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 839d57d7f1a..bcb02245aff 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,7 +10,6 @@ *******************************************************************************/ 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.service.DsfSession; import org.eclipse.dd.mi.service.MIRunControlNS; @@ -20,14 +19,6 @@ 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 GDBProcesses_7_0(session); - } - return new GDBProcesses(session); - } @Override protected IRunControl createRunControlService(DsfSession session) { diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java index 19adb456d9f..b25d5957473 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java @@ -120,8 +120,8 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { private PTY fPty; - public GDBControl(DsfSession session, ILaunchConfiguration config, boolean useThreadAndFrameOptions) { - super(session, "gdbcontrol[" + ++fgInstanceCounter + "]", useThreadAndFrameOptions); //$NON-NLS-1$ //$NON-NLS-2$ + public GDBControl(DsfSession session, ILaunchConfiguration config) { + super(session, "gdbcontrol[" + ++fgInstanceCounter + "]", false); //$NON-NLS-1$ //$NON-NLS-2$ fSessionType = LaunchUtils.getSessionType(config); fAttach = LaunchUtils.getIsAttach(config); fGdbPath = LaunchUtils.getGDBPath(config); @@ -418,8 +418,8 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { return fInferiorProcess; } - public CLIEventProcessor getCLICommandProcessor() { - return fCLICommandProcessor; + public void resetInferior(MIInferiorProcess inferior) { + fCLICommandProcessor.resetInferior(inferior); } public boolean isGDBExited() { diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java new file mode 100644 index 00000000000..1cf8c4529a8 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl_7_0.java @@ -0,0 +1,761 @@ +/******************************************************************************* + * 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 - Modified for additional features in DSF Reference implementation + * Ericsson - New version for 7_0 + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.provisional.service.command; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.cdt.utils.spawner.Spawner; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DsfRunnable; +import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.concurrent.Sequence; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.debug.service.command.ICommandControl; +import org.eclipse.dd.dsf.debug.service.command.ICommandControlService; +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.launching.GdbLaunch; +import org.eclipse.dd.gdb.internal.provisional.launching.LaunchUtils; +import org.eclipse.dd.gdb.internal.provisional.service.SessionType; +import org.eclipse.dd.mi.service.command.AbstractCLIProcess; +import org.eclipse.dd.mi.service.command.AbstractMIControl; +import org.eclipse.dd.mi.service.command.CLIEventProcessor_7_0; +import org.eclipse.dd.mi.service.command.MIControlDMContext; +import org.eclipse.dd.mi.service.command.MIInferiorProcess; +import org.eclipse.dd.mi.service.command.MIRunControlEventProcessor_7_0; +import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorStartedDMEvent; +import org.eclipse.dd.mi.service.command.commands.MIBreakInsert; +import org.eclipse.dd.mi.service.command.commands.MICommand; +import org.eclipse.dd.mi.service.command.commands.MIExecContinue; +import org.eclipse.dd.mi.service.command.commands.MIExecRun; +import org.eclipse.dd.mi.service.command.commands.MIGDBExit; +import org.eclipse.dd.mi.service.command.commands.MIInferiorTTYSet; +import org.eclipse.dd.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.osgi.framework.BundleContext; + +/** + * GDB Debugger control implementation. This implementation extends the + * base MI control implementation to provide the GDB-specific debugger + * features. This includes:
+ * - CLI console support,
+ * - inferior process status tracking.
+ */ +public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl { + + /** + * Event indicating that the back end process has started. + */ + private static class GDBControlInitializedDMEvent extends AbstractDMEvent + implements ICommandControlInitializedDMEvent + { + public GDBControlInitializedDMEvent(ICommandControlDMContext context) { + super(context); + } + } + + /** + * Event indicating that the back end process has terminated. + */ + private static class GDBControlShutdownDMEvent extends AbstractDMEvent + implements ICommandControlShutdownDMEvent + { + public GDBControlShutdownDMEvent(ICommandControlDMContext context) { + super(context); + } + } + + private static int fgInstanceCounter = 0; + private final GDBControlDMContext fControlDmc; + + private SessionType fSessionType; + + private boolean fAttach; + + private boolean fConnected = true; + + private MonitorJob fMonitorJob; + private IPath fGdbPath; + private IPath fExecPath; + private Process fProcess; + private int fGDBExitValue; + private int fGDBLaunchTimeout = 30; + + private MIRunControlEventProcessor_7_0 fMIEventProcessor; + private CLIEventProcessor_7_0 fCLICommandProcessor; + private AbstractCLIProcess fCLIProcess; + private MIInferiorProcess fInferiorProcess = null; + + private PTY fPty; + + public GDBControl_7_0(DsfSession session, ILaunchConfiguration config) { + super(session, "gdbcontrol[" + ++fgInstanceCounter + "]", true); //$NON-NLS-1$ //$NON-NLS-2$ + fSessionType = LaunchUtils.getSessionType(config); + fAttach = LaunchUtils.getIsAttach(config); + fGdbPath = LaunchUtils.getGDBPath(config); + try { + fExecPath = LaunchUtils.verifyProgramPath(config, LaunchUtils.getCProject(config)); + } catch (CoreException e) { + fExecPath = new Path(""); //$NON-NLS-1$ + } + fControlDmc = new GDBControlDMContext(session.getId(), getId()); + } + + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize( new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + doInitialize(requestMonitor); + } + }); + } + + public void doInitialize(final RequestMonitor requestMonitor) { + final Sequence.Step[] initializeSteps = new Sequence.Step[] { + new GDBProcessStep(InitializationShutdownStep.Direction.INITIALIZING), + new MonitorJobStep(InitializationShutdownStep.Direction.INITIALIZING), + new CommandMonitoringStep(InitializationShutdownStep.Direction.INITIALIZING), + new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.INITIALIZING), + new CommandProcessorsStep(InitializationShutdownStep.Direction.INITIALIZING), + new RegisterStep(InitializationShutdownStep.Direction.INITIALIZING), + }; + + Sequence startupSequence = new Sequence(getExecutor(), requestMonitor) { + @Override public Step[] getSteps() { return initializeSteps; } + }; + getExecutor().execute(startupSequence); + } + + @Override + public void shutdown(final RequestMonitor requestMonitor) { + final Sequence.Step[] shutdownSteps = new Sequence.Step[] { + new RegisterStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new CommandProcessorsStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new InferiorInputOutputInitStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new CommandMonitoringStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new MonitorJobStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + new GDBProcessStep(InitializationShutdownStep.Direction.SHUTTING_DOWN), + }; + Sequence shutdownSequence = new Sequence(getExecutor(), requestMonitor) { + @Override public Step[] getSteps() { return shutdownSteps; } + }; + getExecutor().execute(shutdownSequence); + + } + + @Override + public MIControlDMContext getControlDMContext() { + return fControlDmc; + } + + public ICommandControlDMContext getContext() { + return fControlDmc; + } + + /** + * More strongly typed version of {@link #getControlDMContext()}. + */ + public GDBControlDMContext getGDBDMContext() { + return (GDBControlDMContext) getControlDMContext(); + } + + public SessionType getSessionType() { + return fSessionType; + } + + public boolean getIsAttachSession() { + return fAttach; + } + public boolean canInterrupt() { + return fProcess instanceof Spawner; + } + + public void interrupt() { + if (fProcess instanceof Spawner) { + Spawner gdbSpawner = (Spawner) fProcess; + gdbSpawner.interrupt(); + } + } + + public void destroy() { + if (fProcess instanceof Spawner) { + Spawner gdbSpawner = (Spawner) fProcess; + gdbSpawner.destroy(); + } + } + + public void terminate(final RequestMonitor rm) { + // Schedule a runnable to be executed 2 seconds from now. + // If we don't get a response to the quit command, this + // runnable will kill the task. + final Future quitTimeoutFuture = getExecutor().schedule( + new DsfRunnable() { + public void run() { + if (!isGDBExited()) { + destroy(); + } + rm.done(); + } + + @Override + protected boolean isExecutionRequired() { + return false; + } + }, + 2, TimeUnit.SECONDS); + + MIGDBExit cmd = new MIGDBExit(fControlDmc); + queueCommand( + cmd, + new DataRequestMonitor(getExecutor(), rm) { + @Override + public void handleCompleted() { + // Cancel the time out runnable (if it hasn't run yet). + if (quitTimeoutFuture.cancel(false)) { + if (!isSuccess() && !isGDBExited()) { + destroy(); + } + rm.done(); + } + } + } + ); + } + + /* + * This method does the necessary work to setup the input/output streams for the + * inferior process, by either preparing the PTY to be used, to simply leaving + * the PTY null, which indicates that the input/output streams of the CLI should + * be used instead; this decision is based on the type of session. + */ + public void initInferiorInputOutput(final RequestMonitor requestMonitor) { + if (fSessionType == SessionType.REMOTE || fAttach) { + // These types do not use a PTY + fPty = null; + requestMonitor.done(); + } else { + // These types always use a PTY + try { + fPty = new PTY(); + + // Tell GDB to use this PTY + queueCommand( + new MIInferiorTTYSet(fControlDmc, fPty.getSlaveName()), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleFailure() { + // We were not able to tell GDB to use the PTY + // so we won't use it at all. + fPty = null; + requestMonitor.done(); + } + }); + } catch (IOException e) { + fPty = null; + requestMonitor.done(); + } + } + } + + + public boolean canRestart() { + if (fAttach) return false; + + // Before GDB6.8, the Linux gdbserver would restart a new + // process when getting a -exec-run but the communication + // with GDB had a bug and everything hung. + // with GDB6.8 the program restarts properly one time, + // but on a second attempt, gdbserver crashes. + // So, lets just turn off the Restart for Remote debugging + if (fSessionType == SessionType.REMOTE) return false; + + return true; + } + + /* + * Start the program. + */ + public void start(GdbLaunch launch, final RequestMonitor requestMonitor) { + startOrRestart(launch, false, requestMonitor); + } + + /* + * Before restarting the inferior, we must re-initialize its input/output streams + * and create a new inferior process object. Then we can restart the inferior. + */ + public void restart(final GdbLaunch launch, final RequestMonitor requestMonitor) { + startOrRestart(launch, true, requestMonitor); + } + + /* + * Insert breakpoint at entry if set, and start or restart the program. + */ + protected void startOrRestart(final GdbLaunch launch, boolean restart, final RequestMonitor requestMonitor) { + if (fAttach) { + // When attaching to a running process, we do not need to set a breakpoint or + // start the program; it is left up to the user. + requestMonitor.done(); + return; + } + + final MICommand execCommand; + if (fSessionType == SessionType.REMOTE) { + // When doing remote debugging, we use -exec-continue instead of -exec-run + execCommand = new MIExecContinue(fControlDmc); + } else { + execCommand = new MIExecRun(fControlDmc, new String[0]); + } + + boolean stopInMain = false; + try { + stopInMain = launch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN, false ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Cannot retrieve stop at entry point boolean", e)); //$NON-NLS-1$ + requestMonitor.done(); + return; + } + + final DataRequestMonitor execMonitor = new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + getSession().dispatchEvent(new InferiorStartedDMEvent(getGDBDMContext()), getProperties()); + super.handleSuccess(); + } + }; + + if (!stopInMain) { + // Just start the program. + queueCommand(execCommand, execMonitor); + } else { + String stopSymbol = null; + try { + stopSymbol = launch.getLaunchConfiguration().getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_STOP_AT_MAIN_SYMBOL, ICDTLaunchConfigurationConstants.DEBUGGER_STOP_AT_MAIN_SYMBOL_DEFAULT ); + } catch (CoreException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.CONFIGURATION_INVALID, "Cannot retrieve the entry point symbol", e)); //$NON-NLS-1$ + requestMonitor.done(); + return; + } + + // Insert a breakpoint at the requested stop symbol. + queueCommand( + new MIBreakInsert(fControlDmc, true, false, null, 0, stopSymbol, 0), + new DataRequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + // After the break-insert is done, execute the -exec-run or -exec-continue command. + queueCommand(execCommand, execMonitor); + } + }); + } + } + + /* + * This method creates a new inferior process object based on the current Pty or output stream. + */ + public void createInferiorProcess() { + if (fPty == null) { + fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fProcess.getOutputStream()); + } else { + fInferiorProcess = new GDBInferiorProcess(GDBControl_7_0.this, fPty); + } + } + + public boolean isConnected() { + return fInferiorProcess.getState() != MIInferiorProcess.State.TERMINATED && fConnected; + } + + public void setConnected(boolean connected) { + fConnected = connected; + } + + public Process getGDBProcess() { + return fProcess; + } + + public AbstractCLIProcess getCLIProcess() { + return fCLIProcess; + } + + public MIInferiorProcess getInferiorProcess() { + return fInferiorProcess; + } + + public void resetInferior(MIInferiorProcess inferior) { + fCLICommandProcessor.resetInferior(inferior); + } + + public boolean isGDBExited() { + return fMonitorJob != null && fMonitorJob.fExited; + } + + public int getGDBExitCode() { + return fGDBExitValue; + } + + public IPath getExecutablePath() { return fExecPath; } + + public void getInferiorProcessId(DataRequestMonitor rm) { + String pid = null; + if (fInferiorProcess != null) { + pid = fInferiorProcess.getPid(); + } + rm.setData(pid); + rm.done(); + } + + @DsfServiceEventHandler + public void eventDispatched(ICommandControlShutdownDMEvent e) { + // Handle our "GDB Exited" event and stop processing commands. + stopCommandProcessing(); + } + + /** + * Monitors a system process, waiting for it to terminate, and + * then notifies the associated runtime process. + */ + private class MonitorJob extends Job { + boolean fExited = false; + DsfRunnable fMonitorStarted; + Process fMonProcess; + + @Override + protected IStatus run(IProgressMonitor monitor) { + synchronized(fMonProcess) { + getExecutor().submit(fMonitorStarted); + while (!fExited) { + try { + fMonProcess.waitFor(); + fGDBExitValue = fMonProcess.exitValue(); + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } finally { + fExited = true; + getSession().dispatchEvent(new GDBControlShutdownDMEvent(fControlDmc) {}, getProperties()); + } + } + } + return Status.OK_STATUS; + } + + MonitorJob(Process process, DsfRunnable monitorStarted) { + super("GDB process monitor job."); //$NON-NLS-1$ + fMonProcess = process; + fMonitorStarted = monitorStarted; + setSystem(true); + } + + void kill() { + synchronized(fMonProcess) { + if (!fExited) { + getThread().interrupt(); + } + } + } + } + + public static class InitializationShutdownStep extends Sequence.Step { + public enum Direction { INITIALIZING, SHUTTING_DOWN } + + private Direction fDirection; + InitializationShutdownStep(Direction direction) { fDirection = direction; } + + @Override + final public void execute(RequestMonitor requestMonitor) { + if (fDirection == Direction.INITIALIZING) { + initialize(requestMonitor); + } else { + shutdown(requestMonitor); + } + } + + @Override + final public void rollBack(RequestMonitor requestMonitor) { + if (fDirection == Direction.INITIALIZING) { + shutdown(requestMonitor); + } else { + super.rollBack(requestMonitor); + } + } + + protected void initialize(RequestMonitor requestMonitor) { + requestMonitor.done(); + } + protected void shutdown(RequestMonitor requestMonitor) { + requestMonitor.done(); + } + } + + protected class GDBProcessStep extends InitializationShutdownStep { + GDBProcessStep(Direction direction) { super(direction); } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + class GDBLaunchMonitor { + boolean fLaunched = false; + boolean fTimedOut = false; + } + final GDBLaunchMonitor fGDBLaunchMonitor = new GDBLaunchMonitor(); + + final RequestMonitor gdbLaunchRequestMonitor = new RequestMonitor(getExecutor(), null) { + @Override + protected void handleCompleted() { + if (!fGDBLaunchMonitor.fTimedOut) { + fGDBLaunchMonitor.fLaunched = true; + if (!isSuccess()) { + requestMonitor.setStatus(getStatus()); + } + requestMonitor.done(); + } + } + }; + + final Job startGdbJob = new Job("Start GDB Process Job") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + List commandList = new ArrayList(); + + // The goal here is to keep options to an absolute minimum. + // All configuration should be done in the launch sequence + // to allow for easy overriding. + commandList.add(fGdbPath.toOSString()); + commandList.add("--interpreter"); //$NON-NLS-1$ + // We currently work with MI version 2 + commandList.add("mi2"); //$NON-NLS-1$ + // Don't read the gdbinit file here. It is read explicitly in + // the LaunchSequence to make it easier to customize. + commandList.add("--nx"); //$NON-NLS-1$ + + String[] commandLine = commandList.toArray(new String[commandList.size()]); + + try { + fProcess = ProcessFactory.getFactory().exec(commandLine); + } catch(IOException e) { + String message = "Error while launching command " + commandList.toString(); //$NON-NLS-1$ + gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, message, e)); + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + + try { + InputStream stream = fProcess.getInputStream(); + Reader r = new InputStreamReader(stream); + BufferedReader reader = new BufferedReader(r); + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + //System.out.println("GDB " + line); + if (line.endsWith("(gdb)")) { //$NON-NLS-1$ + break; + } + } + } catch (IOException e) { + gdbLaunchRequestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, -1, "Error reading GDB STDOUT", e)); //$NON-NLS-1$ + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + + gdbLaunchRequestMonitor.done(); + return Status.OK_STATUS; + } + }; + startGdbJob.schedule(); + + getExecutor().schedule(new Runnable() { + public void run() { + // Only process the event if we have not finished yet (hit the breakpoint). + if (!fGDBLaunchMonitor.fLaunched) { + fGDBLaunchMonitor.fTimedOut = true; + Thread jobThread = startGdbJob.getThread(); + if (jobThread != null) { + jobThread.interrupt(); + } + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.TARGET_REQUEST_FAILED, "Timed out trying to launch GDB.", null)); //$NON-NLS-1$ + requestMonitor.done(); + } + }}, + fGDBLaunchTimeout, TimeUnit.SECONDS); + + } + + @Override + protected void shutdown(final RequestMonitor requestMonitor) { + new Job("Terminating GDB process.") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + fProcess.destroy(); + + int attempts = 0; + while (attempts < 10) { + try { + // Don't know if we really need the exit value... but what the hell. + fGDBExitValue = fProcess.exitValue(); // throws exception if process not exited + + requestMonitor.done(); + return Status.OK_STATUS; + } catch (IllegalThreadStateException ie) { + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + attempts++; + } + requestMonitor.setStatus(new Status( + IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Process terminate failed", null)); //$NON-NLS-1$ + requestMonitor.done(); + return Status.OK_STATUS; + } + }.schedule(); + } + } + + protected class MonitorJobStep extends InitializationShutdownStep { + MonitorJobStep(Direction direction) { super(direction); } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + fMonitorJob = new MonitorJob( + fProcess, + new DsfRunnable() { + public void run() { + requestMonitor.done(); + } + }); + fMonitorJob.schedule(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + if (!fMonitorJob.fExited) { + fMonitorJob.kill(); + } + requestMonitor.done(); + } + } + + protected class CommandMonitoringStep extends InitializationShutdownStep { + CommandMonitoringStep(Direction direction) { super(direction); } + + @Override + protected void initialize(final RequestMonitor requestMonitor) { + startCommandProcessing(fProcess.getInputStream(), fProcess.getOutputStream()); + requestMonitor.done(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + stopCommandProcessing(); + requestMonitor.done(); + } + } + + protected class InferiorInputOutputInitStep extends InitializationShutdownStep { + InferiorInputOutputInitStep(Direction direction) { super(direction); } + + @Override + protected void initialize(final RequestMonitor requestMonitor) { + initInferiorInputOutput(requestMonitor); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + requestMonitor.done(); + } + } + + protected class CommandProcessorsStep extends InitializationShutdownStep { + CommandProcessorsStep(Direction direction) { super(direction); } + + @Override + public void initialize(final RequestMonitor requestMonitor) { + try { + fCLIProcess = new GDBCLIProcess(GDBControl_7_0.this); + } + catch(IOException e) { + requestMonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Failed to create CLI Process", e)); //$NON-NLS-1$ + requestMonitor.done(); + return; + } + + createInferiorProcess(); + + fCLICommandProcessor = new CLIEventProcessor_7_0(GDBControl_7_0.this, fControlDmc, fInferiorProcess); + fMIEventProcessor = new MIRunControlEventProcessor_7_0(GDBControl_7_0.this, fControlDmc); + + requestMonitor.done(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + fCLICommandProcessor.dispose(); + fMIEventProcessor.dispose(); + fCLIProcess.dispose(); + fInferiorProcess.dispose(); + + requestMonitor.done(); + } + } + + protected class RegisterStep extends InitializationShutdownStep { + RegisterStep(Direction direction) { super(direction); } + @Override + public void initialize(final RequestMonitor requestMonitor) { + getSession().addServiceEventListener(GDBControl_7_0.this, null); + register( + new String[]{ ICommandControl.class.getName(), + ICommandControlService.class.getName(), + AbstractMIControl.class.getName(), + IGDBControl.class.getName() }, + new Hashtable()); + getSession().dispatchEvent(new GDBControlInitializedDMEvent(getGDBDMContext()), getProperties()); + requestMonitor.done(); + } + + @Override + protected void shutdown(RequestMonitor requestMonitor) { + unregister(); + getSession().removeServiceEventListener(GDBControl_7_0.this); + requestMonitor.done(); + } + } +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java index 147777c2a05..c93d6202a53 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/IGDBControl.java @@ -17,7 +17,6 @@ import org.eclipse.dd.dsf.debug.service.command.ICommandControlService; import org.eclipse.dd.gdb.internal.provisional.launching.GdbLaunch; import org.eclipse.dd.gdb.internal.provisional.service.SessionType; import org.eclipse.dd.mi.service.command.AbstractCLIProcess; -import org.eclipse.dd.mi.service.command.CLIEventProcessor; import org.eclipse.dd.mi.service.command.MIInferiorProcess; public interface IGDBControl extends ICommandControlService { @@ -49,8 +48,8 @@ public interface IGDBControl extends ICommandControlService { MIInferiorProcess getInferiorProcess(); - CLIEventProcessor getCLICommandProcessor(); - + public void resetInferior(MIInferiorProcess inferior); + boolean isGDBExited(); int getGDBExitCode(); 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 926247df02a..75beb229b4e 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 @@ -13,8 +13,6 @@ package org.eclipse.dd.mi.service.command; -import java.util.LinkedList; -import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -58,7 +56,6 @@ public class CLIEventProcessor private final ICommandControlService fCommandControl; private MIInferiorProcess fInferior; private final ICommandControlDMContext fControlDmc; - private final List fEventList = new LinkedList(); // Last Thread ID created private static int fLastThreadId; @@ -102,7 +99,6 @@ public class CLIEventProcessor else if (token.getCommand() instanceof MIInterpreterExecConsole) { processSettingChanges( (MIInterpreterExecConsole)token.getCommand() ); } - fEventList.clear(); } public void commandQueued(ICommandToken token) { @@ -115,8 +111,6 @@ public class CLIEventProcessor public void eventReceived(Object output) { for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { - fEventList.add(oobr); - if (oobr instanceof MIConsoleStreamOutput) { // Process Events of type DsfMIConsoleStreamOutput here MIConsoleStreamOutput exec = (MIConsoleStreamOutput) oobr; diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor_7_0.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor_7_0.java new file mode 100644 index 00000000000..701cb003233 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor_7_0.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * Copyright (c) 2008 QNX Software 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: + * QNX Software Systems - Initial API and implementation + * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson AB - Additional handling of events + * Ericsson - Version 7.0 + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command; + +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.dsf.debug.service.ISignals.ISignalsDMContext; +import org.eclipse.dd.dsf.debug.service.command.ICommandControlService; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.ICommandToken; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.IMIProcesses; +import org.eclipse.dd.mi.service.command.commands.CLICommand; +import org.eclipse.dd.mi.service.command.commands.MIInterpreterExecConsole; +import org.eclipse.dd.mi.service.command.events.MIBreakpointChangedEvent; +import org.eclipse.dd.mi.service.command.events.MIDetachedEvent; +import org.eclipse.dd.mi.service.command.events.MIErrorEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISignalChangedEvent; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; + +/** + * GDB debugger output listener. + */ +@ConfinedToDsfExecutor("fConnection#getExecutor") +public class CLIEventProcessor_7_0 + implements ICommandListener, IEventListener +{ + private final ICommandControlService fCommandControl; + private MIInferiorProcess fInferior; + private final ICommandControlDMContext fControlDmc; + + private final DsfServicesTracker fServicesTracker; + + public CLIEventProcessor_7_0(ICommandControlService connection, IContainerDMContext containerDmc, MIInferiorProcess inferior) { + fCommandControl = connection; + fInferior = inferior; + fControlDmc = DMContexts.getAncestorOfType(containerDmc, ICommandControlDMContext.class); + fServicesTracker = new DsfServicesTracker(MIPlugin.getBundleContext(), fCommandControl.getSession().getId()); + connection.addCommandListener(this); + connection.addEventListener(this); + } + + public void dispose() { + fCommandControl.removeCommandListener(this); + fCommandControl.removeEventListener(this); + fServicesTracker.dispose(); + } + + public void resetInferior(MIInferiorProcess inferior) { + fInferior = inferior; + } + + public void commandSent(ICommandToken token) { + if (token.getCommand() instanceof CLICommand) { + processStateChanges( (CLICommand)token.getCommand() ); + } + else if (token.getCommand() instanceof MIInterpreterExecConsole) { + processStateChanges( (MIInterpreterExecConsole)token.getCommand() ); + } + } + + public void commandDone(ICommandToken token, ICommandResult result) { + if (token.getCommand() instanceof CLICommand) { + processSettingChanges( (CLICommand)token.getCommand() ); + } + else if (token.getCommand() instanceof MIInterpreterExecConsole) { + processSettingChanges( (MIInterpreterExecConsole)token.getCommand() ); + } + } + + public void commandQueued(ICommandToken token) { + // No action + } + + public void commandRemoved(ICommandToken token) { + // No action + } + + public void eventReceived(Object output) { + // GDB can send an error result following sending an OK result. + // In this case the error is routed as an event. + MIResultRecord rr = ((MIOutput)output).getMIResultRecord(); + if (rr != null) { + // Check if the state changed. + String state = rr.getResultClass(); + if (fInferior != null && "error".equals(state)) { //$NON-NLS-1$ + if (fInferior.getState() == MIInferiorProcess.State.RUNNING) { + fInferior.setState(MIInferiorProcess.State.STOPPED); + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); + 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()); + } + } + } + } + + + private void processStateChanges(CLICommand cmd) { + String operation = cmd.getOperation().trim(); + // In refactoring we are no longer generating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processStateChanges(0, operation); + } + + private void processStateChanges(MIInterpreterExecConsole exec) { + String[] operations = exec.getParameters(); + if (operations != null && operations.length > 0) { + // In refactoring we are no longer generating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processStateChanges(0, operations[0]); + } + } + + private void processStateChanges(int token, String operation) { + // Get the command name. + int indx = operation.indexOf(' '); + if (indx != -1) { + operation = operation.substring(0, indx).trim(); + } else { + operation = operation.trim(); + } + + // Check the type of command + int type = getSteppingOperationKind(operation); + if (type != -1) { + // Should set MIrunControlEventProcessor_7_0.fLastRunningCmdType + } + } + + /** + * An attempt to discover the command type and + * fire an event if necessary. + */ + private void processSettingChanges(CLICommand cmd) { + String operation = cmd.getOperation().trim(); + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processSettingChanges(cmd.getContext(), 0, operation); + } + + private void processSettingChanges(MIInterpreterExecConsole exec) { + String[] operations = exec.getParameters(); + if (operations != null && operations.length > 0) { + // In refactoring we are no longer genwerating the token id as + // part of the command. It is passed here and stored away and + // then never really used. So it has just been changed to 0. + processSettingChanges(exec.getContext(), 0, operations[0]); + } + } + + private void processSettingChanges(IDMContext dmc, int token, String operation) { + // Get the command name. + int indx = operation.indexOf(' '); + if (indx != -1) { + operation = operation.substring(0, indx).trim(); + } else { + operation = operation.trim(); + } + + // Check the type of command + + if (isSettingBreakpoint(operation) || + isSettingWatchpoint(operation) || + isChangeBreakpoint(operation) || + isDeletingBreakpoint(operation)) + { + // We know something change, we just do not know what. + // So the easiest way is to let the top layer handle it. + MIEvent event = new MIBreakpointChangedEvent( + DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class), 0); + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } else if (isSettingSignal(operation)) { + // We do no know which signal let the upper layer find it. + MIEvent event = new MISignalChangedEvent( + DMContexts.getAncestorOfType(dmc, ISignalsDMContext.class), ""); //$NON-NLS-1$ + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } else if (isDetach(operation)) { + // if it was a "detach" command change the state. + MIEvent event = new MIDetachedEvent(DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class), token); + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + + private static int getSteppingOperationKind(String operation) { + int type = -1; + /* execution commands: n, next, s, step, si, stepi, u, until, finish, + c, continue, fg */ + if (operation.equals("n") || operation.equals("next")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.NEXT; + } else if (operation.equals("ni") || operation.equals("nexti")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.NEXTI; + } else if (operation.equals("s") || operation.equals("step")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.STEP; + } else if (operation.equals("si") || operation.equals("stepi")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.STEPI; + } else if (operation.equals("u") || //$NON-NLS-1$ + (operation.startsWith("unt") && "until".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.UNTIL; + } else if (operation.startsWith("fin") && "finish".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.FINISH; + } else if (operation.equals("c") || operation.equals("fg") || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("cont") && "continue".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.startsWith("sig") && "signal".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.startsWith("j") && "jump".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } else if (operation.equals("r") || operation.equals("run")) { //$NON-NLS-1$ //$NON-NLS-2$ + type = MIRunningEvent.CONTINUE; + } + return type; + } + + /** + * Return true if the operation is a stepping operation. + * + * @param operation + * @return + */ + public static boolean isSteppingOperation(String operation) { + int type = getSteppingOperationKind(operation); + return type != -1; + } + + private boolean isSettingBreakpoint(String operation) { + boolean isbreak = false; + /* breakpoints: b, break, hbreak, tbreak, rbreak, thbreak */ + /* watchpoints: watch, rwatch, awatch, tbreak, rbreak, thbreak */ + if ((operation.startsWith("b") && "break".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("tb") && "tbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("hb") && "hbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("thb") && "thbreak".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("rb") && "rbreak".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isbreak = true; + } + return isbreak; + } + + private boolean isSettingWatchpoint(String operation) { + boolean isWatch = false; + /* watchpoints: watch, rwatch, awatch, tbreak, rbreak, thbreak */ + if ((operation.startsWith("wa") && "watch".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("rw") && "rwatch".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("aw") && "awatch".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isWatch = true; + } + return isWatch; + } + + private boolean isDeletingBreakpoint(String operation) { + boolean isDelete = false; + /* deleting breaks: clear, delete */ + if ((operation.startsWith("cl") && "clear".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.equals("d") || (operation.startsWith("del") && "delete".indexOf(operation) != -1))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + isDelete = true; + } + return isDelete; + } + + private boolean isChangeBreakpoint(String operation) { + boolean isChange = false; + /* changing breaks: enable, disable */ + if ((operation.equals("dis") || operation.equals("disa") || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("disa") && "disable".indexOf(operation) != -1)) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.equals("en") || (operation.startsWith("en") && "enable".indexOf(operation) != -1)) || //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (operation.startsWith("ig") && "ignore".indexOf(operation) != -1) || //$NON-NLS-1$ //$NON-NLS-2$ + (operation.startsWith("cond") && "condition".indexOf(operation) != -1)) { //$NON-NLS-1$ //$NON-NLS-2$ + isChange = true; + } + return isChange; + } + + private boolean isSettingSignal(String operation) { + boolean isChange = false; + /* changing signal: handle, signal */ + if (operation.startsWith("ha") && "handle".indexOf(operation) != -1) { //$NON-NLS-1$ //$NON-NLS-2$ + isChange = true; + } + return isChange; + } + + /** + * @param operation + * @return + */ + private boolean isDetach(String operation) { + return (operation.startsWith("det") && "detach".indexOf(operation) != -1); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} 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 8aae2b8194c..6ed3c59b872 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 @@ -46,16 +46,11 @@ import org.eclipse.dd.mi.service.command.events.MIRunningEvent; import org.eclipse.dd.mi.service.command.events.MISignalEvent; 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; import org.eclipse.dd.mi.service.command.output.MIExecAsyncOutput; import org.eclipse.dd.mi.service.command.output.MIInfo; -import org.eclipse.dd.mi.service.command.output.MINotifyAsyncOutput; import org.eclipse.dd.mi.service.command.output.MIOOBRecord; import org.eclipse.dd.mi.service.command.output.MIOutput; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -71,7 +66,6 @@ public class MIRunControlEventProcessor implements IEventListener, ICommandListener { private static final String STOPPED_REASON = "stopped"; //$NON-NLS-1$ - private static final String RUNNING_REASON = "running"; //$NON-NLS-1$ /** * The connection service that this event processor is registered with. @@ -149,84 +143,6 @@ public class MIRunControlEventProcessor fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); } } - else if ("running".equals(state)) { //$NON-NLS-1$ - MIEvent event = createEvent(RUNNING_REASON, exec); - 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-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ - String threadId = null; - String groupId = null; - - MIResult[] results = exec.getMIResults(); - for (int i = 0; i < results.length; i++) { - String var = results[i].getVariable(); - MIValue val = results[i].getMIValue(); - if (var.equals("group-id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - groupId = ((MIConst) val).getString(); - } - } else if (var.equals("id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - threadId = ((MIConst) val).getString(); - } - } - } - - IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - - 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 = new MIThreadCreatedEvent(processContainerDmc, exec.getToken(), threadId); - } else if ("thread-exited".equals(miEvent)) { //$NON-NLS-1$ - event = new MIThreadExitEvent(processContainerDmc, exec.getToken(), threadId); - } - - if (event != null) { - fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); - } - } else 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()); - } - } - } } } } @@ -244,18 +160,13 @@ public class MIRunControlEventProcessor if (val instanceof MIConst) { threadId = ((MIConst)val).getString(); } - } else if (var.equals("group-id")) { //$NON-NLS-1$ - if (val instanceof MIConst) { - groupId = ((MIConst)val).getString(); - } } } IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); - if (groupId == null) { - groupId = procService.getExecutionGroupIdFromThread(threadId); - } + groupId = procService.getExecutionGroupIdFromThread(threadId); + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); @@ -289,8 +200,6 @@ public class MIRunControlEventProcessor event = MIInferiorSignalExitEvent.parse(fCommandControl.getControlDMContext(), exec.getToken(), exec.getMIResults()); } else if (STOPPED_REASON.equals(reason)) { event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); - } else if (RUNNING_REASON.equals(reason)) { - event = new MIRunningEvent(execDmc, exec.getToken(), MIRunningEvent.CONTINUE); } return event; } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor_7_0.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor_7_0.java new file mode 100644 index 00000000000..f136177ef08 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor_7_0.java @@ -0,0 +1,340 @@ +/******************************************************************************* + * 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 - Version 7.0 + *******************************************************************************/ +package org.eclipse.dd.mi.service.command; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.dd.dsf.debug.service.IProcesses.IThreadDMContext; +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.command.ICommand; +import org.eclipse.dd.dsf.debug.service.command.ICommandListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandResult; +import org.eclipse.dd.dsf.debug.service.command.ICommandToken; +import org.eclipse.dd.dsf.debug.service.command.IEventListener; +import org.eclipse.dd.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; +import org.eclipse.dd.dsf.service.DsfServicesTracker; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.IMIProcesses; +import org.eclipse.dd.mi.service.command.commands.MIExecContinue; +import org.eclipse.dd.mi.service.command.commands.MIExecFinish; +import org.eclipse.dd.mi.service.command.commands.MIExecNext; +import org.eclipse.dd.mi.service.command.commands.MIExecNextInstruction; +import org.eclipse.dd.mi.service.command.commands.MIExecReturn; +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.events.MIBreakpointHitEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIFunctionFinishedEvent; +import org.eclipse.dd.mi.service.command.events.MIInferiorExitEvent; +import org.eclipse.dd.mi.service.command.events.MIInferiorSignalExitEvent; +import org.eclipse.dd.mi.service.command.events.MILocationReachedEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISignalEvent; +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; +import org.eclipse.dd.mi.service.command.output.MIExecAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MINotifyAsyncOutput; +import org.eclipse.dd.mi.service.command.output.MIOOBRecord; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIResultRecord; +import org.eclipse.dd.mi.service.command.output.MIValue; + +/** + * MI debugger output listener that listens for the parsed MI output, and + * generates corresponding MI events. The generated MI events are then + * received by other services and clients. + */ +public class MIRunControlEventProcessor_7_0 + implements IEventListener, ICommandListener +{ + private static final String STOPPED_REASON = "stopped"; //$NON-NLS-1$ + private static final String RUNNING_REASON = "running"; //$NON-NLS-1$ + + private Integer fLastRunningCmdType = null; + /** + * The connection service that this event processor is registered with. + */ + private final AbstractMIControl fCommandControl; + + /** + * Container context used as the context for the run control events generated + * by this processor. + */ + private final ICommandControlDMContext fControlDmc; + + private final DsfServicesTracker fServicesTracker; + + /** + * Creates the event processor and registers it as listener with the debugger + * control. + * @param connection + * @param inferior + */ + public MIRunControlEventProcessor_7_0(AbstractMIControl connection, ICommandControlDMContext controlDmc) { + fCommandControl = connection; + fControlDmc = controlDmc; + fServicesTracker = new DsfServicesTracker(MIPlugin.getBundleContext(), fCommandControl.getSession().getId()); + connection.addEventListener(this); + connection.addCommandListener(this); + } + + /** + * This processor must be disposed before the control service is un-registered. + */ + public void dispose() { + fCommandControl.removeEventListener(this); + fCommandControl.removeCommandListener(this); + fServicesTracker.dispose(); + } + + public void eventReceived(Object output) { + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + List> events = new LinkedList>(); + if (oobr instanceof MIExecAsyncOutput) { + MIExecAsyncOutput exec = (MIExecAsyncOutput) oobr; + // Change of state. + String state = exec.getAsyncClass(); + if ("stopped".equals(state)) { //$NON-NLS-1$ + // Re-set the thread and stack level to -1 when stopped event is recvd. + // This is to synchronize the state between GDB back-end and AbstractMIControl. + fCommandControl.resetCurrentThreadLevel(); + fCommandControl.resetCurrentStackLevel(); + + 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("reason")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + String reason = ((MIConst) val).getString(); + MIEvent e = createEvent(reason, exec); + if (e != null) { + events.add(e); + continue; + } + } + } + } + // We were stopped for some unknown reason, for example + // GDB for temporary breakpoints will not send the + // "reason" ??? still fire a stopped event. + if (events.isEmpty()) { + MIEvent e = createEvent(STOPPED_REASON, exec); + events.add(e); + } + + for (MIEvent event : events) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + else if ("running".equals(state)) { //$NON-NLS-1$ + MIEvent event = createEvent(RUNNING_REASON, exec); + 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-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ + String threadId = null; + String groupId = null; + + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("group-id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + groupId = ((MIConst) val).getString(); + } + } else if (var.equals("id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + threadId = ((MIConst) val).getString(); + } + } + } + + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); + + 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 = new MIThreadCreatedEvent(processContainerDmc, exec.getToken(), threadId); + } else if ("thread-exited".equals(miEvent)) { //$NON-NLS-1$ + event = new MIThreadExitEvent(processContainerDmc, exec.getToken(), threadId); + } + + if (event != null) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } else 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; + 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("thread-id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + threadId = ((MIConst)val).getString(); + } + } else if (var.equals("group-id")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + groupId = ((MIConst)val).getString(); + } + } + } + + IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class); + + if (groupId == null) { + groupId = procService.getExecutionGroupIdFromThread(threadId); + } + IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId); + IContainerDMContext processContainerDmc = procService.createExecutionGroupContext(procDmc, groupId); + + IExecutionDMContext execDmc = processContainerDmc; + if (procService != null && threadId != null) { + IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId); + execDmc = procService.createExecutionContext(processContainerDmc, threadDmc, threadId); + } + + MIEvent event = null; + if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$ + event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ( + "watchpoint-trigger".equals(reason) //$NON-NLS-1$ + || "read-watchpoint-trigger".equals(reason) //$NON-NLS-1$ + || "access-watchpoint-trigger".equals(reason)) { //$NON-NLS-1$ + event = MIWatchpointTriggerEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("watchpoint-scope".equals(reason)) { //$NON-NLS-1$ + event = MIWatchpointScopeEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("end-stepping-range".equals(reason)) { //$NON-NLS-1$ + event = MISteppingRangeEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("signal-received".equals(reason)) { //$NON-NLS-1$ + event = MISignalEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("location-reached".equals(reason)) { //$NON-NLS-1$ + event = MILocationReachedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("function-finished".equals(reason)) { //$NON-NLS-1$ + event = MIFunctionFinishedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if ("exited-normally".equals(reason) || "exited".equals(reason)) { //$NON-NLS-1$ //$NON-NLS-2$ + event = MIInferiorExitEvent.parse(fCommandControl.getControlDMContext(), exec.getToken(), exec.getMIResults()); + } else if ("exited-signalled".equals(reason)) { //$NON-NLS-1$ + event = MIInferiorSignalExitEvent.parse(fCommandControl.getControlDMContext(), exec.getToken(), exec.getMIResults()); + } else if (STOPPED_REASON.equals(reason)) { + event = MIStoppedEvent.parse(execDmc, exec.getToken(), exec.getMIResults()); + } else if (RUNNING_REASON.equals(reason)) { + // Retrieve the type of command from what we last stored + int type = MIRunningEvent.CONTINUE; + if (fLastRunningCmdType != null) { + type = fLastRunningCmdType; + fLastRunningCmdType = null; + } + event = new MIRunningEvent(execDmc, exec.getToken(), type); + } + return event; + } + + public void commandQueued(ICommandToken token) { + // Do nothing. + } + + public void commandSent(ICommandToken token) { + // Do nothing. + } + + public void commandRemoved(ICommandToken token) { + // Do nothing. + } + + public void commandDone(ICommandToken token, ICommandResult result) { + ICommand cmd = token.getCommand(); + MIInfo cmdResult = (MIInfo) result ; + MIOutput output = cmdResult.getMIOutput(); + MIResultRecord rr = output.getMIResultRecord(); + if (rr != null) { + int id = rr.getToken(); + // Check if the state changed. + String state = rr.getResultClass(); + if ("running".equals(state)) { //$NON-NLS-1$ + // Store the type of command that is the trigger for the coming + // *running event + if (cmd instanceof MIExecNext) { fLastRunningCmdType = MIRunningEvent.NEXT; } + else if (cmd instanceof MIExecNextInstruction) { fLastRunningCmdType = MIRunningEvent.NEXTI; } + else if (cmd instanceof MIExecStep) { fLastRunningCmdType = MIRunningEvent.STEP; } + else if (cmd instanceof MIExecStepInstruction) { fLastRunningCmdType = MIRunningEvent.STEPI; } + else if (cmd instanceof MIExecUntil) { fLastRunningCmdType = MIRunningEvent.UNTIL; } + else if (cmd instanceof MIExecFinish) { fLastRunningCmdType = MIRunningEvent.FINISH; } + else if (cmd instanceof MIExecReturn) { fLastRunningCmdType = MIRunningEvent.RETURN; } + else if (cmd instanceof MIExecContinue) { fLastRunningCmdType = MIRunningEvent.CONTINUE; } + else { fLastRunningCmdType = MIRunningEvent.CONTINUE; } + } + } + } +}