From 593106d158c2dec6b52a619705557bbebfee980f Mon Sep 17 00:00:00 2001 From: Francois Chouinard Date: Tue, 22 Jul 2008 19:19:48 +0000 Subject: [PATCH] Patch for non-stop multi-threading --- .../debug/model/DsfMemoryBlockRetrieval.java | 9 +- .../dd/dsf/debug/service/IRunControl.java | 2 +- .../ui/breakpoints/GdbThreadFilterEditor.java | 10 +- .../ui/launching/GdbDebuggerPage.java | 31 + .../ui/launching/LaunchUIMessages.properties | 1 + .../ui/viewmodel/launch/ContainerVMNode.java | 16 +- .../ui/viewmodel/launch/ThreadVMNode.java | 10 +- .../IGDBLaunchConfigurationConstants.java | 11 + .../launching/GdbLaunchDelegate.java | 23 +- .../provisional/service/GDBRunControl.java | 21 +- .../provisional/service/GDBRunControlNS.java | 129 +++ .../service/GdbDebugServicesFactoryNS.java | 33 + .../provisional/service/IGDBRunControl.java | 41 + .../service/command/GDBControl.java | 2 +- .../org.eclipse.dd.mi/META-INF/MANIFEST.MF | 1 + .../dd/mi/service/ExpressionService.java | 1 - .../eclipse/dd/mi/service/IMIRunControl.java | 27 + .../dd/mi/service/MIBreakpointsManager.java | 5 +- .../org/eclipse/dd/mi/service/MIMemory.java | 9 +- .../eclipse/dd/mi/service/MIRunControl.java | 385 ++++---- .../eclipse/dd/mi/service/MIRunControlNS.java | 897 ++++++++++++++++++ .../org/eclipse/dd/mi/service/MIStackNS.java | 677 +++++++++++++ .../mi/service/command/AbstractMIControl.java | 68 +- .../mi/service/command/CLIEventProcessor.java | 35 +- .../command/MIRunControlEventProcessor.java | 142 ++- .../command/commands/MIExecContinue.java | 13 +- .../command/commands/MIExecInterrupt.java | 17 +- .../service/command/commands/MIExecNext.java | 30 +- .../commands/MIExecNextInstruction.java | 16 +- .../command/commands/MIExecReturn.java | 3 +- .../service/command/commands/MIExecStep.java | 18 +- .../commands/MIExecStepInstruction.java | 18 +- .../service/command/commands/MIExecUntil.java | 21 +- .../command/commands/MIStackInfoDepth.java | 21 +- .../commands/MIStackListArguments.java | 35 +- .../command/commands/MIStackListFrames.java | 19 +- .../command/commands/MIStackListLocals.java | 19 +- .../command/commands/MIStackSelectFrame.java | 6 +- .../command/commands/MIThreadInfo.java | 42 + .../service/command/commands/MIVarCreate.java | 2 +- .../command/events/MIBreakpointHitEvent.java | 4 +- .../events/MIFunctionFinishedEvent.java | 4 +- .../events/MILocationReachedEvent.java | 4 +- .../command/events/MISharedLibEvent.java | 4 +- .../service/command/events/MISignalEvent.java | 4 +- .../command/events/MISteppingRangeEvent.java | 4 +- .../command/events/MIStoppedEvent.java | 4 +- .../command/events/MIThreadCreatedEvent.java | 24 + .../command/events/MIThreadExitEvent.java | 24 + .../events/MIWatchpointScopeEvent.java | 4 +- .../events/MIWatchpointTriggerEvent.java | 4 +- .../command/output/CLIInfoThreadsInfo.java | 2 +- .../command/output/MIThreadInfoInfo.java | 254 +++++ .../org/eclipse/dd/tests/gdb/AllTests.java | 3 +- .../dd/tests/gdb/GDBProcessesTest.java | 16 +- 55 files changed, 2808 insertions(+), 417 deletions(-) create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControlNS.java create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java create mode 100644 plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBRunControl.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIRunControl.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStackNS.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadInfo.java create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadInfoInfo.java diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java index 9987a882ae5..1070fbc06ed 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/model/DsfMemoryBlockRetrieval.java @@ -379,8 +379,9 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException { // Drill for the actual DMC IMemoryDMContext memoryDmc = null; + IDMContext dmc = null; if (context instanceof IAdaptable) { - IDMContext dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class); + dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class); if (dmc != null) { memoryDmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class); } @@ -425,7 +426,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl // In case of failure, simply return 'null' // Resolve the expression - blockAddress = resolveMemoryAddress(memoryDmc, expression); + blockAddress = resolveMemoryAddress(dmc, expression); if (blockAddress == null) { return null; } @@ -451,7 +452,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl // Helper functions /////////////////////////////////////////////////////////////////////////// - private BigInteger resolveMemoryAddress(final IDMContext idmContext, final String expression) throws DebugException { + private BigInteger resolveMemoryAddress(final IDMContext dmc, final String expression) throws DebugException { // Use a Query to "synchronize" the downstream calls Query query = new Query() { @@ -461,7 +462,7 @@ public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBl final IExpressions expressionService = (IExpressions) fExpressionServiceTracker.getService(); if (expressionService != null) { // Create the expression - final IExpressionDMContext expressionDMC = expressionService.createExpression(idmContext, expression); + final IExpressionDMContext expressionDMC = expressionService.createExpression(dmc, expression); String formatId = IFormattedValues.HEX_FORMAT; FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(expressionDMC, formatId); expressionService.getFormattedExpressionValue( diff --git a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IRunControl.java b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IRunControl.java index b325450779a..ae168409f50 100644 --- a/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IRunControl.java +++ b/plugins/org.eclipse.dd.dsf.debug/src/org/eclipse/dd/dsf/debug/service/IRunControl.java @@ -37,7 +37,7 @@ public interface IRunControl extends IDMService /** * Context representing a process, kernel, or some other logical container - * for execution cotnexts, which by itself can perform run-control + * for execution contexts, which by itself can perform run-control * operations. */ diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java index 3e525b8f3f2..0f576ee2f9e 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/breakpoints/GdbThreadFilterEditor.java @@ -30,8 +30,8 @@ import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.gdb.internal.provisional.breakpoints.CBreakpointGdbThreadsFilterExtension; import org.eclipse.dd.gdb.internal.provisional.launching.GdbLaunch; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl.IGDBThreadData; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; import org.eclipse.dd.gdb.internal.ui.GdbUIPlugin; import org.eclipse.dd.mi.service.IMIExecutionDMContext; @@ -493,12 +493,12 @@ public class GdbThreadFilterEditor { return; } - ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), GDBRunControl.class + ServiceTracker tracker = new ServiceTracker(GdbUIPlugin.getBundleContext(), IGDBRunControl.class .getName(), null); tracker.open(); - GDBRunControl runControl = (GDBRunControl) tracker.getService(); + IGDBRunControl runControl = (IGDBRunControl) tracker.getService(); if (runControl != null) { - runControl.getThreadData((IMIExecutionDMContext) thread, new DataRequestMonitor( + runControl.getThreadData((IMIExecutionDMContext) thread, new DataRequestMonitor( ImmediateExecutor.getInstance(), rm) { @Override protected void handleSuccess() { diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/GdbDebuggerPage.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/GdbDebuggerPage.java index 96d86ba7161..fb30978055d 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/GdbDebuggerPage.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/GdbDebuggerPage.java @@ -45,6 +45,7 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { protected TabFolder fTabFolder; protected Text fGDBCommandText; protected Text fGDBInitText; + protected Button fNonStopCheckBox; private IMILaunchConfigurationComponent fSolibBlock; private boolean fIsInitializing = false; @@ -64,6 +65,9 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT); configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT); + configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT); + if (fSolibBlock != null) fSolibBlock.setDefaults(configuration); } @@ -86,6 +90,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { setInitializing(true); String gdbCommand = IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT; String gdbInit = IGDBLaunchConfigurationConstants.DEBUGGER_GDB_INIT_DEFAULT; + boolean nonStopMode = IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT; + try { gdbCommand = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUG_NAME, IGDBLaunchConfigurationConstants.DEBUGGER_DEBUG_NAME_DEFAULT); @@ -99,10 +105,18 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { catch(CoreException e) { } + try { + nonStopMode = configuration.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT); + } + catch(CoreException e) { + } + if (fSolibBlock != null) fSolibBlock.initializeFrom(configuration); fGDBCommandText.setText(gdbCommand); fGDBInitText.setText(gdbInit); + fNonStopCheckBox.setSelection(nonStopMode); setInitializing(false); } @@ -112,6 +126,8 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { fGDBCommandText.getText().trim()); configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_GDB_INIT, fGDBInitText.getText().trim()); + configuration.setAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + fNonStopCheckBox.getSelection()); if (fSolibBlock != null) fSolibBlock.performApply(configuration); @@ -242,8 +258,23 @@ public class GdbDebuggerPage extends AbstractCDebuggerPage implements Observer { fGDBInitText.setText(res); } }); + + // TODO: Fetch the string from LaunchUIMessages + // TODO: Ideally, this field should be disabled if the back-end doesn't support non-stop debugging + // TODO: Find a way to determine if non-stop is supported (i.e. find the GDB version) then grey out the check box if necessary + // Button fNonStopButton = ControlFactory.createCheckBox(subComp, LaunchUIMessages.getString( "GDBDebuggerPage.15") ); //$NON-NLS-1$ + fNonStopCheckBox = ControlFactory.createCheckBox(subComp, LaunchUIMessages.getString("GDBDebuggerPage.13")); //$NON-NLS-1$ + fNonStopCheckBox.setEnabled(false); + fNonStopCheckBox.addSelectionListener( new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + updateLaunchConfigurationDialog(); + } + }); + label = ControlFactory.createLabel(subComp, LaunchUIMessages.getString("GDBDebuggerPage.9"), //$NON-NLS-1$ 200, SWT.DEFAULT, SWT.WRAP); + gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; gd.widthHint = 200; diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/LaunchUIMessages.properties b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/LaunchUIMessages.properties index 6dd5cf12abb..139a457a8bf 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/LaunchUIMessages.properties +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/launching/LaunchUIMessages.properties @@ -24,6 +24,7 @@ GDBDebuggerPage.9=(Warning: Some commands in this file may interfere with the st GDBDebuggerPage.10=Shared Libraries GDBDebuggerPage.11=Protocol: GDBDebuggerPage.12=Default +GDBDebuggerPage.13=Non-stop mode (Note: Requires non-stop GDB) StandardGDBDebuggerPage.0=Debugger executable must be specified. StandardGDBDebuggerPage.1=GDB Debugger Options StandardGDBDebuggerPage.2=Main diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java index fcc21969291..6070c328881 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java @@ -25,8 +25,8 @@ import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; import org.eclipse.dd.dsf.ui.viewmodel.VMDelta; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl.GDBProcessData; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl.IGDBProcessData; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControlDMContext; import org.eclipse.dd.mi.service.command.MIInferiorProcess; @@ -72,7 +72,7 @@ public class ContainerVMNode extends AbstractContainerVMNode @Override protected void updateLabelInSessionThread(final ILabelUpdate update) { - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + final IGDBRunControl runControl = getServicesTracker().getService(IGDBRunControl.class); if ( runControl == null ) { handleFailedUpdate(update); return; @@ -90,7 +90,7 @@ public class ContainerVMNode extends AbstractContainerVMNode runControl.getProcessData( dmc, - new ViewerDataRequestMonitor(getExecutor(), update) { + new ViewerDataRequestMonitor(getExecutor(), update) { @Override public void handleCompleted() { if (!isSuccess()) { @@ -151,11 +151,11 @@ public class ContainerVMNode extends AbstractContainerVMNode try { getSession().getExecutor().execute(new DsfRunnable() { public void run() { - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + final IGDBRunControl runControl = getServicesTracker().getService(IGDBRunControl.class); if ( runControl != null ) { runControl.getProcessData( procDmc, - new ViewerDataRequestMonitor(runControl.getExecutor(), request) { + new ViewerDataRequestMonitor(runControl.getExecutor(), request) { @Override protected void handleCompleted() { if ( getStatus().isOK() ) { @@ -203,11 +203,11 @@ public class ContainerVMNode extends AbstractContainerVMNode try { getSession().getExecutor().execute(new DsfRunnable() { public void run() { - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + final IGDBRunControl runControl = getServicesTracker().getService(IGDBRunControl.class); if ( runControl != null ) { runControl.getProcessData( procDmc, - new ViewerDataRequestMonitor(runControl.getExecutor(), request) { + new ViewerDataRequestMonitor(runControl.getExecutor(), request) { @Override protected void handleCompleted() { if ( getStatus().isOK() ) { diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java index d717ab24128..5b97341e037 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ThreadVMNode.java @@ -20,8 +20,8 @@ import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl.IGDBThreadData; import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest; import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider; @@ -49,7 +49,7 @@ public class ThreadVMNode extends AbstractThreadVMNode @Override protected void updateLabelInSessionThread(ILabelUpdate[] updates) { for (final ILabelUpdate update : updates) { - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + final IGDBRunControl runControl = getServicesTracker().getService(IGDBRunControl.class); if ( runControl == null ) { handleFailedUpdate(update); continue; @@ -78,7 +78,7 @@ public class ThreadVMNode extends AbstractThreadVMNode // We're in a new dispatch cycle, and we have to check whether the // service reference is still valid. - final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); + final IGDBRunControl runControl = getServicesTracker().getService(IGDBRunControl.class); if ( runControl == null ) { handleFailedUpdate(update); return; @@ -89,7 +89,7 @@ public class ThreadVMNode extends AbstractThreadVMNode // Retrieve the rest of the thread information runControl.getThreadData( dmc, - new ViewerDataRequestMonitor(getSession().getExecutor(), update) { + new ViewerDataRequestMonitor(getSession().getExecutor(), update) { @Override public void handleCompleted() { if (!isSuccess()) { diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/IGDBLaunchConfigurationConstants.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/IGDBLaunchConfigurationConstants.java index 501651cc8bd..fb21f720f49 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/IGDBLaunchConfigurationConstants.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/IGDBLaunchConfigurationConstants.java @@ -48,6 +48,12 @@ public class IGDBLaunchConfigurationConstants { */ public static final String ATTR_GDB_INIT = GdbPlugin.PLUGIN_ID + ".GDB_INIT"; //$NON-NLS-1$ + /** + * Launch configuration attribute key. Boolean value to set the non-stop mode + * Debuger/gdb/MI property. + */ + public static final String ATTR_DEBUGGER_NON_STOP = GdbPlugin.PLUGIN_ID + ".NON_STOP"; //$NON-NLS-1$ + /** * Launch configuration attribute key. Boolean value to set the 'automatically load shared library symbols' flag of the debugger. */ @@ -78,6 +84,11 @@ public class IGDBLaunchConfigurationConstants { */ public static final String DEBUGGER_GDB_INIT_DEFAULT = ".gdbinit"; //$NON-NLS-1$ + /** + * Launch configuration attribute value. The key is ATTR_DEBUGGER_NON_STOP. + */ + public static final boolean DEBUGGER_NON_STOP_DEFAULT = false; + /** * Launch configuration attribute value. The key is ATTR_DEBUGGER_AUTO_SOLIB. */ diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java index bcce8623d09..33373c2adcc 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/launching/GdbLaunchDelegate.java @@ -37,6 +37,7 @@ import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.gdb.internal.GdbPlugin; import org.eclipse.dd.gdb.internal.provisional.IGDBLaunchConfigurationConstants; import org.eclipse.dd.gdb.internal.provisional.service.GdbDebugServicesFactory; +import org.eclipse.dd.gdb.internal.provisional.service.GdbDebugServicesFactoryNS; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.SessionType; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; @@ -56,7 +57,9 @@ public class GdbLaunchDelegate extends LaunchConfigurationDelegate { public final static String GDB_DEBUG_MODEL_ID = "org.eclipse.dd.gdb"; //$NON-NLS-1$ - public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { + private boolean isNonStopSession = false; + + public void launch( ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor ) throws CoreException { if ( monitor == null ) { monitor = new NullProgressMonitor(); } @@ -167,6 +170,16 @@ public class GdbLaunchDelegate extends LaunchConfigurationDelegate return SessionType.LOCAL; } + private boolean isNonStopSession(ILaunchConfiguration config) { + try { + boolean nonStopMode = config.getAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, + IGDBLaunchConfigurationConstants.DEBUGGER_NON_STOP_DEFAULT); + return nonStopMode; + } catch (CoreException e) { + } + return false; + } + private boolean getIsAttach(ILaunchConfiguration config) { try { String debugMode = config.getAttribute( ICDTLaunchConfigurationConstants.ATTR_DEBUGGER_START_MODE, ICDTLaunchConfigurationConstants.DEBUGGER_MODE_RUN ); @@ -202,6 +215,8 @@ public class GdbLaunchDelegate extends LaunchConfigurationDelegate // the adapters will be created for the whole session, including // the source lookup adapter. + isNonStopSession = isNonStopSession(configuration); + GdbLaunch launch = new GdbLaunch(configuration, mode, null); launch.initialize(); launch.setSourceLocator(getSourceLocator(configuration, launch.getSession())); @@ -314,6 +329,12 @@ public class GdbLaunchDelegate extends LaunchConfigurationDelegate } private IDsfDebugServicesFactory newServiceFactory(String version) { + + // TODO: Fix version number once non-stop GDB is delivered + if (isNonStopSession && version.startsWith("6.8.50.20080327")) { //$NON-NLS-1$ + return new GdbDebugServicesFactoryNS(version); + } + if (version.startsWith("6.6") || //$NON-NLS-1$ version.startsWith("6.7") || //$NON-NLS-1$ version.startsWith("6.8")) { //$NON-NLS-1$ diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java index 5bec187a200..251381c71a3 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControl.java @@ -29,19 +29,21 @@ import org.eclipse.dd.gdb.internal.GdbPlugin; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControlDMContext; import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.MIRunControl; import org.eclipse.dd.mi.service.command.commands.CLIInfoThreads; import org.eclipse.dd.mi.service.command.events.MIEvent; import org.eclipse.dd.mi.service.command.events.MIThreadExitEvent; import org.eclipse.dd.mi.service.command.output.CLIInfoThreadsInfo; -public class GDBRunControl extends MIRunControl { - /** +public class GDBRunControl extends MIRunControl implements IGDBRunControl { + + /** * Implement a custom execution data for threads in order to provide additional * information. This object can be made separate from IExecutionDMData after * the deprecated method: IDMService.getModelData() is no longer used. */ - public static class GDBThreadData { + public static class GDBThreadData implements IGDBThreadData { private final String fId; private final String fName; @@ -63,7 +65,7 @@ public class GDBRunControl extends MIRunControl { * information. This object can be made separate from IExecutionDMData after * the deprecated method: IDMService.getModelData() is no longer used. */ - public static class GDBProcessData { + public static class GDBProcessData implements IGDBProcessData { private final String fName; GDBProcessData(String name) { @@ -74,7 +76,7 @@ public class GDBRunControl extends MIRunControl { return fName; } } - + private GDBControl fGdb; // Record list of execution contexts @@ -98,8 +100,9 @@ public class GDBRunControl extends MIRunControl { private void doInitialize(final RequestMonitor requestMonitor) { fGdb = getServicesTracker().getService(GDBControl.class); - register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName()}, new Hashtable()); - + register(new String[]{IRunControl.class.getName(), + IMIRunControl.class.getName(), MIRunControl.class.getName(), + IGDBRunControl.class.getName(), GDBRunControl.class.getName()}, new Hashtable()); requestMonitor.done(); } @@ -149,12 +152,12 @@ public class GDBRunControl extends MIRunControl { super.getExecutionContexts(c, rm1); } - public void getProcessData(GDBControlDMContext gdbDmc, DataRequestMonitor rm) { + public void getProcessData(GDBControlDMContext gdbDmc, DataRequestMonitor rm) { rm.setData( new GDBProcessData(fGdb.getExecutablePath().lastSegment()) ); rm.done(); } - public void getThreadData(final IMIExecutionDMContext execDmc, final DataRequestMonitor rm) { + public void getThreadData(final IMIExecutionDMContext execDmc, final DataRequestMonitor rm) { IContainerDMContext containerDmc = DMContexts.getAncestorOfType(execDmc, IContainerDMContext.class); assert containerDmc != null; // Every exec context should have a container as an ancestor. getCache().execute(new CLIInfoThreads(containerDmc), diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControlNS.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControlNS.java new file mode 100644 index 00000000000..f93482d4286 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GDBRunControlNS.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * 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 AB - Modified for additional functionality + *******************************************************************************/ + +package org.eclipse.dd.gdb.internal.provisional.service; + + +import java.util.Hashtable; + +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.debug.service.IRunControl; +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.GDBControlDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIRunControl; +import org.eclipse.dd.mi.service.MIRunControlNS; +import org.eclipse.dd.mi.service.command.commands.MIThreadInfo; +import org.eclipse.dd.mi.service.command.output.MIThreadInfoInfo; + +public class GDBRunControlNS extends MIRunControlNS implements IGDBRunControl +{ + /** + * Implement a custom execution data for threads in order to provide additional + * information. This object can be made separate from IExecutionDMData after + * the deprecated method: IDMService.getModelData() is no longer used. + */ + private static class GDBThreadData implements IGDBThreadData { + private final String fId; + private final String fName; + + GDBThreadData(String id, String name) { + fId = id; + fName = name; + } + + public String getName() { + return fName; + } + public String getId() { return fId; } + + public boolean isDebuggerAttached() { return true; } + } + + /** + * Implement a custom execution data the process in order to provide additional + * information. This object can be made separate from IExecutionDMData after + * the deprecated method: IDMService.getModelData() is no longer used. + */ + private static class GDBProcessData implements IGDBProcessData { + private final String fName; + + GDBProcessData(String name) { + fName = name; + } + + public String getName() { + return fName; + } + } + + private GDBControl fGdb; + + public GDBRunControlNS(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(GDBControl.class); + register(new String[]{IRunControl.class.getName(), IMIRunControl.class.getName(), IGDBRunControl.class.getName()}, new Hashtable()); + + requestMonitor.done(); + } + + @Override + public void shutdown(final RequestMonitor requestMonitor) { + unregister(); + super.shutdown(requestMonitor); + } + + public void getProcessData(GDBControlDMContext gdbDmc, DataRequestMonitor rm) { + rm.setData( new GDBProcessData(fGdb.getExecutablePath().lastSegment()) ); + rm.done(); + } + + public void getThreadData(final IMIExecutionDMContext execDmc, final DataRequestMonitor rm) { + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(execDmc, IContainerDMContext.class); + getCache().execute(new MIThreadInfo(containerDmc, execDmc.getThreadId()), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(createThreadInfo(execDmc, getData())); + rm.done(); + } + }); + } + + private GDBThreadData createThreadInfo(IMIExecutionDMContext dmc, MIThreadInfoInfo info) { + // There should be only 1 thread in the result, but just in case... + for (MIThreadInfoInfo.ThreadInfo thread : info.getThreadInfoList()) { + if (Integer.parseInt(thread.getGdbId()) == dmc.getThreadId()){ + return new GDBThreadData(thread.getOsId(), ""); //$NON-NLS-1$ + } + } + return new GDBThreadData("", ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java new file mode 100644 index 00000000000..5ba6a8ff947 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/GdbDebugServicesFactoryNS.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Ericsson - initial API and implementation + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.provisional.service; + +import org.eclipse.dd.dsf.debug.service.IRunControl; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.service.MIStackNS; + +public class GdbDebugServicesFactoryNS extends GdbDebugServicesFactory { + + public GdbDebugServicesFactoryNS(String version) { + super(version); + } + + @Override + protected IStack createStackService(DsfSession session) { + return new MIStackNS(session); + } + + @Override + protected IRunControl createRunControlService(DsfSession session) { + return new GDBRunControlNS(session); + } +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBRunControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBRunControl.java new file mode 100644 index 00000000000..53c8e10b075 --- /dev/null +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/IGDBRunControl.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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 functionality + *******************************************************************************/ +package org.eclipse.dd.gdb.internal.provisional.service; + +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControlDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIRunControl; + +/** + * This interface provides access to controlling and monitoring the execution + * state of a process being debugged. This interface does not actually + * provide methods for creating or destroying execution contexts, it doesn't + * even have methods for getting labels. That's because it is expected that + * higher level services, ones that deal with processes, kernels, or target + * features will provide that functionality. + */ +public interface IGDBRunControl extends IMIRunControl +{ + public interface IGDBThreadData { + public String getName(); + public String getId(); + public boolean isDebuggerAttached(); + } + + public interface IGDBProcessData { + public String getName(); + } + + public void getProcessData(GDBControlDMContext gdbDmc, DataRequestMonitor rm); + public void getThreadData(final IMIExecutionDMContext execDmc, final DataRequestMonitor dataRequestMonitor); +} diff --git a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java index 434b91e0781..e058dbebf7b 100644 --- a/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java +++ b/plugins/org.eclipse.dd.gdb/src/org/eclipse/dd/gdb/internal/provisional/service/command/GDBControl.java @@ -179,7 +179,7 @@ public class GDBControl extends AbstractMIControl { * More strongly typed version of {@link #getControlDMContext()}. */ public GDBControlDMContext getGDBDMContext() { - return (GDBControlDMContext)getControlDMContext(); + return (GDBControlDMContext) getControlDMContext(); } public SessionType getSessionType() { diff --git a/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF index 610b81c62fe..e004e0ad24b 100644 --- a/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.dd.mi/META-INF/MANIFEST.MF @@ -13,6 +13,7 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.cdt.debug.core, org.eclipse.cdt.core Export-Package: + org.eclipse.dd.mi.internal, org.eclipse.dd.mi.service, org.eclipse.dd.mi.service.command, org.eclipse.dd.mi.service.command.commands, diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java index a02e3ad8579..bc1d800a9ef 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/ExpressionService.java @@ -893,7 +893,6 @@ public class ExpressionService extends AbstractDsfService implements IExpression } } - @DsfServiceEventHandler public void eventDispatched(IRunControl.IResumedDMEvent e) { fExpressionCache.setContextAvailable(e.getDMContext(), false); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIRunControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIRunControl.java new file mode 100644 index 00000000000..b8337877008 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/IMIRunControl.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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 functionality + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import org.eclipse.dd.dsf.debug.service.IRunControl; + +/** + * This interface provides access to controlling and monitoring the execution + * state of a process being debugged. This interface does not actually + * provide methods for creating or destroying execution contexts, it doesn't + * even have methods for getting labels. That's because it is expected that + * higher level services, ones that deal with processes, kernels, or target + * features will provide that functionality. + */ +public interface IMIRunControl extends IRunControl +{ + public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId); +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java index 89eaa934ee0..974db268b71 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIBreakpointsManager.java @@ -71,7 +71,6 @@ import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointAddedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointRemovedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.BreakpointUpdatedEvent; import org.eclipse.dd.mi.service.MIBreakpoints.MIBreakpointDMContext; -import org.eclipse.dd.mi.service.MIRunControl.MIExecutionDMC; import org.eclipse.dd.mi.service.breakpoint.actions.BreakpointActionAdapter; import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; import org.eclipse.dd.mi.service.command.events.MIGDBExitEvent; @@ -1516,8 +1515,8 @@ public class MIBreakpointsManager extends AbstractDsfService implements IBreakpo Set results = new HashSet(); if ((threads != null) && (supportsThreads(breakpoint))) { for (IExecutionDMContext thread : threads) { - if (thread instanceof MIExecutionDMC) { - MIExecutionDMC dmc = (MIExecutionDMC) thread; + if (thread instanceof IMIExecutionDMContext) { + IMIExecutionDMContext dmc = (IMIExecutionDMContext) thread; results.add(((Integer) dmc.getThreadId()).toString()); } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java index 1136b1c728a..0b5400752c6 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIMemory.java @@ -69,8 +69,6 @@ public class MIMemory extends AbstractDsfService implements IMemory { } } - @SuppressWarnings("unused") - private MIRunControl fRunControl; private MIMemoryCache fMemoryCache; /** @@ -113,9 +111,6 @@ public class MIMemory extends AbstractDsfService implements IMemory { // Register this service register(new String[] { MIMemory.class.getName(), IMemory.class.getName() }, new Hashtable()); - // Get the RunControl so we can retrieve the current Execution context - fRunControl = getServicesTracker().getService(MIRunControl.class); - // Create the memory requests cache fMemoryCache = new MIMemoryCache(); @@ -279,7 +274,7 @@ public class MIMemory extends AbstractDsfService implements IMemory { ////////////////////////////////////////////////////////////////////////// @DsfServiceEventHandler - public void eventDispatched(IRunControl.IResumedDMEvent e) { + public void eventDispatched(IRunControl.IContainerResumedDMEvent e) { fMemoryCache.setTargetAvailable(e.getDMContext(), false); if (e.getReason() != StateChangeReason.STEP) { fMemoryCache.reset(); @@ -287,7 +282,7 @@ public class MIMemory extends AbstractDsfService implements IMemory { } @DsfServiceEventHandler - public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + public void eventDispatched(IRunControl.IContainerSuspendedDMEvent e) { fMemoryCache.setTargetAvailable(e.getDMContext(), true); fMemoryCache.reset(); } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java index b88a1fbf447..8bd60b4faf4 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControl.java @@ -21,7 +21,6 @@ import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMEvent; -import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; import org.eclipse.dd.dsf.debug.service.command.CommandCache; import org.eclipse.dd.dsf.service.AbstractDsfService; @@ -71,197 +70,212 @@ import org.osgi.framework.BundleContext; * events and track service state, to be perfectly in sync with the service * state. */ -public class MIRunControl extends AbstractDsfService implements IRunControl +public class MIRunControl extends AbstractDsfService implements IMIRunControl { - protected class MIExecutionDMC extends AbstractDMContext - implements IMIExecutionDMContext - { - /** - * Integer ID that is used to identify the thread in the GDB/MI protocol. - */ - private final int fThreadId; - - /** - * Constructor for the context. It should not be called directly by clients. - * Instead clients should call {@link MIRunControl#createMIExecutionContext(IContainerDMContext, int)} - * to create instances of this context based on the thread ID. - *

- * Classes extending {@link MIRunControl} may also extend this class to include - * additional information in the context. - * - * @param sessionId Session that this context belongs to. - * @param containerDmc The container that this context belongs to. - * @param threadId GDB/MI thread identifier. - */ - protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, int threadId) { - super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]); - fThreadId = threadId; - } - - /** - * Returns the GDB/MI thread identifier of this context. - * @return - */ - public int getThreadId(){ - return fThreadId; - } - - @Override - public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ - - @Override - public boolean equals(Object obj) { - return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId == fThreadId; - } - - @Override - public int hashCode() { return super.baseHashCode() ^ fThreadId; } - } - - @Immutable - private static class ExecutionData implements IExecutionDMData { - private final StateChangeReason fReason; - ExecutionData(StateChangeReason reason) { - fReason = reason; - } - public StateChangeReason getStateChangeReason() { return fReason; } - } + class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext + { + /** + * Integer ID that is used to identify the thread in the GDB/MI protocol. + */ + private final int fThreadId; - /** - * Base class for events generated by the MI Run Control service. Most events - * generated by the MI Run Control service are directly caused by some MI event. - * Other services may need access to the extended MI data carried in the event. - * - * @param DMC that this event refers to - * @param MIInfo object that is the direct cause of this event - * @see MIRunControl - */ - @Immutable - protected static class RunControlEvent> extends AbstractDMEvent - implements IDMEvent, IMIDMEvent - { - final private T fMIInfo; - public RunControlEvent(V dmc, T miInfo) { - super(dmc); - fMIInfo = miInfo; - } - - public T getMIEvent() { return fMIInfo; } - } - - /** - * Indicates that the given thread has been suspended. - */ - @Immutable - protected static class SuspendedEvent extends RunControlEvent - implements ISuspendedDMEvent - { - SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) { - super(ctx, miInfo); - } - - public StateChangeReason getReason() { - if (getMIEvent() instanceof MIBreakpointHitEvent) { - return StateChangeReason.BREAKPOINT; - } else if (getMIEvent() instanceof MISteppingRangeEvent) { - return StateChangeReason.STEP; - } else if (getMIEvent() instanceof MISharedLibEvent) { - return StateChangeReason.SHAREDLIB; - }else if (getMIEvent() instanceof MISignalEvent) { - return StateChangeReason.SIGNAL; - }else if (getMIEvent() instanceof MIWatchpointTriggerEvent) { - return StateChangeReason.WATCHPOINT; - }else if (getMIEvent() instanceof MIErrorEvent) { - return StateChangeReason.ERROR; - }else { - return StateChangeReason.USER_REQUEST; - } - } - } + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link MIRunControl#createMIExecutionContext(IContainerDMContext, int)} + * to create instances of this context based on the thread ID. + *

