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

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.
This commit is contained in:
Marc Khouzam 2008-09-11 19:36:56 +00:00
parent a980785a88
commit fbb2135214
11 changed files with 1554 additions and 120 deletions

View file

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

View file

@ -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<String,String>());
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<Boolean>(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<IExecutionDMContext[]> rm) {
fProcService.getProcessesBeingDebugged(
containerDmc,
new DataRequestMonitor<IDMContext[]>(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();
}
});
}
}

View file

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

View file

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

View file

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

View file

@ -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:<br * - Launching and monitoring the GDB process,<br>
* - CLI console support,<br>
* - inferior process status tracking.<br>
*/
public class GDBControl_7_0 extends AbstractMIControl implements IGDBControl {
/**
* Event indicating that the back end process has started.
*/
private static class GDBControlInitializedDMEvent extends AbstractDMEvent<ICommandControlDMContext>
implements ICommandControlInitializedDMEvent
{
public GDBControlInitializedDMEvent(ICommandControlDMContext context) {
super(context);
}
}
/**
* Event indicating that the back end process has terminated.
*/
private static class GDBControlShutdownDMEvent extends AbstractDMEvent<ICommandControlDMContext>
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<MIInfo>(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<MIInfo>(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<MIInfo> 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<MIInfo> execMonitor = new DataRequestMonitor<MIInfo>(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<MIBreakInsertInfo>(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<String> 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<String> commandList = new ArrayList<String>();
// 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<String,String>());
getSession().dispatchEvent(new GDBControlInitializedDMEvent(getGDBDMContext()), getProperties());
requestMonitor.done();
}
@Override
protected void shutdown(RequestMonitor requestMonitor) {
unregister();
getSession().removeServiceEventListener(GDBControl_7_0.this);
requestMonitor.done();
}
}
}

View file

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

View file

@ -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<Object> fEventList = new LinkedList<Object>();
// 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;

View file

@ -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<? extends ICommandResult> 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<? extends ICommandResult> 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$
}
}

View file

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

View file

@ -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<MIEvent<?>> events = new LinkedList<MIEvent<?>>();
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; }
}
}
}
}