Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'dsf-gdb')
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java12
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF1
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java8
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties5
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java101
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java93
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java273
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java445
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java50
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc49
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc210
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc38
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java34
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java3
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java395
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java32
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java1
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java32
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java6
19 files changed, 1684 insertions, 104 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
index 51d5f2ea88b..fb440c46362 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/GdbAdapterFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2010 Wind River Systems and others.
+ * Copyright (c) 2006, 2013 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
@@ -9,6 +9,7 @@
* Wind River Systems - initial API and implementation
* Navid Mehregani (TI) - Bug 289526 - Migrate the Restart feature to the new one, as supported by the platform
* Patrick Chuong (Texas Instruments) - Add support for icon overlay in the debug view (Bug 334566)
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal.ui;
@@ -27,6 +28,7 @@ import org.eclipse.cdt.debug.core.model.IReverseStepOverHandler;
import org.eclipse.cdt.debug.core.model.IReverseToggleHandler;
import org.eclipse.cdt.debug.core.model.ISaveTraceDataHandler;
import org.eclipse.cdt.debug.core.model.IStartTracingHandler;
+import org.eclipse.cdt.debug.core.model.IStepIntoSelectionHandler;
import org.eclipse.cdt.debug.core.model.ISteppingModeTarget;
import org.eclipse.cdt.debug.core.model.IStopTracingHandler;
import org.eclipse.cdt.debug.core.model.IUncallHandler;
@@ -35,9 +37,11 @@ import org.eclipse.cdt.dsf.concurrent.Immutable;
import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfResumeCommand;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoSelectionCommand;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepOverCommand;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepReturnCommand;
import org.eclipse.cdt.dsf.debug.ui.actions.DsfSuspendCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.IDsfStepIntoSelection;
import org.eclipse.cdt.dsf.debug.ui.sourcelookup.DsfSourceDisplayAdapter;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.DefaultRefreshAllTarget;
@@ -105,6 +109,7 @@ public class GdbAdapterFactory
final GdbViewModelAdapter fViewModelAdapter;
final DsfSourceDisplayAdapter fSourceDisplayAdapter;
final DsfStepIntoCommand fStepIntoCommand;
+ final DsfStepIntoSelectionCommand fStepIntoSelectionCommand;
final GdbReverseStepIntoCommand fReverseStepIntoCommand;
final DsfStepOverCommand fStepOverCommand;
final GdbReverseStepOverCommand fReverseStepOverCommand;
@@ -154,6 +159,7 @@ public class GdbAdapterFactory
fSteppingModeTarget = new GdbSteppingModeTarget(session);
fStepIntoCommand = new DsfStepIntoCommand(session, fSteppingModeTarget);
+ fStepIntoSelectionCommand = new DsfStepIntoSelectionCommand(session);
fReverseStepIntoCommand = new GdbReverseStepIntoCommand(session, fSteppingModeTarget);
fStepOverCommand = new DsfStepOverCommand(session, fSteppingModeTarget);
fReverseStepOverCommand = new GdbReverseStepOverCommand(session, fSteppingModeTarget);
@@ -181,6 +187,7 @@ public class GdbAdapterFactory
session.registerModelAdapter(ISteppingModeTarget.class, fSteppingModeTarget);
session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand);
+ session.registerModelAdapter(IStepIntoSelectionHandler.class, fStepIntoSelectionCommand);
session.registerModelAdapter(IReverseStepIntoHandler.class, fReverseStepIntoCommand);
session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand);
session.registerModelAdapter(IReverseStepOverHandler.class, fReverseStepOverCommand);
@@ -204,6 +211,7 @@ public class GdbAdapterFactory
session.registerModelAdapter(ISelectNextTraceRecordHandler.class, fSelectNextRecordTarget);
session.registerModelAdapter(ISelectPrevTraceRecordHandler.class, fSelectPrevRecordTarget);
session.registerModelAdapter(IPinProvider.class, fPinProvider);
+ session.registerModelAdapter(IDsfStepIntoSelection.class, fStepIntoSelectionCommand);
fDebugModelProvider = new IDebugModelProvider() {
// @see org.eclipse.debug.core.model.IDebugModelProvider#getModelIdentifiers()
@@ -242,6 +250,7 @@ public class GdbAdapterFactory
session.unregisterModelAdapter(ISteppingModeTarget.class);
session.unregisterModelAdapter(IStepIntoHandler.class);
+ session.unregisterModelAdapter(IStepIntoSelectionHandler.class);
session.unregisterModelAdapter(IReverseStepIntoHandler.class);
session.unregisterModelAdapter(IStepOverHandler.class);
session.unregisterModelAdapter(IReverseStepOverHandler.class);
@@ -273,6 +282,7 @@ public class GdbAdapterFactory
fSteppingModeTarget.dispose();
fStepIntoCommand.dispose();
+ fStepIntoSelectionCommand.dispose();
fReverseStepIntoCommand.dispose();
fStepOverCommand.dispose();
fReverseStepOverCommand.dispose();
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF
index 875fd3ece60..59bbcce538b 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/META-INF/MANIFEST.MF
@@ -23,6 +23,7 @@ Export-Package: org.eclipse.cdt.dsf.gdb,
org.eclipse.cdt.dsf.gdb.internal;x-friends:="org.eclipse.cdt.dsf.gdb.ui,org.eclipse.cdt.debug.gdbjtag.ui",
org.eclipse.cdt.dsf.gdb.internal.commands;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
org.eclipse.cdt.dsf.gdb.internal.memory;x-internal:=true,
+ org.eclipse.cdt.dsf.gdb.internal.service.control;x-internal:=true,
org.eclipse.cdt.dsf.gdb.internal.service.command.events;x-internal:=true,
org.eclipse.cdt.dsf.gdb.internal.tracepointactions;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
org.eclipse.cdt.dsf.gdb.launching,
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java
index ee19d3c3678..60fd44bb351 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 Mentor Graphics and others.
+ * Copyright (c) 2011, 2013 Mentor Graphics 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Mentor Graphics - Initial API and implementation
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.internal;
@@ -22,6 +23,11 @@ public class Messages extends NLS {
public static String CustomTimeoutsMap_Invalid_custom_timeout_value;
public static String GDBControl_Session_is_terminated;
+
+ public static String StepIntoSelection;
+
+ public static String StepIntoSelection_Execution_did_not_enter_function;
+
static {
// initialize resource bundle
NLS.initializeMessages( Messages.class.getName(), Messages.class );
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties
index 9a4e8c3dbbe..978adaa94e6 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/Messages.properties
@@ -1,5 +1,5 @@
#######################################################################################
-# Copyright (c) 2011 Mentor Graphics and others.
+# Copyright (c) 2011, 2013 Mentor Graphics 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
@@ -7,9 +7,12 @@
#
# Contributors:
# Mentor Graphics - Initial API and implementation
+# Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection
#######################################################################################
CustomTimeoutsMap_Error_initializing_custom_timeouts=Error initializing custom timeouts
CustomTimeoutsMap_Invalid_custom_timeout_data=Invalid custom timeout data.
CustomTimeoutsMap_Invalid_custom_timeout_value=Invalid custom timeout value for '%s'.
GDBControl_Session_is_terminated=Session is terminated.\nReason: %s
+StepIntoSelection=Step into selection
+StepIntoSelection_Execution_did_not_enter_function=Execution did not enter \"{0}\"
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java
new file mode 100644
index 00000000000..8f9e5c29e11
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionActiveOperation.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson AB 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:
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.gdb.internal.service.control;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
+
+/**
+ * @since 4.2
+ */
+public class StepIntoSelectionActiveOperation {
+ private final IFunctionDeclaration fTargetFunction;
+ private final IMIExecutionDMContext fThreadContext;
+ private String fBaseFileLocation = null;
+ private int fBaseLine = 0;
+ private int fOriginalStackDepth=0;
+ private String fFunctionSignature = null;
+ private MIFrame fRunToLineFrame = null;
+
+ public StepIntoSelectionActiveOperation(IMIExecutionDMContext threadContext, int line, IFunctionDeclaration targetFunction,
+ int stackDepth, MIFrame runToLineFrame) {
+ fThreadContext = threadContext;
+ fBaseLine = line;
+ fTargetFunction = targetFunction;
+ fOriginalStackDepth = stackDepth;
+
+ fRunToLineFrame = runToLineFrame;
+ init();
+ }
+
+ private void init() {
+ if (fRunToLineFrame == null) {
+ return;
+ }
+
+ fBaseFileLocation = fRunToLineFrame.getFile() + ":" + fBaseLine; //$NON-NLS-1$
+ }
+
+ public IFunctionDeclaration getTargetFunctionDeclaration() {
+ return fTargetFunction;
+ }
+
+ public IMIExecutionDMContext getThreadContext() {
+ return fThreadContext;
+ }
+
+ public String getFileLocation() {
+ return fBaseFileLocation;
+ }
+
+ public int getLine() {
+ return fBaseLine;
+ }
+
+ public int getOriginalStackDepth() {
+ return fOriginalStackDepth;
+ }
+
+ public void setOriginalStackDepth(Integer originalStackDepth) {
+ fOriginalStackDepth = originalStackDepth;
+ }
+
+ public MIFrame getRunToLineFrame() {
+ return fRunToLineFrame;
+ }
+
+ public void setRunToLineFrame(MIFrame runToLineFrame) {
+ if (runToLineFrame != null) {
+ fRunToLineFrame = runToLineFrame;
+ init();
+ }
+ }
+
+ public String getTargetFunctionSignature() {
+ if (fFunctionSignature != null) {
+ return fFunctionSignature;
+ } else {
+ if (fTargetFunction != null) {
+ StringBuilder sb = null;
+ sb = new StringBuilder();
+ if (fTargetFunction.getParent() != null) {
+ sb.append(fTargetFunction.getParent().getElementName() + StepIntoSelectionUtils.cppSep);
+ }
+
+ sb.append(fTargetFunction.getElementName());
+ fFunctionSignature = sb.toString();
+ }
+ }
+
+ return fFunctionSignature;
+ }
+} \ No newline at end of file
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java
new file mode 100644
index 00000000000..590404dde97
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/internal/service/control/StepIntoSelectionUtils.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson AB 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:
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.gdb.internal.service.control;
+
+import org.eclipse.cdt.dsf.gdb.IGdbDebugConstants;
+import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.Messages;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIArg;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IStatusHandler;
+import org.eclipse.osgi.util.NLS;
+
+public class StepIntoSelectionUtils {
+
+ public static final String cppSep = "::"; //$NON-NLS-1$
+
+ public static boolean sameSignature(MIFrame currentFrame, StepIntoSelectionActiveOperation stepOperation) {
+ String currentFunctionName = currentFrame.getFunction();
+ String targetFunctionName = stepOperation.getTargetFunctionSignature();
+
+ if (!sameNumberOfArgumets(currentFrame, stepOperation)) {
+ return false;
+ }
+
+ // Simplified validation
+ if (currentFunctionName.equals(targetFunctionName)) {
+ return true;
+ }
+
+ // Check if the last segment of the function name match
+ String[] currentFunctTokens = currentFunctionName.split(cppSep);
+ String[] targetFunctTokens = targetFunctionName.split(cppSep);
+ if (currentFunctTokens.length > 1) {
+ currentFunctionName = currentFunctTokens[currentFunctTokens.length - 1];
+ }
+
+ if (targetFunctTokens.length > 1) {
+ targetFunctionName = targetFunctTokens[targetFunctTokens.length - 1];
+ }
+
+ if (currentFunctionName.equals(targetFunctionName)) {
+ // Function name matches and parent name does not. One of the parents may be a super class
+ // Simple enough for initial implementation.
+ return true;
+ }
+
+ // TODO: A more detailed check can be implemented in order to cover for parameter types return types, etc..
+ // This with the intention to avoid early stops, however this implementation need to be tested extensively in
+ // order to avoid missing the target due to unexpected formatting mismatch between declaration and GDB representation.
+
+ return false;
+ }
+
+ private static boolean sameNumberOfArgumets(MIFrame currentFrame, StepIntoSelectionActiveOperation stepOperation) {
+ int argSizeAdjustment = 0;
+ MIArg[] args = currentFrame.getArgs();
+ if (args.length > 0) {
+ // GDB may add the argument "this" e.g. in c++ programs
+ if (args[0].getName().equals("this")) { //$NON-NLS-1$
+ argSizeAdjustment = 1;
+ }
+ }
+
+ return ((currentFrame.getArgs().length - argSizeAdjustment) == stepOperation.getTargetFunctionDeclaration().getNumberOfParameters());
+ }
+
+ public static void missedSelectedTarget(StepIntoSelectionActiveOperation stepOperation) {
+ final String functionName = stepOperation.getTargetFunctionDeclaration().getElementName();
+ IStatus status = new Status(IStatus.INFO, GdbPlugin.PLUGIN_ID, IGdbDebugConstants.STATUS_HANDLER_CODE, Messages.StepIntoSelection + "\n" + NLS.bind(Messages.StepIntoSelection_Execution_did_not_enter_function, functionName), null); //$NON-NLS-1$
+ IStatusHandler statusHandler = DebugPlugin.getDefault().getStatusHandler(status);
+ if (statusHandler != null) {
+ try {
+ statusHandler.handleStatus(status, null);
+ } catch (CoreException ex) {
+ GdbPlugin.getDefault().getLog().log(ex.getStatus());
+ }
+ }
+ }
+
+}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java
index c8fa3ba586b..d8bbebf4277 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl.java
@@ -9,6 +9,7 @@
* Wind River Systems - initial API and implementation
* Ericsson AB - Modified for additional functionality
* Nokia - create and use backend service.
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
@@ -19,7 +20,9 @@ import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
@@ -29,7 +32,11 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
+import org.eclipse.cdt.dsf.debug.service.IRunControl3;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
+import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionActiveOperation;
+import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionUtils;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
@@ -46,6 +53,7 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIStackInfoDepthInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
@@ -80,13 +88,15 @@ public class GDBRunControl extends MIRunControl {
private IGDBBackend fGdb;
private IMIProcesses fProcService;
private CommandFactory fCommandFactory;
+ private ICommandControlService fConnection;
// Record list of execution contexts
private IExecutionDMContext[] fOldExecutionCtxts;
private RunToLineActiveOperation fRunToLineActiveOperation = null;
-
+ private StepIntoSelectionActiveOperation fStepInToSelectionActiveOperation = null;
+
public GDBRunControl(DsfSession session) {
super(session);
}
@@ -106,9 +116,11 @@ public class GDBRunControl extends MIRunControl {
fGdb = getServicesTracker().getService(IGDBBackend.class);
fProcService = getServicesTracker().getService(IMIProcesses.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
+ fConnection = getServicesTracker().getService(ICommandControlService.class);
register(new String[]{IRunControl.class.getName(),
IRunControl2.class.getName(),
+ IRunControl3.class.getName(),
IMIRunControl.class.getName(),
MIRunControl.class.getName(),
GDBRunControl.class.getName()}, new Hashtable<String,String>());
@@ -332,6 +344,7 @@ public class GDBRunControl extends MIRunControl {
getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
+ fStepInToSelectionActiveOperation = null;
super.handleFailure();
}
@@ -361,13 +374,26 @@ public class GDBRunControl extends MIRunControl {
getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
+ fStepInToSelectionActiveOperation = null;
}
}
/** @since 2.0 */
@Override
@DsfServiceEventHandler
- public void eventDispatched(final MIStoppedEvent e) {
+ public void eventDispatched(final MIStoppedEvent e) {
+ if (processRunToLineStoppedEvent(e)) {
+ // If RunToLine is not completed
+ return;
+ }
+
+ if (!processStepIntoSelection(e)) {
+ //Step into Selection is not in progress broadcast the stop event
+ super.eventDispatched(e);
+ }
+ }
+
+ private boolean processRunToLineStoppedEvent(final MIStoppedEvent e) {
if (fRunToLineActiveOperation != null) {
int bpId = 0;
if (e instanceof MIBreakpointHitEvent) {
@@ -407,7 +433,7 @@ public class GDBRunControl extends MIRunControl {
new DataRequestMonitor<MIInfo>(getExecutor(), null));
// Don't send the stop event since we are resuming again.
- return;
+ return true;
} else {
// Stopped at another breakpoint that we should not skip.
// Or got an interrupt signal from a suspend command.
@@ -423,11 +449,119 @@ public class GDBRunControl extends MIRunControl {
getConnection().queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {fRunToLineActiveOperation.getBreakointId()}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
+ fStepInToSelectionActiveOperation = null;
}
}
}
+
+ return false;
+ }
+
+ private boolean processStepIntoSelection(final MIStoppedEvent e) {
+ if (fStepInToSelectionActiveOperation == null) {
+ return false;
+ }
+
+ // First check if it is the right thread that stopped
+ final IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
+ if (fStepInToSelectionActiveOperation.getThreadContext().equals(threadDmc)) {
+ final MIFrame frame = e.getFrame();
+
+ assert(fStepInToSelectionActiveOperation.getLine() == frame.getLine());
+ assert(fRunToLineActiveOperation == null);
+
+ if (fStepInToSelectionActiveOperation.getRunToLineFrame() == null) {
+ // Shall now be at the runToline location
+ fStepInToSelectionActiveOperation.setRunToLineFrame(frame);
+ }
+
+ // Step - Not at the right place just yet
+ // Initiate an async call chain parent
+ getStackDepth(threadDmc, new DataRequestMonitor<Integer>(getExecutor(), null) {
+ private int originalStackDepth = fStepInToSelectionActiveOperation.getOriginalStackDepth();
+
+ @Override
+ protected void handleSuccess() {
+ int frameDepth = getStackDepth();
+
+ if (frameDepth > originalStackDepth) {
+ //shall be true as this is using stepinto step type vs instruction stepinto
+ assert(frameDepth == originalStackDepth + 1);
+
+ // Check for a match
+ if (StepIntoSelectionUtils.sameSignature(frame, fStepInToSelectionActiveOperation)) {
+ // Hit !!
+ stopStepIntoSelection(e);
+ return;
+ }
+
+ // Located deeper in the stack, Shall continue step / search
+ // Step return
+ continueStepping(e, StepType.STEP_RETURN);
+ } else if (frameDepth == originalStackDepth) {
+ // Continue step / search as long as
+ // this is the starting base line for the search
+ String currentLocation = frame.getFile() + ":" + frame.getLine(); //$NON-NLS-1$
+ String searchLineLocation = fStepInToSelectionActiveOperation.getFileLocation();
+ if (currentLocation.equals(searchLineLocation)) {
+ continueStepping(e, StepType.STEP_INTO);
+ } else {
+ // We have moved to a line
+ // different from the base
+ // search line i.e. missed the
+ // target function !!
+ StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation);
+ stopStepIntoSelection(e);
+ }
+ } else {
+ // missed the target point
+ StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation); }
+ }
+
+ @Override
+ protected void handleFailure() {
+ // log error
+ if (getStatus() != null) {
+ GdbPlugin.getDefault().getLog().log(getStatus());
+ }
+
+ stopStepIntoSelection(e);
+ }
+
+ private int getStackDepth() {
+ Integer stackDepth = null;
+ if (isSuccess() && getData() != null) {
+ stackDepth = getData();
+ // This is the base frame, the original stack depth shall be updated
+ if (frame == fStepInToSelectionActiveOperation.getRunToLineFrame()) {
+ fStepInToSelectionActiveOperation.setOriginalStackDepth(stackDepth);
+ originalStackDepth = stackDepth;
+ }
+ }
- super.eventDispatched(e);
+ if (stackDepth == null) {
+ // Unsuccessful resolution of stack depth, default to same stack depth to detect a change of line within the original frame
+ return fStepInToSelectionActiveOperation.getOriginalStackDepth();
+ }
+
+ return stackDepth.intValue();
+ }
+ });
+
+ //Processing step into selection
+ return true;
+ }
+
+ //All threads stopped, however outside the scope of the step into selection context
+ //We need to abort the step into selection and broadcast the stop
+ fStepInToSelectionActiveOperation = null;
+ return false;
+ }
+
+ private void stopStepIntoSelection(final MIStoppedEvent e) {
+ fStepInToSelectionActiveOperation = null;
+ // Need to broadcast the stop
+ super.eventDispatched(e);
}
/**
@@ -435,5 +569,134 @@ public class GDBRunControl extends MIRunControl {
*/
protected int getInterruptTimeout() {
return IGDBBackend.INTERRUPT_TIMEOUT_DEFAULT;
- }
+ }
+
+ private void continueStepping(final MIStoppedEvent event, StepType steptype) {
+ step(fStepInToSelectionActiveOperation.getThreadContext(), steptype, false, new RequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleFailure() {
+ // log error
+ if (getStatus() != null) {
+ GdbPlugin.getDefault().getLog().log(getStatus());
+ }
+
+ stopStepIntoSelection(event);
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Step into Selection
+ // ------------------------------------------------------------------------
+ private void stepIntoSelection(final IExecutionDMContext context, final int baseLine, final String baseLineLocation, final boolean skipBreakpoints, final IFunctionDeclaration targetFunction,
+ final RequestMonitor rm) {
+
+ assert context != null;
+
+ final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
+ if (dmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ if (!doCanResume(dmc)) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ if (fLatestEvent == null || !(fLatestEvent instanceof SuspendedEvent)) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " invalid suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ SuspendedEvent suspendedEvent = (SuspendedEvent) fLatestEvent;
+ final MIFrame currentFrame = suspendedEvent.getMIEvent().getFrame();
+ if (currentFrame == null) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given event: " + suspendedEvent + " with invalid frame.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ getStackDepth(dmc, new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ public void handleSuccess() {
+ if (getData() != null) {
+ final int framesSize = getData().intValue();
+
+ // make sure the operation is removed upon
+ // failure detection
+ final RequestMonitor rms = new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ fStepInToSelectionActiveOperation = null;
+ super.handleFailure();
+ }
+ };
+
+ if ((currentFrame.getFile() + ":" + currentFrame.getLine()).endsWith(baseLineLocation)) { //$NON-NLS-1$
+ // Save the step into selection information
+ fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize,
+ currentFrame);
+ // Ready to step into a function selected
+ // within a current line
+ step(dmc, StepType.STEP_INTO, rms);
+ } else {
+ // Save the step into selection information
+ fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, null);
+ // Pointing to a line different than the current line
+ // Needs to RunToLine before stepping to the selection
+ runToLocation(dmc, baseLineLocation, skipBreakpoints, rms);
+ }
+ } else {
+ rm.done();
+ }
+ }
+ });
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) {
+ canStep(context, StepType.STEP_INTO, rm);
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void stepIntoSelection(final IExecutionDMContext context, String sourceFile, final int lineNumber, final boolean skipBreakpoints, final IFunctionDeclaration selectedFunction, final RequestMonitor rm) {
+ determineDebuggerPath(context, sourceFile, new ImmediateDataRequestMonitor<String>(rm) {
+ @Override
+ protected void handleSuccess() {
+ stepIntoSelection(context, lineNumber, getData() + ":" + Integer.toString(lineNumber), skipBreakpoints, selectedFunction, rm); //$NON-NLS-1$
+ }
+ });
+ }
+
+ /**
+ * Help method used when the stopped event has not been broadcasted e.g. in the middle of step into selection
+ *
+ * @param dmc
+ * @param rm
+ */
+ private void getStackDepth(final IMIExecutionDMContext dmc, final DataRequestMonitor<Integer> rm) {
+ if (dmc != null) {
+ fConnection.queueCommand(fCommandFactory.createMIStackInfoDepth(dmc), new DataRequestMonitor<MIStackInfoDepthInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData().getDepth());
+ rm.done();
+ }
+ });
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java
index a3d72580739..b4361367d53 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2012 Wind River Systems and others.
+ * Copyright (c) 2006, 2013 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
@@ -10,6 +10,7 @@
* Ericsson AB - Modified for handling of multiple threads
* Indel AG - [369622] fixed moveToLine using MinGW
* Marc Khouzam (Ericsson) - Support for operations on multiple execution contexts (bug 330974)
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
@@ -25,6 +26,7 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
@@ -51,6 +53,7 @@ import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl;
import org.eclipse.cdt.dsf.debug.service.IRunControl2;
+import org.eclipse.cdt.dsf.debug.service.IRunControl3;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
@@ -59,6 +62,8 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlShutdownDMEvent;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.internal.service.command.events.MITracepointSelectedEvent;
+import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionActiveOperation;
+import org.eclipse.cdt.dsf.gdb.internal.service.control.StepIntoSelectionUtils;
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
@@ -87,7 +92,9 @@ import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadCreatedEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIThreadExitEvent;
import org.eclipse.cdt.dsf.mi.service.command.events.MIWatchpointTriggerEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIStackInfoDepthInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIThread;
import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadInfoInfo;
import org.eclipse.cdt.dsf.service.AbstractDsfService;
@@ -111,8 +118,11 @@ import org.osgi.framework.BundleContext;
* sync with the service state.
* @since 1.1
*/
-public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunControl, IMultiRunControl, ICachingService
-{
+public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunControl, IMultiRunControl, ICachingService, IRunControl3 {
+ // /////////////////////////////////////////////////////////////////////////
+ // CONSTANTS
+ // /////////////////////////////////////////////////////////////////////////
+
@Immutable
private static class ExecutionData implements IExecutionDMData2 {
private final StateChangeReason fReason;
@@ -295,6 +305,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
boolean fSuspended = false;
boolean fResumePending = false;
boolean fStepping = false;
+ RunControlEvent<IExecutionDMContext, ?> fLatestEvent = null;
/**
* What caused the state change. E.g., a signal was thrown.
@@ -336,7 +347,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
public boolean shouldSkipBreakpoints() { return fSkipBreakpoints; }
}
- ///////////////////////////////////////////////////////////////////////////
+ // /////////////////////////////////////////////////////////////////////////
// MIRunControlNS
///////////////////////////////////////////////////////////////////////////
@@ -350,6 +361,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
protected Map<IMIExecutionDMContext, MIThreadRunState> fThreadRunStates = new HashMap<IMIExecutionDMContext, MIThreadRunState>();
private RunToLineActiveOperation fRunToLineActiveOperation = null;
+
+ private StepIntoSelectionActiveOperation fStepInToSelectionActiveOperation = null;
/** @since 4.0 */
protected RunToLineActiveOperation getRunToLineActiveOperation() {
@@ -404,7 +417,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
register(new String[]{ IRunControl.class.getName(),
IRunControl2.class.getName(),
IMIRunControl.class.getName(),
- IMultiRunControl.class.getName() },
+ IMultiRunControl.class.getName(),
+ IRunControl3.class.getName()},
new Hashtable<String,String>());
fConnection = getServicesTracker().getService(ICommandControlService.class);
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
@@ -712,6 +726,10 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
@Override
public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
+ step(context, stepType, true, rm);
+ }
+
+ private void step(IExecutionDMContext context, StepType stepType, boolean checkCanResume, final RequestMonitor rm) {
assert context != null;
@@ -722,9 +740,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
return;
}
- if (!doCanResume(dmc)) {
- rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE,
- "Cannot resume context", null)); //$NON-NLS-1$
+ if (checkCanResume && !doCanResume(dmc)) {
+ rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
return;
}
@@ -839,6 +856,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {bpId}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
+ fStepInToSelectionActiveOperation = null;
super.handleFailure();
}
@@ -849,9 +867,87 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
}
// ------------------------------------------------------------------------
- // Resume at location
+ // Step into Selection
// ------------------------------------------------------------------------
+ private void stepIntoSelection(final IExecutionDMContext context, final int baseLine, final String baseLineLocation, final boolean skipBreakpoints, final IFunctionDeclaration targetFunction,
+ final RequestMonitor rm) {
+
+ assert context != null;
+
+ final IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
+ if (dmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Given context: " + context + " is not an MI execution context.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ if (!doCanResume(dmc)) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ MIThreadRunState threadState = fThreadRunStates.get(dmc);
+ if (threadState == null) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " can't be found.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ if (threadState.fLatestEvent == null || !(threadState.fLatestEvent instanceof SuspendedEvent)) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given context: " + context + " invalid suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ SuspendedEvent suspendedEvent = (SuspendedEvent) threadState.fLatestEvent;
+ final MIFrame currentFrame = suspendedEvent.getMIEvent().getFrame();
+ if (currentFrame == null) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Given event: " + suspendedEvent + " invalid frame in suspended event.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ rm.done();
+ return;
+ }
+
+ getStackDepth(dmc, new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ public void handleSuccess() {
+ if (getData() != null) {
+ final int framesSize = getData().intValue();
+
+ // make sure the operation is removed upon
+ // failure detection
+ final RequestMonitor rms = new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ fStepInToSelectionActiveOperation = null;
+ super.handleFailure();
+ }
+ };
+ if ((currentFrame.getFile() + ":" + currentFrame.getLine()).endsWith(baseLineLocation)) { //$NON-NLS-1$
+ // Save the step into selection information
+ fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize,
+ currentFrame);
+ // Ready to step into a function selected
+ // within a current line
+ step(dmc, StepType.STEP_INTO, rms);
+ } else {
+ // Save the step into selection information
+ fStepInToSelectionActiveOperation = new StepIntoSelectionActiveOperation(dmc, baseLine, targetFunction, framesSize, null);
+ // Pointing to a line different than the current line
+ // Needs to RunToLine before stepping to the selection
+ runToLocation(dmc, baseLineLocation, skipBreakpoints, rms);
+ }
+ } else {
+ rm.done();
+ }
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Resume at location
+ // ------------------------------------------------------------------------
private void resumeAtLocation(IExecutionDMContext context, String location, RequestMonitor rm) {
assert context != null;
@@ -958,6 +1054,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
threadState.fStateChangeReason = reason;
threadState.fStateChangeDetails = null; // we have no details of interest for a resume
threadState.fStepping = isStepping;
+ threadState.fLatestEvent = event;
}
private void updateThreadState(IMIExecutionDMContext context, SuspendedEvent event) {
@@ -971,7 +1068,8 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
threadState.fResumePending = false;
threadState.fStepping = false;
threadState.fStateChangeReason = reason;
- threadState.fStateChangeDetails = event.getDetails();
+ threadState.fStateChangeDetails = event.getDetails();
+ threadState.fLatestEvent = event;
}
/* ******************************************************************************
@@ -1439,89 +1537,225 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
*/
@DsfServiceEventHandler
public void eventDispatched(final MIStoppedEvent e) {
- if (fRunToLineActiveOperation != null) {
- // First check if it is the right thread that stopped
- IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
- if (fRunToLineActiveOperation.getThreadContext().equals(threadDmc)) {
- int bpId = 0;
- if (e instanceof MIBreakpointHitEvent) {
- bpId = ((MIBreakpointHitEvent)e).getNumber();
- }
- String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$
- String addrLocation = e.getFrame().getAddress();
- // Here we check three different things to see if we are stopped at the right place
- // 1- The actual location in the file. But this does not work for breakpoints that
- // were set on non-executable lines
- // 2- The address where the breakpoint was set. But this does not work for breakpoints
- // that have multiple addresses (GDB returns <MULTIPLE>.) I think that is for multi-process
- // 3- The breakpoint id that was hit. But this does not work if another breakpoint
- // was also set on the same line because GDB may return that breakpoint as being hit.
- //
- // So this works for the large majority of cases. The case that won't work is when the user
- // does a runToLine to a line that is non-executable AND has another breakpoint AND
- // has multiple addresses for the breakpoint. I'm mean, come on!
- if (fileLocation.equals(fRunToLineActiveOperation.getFileLocation()) ||
- addrLocation.equals(fRunToLineActiveOperation.getAddrLocation()) ||
- bpId == fRunToLineActiveOperation.getBreakointId()) {
- // We stopped at the right place. All is well.
- fRunToLineActiveOperation = null;
- } else {
- // The right thread stopped but not at the right place yet
- if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
- fConnection.queueCommand(
- fCommandFactory.createMIExecContinue(fRunToLineActiveOperation.getThreadContext()),
- new DataRequestMonitor<MIInfo>(getExecutor(), null));
-
- // Don't send the stop event since we are resuming again.
- return;
- } else {
- // Stopped for any other reasons. Just remove our temporary one
- // since we don't want it to hit later
- //
- // Note that in Non-stop, we don't cancel a run-to-line when a new
- // breakpoint is inserted. This is because the new breakpoint could
- // be for another thread altogether and should not affect the current thread.
- IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(),
- IBreakpointsTargetDMContext.class);
-
- fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {fRunToLineActiveOperation.getBreakointId()}),
- new DataRequestMonitor<MIInfo>(getExecutor(), null));
- fRunToLineActiveOperation = null;
- }
- }
- }
- }
-
+ if (processRunToLineStoppedEvent(e)) {
+ // If RunToLine is not completed
+ return;
+ }
+
+ if (!processStepIntoSelection(e)) {
+ //Step into Selection is not in progress
+ broadcastStop(e);
+ }
+ }
+
+ private void broadcastStop(final MIStoppedEvent e) {
IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
- if (e instanceof MISignalEvent && fDisableNextSignalEventDmcSet.remove(threadDmc)) {
+ if (e instanceof MISignalEvent && fDisableNextSignalEventDmcSet.remove(threadDmc)) {
fSilencedSignalEventMap.put(threadDmc, e);
-
// Don't broadcast the stopped event
return;
}
+
+ IDMEvent<?> event = null;
+ MIBreakpointDMContext bp = null;
+ if (e instanceof MIBreakpointHitEvent) {
+ int bpId = ((MIBreakpointHitEvent) e).getNumber();
+ IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class);
+ if (bpsTarget != null && bpId >= 0) {
+ bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] { bpsTarget }, bpId);
+ event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent) e, bp);
+ }
+ }
+ if (event == null) {
+ event = new SuspendedEvent(e.getDMContext(), e);
+ }
+
+ getSession().dispatchEvent(event, getProperties());
+ }
+
+ private boolean processStepIntoSelection(final MIStoppedEvent e) {
+ if (fStepInToSelectionActiveOperation == null) {
+ return false;
+ }
- IDMEvent<?> event = null;
- MIBreakpointDMContext bp = null;
- if (e instanceof MIBreakpointHitEvent) {
- int bpId = ((MIBreakpointHitEvent)e).getNumber();
- IBreakpointsTargetDMContext bpsTarget = DMContexts.getAncestorOfType(e.getDMContext(), IBreakpointsTargetDMContext.class);
- if (bpsTarget != null && bpId >= 0) {
- bp = new MIBreakpointDMContext(getSession().getId(), new IDMContext[] {bpsTarget}, bpId);
- event = new BreakpointHitEvent(e.getDMContext(), (MIBreakpointHitEvent)e, bp);
- }
- }
- if (event == null) {
- event = new SuspendedEvent(e.getDMContext(), e);
- }
-
- getSession().dispatchEvent(event, getProperties());
+ // First check if it is the right thread that stopped
+ final IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
+ if (fStepInToSelectionActiveOperation.getThreadContext().equals(threadDmc)) {
+ final MIFrame frame = e.getFrame();
+
+ assert(fRunToLineActiveOperation == null);
+
+ if (fStepInToSelectionActiveOperation.getRunToLineFrame() == null) {
+ assert(fStepInToSelectionActiveOperation.getLine() == frame.getLine());
+ // Shall now be at the runToline location
+ fStepInToSelectionActiveOperation.setRunToLineFrame(frame);
+ }
+
+ // Step - Not at the right place just yet
+ // Initiate an async call chain parent
+ getStackDepth(threadDmc, new DataRequestMonitor<Integer>(getExecutor(), null) {
+ private int originalStackDepth = fStepInToSelectionActiveOperation.getOriginalStackDepth();
+
+ @Override
+ protected void handleSuccess() {
+ int frameDepth = getStackDepth();
+
+ if (frameDepth > originalStackDepth) {
+ //shall be true as this is using stepinto step type vs instruction stepinto
+ assert(frameDepth == originalStackDepth + 1);
+
+ // Check for a match
+ if (StepIntoSelectionUtils.sameSignature(frame, fStepInToSelectionActiveOperation)) {
+ // Hit !!
+ stopStepIntoSelection(e);
+ return;
+ }
+
+ // Located deeper in the stack, Shall continue step / search
+ // Step return
+ continueStepping(e, StepType.STEP_RETURN);
+ } else if (frameDepth == originalStackDepth) {
+ // Continue step / search as long as
+ // this is the starting base line for the search
+ String currentLocation = frame.getFile() + ":" + frame.getLine(); //$NON-NLS-1$
+ String searchLineLocation = fStepInToSelectionActiveOperation.getFileLocation();
+ if (currentLocation.equals(searchLineLocation)) {
+ continueStepping(e, StepType.STEP_INTO);
+ } else {
+ // We have moved to a line
+ // different from the base
+ // search line i.e. missed the
+ // target function !!
+ StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation);
+ stopStepIntoSelection(e);
+ }
+ } else {
+ // missed the target point
+ StepIntoSelectionUtils.missedSelectedTarget(fStepInToSelectionActiveOperation);
+ }
+ }
+
+ @Override
+ protected void handleFailure() {
+ // log error
+ if (getStatus() != null) {
+ GdbPlugin.getDefault().getLog().log(getStatus());
+ }
+
+ stopStepIntoSelection(e);
+ }
+
+ private int getStackDepth() {
+ Integer stackDepth = null;
+ if (isSuccess() && getData() != null) {
+ stackDepth = getData();
+ // This is the base frame, the original stack depth shall be updated
+ if (frame == fStepInToSelectionActiveOperation.getRunToLineFrame()) {
+ fStepInToSelectionActiveOperation.setOriginalStackDepth(stackDepth);
+ originalStackDepth = stackDepth;
+ }
+ }
+
+ if (stackDepth == null) {
+ // Unsuccessful resolution of stack depth, default to same stack depth to detect a change of line within the original frame
+ return fStepInToSelectionActiveOperation.getOriginalStackDepth();
+ }
+
+ return stackDepth.intValue();
+ }
+ });
+
+ //Processing step into selection
+ return true;
+ }
+
+ //The thread related to this event is outside the scope of the step into selection context
+ return false;
}
+ private void stopStepIntoSelection(final MIStoppedEvent e) {
+ fStepInToSelectionActiveOperation = null;
+ // Need to broadcast the stop
+ broadcastStop(e);
+ }
- /**
- * @nooverride This method is not intended to be re-implemented or extended by clients.
- * @noreference This method is not intended to be referenced by clients.
- */
+ private void continueStepping(final MIStoppedEvent event, StepType steptype) {
+ step(fStepInToSelectionActiveOperation.getThreadContext(), steptype, false, new RequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleFailure() {
+ // log error
+ if (getStatus() != null) {
+ GdbPlugin.getDefault().getLog().log(getStatus());
+ }
+
+ stopStepIntoSelection(event);
+ }
+ });
+ }
+
+ private boolean processRunToLineStoppedEvent(final MIStoppedEvent e) {
+ if (fRunToLineActiveOperation == null) {
+ return false;
+ }
+
+ // First check if it is the right thread that stopped
+ IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(e.getDMContext(), IMIExecutionDMContext.class);
+ if (fRunToLineActiveOperation.getThreadContext().equals(threadDmc)) {
+ int bpId = 0;
+ if (e instanceof MIBreakpointHitEvent) {
+ bpId = ((MIBreakpointHitEvent) e).getNumber();
+ }
+
+ String fileLocation = e.getFrame().getFile() + ":" + e.getFrame().getLine(); //$NON-NLS-1$
+ String addrLocation = e.getFrame().getAddress();
+
+ // Here we check three different things to see if we are stopped at the right place
+ // 1- The actual location in the file. But this does not work for breakpoints that
+ // were set on non-executable lines
+ // 2- The address where the breakpoint was set. But this does not work for breakpoints
+ // that have multiple addresses (GDB returns <MULTIPLE>.) I think that is for multi-process
+ // 3- The breakpoint id that was hit. But this does not work if another breakpoint
+ // was also set on the same line because GDB may return that breakpoint as being hit.
+ //
+ // So this works for the large majority of cases. The case that won't work is when the user
+ // does a runToLine to a line that is non-executable AND has another breakpoint AND
+ // has multiple addresses for the breakpoint. I'm mean, come on!
+ if (fileLocation.equals(fRunToLineActiveOperation.getFileLocation()) || addrLocation.equals(fRunToLineActiveOperation.getAddrLocation())
+ || bpId == fRunToLineActiveOperation.getBreakointId()) {
+ // We stopped at the right place. All is well.
+ // Run to line completed
+ fRunToLineActiveOperation = null;
+ } else {
+ // The right thread stopped but not at the right place yet
+ if (fRunToLineActiveOperation.shouldSkipBreakpoints() && e instanceof MIBreakpointHitEvent) {
+ fConnection.queueCommand(fCommandFactory.createMIExecContinue(fRunToLineActiveOperation.getThreadContext()), new DataRequestMonitor<MIInfo>(getExecutor(), null));
+
+ // Continue i.e. Don't send the stop event since we are
+ // resuming again.
+ return true;
+ } else {
+ // Stopped for any other reasons. Just remove our temporary one
+ // since we don't want it to hit later
+ //
+ // Note that in Non-stop, we don't cancel a run-to-line when a new
+ // breakpoint is inserted. This is because the new breakpoint could
+ // be for another thread altogether and should not affect the current thread.
+ IBreakpointsTargetDMContext bpDmc = DMContexts.getAncestorOfType(fRunToLineActiveOperation.getThreadContext(), IBreakpointsTargetDMContext.class);
+
+ fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] { fRunToLineActiveOperation.getBreakointId() }), new DataRequestMonitor<MIInfo>(getExecutor(), null));
+ fRunToLineActiveOperation = null;
+ fStepInToSelectionActiveOperation = null;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @nooverride This method is not intended to be re-implemented or extended by clients.
+ * @noreference This method is not intended to be referenced by clients.
+ */
@DsfServiceEventHandler
public void eventDispatched(final MIThreadCreatedEvent e) {
IContainerDMContext containerDmc = e.getDMContext();
@@ -1620,6 +1854,7 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
+ fStepInToSelectionActiveOperation = null;
}
/**
@@ -2209,4 +2444,46 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
}
return execDmcForOperationList;
}
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) {
+ canStep(context, StepType.STEP_INTO, rm);
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void stepIntoSelection(final IExecutionDMContext context, String sourceFile, final int lineNumber, final boolean skipBreakpoints, final IFunctionDeclaration selectedFunction, final RequestMonitor rm) {
+ determineDebuggerPath(context, sourceFile, new ImmediateDataRequestMonitor<String>(rm) {
+ @Override
+ protected void handleSuccess() {
+ stepIntoSelection(context, lineNumber, getData() + ":" + Integer.toString(lineNumber), skipBreakpoints, selectedFunction, rm); //$NON-NLS-1$
+ }
+ });
+ }
+
+ /**
+ * Help method used when the stopped event has not been broadcasted e.g. in the middle of step into selection
+ *
+ * @param dmc
+ * @param rm
+ */
+ private void getStackDepth(final IMIExecutionDMContext dmc, final DataRequestMonitor<Integer> rm) {
+ if (dmc != null) {
+ fConnection.queueCommand(fCommandFactory.createMIStackInfoDepth(dmc), new DataRequestMonitor<MIStackInfoDepthInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData().getDepth());
+ rm.done();
+ }
+ });
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java
index de72f05ae9b..e5cc1412f58 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIRunControl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2012 Wind River Systems and others.
+ * Copyright (c) 2006, 2013 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
@@ -11,6 +11,7 @@
* Vladimir Prus (Mentor Graphics) - Add proper stop reason for step return (Bug 362274)
* Indel AG - [369622] fixed moveToLine using MinGW
* Marc Khouzam (Ericsson) - Make each thread an IDisassemblyDMContext (bug 352748)
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
@@ -19,6 +20,7 @@ import java.util.LinkedList;
import java.util.Map;
import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
@@ -41,6 +43,7 @@ import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension.IBreakpointHitDME
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext;
import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRunControl3;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
@@ -96,7 +99,7 @@ import org.osgi.framework.BundleContext;
* state.
* @since 3.0
*/
-public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService
+public class MIRunControl extends AbstractDsfService implements IMIRunControl, ICachingService, IRunControl3
{
private static class MIExecutionDMC extends AbstractDMContext implements IMIExecutionDMContext, IDisassemblyDMContext
{
@@ -375,6 +378,10 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
private boolean fResumePending = false;
private boolean fStepping = false;
private boolean fTerminated = false;
+ /**
+ * @since 4.2
+ */
+ protected RunControlEvent<IExecutionDMContext, ?> fLatestEvent = null;
/**
@@ -411,7 +418,7 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
super(session);
}
- @Override
+ @Override
public void initialize(final RequestMonitor rm) {
super.initialize(
new ImmediateRequestMonitor(rm) {
@@ -593,6 +600,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
fStateChangeReason = e.getReason();
fStateChangeDetails = null; // we have no details of interest for a resume
fMICommandCache.setContextAvailable(e.getDMContext(), false);
+ fLatestEvent = e;
+
//fStateChangeTriggeringContext = e.getTriggeringContext();
if (e.getReason().equals(StateChangeReason.STEP)) {
fStepping = true;
@@ -615,7 +624,8 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
? e.getTriggeringContexts()[0] : null;
fSuspended = true;
fStepping = false;
-
+ fLatestEvent = e;
+
fResumePending = false;
}
@@ -780,7 +790,14 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
}
@Override
- public void step(final IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
+ public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
+ step(context, stepType, true, rm);
+ }
+
+ /**
+ * @since 4.2
+ */
+ protected void step(final IExecutionDMContext context, StepType stepType, boolean checkCanResume, final RequestMonitor rm) {
assert context != null;
IMIExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IMIExecutionDMContext.class);
@@ -790,7 +807,7 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
return;
}
- if (!doCanResume(context)) {
+ if (checkCanResume && !doCanResume(context)) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_STATE, "Cannot resume context", null)); //$NON-NLS-1$
rm.done();
return;
@@ -1594,8 +1611,9 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
* @param dmc A context that can be used to obtain the sourcelookup context.
* @param hostPath The path of the file on the host, which must be converted.
* @param rm The result of the conversion.
+ * @since 4.2
*/
- private void determineDebuggerPath(IDMContext dmc, String hostPath, final DataRequestMonitor<String> rm)
+ protected void determineDebuggerPath(IDMContext dmc, String hostPath, final DataRequestMonitor<String> rm)
{
ISourceLookup sourceLookup = getServicesTracker().getService(ISourceLookup.class);
ISourceLookupDMContext srcDmc = DMContexts.getAncestorOfType(dmc, ISourceLookupDMContext.class);
@@ -1615,4 +1633,22 @@ public class MIRunControl extends AbstractDsfService implements IMIRunControl, I
}
});
}
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm) {
+ rm.done(false);
+ }
+
+ /**
+ * @since 4.2
+ */
+ @Override
+ public void stepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber, boolean skipBreakpoints, IFunctionDeclaration selectedFunction, RequestMonitor rm) {
+ IStatus status = new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Step Into Selection not supported", null); //$NON-NLS-1$
+ rm.done(status);
+ }
+
}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc
new file mode 100644
index 00000000000..7e98cbf6be9
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Artifact.cc
@@ -0,0 +1,49 @@
+
+using namespace std;
+
+#include<string>
+//#include<>
+
+//The 'Component' node
+class Artifact {
+public:
+ Artifact(string name) {
+ fName = name;
+ fParent = NULL;
+ }
+
+ //Exercising Polymorphysm
+ virtual void print() = 0;
+ virtual string toString() = 0;
+ virtual void print(char& padc) = 0;
+ virtual string toString(char& padc) = 0;
+
+ string getName() {
+ return fName;
+ }
+
+ string getLocation() {
+ return fPath + "/" + fName;
+ }
+
+ virtual void setParent(Artifact &parent) {
+ fPath = parent.getLocation();
+ fParent = &parent;
+ }
+
+ void deleteParent() {
+ fPath = "";
+ fParent = NULL;
+ }
+
+ virtual ~Artifact() {
+ }
+
+protected:
+ string fName;
+ string fPath;
+ Artifact* fParent;
+
+private:
+ Artifact();
+};
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc
new file mode 100644
index 00000000000..dae86028134
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Composite.cc
@@ -0,0 +1,210 @@
+/*
+ * Composite Pattern
+ */
+#include<iostream>
+#include<string>
+#include<vector>
+#include "Leaf.cc"
+
+using namespace std;
+
+//The 'Composite' node
+class CompositeNode: public Artifact {
+public:
+ CompositeNode(string name) :
+ Artifact(name) {
+ }
+
+ void Add(Artifact* child) {
+ child->setParent(*this);
+ fChildren.push_back(child);
+ }
+
+ void setParent(Artifact &parent) {
+ fPath = parent.getLocation();
+ fParent = &parent;
+
+ //Refresh the parent information path to all children
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ Artifact* child = *it;
+ child->setParent(*this);
+ ++it;
+ }
+ }
+
+ void Remove(Artifact* child) {
+ child->deleteParent();
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ if (*it == child) {
+ delete child;
+ fChildren.erase(it);
+ break;
+ }
+ ++it;
+ }
+
+ }
+
+ void print() {
+ cout << getLocation() << endl;
+
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ (*it)->print();
+ ++it;
+ }
+ }
+
+ void print(char& cpad) {
+ string padding(fPath.length(), cpad);
+ cout << padding << "+ " << fName << endl;
+
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ (*it)->print(cpad);
+ ++it;
+ }
+ }
+
+ string toString() {
+ string strAccumulator(getLocation() + "\n");
+
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ strAccumulator.append((*it)->toString());
+ ++it;
+ }
+
+ return strAccumulator;
+ }
+
+ string toString(char& cpad) {
+ string strAccumulation(fPath.length(), cpad);
+ strAccumulation.append("+ " + fName + "\n");
+
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ strAccumulation.append((*it)->toString(cpad));
+ ++it;
+ }
+
+ return strAccumulation;
+ }
+
+ virtual int getArtifactsSize() {
+ return fChildren.size();
+ }
+
+ virtual Artifact* getArtifact(int index) {
+ if (index < fChildren.size()) {
+ return fChildren.at(index);
+ }
+
+ else
+ return 0;
+ }
+
+ virtual Artifact* getArtifact(string description) {
+ vector<Artifact*>::iterator it = fChildren.begin();
+ while (it != fChildren.end()) {
+ if ((*it)->getName().compare(description)) {
+ return *it;
+ }
+ ++it;
+ }
+
+ return 0;
+ }
+
+ virtual ~CompositeNode() {
+ while (!fChildren.empty()) {
+ vector<Artifact*>::iterator it = fChildren.begin();
+ delete *it;
+ fChildren.erase(it);
+ }
+ }
+
+private:
+ CompositeNode();
+ vector<Artifact*> fChildren;
+};
+
+//The Main method
+int main() {
+ //Create a tree root
+ CompositeNode* root = new CompositeNode("Dogs");
+
+ //Create composite nodes
+ CompositeNode* comp = new CompositeNode("Companion");
+ comp->Add(new LeafNode("Puddle"));
+ comp->Add(new LeafNode("Bichon"));
+
+ CompositeNode* sport = new CompositeNode("Guardian");
+ sport->Add(new LeafNode("Boxer"));
+ sport->Add(new LeafNode("Rottweiler"));
+ sport->Add(new LeafNode("Mastiff"));
+
+ //Create a Branch
+ CompositeNode* gun = new CompositeNode("Gun");
+ gun->Add(new LeafNode("Cocker"));
+ gun->Add(new LeafNode("Pointer"));
+ gun->Add(new LeafNode("Golden Retriever"));
+
+ CompositeNode* herd = new CompositeNode("Herding");
+ herd->Add(new LeafNode("Cattle dog"));
+ herd->Add(new LeafNode("Sheepdog"));
+
+ CompositeNode* north = new CompositeNode("Northern");
+ north->Add(new LeafNode("Akita"));
+ north->Add(new LeafNode("Chow Chow"));
+
+ CompositeNode* hound = new CompositeNode("Hound");
+ hound->Add(new LeafNode("Basset Hound"));
+ hound->Add(new LeafNode("Beagle"));
+
+ CompositeNode* terrier = new CompositeNode("Terrier");
+ terrier->Add(new LeafNode("Bull Terrier"));
+ terrier->Add(new LeafNode("Border Terrier"));
+
+ //Create some leaf nodes
+ LeafNode* pe1 = new LeafNode("German Shepperd");
+ LeafNode* pe2 = new LeafNode("Great Dane");
+
+ //Add nodes to start from the same root
+ root->Add(comp);
+ root->Add(sport);
+ root->Add(gun);
+ root->Add(herd);
+ root->Add(north);
+ root->Add(hound);
+ root->Add(terrier);
+ //Add leaf nodes to root
+ root->Add(pe1);
+ root->Add(pe2);
+
+ char cpad = '-';
+ char cpad2 = '_';
+ //Test stub + toString variants
+ if (root->getArtifactsSize() > 0
+ && (root->getArtifact(0) != 0 && (root->getArtifact("Bichon") != 0))) {
+ string sout = root->getArtifact(0)->toString() + "\n" + root->getArtifact(1)->toString(cpad2);
+ cout << sout << endl;
+ }
+
+ //Test Remove primitive elements
+ root->Remove(pe1);
+ root->Remove(pe2);
+
+ //Test Print variants
+ root->getArtifact(2)->print(); root->getArtifact(3)->print(cpad);
+
+ //Test toString all
+ cout << "\n\nAll Tree\n" + root->toString(cpad);
+
+ //delete the allocated memory
+ delete root;
+
+ return 0;
+}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc
new file mode 100644
index 00000000000..bc53da4ef34
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/Leaf.cc
@@ -0,0 +1,38 @@
+#include<iostream>
+#include<string>
+#include "Artifact.cc"
+
+
+//The 'Leaf' class
+class LeafNode: public Artifact {
+public:
+ LeafNode(string name) :
+ Artifact(name) {
+ }
+
+ void print() {
+ cout << getLocation() << endl;
+ }
+
+ void print(char& cpad) {
+ string padding(fPath.length(), cpad);
+ cout << padding << " " << fName << endl;
+ }
+
+
+ string toString() {
+ return getLocation() + "\n";
+ }
+
+ string toString(char& cpad) {
+ string padding(fPath.length(), cpad);
+ string rstr = padding + " " + fName + "\n";
+ return rstr;
+ }
+
+ virtual ~LeafNode() {
+ }
+
+private:
+ LeafNode();
+};
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java
index be375f9c9c1..b64c80f21f8 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/framework/ServiceEventWaitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2012 Ericsson and others.
+ * Copyright (c) 2007, 2013 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
@@ -8,6 +8,7 @@
* Contributors:
* Ericsson - Initial Implementation
* Marc Khouzam (Ericsson) - Add support to receive multiple events
+ * Alvaro Sanchez-Leon (Ericsson) - Add filter out and wait for a given type of event
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.framework;
@@ -94,6 +95,30 @@ public class ServiceEventWaitor<V> {
}
}
+ /**
+ * Will wait and discard events that are not either of the specified type or a subtype
+ * It will stop and return the first one found or exit after the specified timeout
+ *
+ * @param type - The parent type of an acceptable event
+ * @param timeout the maximum time to wait in milliseconds to wait for a specified event
+ */
+ @SuppressWarnings("unchecked")
+ public synchronized <T extends V> T waitForEvent(Class<T> type, int timeout) throws Exception {
+ long startMs = System.currentTimeMillis();
+ //The Specified Event received or Timeout exception will exit the loop
+ while (true) {
+ int timeRemaining = (int) (timeout - (System.currentTimeMillis() - startMs));
+ if (timeRemaining > 0) {
+ V sevent = waitForEvent(timeRemaining);
+ if (type.isAssignableFrom(sevent.getClass())) {
+ return (T) sevent;
+ }
+ } else {
+ throw new Exception("Timed out waiting for ServiceEvent: " + type.getName());
+ }
+ }
+ }
+
/*
* Block until 'timeout' or the expected event occurs. The expected event is
* specified at construction time.
@@ -163,7 +188,10 @@ public class ServiceEventWaitor<V> {
}
}
- return fEventQueue.remove(0);
+ V vevent = fEventQueue.remove(0);
+
+
+ return vevent;
}
/*
@@ -177,6 +205,8 @@ public class ServiceEventWaitor<V> {
fEventQueue.add(event);
notifyAll();
}
+ } else {
+ System.out.println("NOT QUEUEING: SevericeEventWaitor: Class: " + fEventTypeClass.getName() + " is NOT assignable from event class: " + event.getClass());
}
}
}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java
index 5b00c8877b2..2497c8243a8 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/AllTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2011 Ericsson and others.
+ * Copyright (c) 2009, 2013 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
@@ -40,6 +40,7 @@ import org.junit.runners.Suite;
PostMortemCoreTest.class,
CommandTimeoutTest.class,
Suite_Sessionless_Tests.class,
+ StepIntoSelectionTest.class,
/* Add your suite class here */
})
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java
new file mode 100644
index 00000000000..92a5cf2a1df
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/StepIntoSelectionTest.java
@@ -0,0 +1,395 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.gdb.tests;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import javax.naming.OperationNotSupportedException;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext;
+import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl3;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
+import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
+import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
+import org.eclipse.cdt.dsf.mi.service.MIProcesses;
+import org.eclipse.cdt.dsf.mi.service.command.events.MILocationReachedEvent;
+import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
+import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.internal.core.model.FunctionDeclaration;
+import org.eclipse.cdt.tests.dsf.gdb.framework.AsyncCompletionWaitor;
+import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
+import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase;
+import org.eclipse.cdt.tests.dsf.gdb.framework.ServiceEventWaitor;
+import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
+import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests Non Stop GDB RunControl "Step into Selection feature"
+ *
+ */
+@SuppressWarnings("restriction")
+@RunWith(BackgroundRunner.class)
+public class StepIntoSelectionTest extends BaseTestCase {
+
+ private DsfServicesTracker fServicesTracker;
+
+ private IGDBControl fGDBCtrl;
+ private IRunControl3 fRunCtrl;
+
+ private IContainerDMContext fContainerDmc;
+ private IExecutionDMContext fThreadExecDmc;
+
+ /*
+ * Path to executable
+ */
+ private static final String EXEC_PATH = "data/launch/bin/";
+
+ /*
+ * Name of the executable
+ */
+ private static final String BIN_COMPOSITE = "Composite.exe";
+
+ // Composite Locations
+ private static final String SRC_COMPOSITE = "Composite.cc";
+ private static final int COMPOSITE_GETARTIFACTSIZE_LINE_1 = 97;
+ private static final int COMPOSITE_GETARTIFACT_LINE_1 = 101;
+ private static final int COMPOSITE_MAIN_LINE_S5 = 89;
+ private static final int COMPOSITE_MAIN_LINE_M1 = 190;
+ private static final int COMPOSITE_MAIN_LINE_M2 = 191;
+ private static final int COMPOSITE_MAIN_LINE_L1 = 192;
+ private static final int COMPOSITE_MAIN_LINE_L2 = 197;
+ private static final int COMPOSITE_MAIN_LINE_L3 = 201;
+ private static final int COMPOSITE_MAIN_LINE_L4 = 204;
+ private static final int COMPOSITE_TOSTRING_LINE_1 = 72;
+ private static final int COMPOSITE_TOSTRING_C_LINE_1 = 84;
+ private static final String COMPOSITE_GETARTIFACTSIZE = "getArtifactsSize";
+ private static final String COMPOSITE_GETARTIFACT = "getArtifact";
+ private static final String COMPOSITE_TOSTRING = "toString";
+
+ // Artifact Locations
+ private static final String ARTIFACT_GETLOCATION = "getLocation";
+ private static final int ARTIFACT_GETLOCATION_LINE_1 = 26;
+
+ // Leaf Locations
+ private static final String SRC_LEAF = "Leaf.cc";
+ private static final int LEAF_PRINT_LINE_1 = 14;
+
+ //Target Functions
+ private final static FunctionDeclaration funcCompGetArtifactSize = new FunctionDeclaration(null, COMPOSITE_GETARTIFACTSIZE);
+ private final static FunctionDeclaration funcCompGetArtifact_i = new FunctionDeclaration(null, COMPOSITE_GETARTIFACT);
+ private final static FunctionDeclaration funcArtifactGetLocation = new FunctionDeclaration(null, ARTIFACT_GETLOCATION);
+ private final static FunctionDeclaration funcCompToString = new FunctionDeclaration(null, COMPOSITE_TOSTRING);
+ private final static FunctionDeclaration funcCompToString_c = new FunctionDeclaration(null, COMPOSITE_TOSTRING);
+
+ static {
+ funcCompGetArtifact_i.setParameterTypes(new String[]{"int"});
+ funcCompToString_c.setParameterTypes(new String[]{"Char&"});
+ }
+
+ class ResultContext {
+ MIStoppedEvent fEvent = null;
+ IExecutionDMContext fContext = null;
+
+ public ResultContext(MIStoppedEvent event, IExecutionDMContext context) {
+ this.fEvent = event;
+ this.fContext = context;
+ }
+
+ public MIStoppedEvent getEvent() {
+ return fEvent;
+ }
+
+ public IExecutionDMContext getContext() {
+ return fContext;
+ }
+ }
+
+ @Override
+ public void doBeforeTest() throws Exception {
+ super.doBeforeTest();
+
+ final DsfSession session = getGDBLaunch().getSession();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), session.getId());
+ fGDBCtrl = fServicesTracker.getService(IGDBControl.class);
+
+ IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
+ IProcessDMContext procDmc = procService.createProcessContext(fGDBCtrl.getContext(), MIProcesses.UNIQUE_GROUP_ID);
+ fContainerDmc = procService.createContainerContext(procDmc, MIProcesses.UNIQUE_GROUP_ID);
+ IThreadDMContext threadDmc = procService.createThreadContext(procDmc, "1");
+ fThreadExecDmc = procService.createExecutionContext(fContainerDmc, threadDmc, "1");
+
+ fRunCtrl = fServicesTracker.getService(IRunControl3.class);
+ }
+ };
+ session.getExecutor().submit(runnable).get();
+ }
+
+ @Override
+ public void doAfterTest() throws Exception {
+ super.doAfterTest();
+
+ fServicesTracker.dispose();
+ }
+
+ @Override
+ protected void setLaunchAttributes() {
+ super.setLaunchAttributes();
+ setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + BIN_COMPOSITE);
+ setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
+ }
+
+ private IExecutionDMContext gdbRunToStartLine(String sourceName, int targetLine, ServiceEventWaitor<MIStoppedEvent> waitor) throws Throwable {
+ // run gdb to the specified line an resolve the execution context where the MI signal events are being processed
+ SyncUtil.runToLine(fThreadExecDmc, sourceName, Integer.toString(targetLine), true);
+ MILocationReachedEvent locEvent = waitor.waitForEvent(MILocationReachedEvent.class, TestsPlugin.massageTimeout(500));
+ return locEvent.getDMContext();
+ }
+
+ private MIStoppedEvent getLastEvent(ServiceEventWaitor<MIStoppedEvent> gdbStopListener) {
+ // Fetch the last stopped event as stepping into selection needs to step several times.
+ MIStoppedEvent event = null;
+ // Run until Timeout exception i.e. no more events in the queue
+ try {
+ while (true) {
+ // Wait or fetch the next stopped event in the queue
+ event = gdbStopListener.waitForEvent(MIStoppedEvent.class, TestsPlugin.massageTimeout(500));
+ }
+ } catch (Exception e) {
+ assertTrue("Exception: " + e.getMessage(), e.getMessage().contains("Timed out"));
+ }
+
+ return event;
+ }
+
+ private void validateLocation(IExecutionDMContext exeContext, MIFrame frame, String funcName) throws Throwable {
+ // Validate that the frame received is at the specified location
+ assertTrue(frame.getFunction().endsWith(funcName));
+
+ // Validate that GDB is in sync at the specified location
+ IFrameDMData gdbFrame = SyncUtil.getFrameData(exeContext, 0);
+ assertTrue(gdbFrame.getFunction().endsWith(funcName));
+ }
+
+ private void checkGdbIsSuspended() throws Throwable {
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+ final IContainerDMContext containerDmc = SyncUtil.getContainerContext();
+
+ // Execution shall be suspended
+ fRunCtrl.getExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ wait.setReturnInfo(fRunCtrl.isSuspended(containerDmc));
+ wait.waitFinished();
+ }
+ });
+
+ wait.waitUntilDone(TestsPlugin.massageTimeout(5000));
+ assertTrue("Target is running. It should have been suspended", (Boolean) wait.getReturnInfo());
+
+ wait.waitReset();
+ }
+
+ private void triggerRunToLine(final IExecutionDMContext exeContext, final String sourceName, final int targetLine) throws InterruptedException {
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+
+ fRunCtrl.getExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ fRunCtrl.runToLine(exeContext, sourceName, targetLine, true, new RequestMonitor(fRunCtrl.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ wait.waitFinished(getStatus());
+ }
+ });
+ }
+ });
+
+ wait.waitUntilDone(TestsPlugin.massageTimeout(10000));
+ wait.waitReset();
+ }
+
+ private void triggerStepIntoSelection(final IExecutionDMContext exeContext, final String sourceName, final int targetLine, final IFunctionDeclaration function, final boolean skipBreakPoints) throws InterruptedException {
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+ final OperationNotSupportedException[] exception = new OperationNotSupportedException[1];
+ // Trigger Stepping into a specified 'function' on the current line
+ fRunCtrl.getExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ fRunCtrl.stepIntoSelection(exeContext, sourceName, targetLine, skipBreakPoints, function, new RequestMonitor(fRunCtrl.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ wait.waitFinished(getStatus());
+ }
+ });
+ }
+ });
+
+ wait.waitUntilDone(TestsPlugin.massageTimeout(10000));
+ wait.waitReset();
+
+ if (exception[0] != null) {
+ fail("Step into selection failed: " + exception[0].getMessage());
+ }
+
+ }
+
+ private ResultContext runToLine(IExecutionDMContext exeContext, String sourceName, int runToLine) throws Throwable {
+ DsfSession session = getGDBLaunch().getSession();
+
+ ServiceEventWaitor<MIStoppedEvent> gdbStopListener = new ServiceEventWaitor<MIStoppedEvent>(session, MIStoppedEvent.class);
+
+ // Trigger Run to line
+ triggerRunToLine(exeContext, sourceName, runToLine);
+
+ // Fetch the last stopped event as stepping into selection needs to step several times.
+ MIStoppedEvent event = gdbStopListener.waitForEvent(MIStoppedEvent.class, TestsPlugin.massageTimeout(500));
+
+ assertNotNull(event);
+
+ // Validate that the last stopped frame received is at the specified location
+ MIFrame frame = event.getFrame();
+ assertTrue(frame.getLine() == runToLine);
+ return new ResultContext(event, exeContext);
+ }
+
+ private ResultContext stepIntoSelectionBase(String sourceName, int runToLine, IFunctionDeclaration targetFunction) throws Throwable {
+ return stepIntoSelectionBase(sourceName, runToLine, targetFunction, true, true, null);
+ }
+
+ private ResultContext stepIntoSelectionBase(String sourceName, int runToLine, IFunctionDeclaration targetFunction, boolean validateLocation, boolean skipBreakPoints, IExecutionDMContext dmc) throws Throwable {
+ DsfSession session = getGDBLaunch().getSession();
+
+ ServiceEventWaitor<MIStoppedEvent> gdbStopListener = new ServiceEventWaitor<MIStoppedEvent>(session, MIStoppedEvent.class);
+
+ final IExecutionDMContext exeContext;
+ if (dmc == null) {
+ exeContext = gdbRunToStartLine(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M1, gdbStopListener);
+ } else {
+ exeContext = dmc;
+ }
+
+ // Run to an initial line an resolve the execution context where the MI signal events are being processed
+ assertNotNull(exeContext);
+
+ // Trigger Stepping into a specified 'function' and several lines below the current one
+ triggerStepIntoSelection(exeContext, sourceName, runToLine, targetFunction, skipBreakPoints);
+
+ // Fetch the last stopped event as stepping into selection needs to step several times.
+ MIStoppedEvent event = getLastEvent(gdbStopListener);
+ assertNotNull(event);
+
+ // Validate that the last stopped frame received is at the specified location
+ MIFrame frame = event.getFrame();
+
+ if (validateLocation) {
+ validateLocation(exeContext, frame, targetFunction.getElementName());
+ }
+
+ checkGdbIsSuspended();
+
+ return new ResultContext(event, exeContext);
+ }
+
+ @Test
+ public void stepIntoSelection() throws Throwable {
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M1, funcCompGetArtifactSize);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_GETARTIFACTSIZE_LINE_1);
+ }
+
+ @Test
+ public void stepIntoSelectionWithRunToLine() throws Throwable {
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_M2, funcCompGetArtifact_i);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_GETARTIFACT_LINE_1);
+ }
+
+ @Test
+ public void withSelectedLineOnDifferentFile() throws Throwable {
+ ResultContext result = stepIntoSelectionBase(SRC_LEAF, LEAF_PRINT_LINE_1, funcArtifactGetLocation);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == ARTIFACT_GETLOCATION_LINE_1);
+ }
+
+ /**
+ * A break point is found before reaching search line
+ *
+ * @throws Throwable
+ */
+ @Test
+ public void doNotSkipBreakPoints() throws Throwable {
+ // insert a break point before the run to line
+ SyncUtil.addBreakpoint(SRC_COMPOSITE + ":" + COMPOSITE_MAIN_LINE_L2);
+ //trigger step into selection skip break points is set to false
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L4, funcCompToString_c, false, false, null);
+ MIStoppedEvent event = result.getEvent();
+ int currentLine = event.getFrame().getLine();
+ //validate location, it shall not reach the step to selection line but the break point line instead.
+ assertTrue(currentLine == COMPOSITE_MAIN_LINE_L2);
+ //Make sure the step to selection operation is no longer active by triggering a second run to line before the step into selection line
+ result = runToLine(result.getContext(), SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L3);
+ event = result.getEvent();
+ currentLine = event.getFrame().getLine();
+ //validate location, did not reached the step to selection line but the break point
+ assertTrue(currentLine == COMPOSITE_MAIN_LINE_L3);
+ }
+
+ @Test
+ public void diffMethodByArgsNumber() throws Throwable {
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L1, funcCompToString_c);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1); //first line of toString(char& c)
+ }
+
+ @Test
+ public void diffMethodByArgsNumber2() throws Throwable {
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L1, funcCompToString);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_TOSTRING_LINE_1); //first line of toString()
+ }
+
+ @Test
+ public void stepIntoRecursiveMethod() throws Throwable {
+ //Step to the recursive method
+ ResultContext result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_L4, funcCompToString_c);
+ int currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1);
+
+ //Move away from the first line of the method to validate a successful recursive return to this location
+ int offset = 3;
+ result = runToLine(result.getContext(), SRC_COMPOSITE, COMPOSITE_TOSTRING_C_LINE_1 + offset);
+ currentLine = result.getEvent().getFrame().getLine();
+ assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1 + offset);
+
+ //Step into selection to trigger the recursive call
+ result = stepIntoSelectionBase(SRC_COMPOSITE, COMPOSITE_MAIN_LINE_S5, funcCompToString_c, false, false, result.getContext());
+ currentLine = result.getEvent().getFrame().getLine();
+
+ //Assert going back to the top of the same function
+ assertTrue(currentLine == COMPOSITE_TOSTRING_C_LINE_1);
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java
new file mode 100644
index 00000000000..5095ab20b99
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/StepIntoSelectionTest_6_8.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.gdb.tests.tests_6_8;
+
+import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
+import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
+import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
+import org.eclipse.cdt.tests.dsf.gdb.tests.StepIntoSelectionTest;
+import org.junit.runner.RunWith;
+
+@RunWith(BackgroundRunner.class)
+public class StepIntoSelectionTest_6_8 extends StepIntoSelectionTest {
+ @Override
+ protected void setGdbVersion() {
+ setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_6_8);
+ }
+
+ @Override
+ protected void setLaunchAttributes() {
+ super.setLaunchAttributes();
+
+ setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, false);
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java
index a5b180b6d80..93330c6a4b9 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_6_8/Suite_6_8.java
@@ -44,6 +44,7 @@ import org.junit.runners.Suite;
PostMortemCoreTest_6_8.class,
CommandTimeoutTest_6_8.class,
Suite_Sessionless_Tests.class,
+ StepIntoSelectionTest_6_8.class,
/* Add your test class here */
})
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java
new file mode 100644
index 00000000000..737a015726a
--- /dev/null
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/StepIntoSelectionTest_7_0_NS.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2013 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:
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_0;
+
+import org.eclipse.cdt.dsf.gdb.IGDBLaunchConfigurationConstants;
+import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
+import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
+import org.eclipse.cdt.tests.dsf.gdb.tests.StepIntoSelectionTest;
+import org.junit.runner.RunWith;
+
+@RunWith(BackgroundRunner.class)
+public class StepIntoSelectionTest_7_0_NS extends StepIntoSelectionTest {
+ @Override
+ protected void setGdbVersion() {
+ setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_0);
+ }
+
+ @Override
+ protected void setLaunchAttributes() {
+ super.setLaunchAttributes();
+
+ setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, false);
+ }
+}
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java
index 7b332907ccb..602c08b397c 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/tests_7_0/Suite_7_0.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 Ericsson and others.
+ * Copyright (c) 2009, 2013 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
@@ -46,7 +46,9 @@ import org.junit.runners.Suite;
PostMortemCoreTest_7_0.class,
CommandTimeoutTest_7_0.class,
GDBMultiNonStopRunControlTest_7_0.class,
- Suite_Sessionless_Tests.class,
+ Suite_Sessionless_Tests.class,
+ StepIntoSelectionTest_7_0_NS.class,
+
/* Add your test class here */
})

Back to the top