+ * Classes extending {@link MIRunControl} may also extend this class to include + * additional information in the context. + * + * @param sessionId Session that this context belongs to. + * @param containerDmc The container that this context belongs to. + * @param threadId GDB/MI thread identifier. + */ + protected MIExecutionDMC(String sessionId, IContainerDMContext containerDmc, int threadId) { + super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]); + fThreadId = threadId; + } - @Immutable - protected static class ContainerSuspendedEvent extends SuspendedEvent - implements IContainerSuspendedDMEvent - { - final IExecutionDMContext[] triggeringDmcs; - ContainerSuspendedEvent(IContainerDMContext containerDmc, MIStoppedEvent miInfo, IExecutionDMContext triggeringDmc) { - super(containerDmc, miInfo); - this.triggeringDmcs = triggeringDmc != null - ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; - } - - public IExecutionDMContext[] getTriggeringContexts() { - return triggeringDmcs; - } - } + /** + * Returns the GDB/MI thread identifier of this context. + * @return + */ + public int getThreadId(){ + return fThreadId; + } - @Immutable - protected static class ResumedEvent extends RunControlEvent - implements IResumedDMEvent - { - ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) { - super(ctx, miInfo); - } - - public StateChangeReason getReason() { - switch(getMIEvent().getType()) { - case MIRunningEvent.CONTINUE: - return StateChangeReason.USER_REQUEST; - case MIRunningEvent.NEXT: - case MIRunningEvent.NEXTI: - return StateChangeReason.STEP; - case MIRunningEvent.STEP: - case MIRunningEvent.STEPI: - return StateChangeReason.STEP; - case MIRunningEvent.FINISH: - return StateChangeReason.STEP; - case MIRunningEvent.UNTIL: - case MIRunningEvent.RETURN: - break; - } - return StateChangeReason.UNKNOWN; - } - } + @Override + public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ - @Immutable - protected static class ContainerResumedEvent extends ResumedEvent - implements IContainerResumedDMEvent - { - final IExecutionDMContext[] triggeringDmcs; + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId == fThreadId; + } - ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) { - super(containerDmc, miInfo); - this.triggeringDmcs = triggeringDmc != null - ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; - } - - public IExecutionDMContext[] getTriggeringContexts() { - return triggeringDmcs; - } - } - - @Immutable - protected static class StartedDMEvent extends RunControlEvent - implements IStartedDMEvent - { - StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) { - super(executionDmc, miInfo); - } - } - - @Immutable - protected static class ExitedDMEvent extends RunControlEvent - implements IExitedDMEvent - { - ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) { - super(executionDmc, miInfo); - } - } - - private AbstractMIControl fConnection; + @Override + public int hashCode() { return super.baseHashCode() ^ fThreadId; } + } + + @Immutable + static class ExecutionData implements IExecutionDMData { + private final StateChangeReason fReason; + ExecutionData(StateChangeReason reason) { + fReason = reason; + } + public StateChangeReason getStateChangeReason() { return fReason; } + } + + /** + * Base class for events generated by the MI Run Control service. Most events + * generated by the MI Run Control service are directly caused by some MI event. + * Other services may need access to the extended MI data carried in the event. + * + * @param DMC that this event refers to + * @param MIInfo object that is the direct cause of this event + * @see MIRunControl + */ + @Immutable + static class RunControlEvent> extends AbstractDMEvent + implements IDMEvent, IMIDMEvent + { + final private T fMIInfo; + public RunControlEvent(V dmc, T miInfo) { + super(dmc); + fMIInfo = miInfo; + } + + public T getMIEvent() { return fMIInfo; } + } + + /** + * Indicates that the given thread has been suspended. + */ + @Immutable + static class SuspendedEvent extends RunControlEvent + implements ISuspendedDMEvent + { + SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + if (getMIEvent() instanceof MIBreakpointHitEvent) { + return StateChangeReason.BREAKPOINT; + } else if (getMIEvent() instanceof MISteppingRangeEvent) { + return StateChangeReason.STEP; + } else if (getMIEvent() instanceof MISharedLibEvent) { + return StateChangeReason.SHAREDLIB; + }else if (getMIEvent() instanceof MISignalEvent) { + return StateChangeReason.SIGNAL; + }else if (getMIEvent() instanceof MIWatchpointTriggerEvent) { + return StateChangeReason.WATCHPOINT; + }else if (getMIEvent() instanceof MIErrorEvent) { + return StateChangeReason.ERROR; + }else { + return StateChangeReason.USER_REQUEST; + } + } + } + + @Immutable + static class ContainerSuspendedEvent extends SuspendedEvent + implements IContainerSuspendedDMEvent + { + final IExecutionDMContext[] triggeringDmcs; + ContainerSuspendedEvent(IContainerDMContext containerDmc, MIStoppedEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmcs = triggeringDmc != null + ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return triggeringDmcs; + } + } + + @Immutable + static class ThreadSuspendedEvent extends SuspendedEvent + { + ThreadSuspendedEvent(IExecutionDMContext executionDmc, MIStoppedEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class ResumedEvent extends RunControlEvent + implements IResumedDMEvent + { + ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + switch(getMIEvent().getType()) { + case MIRunningEvent.CONTINUE: + return StateChangeReason.USER_REQUEST; + case MIRunningEvent.NEXT: + case MIRunningEvent.NEXTI: + return StateChangeReason.STEP; + case MIRunningEvent.STEP: + case MIRunningEvent.STEPI: + return StateChangeReason.STEP; + case MIRunningEvent.FINISH: + return StateChangeReason.STEP; + case MIRunningEvent.UNTIL: + case MIRunningEvent.RETURN: + break; + } + return StateChangeReason.UNKNOWN; + } + } + + @Immutable + static class ContainerResumedEvent extends ResumedEvent + implements IContainerResumedDMEvent + { + final IExecutionDMContext[] triggeringDmcs; + + ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmcs = triggeringDmc != null + ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return triggeringDmcs; + } + } + + @Immutable + static class ThreadResumedEvent extends ResumedEvent + { + ThreadResumedEvent(IExecutionDMContext executionDmc, MIRunningEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class StartedDMEvent extends RunControlEvent + implements IStartedDMEvent + { + StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class ExitedDMEvent extends RunControlEvent + implements IExitedDMEvent + { + ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) { + super(executionDmc, miInfo); + } + } + + private AbstractMIControl fConnection; private CommandCache fMICommandCache; - // state flags + // State flags private boolean fSuspended = true; private boolean fResumePending = false; private boolean fStepping = false; @@ -291,9 +305,6 @@ public class MIRunControl extends AbstractDsfService implements IRunControl fMICommandCache = new CommandCache(getSession(), fConnection); fMICommandCache.setContextAvailable(fConnection.getControlDMContext(), true); getSession().addServiceEventListener(this, null); - - //register(new String[]{IRunControl.class.getName(), MIRunControl.class.getName()}, new Hashtable()); - rm.done(); } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java new file mode 100644 index 00000000000..c9d6ad899e7 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIRunControlNS.java @@ -0,0 +1,897 @@ +/******************************************************************************* + * 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 AB - Modified for handling of multiple threads + *******************************************************************************/ + +package org.eclipse.dd.mi.service; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.Immutable; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.IDMEvent; +import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.AbstractMIControl; +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.MIExecInterrupt; +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.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.commands.MIThreadListIds; +import org.eclipse.dd.mi.service.command.events.IMIDMEvent; +import org.eclipse.dd.mi.service.command.events.MIBreakpointHitEvent; +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.MIGDBExitEvent; +import org.eclipse.dd.mi.service.command.events.MIRunningEvent; +import org.eclipse.dd.mi.service.command.events.MISharedLibEvent; +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.MIWatchpointTriggerEvent; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.eclipse.dd.mi.service.command.output.MIThreadListIdsInfo; +import org.osgi.framework.BundleContext; + +/** + * Implementation note: This class implements event handlers for the events that + * are generated by this service itself. When the event is dispatched, these + * handlers will be called first, before any of the clients. These handlers + * update the service's internal state information to make them consistent with + * the events being issued. Doing this in the handlers as opposed to when the + * events are generated, guarantees that the state of the service will always be + * consistent with the events. The purpose of this pattern is to allow clients + * that listen to service events and track service state, to be perfectly in + * sync with the service state. + */ +public class MIRunControlNS extends AbstractDsfService implements IMIRunControl +{ + // This is an exact copy of the structures in MIRunControl. In an ideal world, + // it would be declared only once in IMIRunControl but this is real life and + // it has to be duplicated for the sake of backward compatibility. + // It sucks and leads to bloated, error-prone code but that's the way it is. + class MIExecutionDMCNS extends AbstractDMContext implements IMIExecutionDMContext + { + /** + * Integer ID that is used to identify the thread in the GDB/MI protocol. + */ + private final int fThreadId; + + /** + * Constructor for the context. It should not be called directly by clients. + * Instead clients should call {@link MIRunControl#createMIExecutionContext(IContainerDMContext, int)} + * to create instances of this context based on the thread ID. + *

+ * Classes extending {@link MIRunControl} may also extend this class to include + * additional information in the context. + * + * @param sessionId Session that this context belongs to. + * @param containerDmc The container that this context belongs to. + * @param threadId GDB/MI thread identifier. + */ + protected MIExecutionDMCNS(String sessionId, IContainerDMContext containerDmc, int threadId) { + super(sessionId, containerDmc != null ? new IDMContext[] { containerDmc } : new IDMContext[0]); + fThreadId = threadId; + } + + /** + * Returns the GDB/MI thread identifier of this context. + * @return + */ + public int getThreadId(){ + return fThreadId; + } + + @Override + public String toString() { return baseToString() + ".thread[" + fThreadId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ + + @Override + public boolean equals(Object obj) { + return super.baseEquals(obj) && ((MIExecutionDMCNS)obj).fThreadId == fThreadId; + } + + @Override + public int hashCode() { return super.baseHashCode() ^ fThreadId; } + } + + @Immutable + static class ExecutionData implements IExecutionDMData { + private final StateChangeReason fReason; + ExecutionData(StateChangeReason reason) { + fReason = reason; + } + public StateChangeReason getStateChangeReason() { return fReason; } + } + + /** + * Base class for events generated by the MI Run Control service. Most events + * generated by the MI Run Control service are directly caused by some MI event. + * Other services may need access to the extended MI data carried in the event. + * + * @param DMC that this event refers to + * @param MIInfo object that is the direct cause of this event + * @see MIRunControl + */ + @Immutable + static class RunControlEvent> extends AbstractDMEvent + implements IDMEvent, IMIDMEvent + { + final private T fMIInfo; + public RunControlEvent(V dmc, T miInfo) { + super(dmc); + fMIInfo = miInfo; + } + + public T getMIEvent() { return fMIInfo; } + } + + /** + * Indicates that the given thread has been suspended. + */ + @Immutable + static class SuspendedEvent extends RunControlEvent + implements ISuspendedDMEvent + { + SuspendedEvent(IExecutionDMContext ctx, MIStoppedEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + if (getMIEvent() instanceof MIBreakpointHitEvent) { + return StateChangeReason.BREAKPOINT; + } else if (getMIEvent() instanceof MISteppingRangeEvent) { + return StateChangeReason.STEP; + } else if (getMIEvent() instanceof MISharedLibEvent) { + return StateChangeReason.SHAREDLIB; + }else if (getMIEvent() instanceof MISignalEvent) { + return StateChangeReason.SIGNAL; + }else if (getMIEvent() instanceof MIWatchpointTriggerEvent) { + return StateChangeReason.WATCHPOINT; + }else if (getMIEvent() instanceof MIErrorEvent) { + return StateChangeReason.ERROR; + }else { + return StateChangeReason.USER_REQUEST; + } + } + } + + @Immutable + static class ContainerSuspendedEvent extends SuspendedEvent + implements IContainerSuspendedDMEvent + { + final IExecutionDMContext[] triggeringDmcs; + ContainerSuspendedEvent(IContainerDMContext containerDmc, MIStoppedEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmcs = triggeringDmc != null + ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return triggeringDmcs; + } + } + + @Immutable + static class ThreadSuspendedEvent extends SuspendedEvent + { + ThreadSuspendedEvent(IExecutionDMContext executionDmc, MIStoppedEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class ResumedEvent extends RunControlEvent + implements IResumedDMEvent + { + ResumedEvent(IExecutionDMContext ctx, MIRunningEvent miInfo) { + super(ctx, miInfo); + } + + public StateChangeReason getReason() { + switch(getMIEvent().getType()) { + case MIRunningEvent.CONTINUE: + return StateChangeReason.USER_REQUEST; + case MIRunningEvent.NEXT: + case MIRunningEvent.NEXTI: + return StateChangeReason.STEP; + case MIRunningEvent.STEP: + case MIRunningEvent.STEPI: + return StateChangeReason.STEP; + case MIRunningEvent.FINISH: + return StateChangeReason.STEP; + case MIRunningEvent.UNTIL: + case MIRunningEvent.RETURN: + break; + } + return StateChangeReason.UNKNOWN; + } + } + + @Immutable + static class ContainerResumedEvent extends ResumedEvent + implements IContainerResumedDMEvent + { + final IExecutionDMContext[] triggeringDmcs; + + ContainerResumedEvent(IContainerDMContext containerDmc, MIRunningEvent miInfo, IExecutionDMContext triggeringDmc) { + super(containerDmc, miInfo); + this.triggeringDmcs = triggeringDmc != null + ? new IExecutionDMContext[] { triggeringDmc } : new IExecutionDMContext[0]; + } + + public IExecutionDMContext[] getTriggeringContexts() { + return triggeringDmcs; + } + } + + @Immutable + static class ThreadResumedEvent extends ResumedEvent + { + ThreadResumedEvent(IExecutionDMContext executionDmc, MIRunningEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class StartedDMEvent extends RunControlEvent + implements IStartedDMEvent + { + StartedDMEvent(IMIExecutionDMContext executionDmc, MIThreadCreatedEvent miInfo) { + super(executionDmc, miInfo); + } + } + + @Immutable + static class ExitedDMEvent extends RunControlEvent + implements IExitedDMEvent + { + ExitedDMEvent(IMIExecutionDMContext executionDmc, MIThreadExitEvent miInfo) { + super(executionDmc, miInfo); + } + } + + protected class MIThreadRunState { + // State flags + boolean fSuspended = false; + boolean fResumePending = false; + boolean fStepping = false; + StateChangeReason fStateChangeReason; + } + + /////////////////////////////////////////////////////////////////////////// + // MIRunControlNS + /////////////////////////////////////////////////////////////////////////// + + private AbstractMIControl fConnection; + + // The command cache applies only for the thread-info command at the + // container (process) level and is *always* available in non-stop mode. + // The only thing to do is to reset it every time a thread is created/ + // terminated. + private CommandCache fMICommandCache; + + private boolean fTerminated = false; + + // ThreadStates indexed by the execution context + protected Map fThreadRunStates = new HashMap(); + + /////////////////////////////////////////////////////////////////////////// + // Initialization and shutdown + /////////////////////////////////////////////////////////////////////////// + + public MIRunControlNS(DsfSession session) { + super(session); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize(new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + doInitialize(rm); + } + }); + } + + private void doInitialize(final RequestMonitor rm) { + fConnection = getServicesTracker().getService(AbstractMIControl.class); + fMICommandCache = new CommandCache(getSession(), fConnection); + fMICommandCache.setContextAvailable(fConnection.getControlDMContext(), true); + getSession().addServiceEventListener(this, null); + rm.done(); + } + + @Override + public void shutdown(final RequestMonitor rm) { + getSession().removeServiceEventListener(this); + fMICommandCache.reset(); + super.shutdown(rm); + } + + /////////////////////////////////////////////////////////////////////////// + // AbstractDsfService + /////////////////////////////////////////////////////////////////////////// + + @Override + protected BundleContext getBundleContext() { + return MIPlugin.getBundleContext(); + } + + /////////////////////////////////////////////////////////////////////////// + // IDMService + /////////////////////////////////////////////////////////////////////////// + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof IExecutionDMContext) { + getExecutionData((IExecutionDMContext) dmc, (DataRequestMonitor) rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /////////////////////////////////////////////////////////////////////////// + // IRunControl + /////////////////////////////////////////////////////////////////////////// + + // ------------------------------------------------------------------------ + // Suspend + // ------------------------------------------------------------------------ + + public boolean isSuspended(IExecutionDMContext context) { + + // Thread case + if (context instanceof MIExecutionDMCNS) { + MIThreadRunState threadState = fThreadRunStates.get(context); + return (threadState == null) ? false : !fTerminated && threadState.fSuspended; + } + + // Container case + if (context instanceof IContainerDMContext) { + boolean isSuspended = false; + for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) { + if (DMContexts.isAncestorOf(threadContext, context)) { + isSuspended |= isSuspended(threadContext); + } + } + return isSuspended; + } + + // Default case + return false; + } + + public void canSuspend(IExecutionDMContext context, DataRequestMonitor rm) { + + // Thread case + if (context instanceof MIExecutionDMCNS) { + rm.setData(doCanSuspend(context)); + rm.done(); + return; + } + + // Container case + if (context instanceof IContainerDMContext) { + boolean canSuspend = false; + for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) { + if (DMContexts.isAncestorOf(threadContext, context)) { + canSuspend |= doCanSuspend(threadContext); + } + } + rm.setData(canSuspend); + rm.done(); + return; + } + + // Default case + rm.setData(false); + rm.done(); + } + + private boolean doCanSuspend(IExecutionDMContext context) { + MIThreadRunState threadState = fThreadRunStates.get(context); + return (threadState == null) ? false : !fTerminated && !threadState.fSuspended; + } + + public void suspend(IExecutionDMContext context, final RequestMonitor rm) { + + assert context != null; + + // Thread case + IMIExecutionDMContext thread = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (thread != null) { + doSuspendThread(thread, rm); + return; + } + + // Container case + IContainerDMContext container = DMContexts.getAncestorOfType(context, IContainerDMContext.class); + if (container != null) { + doSuspendContainer(container, rm); + return; + } + + // Default case + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid context type.", null)); //$NON-NLS-1$ + rm.done(); + } + + private void doSuspendThread(IMIExecutionDMContext context, final RequestMonitor rm) { + + if (!doCanSuspend(context)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, + "Given context: " + context + ", is already suspended.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + MIExecInterrupt cmd = new MIExecInterrupt(context, true); + fConnection.queueCommand(cmd, new DataRequestMonitor(getExecutor(), rm)); + } + + private void doSuspendContainer(IExecutionDMContext context, final RequestMonitor rm) { + MIExecInterrupt cmd = new MIExecInterrupt(context, true); + fConnection.queueCommand(cmd, new DataRequestMonitor(getExecutor(), rm)); + } + + // ------------------------------------------------------------------------ + // Resume + // ------------------------------------------------------------------------ + + public void canResume(IExecutionDMContext context, DataRequestMonitor rm) { + + // Thread case + if (context instanceof MIExecutionDMCNS) { + rm.setData(doCanResume(context)); + rm.done(); + return; + } + + // Container case + if (context instanceof IContainerDMContext) { + boolean canSuspend = false; + for (IMIExecutionDMContext threadContext : fThreadRunStates.keySet()) { + if (DMContexts.isAncestorOf(threadContext, context)) { + canSuspend |= doCanResume(threadContext); + } + } + rm.setData(canSuspend); + rm.done(); + return; + } + + // Default case + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid context type.", null)); //$NON-NLS-1$ + rm.done(); + } + + private boolean doCanResume(IExecutionDMContext context) { + MIThreadRunState threadState = fThreadRunStates.get(context); + return (threadState == null) ? false : !fTerminated && threadState.fSuspended && !threadState.fResumePending; + } + + public void resume(IExecutionDMContext context, final RequestMonitor rm) { + + assert context != null; + + // Thread case + IMIExecutionDMContext thread = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (thread != null) { + doResumeThread(thread, rm); + return; + } + + // Container case + IContainerDMContext container = DMContexts.getAncestorOfType(context, IContainerDMContext.class); + if (container != null) { + doResumeContainer(container, rm); + return; + } + + // Default case + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, "Invalid context type.", null)); //$NON-NLS-1$ + rm.done(); + } + + private void doResumeThread(IMIExecutionDMContext context, final RequestMonitor rm) { + + if (!doCanResume(context)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Given context: " + context + ", is already running.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + MIThreadRunState threadState = fThreadRunStates.get(context); + if (threadState == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + threadState.fResumePending = true; + + MIExecContinue cmd = new MIExecContinue(context, context.getThreadId()); + fConnection.queueCommand(cmd, new DataRequestMonitor(getExecutor(), rm)); + } + + private void doResumeContainer(IContainerDMContext context, final RequestMonitor rm) { + MIExecContinue cmd = new MIExecContinue(context, false); + fConnection.queueCommand(cmd, new DataRequestMonitor(getExecutor(), rm)); + } + + // ------------------------------------------------------------------------ + // Step + // ------------------------------------------------------------------------ + + public boolean isStepping(IExecutionDMContext context) { + + // If it's a thread, just look it up + if (context instanceof MIExecutionDMCNS) { + MIThreadRunState threadState = fThreadRunStates.get(context); + return (threadState == null) ? false : !fTerminated && threadState.fStepping; + } + + // Default case + return false; + } + + public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor rm) { + + // If it's a thread, just look it up + if (context instanceof MIExecutionDMCNS) { + canResume(context, rm); + return; + } + + // If it's a container, then we don't want to step it + rm.setData(false); + rm.done(); + } + + public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) { + + assert context != null; + + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, + "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (!doCanResume(context)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Cannot resume context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + MIThreadRunState threadState = fThreadRunStates.get(context); + if (threadState == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Given context: " + context + " can't be found.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + threadState.fResumePending = true; + threadState.fStepping = true; + + switch (stepType) { + case STEP_INTO: + fConnection.queueCommand(new MIExecStep(dmc, true), + new DataRequestMonitor(getExecutor(), rm)); + break; + case STEP_OVER: + fConnection.queueCommand(new MIExecNext(dmc, true), + new DataRequestMonitor(getExecutor(), rm)); + break; + case STEP_RETURN: + // The -exec-finish command operates on the selected stack frame, but here we always + // want it to operate on the stop stack frame. So we manually create a top-frame + // context to use with the MI command. + // We get a local instance of the stack service because the stack service can be shut + // down before the run control service is shut down. So it is possible for the + // getService() request below to return null. + MIStack stackService = getServicesTracker().getService(MIStack.class); + if (stackService != null) { + IFrameDMContext topFrameDmc = stackService.createFrameDMContext(dmc, 0); + fConnection.queueCommand(new MIExecFinish(topFrameDmc), + new DataRequestMonitor(getExecutor(), rm)); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, + "Cannot create context for command, stack service not available.", null)); //$NON-NLS-1$ + rm.done(); + } + break; + case INSTRUCTION_STEP_INTO: + fConnection.queueCommand(new MIExecStepInstruction(dmc, true), + new DataRequestMonitor(getExecutor(), rm)); + break; + case INSTRUCTION_STEP_OVER: + fConnection.queueCommand(new MIExecNextInstruction(dmc, true), + new DataRequestMonitor(getExecutor(), rm)); + break; + default: + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, + INTERNAL_ERROR, "Given step type not supported", null)); //$NON-NLS-1$ + rm.done(); + } + } + + // ------------------------------------------------------------------------ + // Run to line + // ------------------------------------------------------------------------ + + // Later add support for Address and function. + // skipBreakpoints is not used at the moment. Implement later + public void runToLine(IExecutionDMContext context, String fileName, String lineNo, boolean skipBreakpoints, final DataRequestMonitor rm) { + + assert context != null; + + IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class); + if (dmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, NOT_SUPPORTED, + "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (!doCanResume(context)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Cannot resume context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + MIThreadRunState threadState = fThreadRunStates.get(context); + if (threadState == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, + "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + threadState.fResumePending = true; + fConnection.queueCommand(new MIExecUntil(dmc, fileName + ":" + lineNo), //$NON-NLS-1$ + new DataRequestMonitor(getExecutor(), rm)); + } + + // ------------------------------------------------------------------------ + // Support functions + // ------------------------------------------------------------------------ + + public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor rm) { + fMICommandCache.execute(new MIThreadListIds(containerDmc), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(makeExecutionDMCs(containerDmc, getData())); + rm.done(); + } + }); + } + + private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerCtx, MIThreadListIdsInfo info) { + IExecutionDMContext[] executionDmcs = new IMIExecutionDMContext[info.getThreadIds().length]; + for (int i = 0; i < info.getThreadIds().length; i++) { + executionDmcs[i] = createMIExecutionContext(containerCtx, info.getThreadIds()[i]); + } + return executionDmcs; + } + + public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor rm) { + MIThreadRunState threadState = fThreadRunStates.get(dmc); + if (threadState == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID,INVALID_HANDLE, + "Given context: " + dmc + " is not a recognized execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + rm.done(); + return; + } + + if (dmc instanceof IMIExecutionDMContext) { + rm.setData(new ExecutionData(threadState.fSuspended ? threadState.fStateChangeReason : null)); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, + "Given context: " + dmc + " is not a recognized execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + rm.done(); + } + + /////////////////////////////////////////////////////////////////////////// + // IMIRunControl + /////////////////////////////////////////////////////////////////////////// + + public IMIExecutionDMContext createMIExecutionContext(IContainerDMContext container, int threadId) { + return new MIExecutionDMCNS(getSession().getId(), container, threadId); + } + + /////////////////////////////////////////////////////////////////////////// + // IMIRunControl + /////////////////////////////////////////////////////////////////////////// + + public CommandCache getCache() { + return fMICommandCache; + } + + protected AbstractMIControl getConnection() { + return fConnection; + } + + /////////////////////////////////////////////////////////////////////////// + // Event handlers + /////////////////////////////////////////////////////////////////////////// + + @DsfServiceEventHandler + public void eventDispatched(final MIRunningEvent e) { + + IDMEvent event = null; + + // If it's not an execution context (what else could it be?!?), just propagate it + IMIExecutionDMContext executionDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (executionDmc == null) { + event = new ResumedEvent(e.getDMContext(), e); + getSession().dispatchEvent(event, getProperties()); + return; + } + + // It's a thread execution context (since we are in non-stop mode) + event = new ThreadResumedEvent(e.getDMContext(), e); + updateThreadState(executionDmc, (ThreadResumedEvent) event); + getSession().dispatchEvent(event, getProperties()); + fMICommandCache.reset(); + + // Find the container context, which is used in multi-threaded debugging. + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); + if (containerDmc != null) { + IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null; + event = new ContainerResumedEvent(containerDmc, e, triggeringCtx); + getSession().dispatchEvent(event, getProperties()); + } + } + + private void updateThreadState(IMIExecutionDMContext context, ThreadResumedEvent event) { + StateChangeReason reason = event.getReason(); + boolean isStepping = reason.equals(StateChangeReason.STEP); + MIThreadRunState threadState = fThreadRunStates.get(context); + if (threadState == null) { + threadState = new MIThreadRunState(); + fThreadRunStates.put(context, threadState); + } + threadState.fSuspended = false; + threadState.fResumePending = false; + threadState.fStateChangeReason = reason; + threadState.fStepping = isStepping; + } + + @DsfServiceEventHandler + public void eventDispatched(final MIStoppedEvent e) { + + IDMEvent event = null; + + // If it's not an execution context (what else could it be?!?), just propagate it + IMIExecutionDMContext executionDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (executionDmc == null) { + event = new SuspendedEvent(e.getDMContext(), e); + getSession().dispatchEvent(event, getProperties()); + return; + } + + // It's a thread execution context (since we are in non-stop mode) + event = new ThreadSuspendedEvent(e.getDMContext(), e); + updateThreadState(executionDmc, (ThreadSuspendedEvent) event); + getSession().dispatchEvent(event, getProperties()); + fMICommandCache.reset(); + + // Find the container context, which is used in multi-threaded debugging. + IContainerDMContext containerDmc = DMContexts.getAncestorOfType(e.getDMContext(), IContainerDMContext.class); + if (containerDmc != null) { + IExecutionDMContext triggeringCtx = !e.getDMContext().equals(containerDmc) ? e.getDMContext() : null; + event = new ContainerSuspendedEvent(containerDmc, e, triggeringCtx); + getSession().dispatchEvent(event, getProperties()); + } + } + + private void updateThreadState(IMIExecutionDMContext context, ThreadSuspendedEvent event) { + StateChangeReason reason = event.getReason(); + MIThreadRunState threadState = fThreadRunStates.get(context); + if (threadState == null) { + threadState = new MIThreadRunState(); + fThreadRunStates.put(context, threadState); + } + threadState.fSuspended = true; + threadState.fResumePending = false; + threadState.fStepping = false; + threadState.fStateChangeReason = reason; + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadCreatedEvent e) { + IContainerDMContext containerDmc = e.getDMContext(); + IMIExecutionDMContext executionCtx = null; + if (e.getId() != -1) { + executionCtx = createMIExecutionContext(containerDmc, e.getId()); + if (fThreadRunStates.get(executionCtx) == null) { + fThreadRunStates.put(executionCtx, new MIThreadRunState()); + } + } + getSession().dispatchEvent(new StartedDMEvent(executionCtx, e), getProperties()); + } + + @DsfServiceEventHandler + public void eventDispatched(final MIThreadExitEvent e) { + IContainerDMContext containerDmc = e.getDMContext(); + IMIExecutionDMContext executionCtx = null; + if (e.getId() != -1) { + executionCtx = createMIExecutionContext(containerDmc, e.getId()); + fThreadRunStates.remove(executionCtx); + } + getSession().dispatchEvent(new ExitedDMEvent(executionCtx, e), getProperties()); + } + + @DsfServiceEventHandler + public void eventDispatched(ThreadResumedEvent e) { + IMIExecutionDMContext context = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (context == null) { + return; + } + } + + @DsfServiceEventHandler + public void eventDispatched(ThreadSuspendedEvent e) { + IMIExecutionDMContext context = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (context == null) { + return; + } + } + + @DsfServiceEventHandler + public void eventDispatched(ContainerResumedEvent e) { + IMIExecutionDMContext context = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (context == null) { + return; + } + } + + @DsfServiceEventHandler + public void eventDispatched(ContainerSuspendedEvent e) { + IMIExecutionDMContext context = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class); + if (context == null) { + return; + } + } + + @DsfServiceEventHandler + public void eventDispatched(MIGDBExitEvent e) { + fTerminated = true; + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStackNS.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStackNS.java new file mode 100644 index 00000000000..9739233eda9 --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/MIStackNS.java @@ -0,0 +1,677 @@ +/******************************************************************************* + * 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 handling of multiple execution contexts + *******************************************************************************/ +package org.eclipse.dd.mi.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMContext; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IStack; +import org.eclipse.dd.dsf.debug.service.IStack2; +import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason; +import org.eclipse.dd.dsf.debug.service.command.CommandCache; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfServiceEventHandler; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.dd.mi.internal.MIPlugin; +import org.eclipse.dd.mi.service.command.AbstractMIControl; +import org.eclipse.dd.mi.service.command.commands.MIStackInfoDepth; +import org.eclipse.dd.mi.service.command.commands.MIStackListArguments; +import org.eclipse.dd.mi.service.command.commands.MIStackListFrames; +import org.eclipse.dd.mi.service.command.commands.MIStackListLocals; +import org.eclipse.dd.mi.service.command.events.IMIDMEvent; +import org.eclipse.dd.mi.service.command.events.MIEvent; +import org.eclipse.dd.mi.service.command.events.MIStoppedEvent; +import org.eclipse.dd.mi.service.command.output.MIArg; +import org.eclipse.dd.mi.service.command.output.MIFrame; +import org.eclipse.dd.mi.service.command.output.MIStackInfoDepthInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListArgumentsInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListFramesInfo; +import org.eclipse.dd.mi.service.command.output.MIStackListLocalsInfo; +import org.osgi.framework.BundleContext; + +public class MIStackNS extends AbstractDsfService + implements IStack2 +{ + protected static class MIFrameDMC extends AbstractDMContext + implements IFrameDMContext + { + private final int fLevel; + // public MIFrameDMC(MIStack service, int level) { + public MIFrameDMC(String sessionId, IExecutionDMContext execDmc, int level) { + super(sessionId, new IDMContext[] { execDmc }); + fLevel = level; + } + + public int getLevel() { return fLevel; } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && ((MIFrameDMC)other).fLevel == fLevel; + } + + @Override + public int hashCode() { + return super.baseHashCode() ^ fLevel; + } + + @Override + public String toString() { + return baseToString() + ".frame[" + fLevel + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + protected static class MIVariableDMC extends AbstractDMContext + implements IVariableDMContext + { + public enum Type { ARGUMENT, LOCAL } + final private Type fType; + final private int fIndex; + + public MIVariableDMC(MIStackNS service, IFrameDMContext frame, Type type, int index) { + super(service, new IDMContext[] { frame }); + fIndex = index; + fType = type; + } + + public int getIndex() { return fIndex; } + public Type getType() { return fType; } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && + ((MIVariableDMC)other).fType == fType && + ((MIVariableDMC)other).fIndex == fIndex; + } + + @Override + public int hashCode() { + int typeFactor = 0; + if (fType == Type.LOCAL) typeFactor = 2; + else if (fType == Type.ARGUMENT) typeFactor = 3; + return super.baseHashCode() ^ typeFactor ^ fIndex; + } + + @Override + public String toString() { + return baseToString() + ".variable(" + fType + ")[" + fIndex + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + + private CommandCache fMICommandCache; + private MIStoppedEvent fCachedStoppedEvent; + private IMIRunControl fMIRunControl; + + public MIStackNS(DsfSession session) + { + super(session); + } + + @Override + protected BundleContext getBundleContext() + { + return MIPlugin.getBundleContext(); + } + + @Override + public void initialize(final RequestMonitor rm) { + super.initialize( + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + doInitialize(rm); + } + }); + } + + private void doInitialize(RequestMonitor rm) { + AbstractMIControl miControl = getServicesTracker().getService(AbstractMIControl.class); + fMICommandCache = new CommandCache(getSession(), miControl); + fMICommandCache.setContextAvailable(miControl.getControlDMContext(), true); + fMIRunControl = getServicesTracker().getService(IMIRunControl.class); + + getSession().addServiceEventListener(this, null); + register(new String[]{IStack.class.getName(), MIStackNS.class.getName()}, new Hashtable()); + rm.done(); + } + + @Override + public void shutdown(RequestMonitor rm) + { + unregister(); + getSession().removeServiceEventListener(this); + fMICommandCache.reset(); + super.shutdown(rm); + } + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor rm) { + if (dmc instanceof MIFrameDMC) { + getFrameData((MIFrameDMC)dmc, (DataRequestMonitor)rm); + // getFrameData invokes rm + } else if (dmc instanceof MIVariableDMC) { + getVariableData((MIVariableDMC)dmc, (DataRequestMonitor)rm); + // getVariablesData invokes rm + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Creates a frame context. This method is intended to be used by other MI + * services and sub-classes which need to create a frame context directly. + *

+ * Sub-classes can override this method to provide custom stack frame + * context implementation. + *

+ * @param execDmc Execution context that this frame is to be a child of. + * @param level Level of the new context. + * @return A new frame context. + */ + public IFrameDMContext createFrameDMContext(IExecutionDMContext execDmc, int level) { + return new MIFrameDMC(getSession().getId(), execDmc, level); + } + + public void getFrames(final IDMContext ctx, final DataRequestMonitor rm) { + getFrames(ctx, 0, ALL_FRAMES, rm); + } + + public void getFrames(final IDMContext ctx, final int startIndex, final int endIndex, final DataRequestMonitor rm) { + + // Make sure we have an execution context (ideally a thread) + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context " + ctx, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Make sure the indices are OK + if (startIndex < 0 || endIndex > 0 && endIndex < startIndex) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid stack frame range [" + startIndex + ',' + endIndex + ']', null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Make sure the thread is stopped + if (!fMIRunControl.isSuspended(execDmc)) { + rm.setData(new IFrameDMContext[0]); + rm.done(); + return; + } + + // Case of retrieving the top stack frame from the cached stopped event. + if (startIndex == 0 && endIndex == 0) { + if (fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext())) + { + rm.setData(new IFrameDMContext[] { createFrameDMContext(execDmc, fCachedStoppedEvent.getFrame().getLevel()) }); + rm.done(); + return; + } + } + + // Select the proper MI command variant + final MIStackListFrames miStackListCmd; + final int firstIndex; + if (endIndex >= 0) { + miStackListCmd = new MIStackListFrames(execDmc, true, startIndex, endIndex); + firstIndex = startIndex; + } else { + miStackListCmd = new MIStackListFrames(execDmc, true); + firstIndex = 0; + } + + // And go... + fMICommandCache.execute( + miStackListCmd, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getFrames(execDmc, getData(), firstIndex, endIndex, startIndex)); + rm.done(); + } + }); + } + + public void getTopFrame(final IDMContext ctx, final DataRequestMonitor rm) { + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + ctx, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Try to retrieve the top stack frame from the cached stopped event. + if (fCachedStoppedEvent != null && + fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext())) + { + rm.setData(createFrameDMContext(execDmc, fCachedStoppedEvent.getFrame().getLevel())); + rm.done(); + return; + } + + // If stopped event is not available or doesn't contain frame info, + // query top stack frame + getFrames( + ctx, + 0, + 0, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData()[0]); + rm.done(); + } + }); + } + + //private MIFrameDMC[] getFrames(DsfMIStackListFramesInfo info) { + private IFrameDMContext[] getFrames(IMIExecutionDMContext execDmc, MIStackListFramesInfo info, int firstIndex, int lastIndex, int startIndex) { + int length = info.getMIFrames().length; + if (lastIndex > 0) { + int limit= lastIndex - startIndex + 1; + if (limit < length) { + length = limit; + } + } + IFrameDMContext[] frameDMCs = new MIFrameDMC[length]; + for (int i = 0; i < length; i++) { + //frameDMCs[i] = new MIFrameDMC(this, info.getMIFrames()[i].getLevel()); + final MIFrame frame= info.getMIFrames()[i + startIndex - firstIndex]; + assert startIndex + i == frame.getLevel(); + frameDMCs[i] = createFrameDMContext(execDmc, frame.getLevel()); + } + return frameDMCs; + } + + + + public void getFrameData(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + if (!(frameDmc instanceof MIFrameDMC)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context type " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + final MIFrameDMC miFrameDmc = (MIFrameDMC)frameDmc; + + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /** + * Base class for the IFrameDMData object that uses an MIFrame object to + * provide the data. Sub-classes must provide the MIFrame object + */ + abstract class FrameData implements IFrameDMData + { + abstract protected MIFrame getMIFrame(); + + public IAddress getAddress() { + String addr = getMIFrame().getAddress(); + if (addr.startsWith("0x")) { //$NON-NLS-1$ + addr = addr.substring(2); + } + if (addr.length() <= 8) { + return new Addr32(getMIFrame().getAddress()); + } else { + return new Addr64(getMIFrame().getAddress()); + } + } + + public int getColumn() { return 0; } + + public String getFile() { return getMIFrame().getFile(); } + public int getLine() { return getMIFrame().getLine(); } + public String getFunction() { return getMIFrame().getFunction(); } + + @Override + public String toString() { return getMIFrame().toString(); } + } + + // If requested frame is the top stack frame, try to retrieve it from + // the stopped event data. + class FrameDataFromStoppedEvent extends FrameData { + private final MIStoppedEvent fEvent; + FrameDataFromStoppedEvent(MIStoppedEvent event) { fEvent = event; } + @Override + protected MIFrame getMIFrame() { return fEvent.getFrame(); } + } + + // Retrieve the top stack frame from the stopped event only if the selected thread is the one on which stopped event + // is raised + if (fCachedStoppedEvent != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + miFrameDmc.fLevel == 0 && + fCachedStoppedEvent.getFrame() != null) + { + rm.setData(new FrameDataFromStoppedEvent(fCachedStoppedEvent)); + rm.done(); + return; + } + + // If not, retrieve the full list of frame data. + class FrameDataFromMIStackFrameListInfo extends FrameData { + private MIStackListFramesInfo fFrameDataCacheInfo; + private int fFrameIndex; + + FrameDataFromMIStackFrameListInfo(MIStackListFramesInfo info, int index) { + fFrameDataCacheInfo = info; + fFrameIndex = index; + } + + @Override + protected MIFrame getMIFrame() { return fFrameDataCacheInfo.getMIFrames()[fFrameIndex]; } + } + + fMICommandCache.execute( + new MIStackListFrames(execDmc, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Find the index to the correct MI frame object. + int idx = findFrameIndex(getData().getMIFrames(), miFrameDmc.fLevel); + if (idx == -1) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid frame " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the data object. + rm.setData(new FrameDataFromMIStackFrameListInfo(getData(), idx)); + rm.done(); + } + }); + } + + public void getArguments(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + + // If requested frame is the top stack frame, try to retrieve it from + // the stopped event data. + if (frameDmc.getLevel() == 0 && + fCachedStoppedEvent != null && + fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + fCachedStoppedEvent.getFrame().getArgs() != null) + { + rm.setData(makeVariableDMCs( + frameDmc, MIVariableDMC.Type.ARGUMENT, fCachedStoppedEvent.getFrame().getArgs().length)); + rm.done(); + return; + } + + // If not, retrieve the full list of frame data. + fMICommandCache.execute( + new MIStackListArguments(execDmc, true, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Find the index to the correct MI frame object. + // Note: this is a short-cut, but it won't work once we implement retrieving + // partial lists of stack frames. + int idx = frameDmc.getLevel(); + if (idx == -1 || idx >= getData().getMIFrames().length) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_STATE, "Invalid frame " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the variable array out of MIArg array. + MIArg[] args = getData().getMIFrames()[idx].getArgs(); + if (args == null) args = new MIArg[0]; + rm.setData(makeVariableDMCs(frameDmc, MIVariableDMC.Type.ARGUMENT, args.length)); + rm.done(); + } + }); + } + + public void getVariableData(IVariableDMContext variableDmc, final DataRequestMonitor rm) { + if (!(variableDmc instanceof MIVariableDMC)) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context type " + variableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + final MIVariableDMC miVariableDmc = (MIVariableDMC)variableDmc; + + // Extract the frame DMC from the variable DMC. + final MIFrameDMC frameDmc = DMContexts.getAncestorOfType(variableDmc, MIFrameDMC.class); + if (frameDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No frame context found in " + variableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "No execution context found in " + frameDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + /** + * Same as with frame objects, this is a base class for the IVariableDMData object that uses an MIArg object to + * provide the data. Sub-classes must supply the MIArg object. + */ + class VariableData implements IVariableDMData { + private MIArg dsfMIArg; + VariableData(MIArg arg){ + dsfMIArg = arg; + } + public String getName() { return dsfMIArg.getName(); } + public String getValue() { return dsfMIArg.getValue(); } + @Override + public String toString() { return dsfMIArg.toString(); } + } + + // Check if the stopped event can be used to extract the variable value. + if (execDmc != null && miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT && + frameDmc.fLevel == 0 && fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null && + execDmc.equals(fCachedStoppedEvent.getDMContext()) && + fCachedStoppedEvent.getFrame().getArgs() != null) + { + if (miVariableDmc.fIndex >= fCachedStoppedEvent.getFrame().getArgs().length) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, -1, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + rm.setData(new VariableData(fCachedStoppedEvent.getFrame().getArgs()[miVariableDmc.fIndex])); + rm.done(); + return; + } + + if (miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT){ + fMICommandCache.execute( + new MIStackListArguments(execDmc, true, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // Find the correct frame and argument + if ( frameDmc.fLevel >= getData().getMIFrames().length || + miVariableDmc.fIndex >= getData().getMIFrames()[frameDmc.fLevel].getArgs().length ) + { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Create the data object. + rm.setData(new VariableData(getData().getMIFrames()[frameDmc.fLevel].getArgs()[miVariableDmc.fIndex])); + rm.done(); + }}); + }//if + if (miVariableDmc.fType == MIVariableDMC.Type.LOCAL){ + fMICommandCache.execute( + new MIStackListLocals(frameDmc, true, true), + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + + // Create the data object. + MIArg[] locals = getData().getLocals(); + if (locals.length > miVariableDmc.fIndex) { + rm.setData(new VariableData(locals[miVariableDmc.fIndex])); + } else { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid variable " + miVariableDmc, null)); //$NON-NLS-1$ + } + rm.done(); + } + }); + + }//if + + } + + private MIVariableDMC[] makeVariableDMCs(IFrameDMContext frame, MIVariableDMC.Type type, int count) { + MIVariableDMC[] variables = new MIVariableDMC[count]; + for (int i = 0; i < count; i++) { + variables[i]= new MIVariableDMC(this, frame, type, i); + } + return variables; + } + + private int findFrameIndex(MIFrame[] frames, int level) { + for (int idx = 0; idx < frames.length; idx++) { + if (frames[idx].getLevel() == level) { + return idx; + } + } + return -1; + } + + + public void getLocals(final IFrameDMContext frameDmc, final DataRequestMonitor rm) { + + final List localsList = new ArrayList(); + + final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData( localsList.toArray(new IVariableDMContext[localsList.size()]) ); + rm.done(); + } + }; + countingRm.setDoneCount(2); + + getArguments( + frameDmc, + new DataRequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleSuccess() { + localsList.addAll( Arrays.asList(getData()) ); + countingRm.done(); + } + }); + + fMICommandCache.execute( + new MIStackListLocals(frameDmc, true, true), + new DataRequestMonitor(getExecutor(), countingRm) { + @Override + protected void handleSuccess() { + localsList.addAll( Arrays.asList( + makeVariableDMCs(frameDmc, MIVariableDMC.Type.LOCAL, getData().getLocals().length)) ); + countingRm.done(); + } + }); + } + + public void getStackDepth(IDMContext dmc, final int maxDepth, final DataRequestMonitor rm) { + + // Make sure we have an execution context (ideally a thread) + final IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(dmc, IMIExecutionDMContext.class); + if (execDmc == null) { + rm.setStatus(new Status(IStatus.ERROR, MIPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$ + rm.done(); + return; + } + + // Make sure the thread is stopped + if (!fMIRunControl.isSuspended(execDmc)) { + rm.setData(0); + rm.done(); + return; + } + + // Select the proper MI command variant + MIStackInfoDepth depthCommand = null; + if (maxDepth > 0) { + depthCommand = new MIStackInfoDepth(execDmc, true, maxDepth); + } + else { + depthCommand = new MIStackInfoDepth(execDmc); + } + + // And go... + fMICommandCache.execute( + depthCommand, + new DataRequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getDepth()); + rm.done(); + } + }); + } + + // IServiceEventListener + @DsfServiceEventHandler + public void eventDispatched(IResumedDMEvent e) { + fMICommandCache.setContextAvailable(e.getDMContext(), false); + if (e.getReason() != StateChangeReason.STEP) { + fCachedStoppedEvent = null; + fMICommandCache.reset(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(ISuspendedDMEvent e) { + fMICommandCache.setContextAvailable(e.getDMContext(), true); + fMICommandCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(IMIDMEvent e) { + MIEvent miEvent = e.getMIEvent(); + if (miEvent instanceof MIStoppedEvent) { + fCachedStoppedEvent = (MIStoppedEvent)miEvent; + } + } + +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java index c96d066c7e3..483f1049ab8 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/AbstractMIControl.java @@ -31,6 +31,8 @@ import org.eclipse.core.runtime.Status; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfRunnable; 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.IStack.IFrameDMContext; import org.eclipse.dd.dsf.debug.service.command.ICommand; import org.eclipse.dd.dsf.debug.service.command.ICommandControl; @@ -74,7 +76,7 @@ public abstract class AbstractMIControl extends AbstractDsfService private RxThread fRxThread; private int fCurrentStackLevel = -1; - private int fCurrentThreadId = -1; + private int fCurrentThreadId = -1; private final BlockingQueue fTxCommands = new LinkedBlockingQueue(); @@ -85,7 +87,6 @@ public abstract class AbstractMIControl extends AbstractDsfService * that the TX thread should shut down. */ private final CommandHandle fTerminatorHandle = new CommandHandle(null, null); - /* * Various listener control variables used to keep track of listeners who want to monitor @@ -207,7 +208,7 @@ public abstract class AbstractMIControl extends AbstractDsfService // Cast the return token to match the result type of MI Command. This is checking // against an erased type so it should never throw any exceptions. @SuppressWarnings("unchecked") - DataRequestMonitor miDone = (DataRequestMonitor)rm; + DataRequestMonitor miDone = (DataRequestMonitor) rm; final CommandHandle handle = new CommandHandle(miCommand, miDone); @@ -240,38 +241,43 @@ public abstract class AbstractMIControl extends AbstractDsfService } private void processNextQueuedCommand() { - if ( fCommandQueue.size() > 0 ) { - CommandHandle handle = fCommandQueue.remove(0); - if ( handle != null ) { + if (fCommandQueue.size() > 0) { + final CommandHandle handle = fCommandQueue.remove(0); + if (handle != null) { processCommandSent(handle); - // Before the command is sent, Check the Thread Id and send it to - // the queue only if the id has been changed. - if( handle.getThreadId()!= null && - handle.getThreadId().intValue() != fCurrentThreadId && handle.getThreadId().intValue() != 0) - { - // Re-set the level - fCurrentThreadId = handle.getThreadId().intValue(); - CommandHandle cmdHandle = new CommandHandle( - new MIThreadSelect(handle.fCommand.getContext(), fCurrentThreadId), null); - cmdHandle.generateTokenId(); - fTxCommands.add(cmdHandle); - } + // Identify target thread/frame (we might have to update them at the target) + final IDMContext targetContext = handle.fCommand.getContext(); + final int targetThread = (handle.getThreadId() != null) ? handle.getThreadId().intValue() : -1; + final int targetFrame = (handle.getStackFrameId() != null) ? handle.getStackFrameId().intValue() : -1; - // Before the command is sent, Check the Stack level and send it to - // the queue only if the level has been changed. - if( handle.getStackFrameId()!= null && - handle.getStackFrameId().intValue() != fCurrentStackLevel) - { - // Re-set the level - fCurrentStackLevel = handle.getStackFrameId().intValue(); - CommandHandle cmdHandle = new CommandHandle( - new MIStackSelectFrame(handle.fCommand.getContext(), fCurrentStackLevel), null); - cmdHandle.generateTokenId(); - fTxCommands.add(cmdHandle); + // The thread-select and frame-select make sense only if the thread is stopped. + // Some non-stop commands don't require the thread to be stopped so we send the + // command anyway. + IRunControl runControl = getServicesTracker().getService(IRunControl.class); + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(targetContext, IMIExecutionDMContext.class); + if (runControl != null && execDmc != null && runControl.isSuspended(execDmc)) { + // Before the command is sent, Check the Thread Id and send it to + // the queue only if the id has been changed. + if (targetThread != -1 && targetThread != fCurrentThreadId) { + fCurrentThreadId = targetThread; + resetCurrentStackLevel(); + CommandHandle cmdHandle = new CommandHandle(new MIThreadSelect(execDmc), null); + cmdHandle.generateTokenId(); + fTxCommands.add(cmdHandle); + } + + // Before the command is sent, Check the Stack level and send it to + // the queue only if the level has been changed. + if (targetFrame != -1 && targetFrame != fCurrentStackLevel) { + fCurrentStackLevel = targetFrame; + CommandHandle cmdHandle = new CommandHandle(new MIStackSelectFrame(execDmc, targetFrame), null); + cmdHandle.generateTokenId(); + fTxCommands.add(cmdHandle); + } } - handle.generateTokenId(); - fTxCommands.add(handle); + handle.generateTokenId(); + fTxCommands.add(handle); } } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java index 614a063a993..455e15420c9 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/CLIEventProcessor.java @@ -57,7 +57,6 @@ public class CLIEventProcessor // Last Thread ID created private static int fLastThreadId; - public CLIEventProcessor(AbstractMIControl connection, IContainerDMContext containerDmc, MIInferiorProcess inferior) { fCommandControl = connection; fInferior = inferior; @@ -109,32 +108,16 @@ public class CLIEventProcessor fEventList.add(oobr); if (oobr instanceof MIConsoleStreamOutput) { - // Process Events of type DsfMIConsoleStreamOutput here - MIConsoleStreamOutput exec = (MIConsoleStreamOutput) oobr; + // Process Events of type DsfMIConsoleStreamOutput here + MIConsoleStreamOutput exec = (MIConsoleStreamOutput) oobr; - // Look for events with Pattern ^[New Thread 1077300144 (LWP 7973) - Pattern pattern = Pattern.compile("(^\\[New Thread.*LWP\\s*)(\\d*)", Pattern.MULTILINE); //$NON-NLS-1$ - Matcher matcher = pattern.matcher(exec.getCString()); - if (matcher.find()) { - //fMapThreadIds.put(matcher.group(2), Integer.valueOf(++fLastThreadId)); - //DsfMIEvent e = new DsfMIThreadCreatedEvent(Integer.valueOf(matcher.group(2))); - MIEvent e = new MIThreadCreatedEvent(fContainerDmc, ++fLastThreadId); - // Dispatch DsfMIThreadCreatedEvent - fCommandControl.getSession().dispatchEvent(e, fCommandControl.getProperties()); - } - // HACK - For GDB thread exit events, we won't use the events generated by GDB. This event is - // raised in GDBRunControl class by polling and comparing the ExecutionContexts returned by - // -thread-list-ids command. This is done as threads reported by exit event are still reported till - // they completely exit the system. - // Look for Thread Exited Event with Pattern [Thread 1077300144 (LWP 23832) exited]\n - // See bug 200615 for details. -// pattern = Pattern.compile("(^\\[Thread.*LWP\\s)(\\d*)(.*exited.*$)", Pattern.MULTILINE); //$NON-NLS-1$ -// matcher = pattern.matcher(exec.getCString()); -// if (matcher.find()) { -// DsfMIEvent e = new DsfMIThreadExitEvent(fMapThreadIds.get(matcher.group(2)).intValue()); -// // Dispatch DsfMIThreadExitEvent -// fConnection.getSession().dispatchEvent(e, fConnection.getProperties()); -// } + // Look for events with Pattern ^[New Thread 1077300144 (LWP 7973) + Pattern pattern = Pattern.compile("(^\\[New Thread.*LWP\\s*)(\\d*)", Pattern.MULTILINE); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(exec.getCString()); + if (matcher.find()) { + MIEvent e = new MIThreadCreatedEvent(fContainerDmc, ++fLastThreadId); + fCommandControl.getSession().dispatchEvent(e, fCommandControl.getProperties()); + } } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java index 259433b1ed1..8437b9fe801 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/MIRunControlEventProcessor.java @@ -22,7 +22,8 @@ import org.eclipse.dd.dsf.debug.service.command.ICommandToken; import org.eclipse.dd.dsf.debug.service.command.IEventListener; import org.eclipse.dd.dsf.service.DsfServicesTracker; import org.eclipse.dd.mi.internal.MIPlugin; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; +import org.eclipse.dd.mi.service.IMIRunControl; 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; @@ -41,6 +42,8 @@ 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.MIWatchpointScopeEvent; import org.eclipse.dd.mi.service.command.events.MIWatchpointTriggerEvent; import org.eclipse.dd.mi.service.command.output.MIConst; @@ -51,7 +54,6 @@ 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.MIStatusAsyncOutput; import org.eclipse.dd.mi.service.command.output.MIValue; /** @@ -102,57 +104,95 @@ public class MIRunControlEventProcessor } public void eventReceived(Object output) { - for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { - 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(); - - List> events = new LinkedList>(); - 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 = MIStoppedEvent.parse( - fServicesTracker.getService(MIRunControl.class), fContainerDmc, exec.getToken(), exec.getMIResults()); - events.add(e); - } - for (MIEvent event : events) { - fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); - } - } - } - else if (oobr instanceof MIStatusAsyncOutput) { - // Nothing done .. but what about +download?? - } else if (oobr instanceof MINotifyAsyncOutput) { - // Nothing - } - } + for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { + List> events = new LinkedList>(); + if (oobr instanceof MIExecAsyncOutput) { + MIExecAsyncOutput exec = (MIExecAsyncOutput) oobr; + // Change of state. + String state = exec.getAsyncClass(); + if ("stopped".equals(state)) { //$NON-NLS-1$ + // Re-set the thread and stack level to -1 when stopped event is recvd. + // This is to synchronize the state between GDB back-end and AbstractMIControl. + fCommandControl.resetCurrentThreadLevel(); + fCommandControl.resetCurrentStackLevel(); + + MIResult[] results = exec.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + MIValue val = results[i].getMIValue(); + if (var.equals("reason")) { //$NON-NLS-1$ + if (val instanceof MIConst) { + String reason = ((MIConst) val).getString(); + MIEvent e = createEvent(reason, exec); + if (e != null) { + events.add(e); + continue; + } + } + } + } + // We were stopped for some unknown reason, for example + // GDB for temporary breakpoints will not send the + // "reason" ??? still fire a stopped event. + if (events.isEmpty()) { + MIEvent e = MIStoppedEvent.parse( + fServicesTracker.getService(IMIRunControl.class), fContainerDmc, exec.getToken(), exec.getMIResults()); + events.add(e); + } + + for (MIEvent event : events) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + else if ("running".equals(state)) { //$NON-NLS-1$ + int token = exec.getToken(); + 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) { + String thread = ((MIConst) val).getString(); + MIEvent evt = null; + int threadId = 0; + try { + threadId = Integer.parseInt(thread); + IMIExecutionDMContext context = fServicesTracker.getService(IMIRunControl.class).createMIExecutionContext(fContainerDmc, threadId); + evt = new MIRunningEvent(context, token, MIRunningEvent.CONTINUE); + } + catch (NumberFormatException e) { + evt = new MIRunningEvent(fContainerDmc, token, MIRunningEvent.CONTINUE); + + } + fCommandControl.getSession().dispatchEvent(evt, 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)) { //$NON-NLS-1$ + MIEvent event = MIThreadCreatedEvent.parse(fContainerDmc, exec.getToken(), exec.getMIResults()); + if (event != null) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + else if ("thread-exited".equals(miEvent)) { //$NON-NLS-1$ + MIEvent event = MIThreadExitEvent.parse(fContainerDmc, exec.getToken(), exec.getMIResults()); + if (event != null) { + fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties()); + } + } + } + } } protected MIEvent createEvent(String reason, MIExecAsyncOutput exec) { - MIRunControl runControl = fServicesTracker.getService(MIRunControl.class); + IMIRunControl runControl = fServicesTracker.getService(IMIRunControl.class); MIEvent event = null; if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$ event = MIBreakpointHitEvent.parse(runControl, fContainerDmc, exec.getToken(), exec.getMIResults()); @@ -213,7 +253,7 @@ public class MIRunControlEventProcessor else if (cmd instanceof MIExecFinish) { type = MIRunningEvent.FINISH; } else if (cmd instanceof MIExecReturn) { type = MIRunningEvent.RETURN; } else if (cmd instanceof MIExecContinue) { type = MIRunningEvent.CONTINUE; } - else { type = MIRunningEvent.CONTINUE; } + else { type = MIRunningEvent.CONTINUE; } fCommandControl.getSession().dispatchEvent( new MIRunningEvent(fContainerDmc, id, type), fCommandControl.getProperties()); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java index 031cbe38e9a..2d3aea84d00 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecContinue.java @@ -17,7 +17,7 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-continue + * -exec-continue [--thread ] * * Asynchronous command. Resumes the execution of the inferior program * until a breakpoint is encountered, or until the inferior exits. @@ -26,6 +26,17 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; public class MIExecContinue extends MICommand { public MIExecContinue(IExecutionDMContext dmc) { + this(dmc, false); + } + + public MIExecContinue(IExecutionDMContext dmc, boolean allThreads) { super(dmc, "-exec-continue"); //$NON-NLS-1$ + if (allThreads) { + setParameters(new String[] { "--all" }); //$NON-NLS-1$ + } + } + + public MIExecContinue(IExecutionDMContext dmc, int threadId) { + super(dmc, "-exec-continue", new String[] { "--thread", Integer.toString(threadId) }); //$NON-NLS-1$ //$NON-NLS-2$ } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java index fd38aa16b23..35643e96d8a 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecInterrupt.java @@ -14,11 +14,12 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-interrupt + * -exec-interrupt [ --thread | --all ] * * Asynchronous command. Interrupts the background execution of the * target. Note how the token associated with the stop message is the one @@ -31,6 +32,20 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; public class MIExecInterrupt extends MICommand { public MIExecInterrupt(IExecutionDMContext dmc) { + this(dmc, false); + } + + public MIExecInterrupt(IExecutionDMContext dmc, boolean allThreads) { super(dmc, "-exec-interrupt"); //$NON-NLS-1$ + if (allThreads) { + setParameters(new String[] { "--all" }); //$NON-NLS-1$ + } + } + + public MIExecInterrupt(IMIExecutionDMContext dmc, boolean setThread) { + super(dmc, "-exec-interrupt"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()) }); //$NON-NLS-1$ + } } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java index 25617b1152c..22684c18cb4 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNext.java @@ -14,11 +14,12 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-next + * -exec-next [--thread ] [count] * * Asynchronous command. Resumes execution of the inferior program, * stopping when the beginning of the next source line is reached. @@ -26,11 +27,24 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; */ public class MIExecNext extends MICommand { - public MIExecNext(IExecutionDMContext dmc) { - super(dmc, "-exec-next"); //$NON-NLS-1$ - } + public MIExecNext(IExecutionDMContext dmc) { + this(dmc, 1); + } - public MIExecNext(IExecutionDMContext dmc, int count) { - super(dmc, "-exec-next", new String[] { Integer.toString(count) }); //$NON-NLS-1$ - } -} + public MIExecNext(IExecutionDMContext dmc, int count) { + super(dmc, "-exec-next", new String[] { Integer.toString(count) }); //$NON-NLS-1$ + } + + public MIExecNext(IMIExecutionDMContext dmc, boolean setThread) { + this(dmc, setThread, 1); + } + + public MIExecNext(IMIExecutionDMContext dmc, boolean setThread, int count) { + super(dmc, "-exec-next"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()), Integer.toString(count) }); //$NON-NLS-1$ + } else { + setParameters(new String[] { Integer.toString(count) }); + } + } +} \ No newline at end of file diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java index 0bcf2c83b4e..78dd5994558 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecNextInstruction.java @@ -13,6 +13,7 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** @@ -28,10 +29,23 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; public class MIExecNextInstruction extends MICommand { public MIExecNextInstruction(IExecutionDMContext dmc) { - super(dmc, "-exec-next-instruction"); //$NON-NLS-1$ + this(dmc, 1); } public MIExecNextInstruction(IExecutionDMContext dmc, int count) { super(dmc, "-exec-next-instruction", new String[] { Integer.toString(count) }); //$NON-NLS-1$ } + + public MIExecNextInstruction(IMIExecutionDMContext dmc, boolean setThread) { + this(dmc, setThread, 1); + } + + public MIExecNextInstruction(IMIExecutionDMContext dmc, boolean setThread, int count) { + super(dmc, "-exec-next-instruction"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()), Integer.toString(count) }); //$NON-NLS-1$ + } else { + setParameters(new String[] { Integer.toString(count) }); + } + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java index 689c4a2fa02..8aad9a89a50 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecReturn.java @@ -17,7 +17,7 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-return + * -exec-return [args] * *

* Makes current function return immediately. Doesn't execute the @@ -38,5 +38,4 @@ public class MIExecReturn extends MICommand public MIExecReturn(IFrameDMContext dmc, String arg) { super(dmc, "-exec-return", new String[] { arg }); //$NON-NLS-1$ } - } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java index 9ed7b0f474e..aff568b481a 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStep.java @@ -14,11 +14,12 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-step + * -exec-step [--thread ] [count] * * Asynchronous command. Resumes execution of the inferior program, * stopping when the beginning of the next source line is reached, if the @@ -29,10 +30,23 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; public class MIExecStep extends MICommand { public MIExecStep(IExecutionDMContext dmc) { - super(dmc, "-exec-step"); //$NON-NLS-1$ + this(dmc, 1); } public MIExecStep(IExecutionDMContext dmc, int count) { super(dmc, "-exec-step", new String[] { Integer.toString(count) }); //$NON-NLS-1$ } + + public MIExecStep(IMIExecutionDMContext dmc, boolean setThread) { + this(dmc, setThread, 1); + } + + public MIExecStep(IMIExecutionDMContext dmc, boolean setThread, int count) { + super(dmc, "-exec-step"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()), Integer.toString(count) }); //$NON-NLS-1$ + } else { + setParameters(new String[] { Integer.toString(count) }); + } + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java index 9d4087b95e9..aef3a6f4f56 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecStepInstruction.java @@ -13,11 +13,12 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-step-instruction + * -exec-step-instruction [--thread ] [count] * Asynchronous command. Resumes the inferior which executes one * machine instruction. The output, once GDB has stopped, will vary @@ -29,10 +30,23 @@ import org.eclipse.dd.mi.service.command.output.MIInfo; public class MIExecStepInstruction extends MICommand { public MIExecStepInstruction(IExecutionDMContext dmc) { - super(dmc, "-exec-step-instruction"); //$NON-NLS-1$ + this(dmc, 1); } public MIExecStepInstruction(IExecutionDMContext dmc, int count) { super(dmc, "-exec-step-instruction", new String[] { Integer.toString(count) }); //$NON-NLS-1$ } + + public MIExecStepInstruction(IMIExecutionDMContext dmc, boolean setThread) { + this(dmc, setThread, 1); + } + + public MIExecStepInstruction(IMIExecutionDMContext dmc, boolean setThread, int count) { + super(dmc, "-exec-step-instruction"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()), Integer.toString(count) }); //$NON-NLS-1$ + } else { + setParameters(new String[] { Integer.toString(count) }); + } + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java index 57b57855267..8f09706aa2e 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIExecUntil.java @@ -14,11 +14,12 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; /** * - * -exec-until [ LOCATION ] + * -exec-until [--thread ] [ LOCATION ] * * Asynchronous command. Executes the inferior until the LOCATION * specified in the argument is reached. If there is no argument, the @@ -34,6 +35,22 @@ public class MIExecUntil extends MICommand } public MIExecUntil(IExecutionDMContext dmc, String loc) { - super(dmc, "-exec-until", new String[]{loc}); //$NON-NLS-1$ + super(dmc, "-exec-until", new String[] { loc }); //$NON-NLS-1$ + } + + public MIExecUntil(IMIExecutionDMContext dmc, boolean setThread) { + super(dmc, "-exec-until"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()) }); //$NON-NLS-1$ + } + } + + public MIExecUntil(IMIExecutionDMContext dmc, boolean setThread, String loc) { + super(dmc, "-exec-until"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(dmc.getThreadId()), loc }); //$NON-NLS-1$ + } else { + setParameters(new String[] { loc }); + } } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java index c0f7a8b63bb..1bffb4120cb 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackInfoDepth.java @@ -17,7 +17,7 @@ import org.eclipse.dd.mi.service.command.output.MIStackInfoDepthInfo; /** * - * -stack-info-depth [maxDepth] + * -stack-info-depth [--thread ] [maxDepth] * * */ @@ -25,13 +25,30 @@ public class MIStackInfoDepth extends MICommand { public MIStackInfoDepth(IMIExecutionDMContext ctx) { + this(ctx, false); + } + + public MIStackInfoDepth(IMIExecutionDMContext ctx, boolean setThread) { super(ctx, "-stack-info-depth"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(ctx.getThreadId()) }); //$NON-NLS-1$ + } } public MIStackInfoDepth(IMIExecutionDMContext ctx, int maxDepth) { - super(ctx, "-stack-info-depth", new String[]{Integer.toString(maxDepth)}); //$NON-NLS-1$ + this(ctx, false, maxDepth); } + public MIStackInfoDepth(IMIExecutionDMContext ctx, boolean setThread, int maxDepth) { + super(ctx, "-stack-info-depth"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(ctx.getThreadId()), Integer.toString(maxDepth) }); //$NON-NLS-1$ + } + else { + setParameters(new String[] { Integer.toString(maxDepth) }); + } + } + @Override public MIStackInfoDepthInfo getResult(MIOutput out) { return new MIStackInfoDepthInfo(out); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java index d9778e91fec..c7b1c774ad8 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListArguments.java @@ -20,7 +20,7 @@ import org.eclipse.dd.mi.service.command.output.MIStackListArgumentsInfo; /** * - * -stack-list-arguments SHOW-VALUES + * -stack-list-arguments [--thread ] SHOW-VALUES * [ LOW-FRAME HIGH-FRAME ] * * Display a list of the arguments for the frames between LOW-FRAME and @@ -35,34 +35,35 @@ import org.eclipse.dd.mi.service.command.output.MIStackListArgumentsInfo; public class MIStackListArguments extends MICommand { public MIStackListArguments(IMIExecutionDMContext execDmc, boolean showValues) { + this(execDmc, false, showValues); + } + + public MIStackListArguments(IMIExecutionDMContext execDmc, boolean setThread, boolean showValues) { super(execDmc, "-stack-list-arguments"); //$NON-NLS-1$ - if (showValues) { - setParameters(new String[]{"1"}); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(execDmc.getThreadId()), showValues ? "1" : "0" } ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else { - setParameters(new String[]{"0"}); //$NON-NLS-1$ + setParameters(new String[] { showValues ? "1" : "0" } ); //$NON-NLS-1$ //$NON-NLS-2$ } } public MIStackListArguments(IFrameDMContext frameDmc, boolean showValues) { - super(frameDmc, "-stack-list-arguments"); //$NON-NLS-1$ - if (showValues) { - setParameters(new String[]{"1"}); //$NON-NLS-1$ - } else { - setParameters(new String[]{"0"}); //$NON-NLS-1$ - } + super(frameDmc, "-stack-list-arguments", new String[] { showValues ? "1" : "0" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } public MIStackListArguments(IMIExecutionDMContext execDmc, boolean showValues, int low, int high) { + this(execDmc, false, showValues, low, high); + } + + public MIStackListArguments(IMIExecutionDMContext execDmc, boolean setThread, boolean showValues, int low, int high) { super(execDmc, "-stack-list-arguments"); //$NON-NLS-1$ - String[] params = new String[3]; - if (showValues) { - params[0] = "1"; //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(execDmc.getThreadId()), //$NON-NLS-1$ + showValues ? "1" : "0", Integer.toString(low), Integer.toString(high) } ); //$NON-NLS-1$ //$NON-NLS-2$ } else { - params[0] = "0"; //$NON-NLS-1$ + setParameters(new String[] { + showValues ? "1" : "0", Integer.toString(low), Integer.toString(high) } ); //$NON-NLS-1$ //$NON-NLS-2$ } - params[1] = Integer.toString(low); - params[2] = Integer.toString(high); - setParameters(params); } @Override diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java index f074292cfab..9b578ae5b30 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListFrames.java @@ -54,12 +54,27 @@ import org.eclipse.dd.mi.service.command.output.MIStackListFramesInfo; public class MIStackListFrames extends MICommand { public MIStackListFrames(IMIExecutionDMContext execDmc) { + this(execDmc, false); + } + + public MIStackListFrames(IMIExecutionDMContext execDmc, boolean setThread) { super(execDmc, "-stack-list-frames"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(execDmc.getThreadId()) } ); //$NON-NLS-1$ + } } public MIStackListFrames(IMIExecutionDMContext execDmc, int low, int high) { - super(execDmc, "-stack-list-frames", new String[]{Integer.toString(low), //$NON-NLS-1$ - Integer.toString(high)}); + this(execDmc, false, low, high); + } + + public MIStackListFrames(IMIExecutionDMContext execDmc, boolean setThread, int low, int high) { + super(execDmc, "-stack-list-frames"); //$NON-NLS-1$ + if (setThread) { + setParameters(new String[] { "--thread", Integer.toString(execDmc.getThreadId()), Integer.toString(low), Integer.toString(high) } ); //$NON-NLS-1$ + } else { + setParameters(new String[] { Integer.toString(low), Integer.toString(high) } ); + } } @Override diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java index 528212bd7ac..9dbfbb90ec7 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackListLocals.java @@ -13,7 +13,9 @@ package org.eclipse.dd.mi.service.command.commands; +import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext; +import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.mi.service.command.output.MIOutput; import org.eclipse.dd.mi.service.command.output.MIStackListLocalsInfo; @@ -30,12 +32,17 @@ public class MIStackListLocals extends MICommand { public MIStackListLocals(IFrameDMContext frameCtx, boolean printValues) { - super(frameCtx, "-stack-list-locals"); //$NON-NLS-1$ - if (printValues) { - setParameters(new String[]{"1"}); //$NON-NLS-1$ - } else { - setParameters(new String[]{"0"}); //$NON-NLS-1$ - } + this(frameCtx, false, printValues); + } + + public MIStackListLocals(IFrameDMContext frameCtx, boolean setThread, boolean printValues) { + super(frameCtx, "-stack-list-locals"); //$NON-NLS-1$ + IMIExecutionDMContext execDmc = DMContexts.getAncestorOfType(frameCtx, IMIExecutionDMContext.class); + if (setThread && execDmc != null) { + setParameters(new String[] { "--thread", Integer.toString(execDmc.getThreadId()), printValues ? "1" : "0" } ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } else { + setParameters(new String[] { printValues ? "1" : "0" } ); //$NON-NLS-1$ //$NON-NLS-2$ + } } @Override diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java index aa12b37b68c..5518359ba1c 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIStackSelectFrame.java @@ -15,8 +15,6 @@ package org.eclipse.dd.mi.service.command.commands; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.mi.service.command.output.MIInfo; - - /** * * -stack-select-frame FRAMENUM @@ -30,4 +28,8 @@ public class MIStackSelectFrame extends MICommand { public MIStackSelectFrame(IDMContext ctx, int frameNum) { super(ctx, "-stack-select-frame", new String[]{Integer.toString(frameNum)}, new String[0]); //$NON-NLS-1$ } + + public MIStackSelectFrame(IDMContext ctx, int threadNum, int frameNum) { + super(ctx, "-stack-select-frame", new String[]{ "--thread", Integer.toString(threadNum), Integer.toString(frameNum) }); //$NON-NLS-1$ //$NON-NLS-2$ + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadInfo.java new file mode 100644 index 00000000000..9edf0bfd92e --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIThreadInfo.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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 + * Ericsson - Modified for new DSF Reference Implementation + *******************************************************************************/ + +package org.eclipse.dd.mi.service.command.commands; + +import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.MIOutput; +import org.eclipse.dd.mi.service.command.output.MIThreadInfoInfo; + +/** + * + * -thread-info [ thread-id ] + * + * Reports information about either a specific thread, if [thread-id] is present, + * or about all threads. When printing information about all threads, also reports + * the current thread. + * + */ +public class MIThreadInfo extends MICommand { + + public MIThreadInfo(IContainerDMContext dmc) { + super(dmc, "-thread-info"); //$NON-NLS-1$ + } + + public MIThreadInfo(IContainerDMContext dmc, int threadId) { + super(dmc, "-thread-info", new String[]{ Integer.toString(threadId) }); //$NON-NLS-1$ + } + + @Override + public MIThreadInfoInfo getResult(MIOutput out) { + return new MIThreadInfoInfo(out); + } +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java index 6e23766bb0d..b67917b112a 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIVarCreate.java @@ -53,7 +53,7 @@ public class MIVarCreate extends MICommand this(dmc, "-", "*", expression); //$NON-NLS-1$ //$NON-NLS-2$ } - public MIVarCreate(IExpressionDMContext dmc,String name, String expression) { + public MIVarCreate(IExpressionDMContext dmc, String name, String expression) { this(dmc, name, "*", expression); //$NON-NLS-1$ } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java index 452632cd5ff..cfdc217e6d7 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIBreakpointHitEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -40,7 +40,7 @@ public class MIBreakpointHitEvent extends MIStoppedEvent { } public static MIBreakpointHitEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { int bkptno = -1; diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java index 2c8cb838873..0ba43986fc3 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIFunctionFinishedEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -54,7 +54,7 @@ public class MIFunctionFinishedEvent extends MIStoppedEvent { } public static MIFunctionFinishedEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { String gdbResult = ""; //$NON-NLS-1$ String returnValue = ""; //$NON-NLS-1$ diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java index 369d6c870bd..46d2f1fd874 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MILocationReachedEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -30,7 +30,7 @@ public class MILocationReachedEvent extends MIStoppedEvent { } public static MILocationReachedEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); return new MILocationReachedEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java index fbb7d01ad67..dbf174374c1 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISharedLibEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -30,7 +30,7 @@ public class MISharedLibEvent extends MIStoppedEvent { } public static MIStoppedEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); return new MISharedLibEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java index 1938022d21f..ad540dc9606 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISignalEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -49,7 +49,7 @@ public class MISignalEvent extends MIStoppedEvent { } public static MISignalEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { String sigName = ""; //$NON-NLS-1$ String sigMeaning = ""; //$NON-NLS-1$ diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java index 6901d9283e0..35a3005b01a 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MISteppingRangeEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -31,7 +31,7 @@ public class MISteppingRangeEvent extends MIStoppedEvent { } public static MISteppingRangeEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { MIStoppedEvent stoppedEvent = MIStoppedEvent.parse(runControl, containerDmc, token, results); return new MISteppingRangeEvent(stoppedEvent.getDMContext(), token, results, stoppedEvent.getFrame()); diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java index a1a45b0d47b..509669ef30e 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIStoppedEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -41,7 +41,7 @@ public class MIStoppedEvent extends MIEvent { } public static MIStoppedEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { int threadId = -1; MIFrame frame = null; diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java index 23583241c39..63576fed697 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadCreatedEvent.java @@ -14,6 +14,9 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; /** @@ -37,4 +40,25 @@ public class MIThreadCreatedEvent extends MIEvent { public int getId() { return tid; } + + public static MIThreadCreatedEvent parse(IContainerDMContext ctx, int token, MIResult[] results) + { + 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) { + try { + int thread = Integer.parseInt(((MIConst) val).getString()); + return new MIThreadCreatedEvent(ctx, token, thread); + } + catch (NumberFormatException e) { + return null; + } + } + } + } + + return null; + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java index e960f8f9b40..0b0fbf240b7 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIThreadExitEvent.java @@ -14,6 +14,9 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; +import org.eclipse.dd.mi.service.command.output.MIConst; +import org.eclipse.dd.mi.service.command.output.MIResult; +import org.eclipse.dd.mi.service.command.output.MIValue; /** @@ -37,4 +40,25 @@ public class MIThreadExitEvent extends MIEvent { public int getId() { return tid; } + + public static MIThreadExitEvent parse(IContainerDMContext ctx, int token, MIResult[] results) + { + 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) { + try { + int thread = Integer.parseInt(((MIConst) val).getString()); + return new MIThreadExitEvent(ctx, token, thread); + } + catch (NumberFormatException e) { + return null; + } + } + } + } + + return null; + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java index 5de47f2a808..26822656d3e 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointScopeEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -42,7 +42,7 @@ public class MIWatchpointScopeEvent extends MIStoppedEvent { } public static MIWatchpointScopeEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { int number = 0; for (int i = 0; i < results.length; i++) { diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java index 81d4da3ace9..c7346565c58 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/events/MIWatchpointTriggerEvent.java @@ -15,7 +15,7 @@ package org.eclipse.dd.mi.service.command.events; import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext; import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext; -import org.eclipse.dd.mi.service.MIRunControl; +import org.eclipse.dd.mi.service.IMIRunControl; import org.eclipse.dd.mi.service.command.output.MIConst; import org.eclipse.dd.mi.service.command.output.MIFrame; import org.eclipse.dd.mi.service.command.output.MIResult; @@ -62,7 +62,7 @@ public class MIWatchpointTriggerEvent extends MIStoppedEvent { } public static MIWatchpointTriggerEvent parse( - MIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) + IMIRunControl runControl, IContainerDMContext containerDmc, int token, MIResult[] results) { int number = 0; String exp = ""; //$NON-NLS-1$ diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java index 9a4612bb141..f94e694a2fa 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/CLIInfoThreadsInfo.java @@ -35,7 +35,7 @@ public class CLIInfoThreadsInfo extends MIInfo { parse(); } - public class ThreadInfo{ + public class ThreadInfo { String fName; String fGdbId; String fPid; diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadInfoInfo.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadInfoInfo.java new file mode 100644 index 00000000000..c5fe86759ec --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/output/MIThreadInfoInfo.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 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 + * Ericsson AB - Modified for DSF Reference Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.output; + +import java.math.BigInteger; +import java.util.List; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.dd.dsf.concurrent.Immutable; + +/** + * GDB/MI thread list parsing. + * + * Example 1: + * + * -thread-info + * ^done,threads=[ + * {id="2",target-id="Thread 0xb7c8ab90 (LWP 7010)", + * frame={level="0",addr="0x08048bba",func="my_func",args=[{name="arg",value="0xbff056f5"}], + * file="my_test.cc",fullname="/home/francois/GDB/my_test.cc",line="26"}, + * running="0"}, + * {id="1",target-id="Thread 0xb7c8b8d0 (LWP 7007)", + * frame={level="0",addr="0x08048a77",func="timer",args=[{name="duration",value="0xbff056f5 \"10\""}], + * file="my_test.cc",fullname="/home/francois/GDB/my_test.cc",line="39"}, + * running="0"} + * ],current-thread-id="2" + * + + * Example 2: + * + * -thread-info 2 + * ^done,threads=[ + * {id="2",target-id="Thread 0xb7c8ab90 (LWP 7010)", + * frame={level="0",addr="0x08048bba",func="my_func",args=[{name="arg",value="0xbff056f5"}], + * file="my_test.cc",fullname="/home/francois/GDB/my_test.cc",line="26"}, + * running="0"} + * ] + * + * + * Example 3 (non-stop): + * + * -thread-info + * ^done,threads=[ + * {id="2",target-id="Thread 0xb7c8eb90 (LWP 7807)",running="1"}, + * {id="1",target-id="Thread 0xb7c8b8d0 (LWP 7007)", + * frame={level="0",addr="0x08048a77",func="timer",args=[{name="duration",value="0xbff056f5 \"10\""}], + * file="my_test.cc",fullname="/home/francois/GDB/my_test.cc",line="39"}, + * running="0"} + * ],current-thread-id="1" + */ +public class MIThreadInfoInfo extends MIInfo { + + @Immutable + public class ThreadInfo { + + final private String fGdbId; + final private String fTargetId; + final private String fOsId; + final private ThreadFrame fTopFrame; + final private boolean fIsRunning; + + public ThreadInfo(String gdbId, String targetId, String osId, ThreadFrame topFrame, boolean isRunning) { + fGdbId = gdbId; + fTargetId = targetId; + fOsId = osId; + fTopFrame = topFrame; + fIsRunning = isRunning; + } + + public String getGdbId() { return fGdbId; } + public String getTargetId() { return fTargetId; } + public String getOsId() { return fOsId; } + public ThreadFrame getTopFrame() { return fTopFrame; } + public boolean isRunning() { return fIsRunning; } + } + + @Immutable + public class ThreadFrame { + final private int fStackLevel; + final private BigInteger fAddress; + final private String fFunction; + final private ThreadFrameFunctionArgs[] fArgs; + final private String fFileName; + final private String fFullName; + final private int fLineNumber; + + public ThreadFrame(int stackLevel, BigInteger address, String function, + ThreadFrameFunctionArgs[] args, String file, String fullName, int line) + { + fStackLevel = stackLevel; + fAddress = address; + fFunction = function; + fArgs = args; + fFileName = file; + fFullName = fullName; + fLineNumber = line; + } + + public int getStackLevel() { return fStackLevel; } + public BigInteger getAddress() { return fAddress; } + public String getFucntion() { return fFunction; } + public ThreadFrameFunctionArgs[] getArgs() { return fArgs; } + public String getFileName() { return fFileName; } + public String getFullName() { return fFullName; } + public int getLineNumber() { return fLineNumber; } + } + + @Immutable + public class ThreadFrameFunctionArgs { + } + + private int fCurrentThread = -1; + private List fThreadInfoList = null; + private int[] fThreadList = null; + + public MIThreadInfoInfo(MIOutput out) { + super(out); + parse(); + } + + public int getCurrentThread() { + return fCurrentThread; + } + + public List getThreadInfoList() { + return fThreadInfoList; + } + + public int[] getThreadList() { + return fThreadList; + } + + // General format: + // threads=[{...}],current-thread-id="n" + private void parse() { + if (isDone()) { + MIOutput out = getMIOutput(); + MIResultRecord rr = out.getMIResultRecord(); + if (rr != null) { + MIResult[] results = rr.getMIResults(); + for (int i = 0; i < results.length; i++) { + String var = results[i].getVariable(); + if (var.equals("threads")) { //$NON-NLS-1$ + MIValue val = results[i].getMIValue(); + if (val instanceof MIList) { + parseThreads((MIList) val); + } + } + else if (var.equals("current-thread-id")) { //$NON-NLS-1$ + MIValue value = results[i].getMIValue(); + if (value instanceof MIConst) { + String str = ((MIConst) value).getCString(); + try { + fCurrentThread = Integer.parseInt(str.trim()); + } catch (NumberFormatException e) { + fCurrentThread = -1; + } + } + } + } + } + } + if (fThreadInfoList == null) { + fThreadInfoList = new Vector(0); + fThreadList = new int[0]; + } + } + + // General formats: + // id="n",target-id="Thread 0xb7c8ab90 (LWP 7010)",frame={...},running="0" + // id="n",target-id="Thread 0xb7c8eb90 (LWP 7807)",running="1" + private void parseThreads(MIList list) { + MIValue[] values = list.getMIValues(); + fThreadInfoList = new Vector(values.length); + fThreadList = new int[values.length]; + + for (int i = 0; i < values.length; i++) { + MITuple value = (MITuple) values[i]; + MIResult[] results = value.getMIResults(); + + String gdbId = null; + String targetId = null; + String osId = null; + ThreadFrame topFrame = null; + boolean isRunning = false; + + for (int j = 0; j < results.length; j++) { + MIResult result = results[j]; + String var = result.getVariable(); + if (var.equals("id")) { //$NON-NLS-1$ + MIValue val = results[j].getMIValue(); + if (val instanceof MIConst) { + gdbId = ((MIConst) val).getCString(); + } + } + else if (var.equals("target-id")) { //$NON-NLS-1$ + MIValue val = results[j].getMIValue(); + if (val instanceof MIConst) { + targetId = ((MIConst) val).getCString(); + osId = parseOsId(targetId); + } + } + else if (var.equals("frame")) { //$NON-NLS-1$ + MIValue val = results[j].getMIValue(); + topFrame = parseFrame(val); + } + else if (var.equals("running")) { //$NON-NLS-1$ + MIValue val = results[j].getMIValue(); + if (val instanceof MIConst) { + String v = ((MIConst) val).getCString(); + isRunning = v.equals("1"); //$NON-NLS-1$ + } + } + } + + fThreadInfoList.add(new ThreadInfo(gdbId, targetId, osId, topFrame, isRunning)); + try { + fThreadList[i] = Integer.parseInt(gdbId); + } catch (NumberFormatException e) { + } + } + } + + // General format: + // "Thread 0xb7c8ab90 (LWP 7010)" + private String parseOsId(String str) { + Pattern pattern = Pattern.compile("(Thread\\s*)(0x[0-9a-fA-F]+|-?\\d+)(\\s*\\(LWP\\s*)(\\d*)", 0); //$NON-NLS-1$ + Matcher matcher = pattern.matcher(str); + if (matcher.find()) { + return matcher.group(4); + } + return null; + } + + // General format: + // level="0",addr="0x08048bba",func="func",args=[...],file="file.cc",fullname="/path/file.cc",line="26" + private ThreadFrame parseFrame(MIValue val) { + // TODO Auto-generated method stub + return null; + } + +} + diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java index 9111e34b42b..2f341ae0c2b 100644 --- a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/AllTests.java @@ -26,7 +26,8 @@ import org.junit.runners.Suite; MIRunControlTest.class, ExpressionServiceTest.class, MIMemoryTest.class, - MIBreakpointsTest.class + MIBreakpointsTest.class, + MIDisassemblyTest.class, /* Add your test class here */ }) diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java index 930aaf98ed0..91d5e921374 100644 --- a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/tests/gdb/GDBProcessesTest.java @@ -24,8 +24,8 @@ import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.service.DsfServicesTracker; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl.GDBProcessData; -import org.eclipse.dd.gdb.internal.provisional.service.GDBRunControl.GDBThreadData; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl.IGDBProcessData; +import org.eclipse.dd.gdb.internal.provisional.service.IGDBRunControl.IGDBThreadData; import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl; import org.eclipse.dd.mi.service.IMIExecutionDMContext; import org.eclipse.dd.tests.gdb.framework.AsyncCompletionWaitor; @@ -91,8 +91,8 @@ public class GDBProcessesTest extends BaseTestCase { /* * Create a request monitor */ - final DataRequestMonitor rm = - new DataRequestMonitor(fSession.getExecutor(), null) { + final DataRequestMonitor rm = + new DataRequestMonitor(fSession.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { @@ -123,7 +123,7 @@ public class GDBProcessesTest extends BaseTestCase { /* * Get process data */ - GDBProcessData processData = rm.getData(); + IGDBProcessData processData = rm.getData(); if(processData == null) Assert.fail("No process data is returned for Process DMC"); @@ -141,8 +141,8 @@ public class GDBProcessesTest extends BaseTestCase { */ @Test public void getThreadData() throws InterruptedException{ - final DataRequestMonitor rm = - new DataRequestMonitor(fSession.getExecutor(), null) { + final DataRequestMonitor rm = + new DataRequestMonitor(fSession.getExecutor(), null) { @Override protected void handleCompleted() { if (isSuccess()) { @@ -166,7 +166,7 @@ public class GDBProcessesTest extends BaseTestCase { fWait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER); assertTrue(fWait.getMessage(), fWait.isOK()); - GDBThreadData threadData = rm.getData(); + IGDBThreadData threadData = rm.getData(); if(threadData == null) fail("Thread data not returned for thread id = " + fExecDmc.getThreadId()); else{