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:
parent
a980785a88
commit
fbb2135214
11 changed files with 1554 additions and 120 deletions
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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$
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue