summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraleon2013-04-30 11:59:16 (EDT)
committer Marc-Andre Laperle2013-04-30 14:26:00 (EDT)
commitbb755a01befd30c031965681aa8af8575bce52c5 (patch)
treef5b597f7cf5696b15c8e6481d8aa9586610a0605
parentcf3acef3f302dfc538ac0895ab90e421bc23df2c (diff)
downloadorg.eclipse.cdt-bb755a01befd30c031965681aa8af8575bce52c5.zip
org.eclipse.cdt-bb755a01befd30c031965681aa8af8575bce52c5.tar.gz
org.eclipse.cdt-bb755a01befd30c031965681aa8af8575bce52c5.tar.bz2
Bug 244865 – Support for Step Into Selectionrefs/changes/05/11305/13
First Implementation: * Non-stop as well as All-stop debugging * Function / Method name validation, arguments size validation (no arguments signature yet) * Ctrl-F5 as short key (consistent with JDT) * Hyper link support with Ctrl-Shift click * Junit Test (Services part) Change-Id: I58903b4b6b7f9fd39a827f5297ad23ac3f96186d Reviewed-on: https://git.eclipse.org/r/11305 Reviewed-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com> IP-Clean: Marc-Andre Laperle <marc-andre.laperle@ericsson.com> Tested-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java4
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties4
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SelectionToDeclarationJob.java431
-rw-r--r--debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IStepIntoSelectionHandler.java20
-rw-r--r--debug/org.eclipse.cdt.debug.ui/plugin.properties5
-rw-r--r--debug/org.eclipse.cdt.debug.ui/plugin.xml71
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/StepIntoSelectionCommandHandler.java22
-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
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF3
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/plugin.properties10
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/plugin.xml23
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/pom.xml2
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java4
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties5
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/sourcelookup/DsfSourceSelectionResolver.java226
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionCommand.java195
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionHyperlinkDetector.java239
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/IDsfStepIntoSelection.java36
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl3.java52
37 files changed, 3023 insertions, 117 deletions
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
index 5d0e53a..c17f8e9 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2010 QNX Software Systems and others.
+ * Copyright (c) 2000, 2013 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
* Tomasz Wesolowski
+ * Alvaro Sanchez-Leon (Ericsson AB)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
@@ -106,6 +107,7 @@ public final class CEditorMessages extends NLS {
public static String CEditor_markOccurrences_job_name;
public static String CEditor_index_expander_job_name;
public static String CEditorActionContributor_ExpandSelectionMenu_label;
+ public static String StepIntoSelection_unable_to_resolve_name;
static {
NLS.initializeMessages(CEditorMessages.class.getName(), CEditorMessages.class);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
index 62aa9c4..eeb64c7 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
@@ -1,5 +1,5 @@
#########################################
-# Copyright (c) 2005, 2012 IBM Corporation and others.
+# Copyright (c) 2005, 2013 IBM Corporation 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
@@ -13,6 +13,7 @@
# Sergey Prigogin (Google)
# Tomasz Wesolowski
# Mathias Kunter
+# Alvaro Sanchez-Leon (Ericsson)
#########################################
AddIncludeOnSelection_label=Add Include
@@ -105,3 +106,4 @@ SemanticHighlighting_externalSDK= External SDK calls
CEditor_markOccurrences_job_name= Occurrences Marker
CEditor_index_expander_job_name= Index Expander
CEditorActionContributor_ExpandSelectionMenu_label=E&xpand Selection To
+StepIntoSelection_unable_to_resolve_name=Unable to resolve the selection to a semantic object \ No newline at end of file
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SelectionToDeclarationJob.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SelectionToDeclarationJob.java
new file mode 100644
index 0000000..fc4abb4
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SelectionToDeclarationJob.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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.internal.ui.editor;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.Region;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.IName;
+import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IParameter;
+import org.eclipse.cdt.core.dom.ast.IProblemBinding;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.index.IIndexManager;
+import org.eclipse.cdt.core.index.IIndexName;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.parser.util.ArrayUtil;
+import org.eclipse.cdt.ui.CUIPlugin;
+
+import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+import org.eclipse.cdt.internal.core.index.IIndexFragmentName;
+import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
+import org.eclipse.cdt.internal.core.model.ext.CElementHandleFactory;
+import org.eclipse.cdt.internal.core.model.ext.ICElementHandle;
+
+import org.eclipse.cdt.internal.ui.ICStatusConstants;
+import org.eclipse.cdt.internal.ui.viewsupport.IndexUI;
+
+/**
+ * Based on class OpenDeclarationsJob
+ * @author Alvaro Sanchez-Leon
+ * @since 5.6
+ */
+public class SelectionToDeclarationJob extends Job implements ASTRunnable {
+ private enum NameKind {
+ REFERENCE, DECLARATION, USING_DECL, DEFINITION
+ }
+
+ private final ITranslationUnit fTranslationUnit;
+ private IIndex fIndex;
+ private final ITextSelection fTextSelection;
+ private IFunctionDeclaration[] fResolvedFunctions;
+
+ public SelectionToDeclarationJob(ITextEditor editor, ITextSelection textSelection) throws CoreException {
+ super(CEditorMessages.OpenDeclarations_dialog_title);
+
+ if (!(editor instanceof CEditor)) {
+ IStatus status = new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, ICStatusConstants.INTERNAL_ERROR, "Action not supportted outside the context of the C Editor", null); //$NON-NLS-1$
+ throw new CoreException(status);
+ }
+
+ fTranslationUnit = ((CEditor) editor).getInputCElement();
+ fTextSelection = textSelection;
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ return resolve(monitor);
+ } catch (CoreException e) {
+ return e.getStatus();
+ }
+ }
+
+ IStatus resolve(IProgressMonitor monitor) throws CoreException {
+ assert fIndex == null;
+ if (fIndex != null)
+ return Status.CANCEL_STATUS;
+
+ fIndex = CCorePlugin.getIndexManager()
+ .getIndex(fTranslationUnit.getCProject(), IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_DEPENDENT | IIndexManager.ADD_EXTENSION_FRAGMENTS_NAVIGATION);
+
+ try {
+ fIndex.acquireReadLock();
+ } catch (InterruptedException e) {
+ return Status.CANCEL_STATUS;
+ }
+
+ try {
+ return ASTProvider.getASTProvider().runOnAST(fTranslationUnit, ASTProvider.WAIT_NO, monitor, this);
+ } finally {
+ fIndex.releaseReadLock();
+ }
+ }
+
+ @Override
+ public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
+
+ // initialize to empty results
+ fResolvedFunctions = new IFunctionDeclaration[0];
+
+ if (ast == null) {
+ return Status.OK_STATUS;
+ }
+
+ int selectionStart = fTextSelection.getOffset();
+ int selectionLength = fTextSelection.getLength();
+
+ final IASTNodeSelector nodeSelector = ast.getNodeSelector(null);
+
+ IASTName sourceName = nodeSelector.findEnclosingName(selectionStart, selectionLength);
+ if (sourceName == null) {
+ IStatus status = new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, CEditorMessages.StepIntoSelection_unable_to_resolve_name);
+ throw new CoreException(status);
+ }
+
+ IName[] implicitTargets = findImplicitTargets(ast, nodeSelector, selectionStart, selectionLength);
+
+ NameKind kind = getNameKind(sourceName);
+ IBinding b = sourceName.resolveBinding();
+ IBinding[] bindings = new IBinding[] { b };
+ if (b instanceof IProblemBinding) {
+ IBinding[] candidateBindings = ((IProblemBinding) b).getCandidateBindings();
+ if (candidateBindings.length != 0) {
+ bindings = candidateBindings;
+ }
+ } else if (kind == NameKind.DEFINITION && b instanceof IType) {
+ // No resolution of type definitions.
+ return Status.OK_STATUS;
+ }
+
+ IName[] targets = IName.EMPTY_ARRAY;
+ String filename = ast.getFilePath();
+ for (IBinding binding : bindings) {
+ if (binding != null && !(binding instanceof IProblemBinding)) {
+ IName[] names = findDeclNames(ast, kind, binding);
+ for (final IName name : names) {
+ if (name != null) {
+ if (name instanceof IIndexName && filename.equals(((IIndexName) name).getFileLocation().getFileName())) {
+ // Exclude index names from the current file.
+ } else if (areOverlappingNames(name, sourceName)) {
+ // Exclude the current location.
+ } else if (binding instanceof IParameter) {
+ if (isInSameFunction(sourceName, name)) {
+ targets = ArrayUtil.append(targets, name);
+ }
+ } else if (binding instanceof ICPPTemplateParameter) {
+ if (isInSameTemplate(sourceName, name)) {
+ targets = ArrayUtil.append(targets, name);
+ }
+ } else {
+ targets = ArrayUtil.append(targets, name);
+ }
+ }
+ }
+ }
+ }
+
+ targets = ArrayUtil.trim(ArrayUtil.addAll(targets, implicitTargets));
+
+ final ArrayList<IFunctionDeclaration> functionElements = new ArrayList<IFunctionDeclaration>();
+ filterToFunctions(fTranslationUnit.getCProject(), fIndex, targets, functionElements);
+
+ // save the resolved function declarations
+ fResolvedFunctions = functionElements.toArray(new IFunctionDeclaration[functionElements.size()]);
+
+ return Status.OK_STATUS;
+ }
+
+ /**
+ * This is the method used to retrieve the results from this job
+ * @return The function(s) matching the selection
+ */
+ public IFunctionDeclaration[] getSelectedFunctions() {
+ return fResolvedFunctions;
+ }
+
+ private IName[] findDeclNames(IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException {
+ IName[] declNames = findNames(fIndex, ast, kind, binding);
+ // Bug 207320, handle template instances.
+ while (declNames.length == 0 && binding instanceof ICPPSpecialization) {
+ binding = ((ICPPSpecialization) binding).getSpecializedBinding();
+ if (binding != null && !(binding instanceof IProblemBinding)) {
+ declNames = findNames(fIndex, ast, NameKind.DEFINITION, binding);
+ }
+ }
+ if (declNames.length == 0 && binding instanceof ICPPMethod) {
+ // Bug 86829, handle implicit methods.
+ ICPPMethod method = (ICPPMethod) binding;
+ if (method.isImplicit()) {
+ IBinding clsBinding = method.getClassOwner();
+ if (clsBinding != null && !(clsBinding instanceof IProblemBinding)) {
+ declNames = findNames(fIndex, ast, NameKind.REFERENCE, clsBinding);
+ }
+ }
+ }
+ return declNames;
+ }
+
+ private IName[] findNames(IIndex index, IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException {
+ IName[] declNames;
+ if (kind == NameKind.DEFINITION) {
+ declNames = findDeclarations(index, ast, binding);
+ } else {
+ declNames = findDefinitions(index, ast, kind, binding);
+ }
+
+ if (declNames.length == 0) {
+ if (kind == NameKind.DEFINITION) {
+ declNames = findDefinitions(index, ast, kind, binding);
+ } else {
+ declNames = findDeclarations(index, ast, binding);
+ }
+ }
+ return declNames;
+ }
+
+ private IName[] findDefinitions(IIndex index, IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException {
+ List<IASTName> declNames = new ArrayList<IASTName>();
+ declNames.addAll(Arrays.asList(ast.getDefinitionsInAST(binding)));
+ for (Iterator<IASTName> i = declNames.iterator(); i.hasNext();) {
+ IASTName name = i.next();
+ final IBinding b2 = name.resolveBinding();
+ if (b2 instanceof ICPPUsingDeclaration) {
+ i.remove();
+ }
+ if (binding != b2 && binding instanceof ICPPSpecialization) {
+ // Make sure binding specializes b2 so that for instance we do
+ // not navigate from
+ // one partial specialization to another.
+ IBinding spec = binding;
+ while (spec instanceof ICPPSpecialization) {
+ spec = ((ICPPSpecialization) spec).getSpecializedBinding();
+ if (spec == b2)
+ break;
+ }
+ if (!(spec instanceof ICPPSpecialization)) {
+ i.remove();
+ }
+ }
+ }
+ if (!declNames.isEmpty()) {
+ return declNames.toArray(new IASTName[declNames.size()]);
+ }
+
+ // 2. Try definition in index.
+ return index.findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
+ }
+
+ private IName[] findDeclarations(IIndex index, IASTTranslationUnit ast, IBinding binding) throws CoreException {
+ IASTName[] astNames = ast.getDeclarationsInAST(binding);
+ ArrayList<IASTName> usingDeclarations = null;
+ for (int i = 0; i < astNames.length; i++) {
+ IASTName name = astNames[i];
+ if (name.isDefinition()) {
+ astNames[i] = null;
+ } else if (CPPVisitor.findAncestorWithType(name, ICPPASTUsingDeclaration.class) != null) {
+ if (usingDeclarations == null)
+ usingDeclarations = new ArrayList<IASTName>(1);
+ usingDeclarations.add(name);
+ astNames[i] = null;
+ }
+ }
+ IName[] declNames = ArrayUtil.removeNulls(astNames);
+ if (declNames.length == 0) {
+ declNames = index.findNames(binding, IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
+ }
+ // 'using' declarations are considered only when there are no other
+ // declarations.
+ if (declNames.length == 0 && usingDeclarations != null) {
+ declNames = usingDeclarations.toArray(new IName[usingDeclarations.size()]);
+ }
+ return declNames;
+ }
+
+ /**
+ * Returns definitions of bindings referenced by implicit name at the given location.
+ */
+ private IName[] findImplicitTargets(IASTTranslationUnit ast, IASTNodeSelector nodeSelector, int offset, int length) throws CoreException {
+ IName[] definitions = IName.EMPTY_ARRAY;
+ IASTName firstName = nodeSelector.findEnclosingImplicitName(offset, length);
+ if (firstName != null) {
+ IASTImplicitNameOwner owner = (IASTImplicitNameOwner) firstName.getParent();
+ for (IASTImplicitName name : owner.getImplicitNames()) {
+ if (((ASTNode) name).getOffset() == ((ASTNode) firstName).getOffset()) {
+ IBinding binding = name.resolveBinding(); // Guaranteed to
+ // resolve.
+ IName[] declNames = findDeclNames(ast, NameKind.REFERENCE, binding);
+ definitions = ArrayUtil.addAll(definitions, declNames);
+ }
+ }
+ }
+ return ArrayUtil.trim(definitions);
+ }
+
+ private static NameKind getNameKind(IName name) {
+ if (name.isDefinition()) {
+ if (getBinding(name) instanceof ICPPUsingDeclaration) {
+ return NameKind.USING_DECL;
+ } else {
+ return NameKind.DEFINITION;
+ }
+ } else if (name.isDeclaration()) {
+ return NameKind.DECLARATION;
+ }
+ return NameKind.REFERENCE;
+ }
+
+ private static IBinding getBinding(IName name) {
+ if (name instanceof IASTName) {
+ return ((IASTName) name).resolveBinding();
+ } else if (name instanceof IIndexFragmentName) {
+ try {
+ return ((IIndexFragmentName) name).getBinding();
+ } catch (CoreException e) {
+ // Fall through to return null.
+ }
+ }
+ return null;
+ }
+
+ private boolean areOverlappingNames(IName n1, IName n2) {
+ if (n1 == n2)
+ return true;
+
+ IASTFileLocation loc1 = n1.getFileLocation();
+ IASTFileLocation loc2 = n2.getFileLocation();
+ if (loc1 == null || loc2 == null)
+ return false;
+ return loc1.getFileName().equals(loc2.getFileName())
+ && max(loc1.getNodeOffset(), loc2.getNodeOffset()) < min(loc1.getNodeOffset() + loc1.getNodeLength(), loc2.getNodeOffset() + loc2.getNodeLength());
+ }
+
+ private static boolean isInSameFunction(IASTName refName, IName funcDeclName) {
+ if (funcDeclName instanceof IASTName) {
+ IASTDeclaration fdef = getEnclosingFunctionDefinition((IASTNode) funcDeclName);
+ return fdef != null && fdef.contains(refName);
+ }
+ return false;
+ }
+
+ private static IASTDeclaration getEnclosingFunctionDefinition(IASTNode node) {
+ while (node != null && !(node instanceof IASTFunctionDefinition)) {
+ node = node.getParent();
+ }
+ return (IASTDeclaration) node;
+ }
+
+ private static boolean isInSameTemplate(IASTName refName, IName templateDeclName) {
+ if (templateDeclName instanceof IASTName) {
+ IASTDeclaration template = getEnclosingTemplateDeclaration(refName);
+ return template != null && template.contains(refName);
+ }
+ return false;
+ }
+
+ private static IASTDeclaration getEnclosingTemplateDeclaration(IASTNode node) {
+ while (node != null && !(node instanceof ICPPASTTemplateDeclaration)) {
+ node = node.getParent();
+ }
+ return (IASTDeclaration) node;
+ }
+
+ private void filterToFunctions(ICProject project, IIndex index, IName[] declNames, List<IFunctionDeclaration> functionElements) {
+ for (IName declName : declNames) {
+ try {
+ ICElement elem = getCElementForName(project, index, declName);
+ if (elem instanceof IFunctionDeclaration) {
+ functionElements.add((IFunctionDeclaration) elem);
+ }
+ } catch (CoreException e) {
+ CUIPlugin.log(e);
+ }
+ }
+ }
+
+ private ICElementHandle getCElementForName(ICProject project, IIndex index, IName declName) throws CoreException {
+ if (declName instanceof IIndexName) {
+ return IndexUI.getCElementForName(project, index, (IIndexName) declName);
+ }
+ if (declName instanceof IASTName) {
+ IASTName astName = (IASTName) declName;
+ IBinding binding = astName.resolveBinding();
+ if (binding != null) {
+ ITranslationUnit tu = IndexUI.getTranslationUnit(project, astName);
+ if (tu != null) {
+ IASTFileLocation loc = astName.getFileLocation();
+ IRegion region = new Region(loc.getNodeOffset(), loc.getNodeLength());
+ return CElementHandleFactory.create(tu, binding, astName.isDefinition(), region, 0);
+ }
+ }
+ return null;
+ }
+ return null;
+ }
+
+}
diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IStepIntoSelectionHandler.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IStepIntoSelectionHandler.java
new file mode 100644
index 0000000..c3006dd
--- /dev/null
+++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/model/IStepIntoSelectionHandler.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * 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.debug.core.model;
+
+import org.eclipse.debug.core.commands.IDebugCommandHandler;
+
+/**
+ * @since 7.3
+ *
+ */
+public interface IStepIntoSelectionHandler extends IDebugCommandHandler {
+}
diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.properties b/debug/org.eclipse.cdt.debug.ui/plugin.properties
index 2266d66..0f70afe 100644
--- a/debug/org.eclipse.cdt.debug.ui/plugin.properties
+++ b/debug/org.eclipse.cdt.debug.ui/plugin.properties
@@ -12,6 +12,7 @@
# Dobrin Alexiev (Texas Instruments) - initial API and implementation (bug 336876)
# Marc Khouzam (Ericsson) - Added support for connect command (Bug 365601)
# Marc Dumais (Ericsson) - Added support for reverse debug action (Bug 365776)
+# Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
###############################################################################
pluginName=C/C++ Development Tools Debugger UI
@@ -248,3 +249,7 @@ DebugNewExecutable.name=Debug New Executable
DebugNewExecutable.description=Debug a new executable
DebugNewExecutable.label=Debug New Executable...
DebugNewExecutable.tooltip=Debug a new executable
+
+# Step into selection
+popup.stepIntoSelection.description=Step into the current selected statement
+popup.stepIntoSelection.name=Step Into Selection
diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.xml b/debug/org.eclipse.cdt.debug.ui/plugin.xml
index d2b3fc1..3ecc0ee 100644
--- a/debug/org.eclipse.cdt.debug.ui/plugin.xml
+++ b/debug/org.eclipse.cdt.debug.ui/plugin.xml
@@ -2088,6 +2088,20 @@
class="org.eclipse.cdt.debug.internal.ui.commands.DebugNewExecutableHandler"
commandId="org.eclipse.cdt.debug.ui.command.debugNewExecutable">
</handler>
+ <handler
+ class="org.eclipse.cdt.debug.internal.ui.commands.StepIntoSelectionCommandHandler"
+ commandId="org.eclipse.cdt.debug.ui.command.StepIntoSelection">
+ <enabledWhen>
+ <and>
+ <with
+ variable="activeEditor">
+ <instanceof
+ value="org.eclipse.ui.texteditor.ITextEditor">
+ </instanceof>
+ </with>
+ </and>
+ </enabledWhen>
+ </handler>
</extension>
<extension
point="org.eclipse.core.expressions.definitions">
@@ -2180,6 +2194,10 @@
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
sequence="SHIFT+F7">
</key>
+ <key sequence="M1+F5"
+ contextId="org.eclipse.cdt.debug.ui.debugging"
+ commandId="org.eclipse.cdt.debug.ui.command.StepIntoSelection"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
<extension
point="org.eclipse.ui.commands">
@@ -2191,6 +2209,13 @@
id="org.eclipse.cdt.debug.command.breakpointProperties"
name="%BreakpointPropertiesCommand.name">
</command>
+ <command
+ categoryId="org.eclipse.debug.ui.category.run"
+ description="%popup.stepIntoSelection.description"
+ helpContextId="step_into_selection_action_context"
+ id="org.eclipse.cdt.debug.ui.command.StepIntoSelection"
+ name="%popup.stepIntoSelection.name">
+ </command>
</extension>
<extension
point="org.eclipse.ui.menus">
@@ -2572,6 +2597,52 @@
style="push"
tooltip="%Connect.tooltip">
</command>
+
+ <!-- Step Into Selection debugging contributions -->
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.ui.run?endof=emptyStepGroup">
+ <command
+ commandId="org.eclipse.cdt.debug.ui.command.StepIntoSelection"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <systemTest
+ property="org.eclipse.cdt.debug.ui.debuggerActive"
+ value="true">
+ </systemTest>
+ <with
+ variable="activeEditor">
+ <instanceof
+ value="org.eclipse.ui.texteditor.ITextEditor">
+ </instanceof>
+ </with>
+ </and>
+ </visibleWhen>
+ </command>
+ </menuContribution>
+ <menuContribution
+ locationURI="popup:#CEditorContext?before=additions">
+ <command
+ commandId="org.eclipse.cdt.debug.ui.command.StepIntoSelection"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <systemTest
+ property="org.eclipse.cdt.debug.ui.debuggerActive"
+ value="true">
+ </systemTest>
+ <with
+ variable="activeEditor">
+ <instanceof
+ value="org.eclipse.ui.texteditor.ITextEditor">
+ </instanceof>
+ </with>
+ </and>
+ </visibleWhen>
+ </command>
</menuContribution>
</extension>
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/StepIntoSelectionCommandHandler.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/StepIntoSelectionCommandHandler.java
new file mode 100644
index 0000000..f9a9b98
--- /dev/null
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/commands/StepIntoSelectionCommandHandler.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.debug.internal.ui.commands;
+
+import org.eclipse.cdt.debug.core.model.IStepIntoSelectionHandler;
+import org.eclipse.debug.ui.actions.DebugCommandHandler;
+
+
+public class StepIntoSelectionCommandHandler extends DebugCommandHandler {
+ @Override
+ protected Class<?> getCommandType() {
+ return IStepIntoSelectionHandler.class;
+ }
+}
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 51d5f2e..fb440c4 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 875fd3e..59bbcce 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 ee19d3c..60fd44b 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 9a4e8c3..978adaa 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 0000000..8f9e5c2
--- /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 0000000..590404d
--- /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 c8fa3ba..d8bbebf 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 a3d7258..b436136 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 de72f05..e5cc141 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 0000000..7e98cbf
--- /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 0000000..dae8602
--- /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 0000000..bc53da4
--- /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 be375f9..b64c80f 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 5b00c88..2497c82 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 0000000..92a5cf2
--- /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 0000000..5095ab2
--- /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 a5b180b..93330c6 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 0000000..737a015
--- /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 7b33290..602c08b 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 */
})
diff --git a/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF
index 3050f5a..3a1a74d 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF
+++ b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-SymbolicName: org.eclipse.cdt.dsf.ui;singleton:=true
-Bundle-Version: 2.3.0.qualifier
+Bundle-Version: 2.4.0.qualifier
Bundle-Activator: org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin
Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui;bundle-version="3.5.0",
@@ -35,6 +35,7 @@ Export-Package: org.eclipse.cdt.dsf.debug.internal.ui;x-internal:=true,
org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text;x-internal:=true,
org.eclipse.cdt.dsf.debug.internal.ui.disassembly.util;x-internal:=true,
org.eclipse.cdt.dsf.debug.internal.ui.preferences;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
+ org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup;x-internal:=true,
org.eclipse.cdt.dsf.debug.internal.ui.viewmodel;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions;x-friends:="org.eclipse.cdt.dsf.gdb.ui",
org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;x-internal:=true,
diff --git a/dsf/org.eclipse.cdt.dsf.ui/plugin.properties b/dsf/org.eclipse.cdt.dsf.ui/plugin.properties
index 8882a84..2d4b876 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/plugin.properties
+++ b/dsf/org.eclipse.cdt.dsf.ui/plugin.properties
@@ -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
# IBM Corporation
# Patrick Chuong (Texas Instruments) - Pin and Clone Supports (331781)
+# Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
###############################################################################
pluginName=Debugger Services Framework UI
providerName=Eclipse CDT
@@ -75,3 +76,10 @@ OpenNewView.name = Open New View
disassemblyRulerColumn.addresses=Addresses
disassemblyRulerColumn.functionOffsets=Function Offsets
disassemblyRulerColumn.opcodes=Opcodes
+
+# Step into selection
+stepIntoSelectionHyperlinkDetector.label = C/C++ Step Into Selection
+stepIntoSelectionHyperlinkDetector.description = Performs the step into selection command on demand via a hyperlink
+
+
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/plugin.xml b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml
index bfa8abf..c7565f7 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/plugin.xml
+++ b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml
@@ -106,8 +106,8 @@
class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesContribution">
</dynamic>
</menu>
- </menuContribution>
-
+ </menuContribution>
+
<!-- Registers view menu commands -->
<menuContribution
locationURI="menu:org.eclipse.debug.ui.RegisterView?after=additions">
@@ -340,9 +340,8 @@
</count>
</with>
</activeWhen>
- </handler>
+ </handler>
</extension>
-
<extension point="org.eclipse.core.expressions.definitions">
<definition id="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive">
<and>
@@ -527,7 +526,7 @@
commandId="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoAddress"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
</extension>
-
+
<extension
point="org.eclipse.ui.contexts">
<context
@@ -878,5 +877,17 @@
</targetClass>
</column>
</extension>
-
+ <!-- Hyperlinking support -->
+ <extension
+ point="org.eclipse.ui.workbench.texteditor.hyperlinkDetectors">
+ <hyperlinkDetector
+ activate="true"
+ class="org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoSelectionHyperlinkDetector"
+ description="%stepIntoSelectionHyperlinkDetector.description"
+ id="org.eclipse.cdt.dsf.debug.ui.hyperlinkdetector.stepIntoSelection"
+ modifierKeys="M1+M3"
+ name="%stepIntoSelectionHyperlinkDetector.label"
+ targetId="org.eclipse.cdt.ui.cCode">
+ </hyperlinkDetector>
+ </extension>
</plugin>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/pom.xml b/dsf/org.eclipse.cdt.dsf.ui/pom.xml
index 3fbd4ce..b3f322f 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/pom.xml
+++ b/dsf/org.eclipse.cdt.dsf.ui/pom.xml
@@ -11,7 +11,7 @@
<relativePath>../../pom.xml</relativePath>
</parent>
- <version>2.3.0-SNAPSHOT</version>
+ <version>2.4.0-SNAPSHOT</version>
<artifactId>org.eclipse.cdt.dsf.ui</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java
index f28a4ab..0761ffc 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others.
+ * Copyright (c) 2009, 2013 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
* Patrick Chuong (Texas Instruments) - Bug 315446: Invalid event breakpoint type (group) name
+ * Alvaro Sanchez-Leon (Ericsson AB) - Support for Step into selection (bug 244865)
*******************************************************************************/
package org.eclipse.cdt.dsf.debug.internal.ui;
@@ -16,6 +17,7 @@ import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
public static String ToggleBreakpointsTargetFactory_description;
public static String ToggleBreakpointsTargetFactory_name;
+ public static String DsfUIStepIntoEditorSelection;
static {
// initialize resource bundle
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties
index 1faea82..37451db 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/Messages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2009, 2010 Wind River Systems and others.
+# Copyright (c) 2009, 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
@@ -8,7 +8,10 @@
# Contributors:
# Wind River Systems - initial API and implementation
# Ericsson - added Tracepoint support
+# Ericsson - added Step into selection support
###############################################################################
ToggleBreakpointsTargetFactory_description=Standard C/C++ breakpoint type.
ToggleBreakpointsTargetFactory_name=C/C++ Breakpoints
+
+DsfUIStepIntoEditorSelection=Step Into
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/sourcelookup/DsfSourceSelectionResolver.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/sourcelookup/DsfSourceSelectionResolver.java
new file mode 100644
index 0000000..aa1f5ab
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/sourcelookup/DsfSourceSelectionResolver.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * 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.debug.internal.ui.sourcelookup;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.debug.internal.ui.CDebugUIUtils;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.internal.ui.editor.CEditor;
+import org.eclipse.cdt.internal.ui.editor.SelectionToDeclarationJob;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public class DsfSourceSelectionResolver implements Runnable {
+ private ITextEditor fEditorPage = null;
+ private ITextSelection fSelection = null;
+ private LineLocation fLineLocation = new LineLocation();
+ private IFunctionDeclaration fFunction = null;
+ private boolean fSuccessful = false;
+
+ public class LineLocation {
+ private String fileName = null;
+ private int lineNumber = 0;
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public void setLineNumber(int lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+ }
+
+ private interface ResolveEditorRunnable extends Runnable {
+ TextEditor getEditor();
+ }
+
+ public DsfSourceSelectionResolver() {
+
+ }
+
+ public DsfSourceSelectionResolver(ITextEditor editor, ITextSelection selection) {
+ fEditorPage = editor;
+ fSelection = selection;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup.IDsfSourceSelectionResolver#run()
+ */
+ @Override
+ public void run() {
+ fEditorPage = resolveEditor();
+ if (fEditorPage != null) {
+ ITextSelection selection = resolveSelection();
+ if (selection != null) {
+ IFunctionDeclaration[] selectedFunctions = resolveSelectedFunction(selection);
+
+ IFunctionDeclaration selFunction = null;
+ if (selectedFunctions == null || selectedFunctions.length != 1 || selectedFunctions[0] == null) {
+ //Unable to resolve selection to a function
+ return;
+ } else {
+ // Continue as expected
+ selFunction = selectedFunctions[0];
+ }
+
+ LineLocation selectedLine = resolveSelectedLine();
+ if (selectedLine == null) {
+ // Unable to resolve the selected line
+ return;
+ }
+
+ fLineLocation = selectedLine;
+ fFunction = selFunction;
+ fSuccessful = true;
+ }
+ }
+ }
+
+ public ITextEditor resolveEditor() {
+ if (fEditorPage != null) {
+ return fEditorPage;
+ }
+
+ final IWorkbench wb = DsfUIPlugin.getDefault().getWorkbench();
+ // Run in UI thread to access UI resources
+ ResolveEditorRunnable reditorRunnable = new ResolveEditorRunnable() {
+ TextEditor result = null;
+
+ @Override
+ public void run() {
+ IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
+ if (win == null || win.getActivePage() == null || win.getActivePage().getActiveEditor() == null) {
+ result = null;
+ } else {
+ IEditorPart editorPart = win.getActivePage().getActiveEditor();
+ if (editorPart instanceof CEditor) {
+ result = (TextEditor) win.getActivePage().getActiveEditor();
+ }
+ }
+ }
+
+ @Override
+ public TextEditor getEditor() {
+ return result;
+ }
+ };
+
+ Display.getDefault().syncExec(reditorRunnable);
+ return reditorRunnable.getEditor();
+ }
+
+ private LineLocation resolveSelectedLine() {
+ String errorMessage = ""; //$NON-NLS-1$
+ IEditorInput input = fEditorPage.getEditorInput();
+ if (input == null) {
+ errorMessage = "Invalid Editor input on selection"; //$NON-NLS-1$
+ } else {
+ IDocument document = fEditorPage.getDocumentProvider().getDocument(input);
+ if (document == null) {
+ errorMessage = "Invalid Editor Document input on selection"; //$NON-NLS-1$
+ } else {
+ ITextSelection selection = resolveSelection();
+ if (selection == null) {
+ errorMessage = "Invalid selection. Only textual selections are supported"; //$NON-NLS-1$
+ } else {
+ String fileName = null;
+ try {
+ fileName = CDebugUIUtils.getEditorFilePath(input);
+ } catch (CoreException e) {
+ // unable to resolve the path
+ DsfUIPlugin.log(e);
+ return null;
+ }
+
+ if (fileName == null) {
+ errorMessage = "Unable to resolve fileName from selection"; //$NON-NLS-1$
+ DsfUIPlugin.logErrorMessage(errorMessage);
+ } else {
+ // Resolve the values
+ LineLocation lineLocation = new LineLocation();
+
+ lineLocation.setFileName(fileName);
+ lineLocation.setLineNumber(selection.getStartLine() + 1);
+ return lineLocation;
+ }
+ }
+ }
+ }
+
+ DsfUIPlugin.logErrorMessage(errorMessage);
+ return null;
+ }
+
+ public ITextSelection resolveSelection() {
+ if (fSelection != null) {
+ //Value received at construction time
+ return fSelection;
+ }
+
+ ISelection selection = fEditorPage.getEditorSite().getSelectionProvider().getSelection();
+ if (selection instanceof ITextSelection) {
+ return (ITextSelection) selection;
+ }
+
+ return null;
+ }
+
+ private IFunctionDeclaration[] resolveSelectedFunction(ITextSelection textSelection) {
+ if (textSelection != null) {
+ SelectionToDeclarationJob job;
+ try {
+ job = new SelectionToDeclarationJob(fEditorPage, textSelection);
+ job.schedule();
+ job.join();
+ } catch (CoreException e1) {
+ DsfUIPlugin.log(e1);
+ return null;
+ } catch (InterruptedException e) {
+ DsfUIPlugin.log(e);
+ return null;
+ }
+
+ //fetch the result
+ return job.getSelectedFunctions();
+ }
+
+ return null;
+ }
+
+ public LineLocation getLineLocation() {
+ return fLineLocation;
+ }
+
+ public IFunctionDeclaration getFunction() {
+ return fFunction;
+ }
+
+ public boolean isSuccessful() {
+ return fSuccessful;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionCommand.java
new file mode 100644
index 0000000..7ec6ce2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionCommand.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * 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.debug.ui.actions;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.debug.core.model.IStepIntoSelectionHandler;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup.DsfSourceSelectionResolver;
+import org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup.DsfSourceSelectionResolver.LineLocation;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl3;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.debug.core.commands.AbstractDebugCommand;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * @since 2.4
+ */
+public class DsfStepIntoSelectionCommand extends AbstractDebugCommand implements IStepIntoSelectionHandler, IDsfStepIntoSelection {
+ private final DsfServicesTracker fTracker;
+ public DsfStepIntoSelectionCommand(DsfSession session) {
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ @Override
+ protected void doExecute(Object[] targets, IProgressMonitor monitor, IRequest request) throws CoreException {
+ // No multiple selections allowed for Step into selection
+ if (targets.length != 1) {
+ return;
+ }
+
+ final IExecutionDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext) targets[0]).getDMContext(), IExecutionDMContext.class);
+ if (dmc == null) {
+ return;
+ }
+
+ DsfSourceSelectionResolver resolveSelection = new DsfSourceSelectionResolver();
+ // Resolve UI selection from the the UI thread
+ Display.getDefault().syncExec(resolveSelection);
+ if (resolveSelection.isSuccessful()) {
+ LineLocation location = resolveSelection.getLineLocation();
+ runToSelection(location.getFileName(), location.getLineNumber(), resolveSelection.getFunction(), dmc);
+ } else {
+ DsfUIPlugin.debug("DSfStepIntoSelectionCommand: Unable to resolve a selected function"); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ protected boolean isExecutable(Object[] targets, IProgressMonitor monitor, IEnabledStateRequest request) throws CoreException {
+ // No multiple selections allowed for Step into selection
+ if (targets.length != 1) {
+ return false;
+ }
+
+ final IExecutionDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext) targets[0]).getDMContext(), IExecutionDMContext.class);
+ if (dmc == null) {
+ return false;
+ }
+
+ return isExecutable(dmc, fTracker);
+ }
+
+ private boolean isExecutable(final IExecutionDMContext dmc, final DsfServicesTracker tracker) {
+ final DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session != null && session.isActive()) {
+ try {
+ Query<Boolean> query = new Query<Boolean>() {
+ @Override
+ protected void execute(DataRequestMonitor<Boolean> rm) {
+ IRunControl3 runControl = tracker.getService(IRunControl3.class);
+ if (runControl != null) {
+ // The selection may not be up to date, this is indicated with
+ // the selectedFunction being set to null
+ runControl.canStepIntoSelection(dmc, null, 0, null, rm);
+ } else {
+ rm.setData(false);
+ rm.done();
+ }
+ }
+ };
+
+ session.getExecutor().execute(query);
+ return query.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ protected Object getTarget(Object element) {
+ if (element instanceof IDMVMContext) {
+ return element;
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean isRemainEnabled(IDebugCommandRequest request) {
+ return true;
+ }
+
+ @Override
+ public boolean isExecutable(final IExecutionDMContext dmc) {
+ if (dmc == null) {
+ return false;
+ }
+
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), dmc.getSessionId());
+ boolean result = isExecutable(dmc, tracker);
+ tracker.dispose();
+ return result;
+ }
+
+ @Override
+ public void runToSelection(final String fileName, final int lineLocation, final IFunctionDeclaration selectedFunction, final IExecutionDMContext dmc) {
+ final DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session != null && session.isActive()) {
+ Throwable exception = null;
+ try {
+ Query<Object> query = new Query<Object>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+
+ boolean skipBreakpoints = DebugUITools.getPreferenceStore().getBoolean(IDebugUIConstants.PREF_SKIP_BREAKPOINTS_DURING_RUN_TO_LINE);
+
+ IRunControl3 runControl = tracker.getService(IRunControl3.class);
+ tracker.dispose();
+ StringBuilder eMessage = null;
+ if (runControl != null) {
+ runControl.stepIntoSelection(dmc, fileName, lineLocation, skipBreakpoints, selectedFunction, rm);
+ return;
+ } else {
+ eMessage = new StringBuilder("IRunControl3 service not available"); //$NON-NLS-1$
+ }
+
+ // Either runControl is null or an Exception has occurred
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, eMessage.toString(), null));
+ rm.done();
+ }
+ };
+
+ session.getExecutor().execute(query);
+ query.get();
+ } catch (RejectedExecutionException e) {
+ exception = e;
+ } catch (InterruptedException e) {
+ exception = e;
+ } catch (ExecutionException e) {
+ exception = e;
+ }
+
+ if (exception != null) {
+ DsfUIPlugin.log(new DebugException(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Failed executing Step into Selection", exception)));//$NON-NLS-1$
+ }
+ } else {
+ DsfUIPlugin.log(new DebugException(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Debug session is not active", null))); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionHyperlinkDetector.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionHyperlinkDetector.java
new file mode 100644
index 0000000..5c2a5a0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoSelectionHyperlinkDetector.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * 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.debug.ui.actions;
+
+import org.eclipse.cdt.core.model.ICLanguageKeywords;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.IWorkingCopy;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.internal.ui.Messages;
+import org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup.DsfSourceSelectionResolver;
+import org.eclipse.cdt.dsf.debug.internal.ui.sourcelookup.DsfSourceSelectionResolver.LineLocation;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.internal.ui.editor.CEditor;
+import org.eclipse.cdt.internal.ui.text.CWordFinder;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.text.ICPartitions;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * @since 2.4
+ *
+ */
+public class DsfStepIntoSelectionHyperlinkDetector extends AbstractHyperlinkDetector {
+ private class DsfStepIntoSelectionHyperlink implements IHyperlink {
+
+ private ITextSelection fSelection = null;
+ private IDsfStepIntoSelection fStepIntoSelectionCommand = null;
+ private DsfSourceSelectionResolver fSelectionResolver = null;
+
+ /**
+ * Constructor
+ *
+ * @param stepIntoSelectionCommand
+ * @param region
+ */
+ public DsfStepIntoSelectionHyperlink(DsfSourceSelectionResolver selectionResolver, IDsfStepIntoSelection stepIntoSelectionCommand) {
+ fSelection = selectionResolver.resolveSelection();
+ fStepIntoSelectionCommand = stepIntoSelectionCommand;
+ fSelectionResolver = selectionResolver;
+ }
+
+ /**
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkRegion()
+ */
+ @Override
+ public IRegion getHyperlinkRegion() {
+ return new Region(fSelection.getOffset(), fSelection.getLength());
+ }
+
+ /**
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkText()
+ */
+ @Override
+ public String getHyperlinkText() {
+ return Messages.DsfUIStepIntoEditorSelection;
+ }
+
+ /**
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getTypeLabel()
+ */
+ @Override
+ public String getTypeLabel() {
+ return null;
+ }
+
+ /**
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#open()
+ */
+ @Override
+ public void open() {
+ // Resolve the debug context
+ final IExecutionDMContext dmc = resolveDebugContext();
+ if (fSelectionResolver.isSuccessful() && dmc != null) {
+ LineLocation location = fSelectionResolver.getLineLocation();
+ fStepIntoSelectionCommand.runToSelection(location.getFileName(), location.getLineNumber(), fSelectionResolver.getFunction(), dmc);
+ } else {
+ String message = null;
+ if (dmc == null) {
+ message = "DSfStepIntoSelection: Unable to resolve the debug context"; //$NON-NLS-1$
+ } else {
+ message = "DSfStepIntoSelection: Unable to resolve a selected function"; //$NON-NLS-1$
+ }
+ DsfUIPlugin.debug(message);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean)
+ */
+ @Override
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, final IRegion region, boolean canShowMultipleHyperlinks) {
+ // Only valid in the context of a selection within the CEditor
+ ITextEditor editor = (ITextEditor) getAdapter(ITextEditor.class);
+ if (editor == null || region == null || !(editor instanceof CEditor))
+ return null;
+
+ ITextSelection selection = resolveSelection(editor, region);
+ if (selection == null) {
+ return null;
+ }
+
+ // Shall only enable hyper link step into selection within a cdt debug execution context
+ IExecutionDMContext dmc = resolveDebugContext();
+ if (dmc == null) {
+ return null;
+ }
+
+ final DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null || !session.isActive()) {
+ return null;
+ }
+
+ IDsfStepIntoSelection stepIntoSelectionCommand = (IDsfStepIntoSelection) session.getModelAdapter(IDsfStepIntoSelection.class);
+ if (stepIntoSelectionCommand == null) {
+ return null;
+ }
+
+ if (!stepIntoSelectionCommand.isExecutable(dmc)) {
+ return null;
+ }
+
+ DsfSourceSelectionResolver functionResolver = new DsfSourceSelectionResolver(editor, selection);
+ functionResolver.run();
+ // Resolve to a selected function
+ if (!functionResolver.isSuccessful()) {
+ // We are not pointing to a valid function
+ return null;
+ }
+
+ return new IHyperlink[] { new DsfStepIntoSelectionHyperlink(functionResolver, stepIntoSelectionCommand) };
+ }
+
+ private ITextSelection resolveSelection(ITextEditor editor, IRegion region) {
+ ITextSelection selection = null;
+ if (editor != null) {
+ IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput());
+ final IWorkingCopy workingCopy = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
+
+ if (document != null && workingCopy != null) {
+ // Check partition type.
+ String partitionType;
+ try {
+ partitionType = TextUtilities.getContentType(document, ICPartitions.C_PARTITIONING, region.getOffset(), false);
+ if (IDocument.DEFAULT_CONTENT_TYPE.equals(partitionType)) {
+ // Regular code i.e. Not a Preprocessor directive.
+ IRegion wregion = getIdentifier(document, region.getOffset(), workingCopy.getLanguage());
+ if (wregion != null) {
+ selection = new TextSelection(document, wregion.getOffset(), wregion.getLength());
+ }
+ }
+ } catch (BadLocationException e) {
+ // Ignore to return null
+ } catch (CoreException e) {
+ // Ignore to return null
+ }
+ }
+ }
+
+ return selection;
+ }
+
+ /**
+ * Returns the identifier at the given offset, or {@code null} if the there is no identifier at the offset.
+ */
+ private static IRegion getIdentifier(IDocument document, int offset, ILanguage language) throws BadLocationException {
+ @SuppressWarnings("restriction")
+ IRegion wordRegion = CWordFinder.findWord(document, offset);
+ if (wordRegion != null && wordRegion.getLength() > 0) {
+ String word = document.get(wordRegion.getOffset(), wordRegion.getLength());
+ if (!Character.isDigit(word.charAt(0)) && !isLanguageKeyword(language, word)) {
+ return wordRegion;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isLanguageKeyword(ILanguage lang, String word) {
+ ICLanguageKeywords keywords = (ICLanguageKeywords) lang.getAdapter(ICLanguageKeywords.class);
+ if (keywords != null) {
+ for (String keyword : keywords.getKeywords()) {
+ if (keyword.equals(word))
+ return true;
+ }
+ for (String type : keywords.getBuiltinTypes()) {
+ if (type.equals(word))
+ return true;
+ }
+ for (String keyword : keywords.getPreprocessorKeywords()) {
+ if (keyword.charAt(0) == '#' && keyword.length() == word.length() + 1 && keyword.regionMatches(1, word, 0, word.length())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private IExecutionDMContext resolveDebugContext() {
+ IExecutionDMContext execContext = null;
+ IAdaptable adaptableContext = DebugUITools.getDebugContext();
+ IDMContext debugContext = null;
+ if (adaptableContext instanceof IDMVMContext) {
+ debugContext = ((IDMVMContext) adaptableContext).getDMContext();
+ }
+
+ if (debugContext != null) {
+ execContext = DMContexts.getAncestorOfType(debugContext, IExecutionDMContext.class);
+ }
+
+ return execContext;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/IDsfStepIntoSelection.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/IDsfStepIntoSelection.java
new file mode 100644
index 0000000..43ca6cd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/IDsfStepIntoSelection.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * 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.debug.ui.actions;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+/**
+ * @since 2.4
+ */
+public interface IDsfStepIntoSelection {
+
+ /**
+ * Checks if within a state to perform step into selection
+ * @param dmc
+ * @return
+ */
+ public boolean isExecutable(final IExecutionDMContext dmc);
+
+ /**
+ * Carries out the actual step into selection action to the specified function location
+ * @param fileName
+ * @param lineLocation
+ * @param selectedFunction
+ * @param context
+ */
+ public void runToSelection(final String fileName, final int lineLocation, final IFunctionDeclaration selectedFunction, final IExecutionDMContext context);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl3.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl3.java
new file mode 100644
index 0000000..f67f709
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl3.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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.debug.service;
+
+import org.eclipse.cdt.core.model.IFunctionDeclaration;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * This interface extends IRunControl2 to let a service support the
+ * "Step into selection" command.
+ * @since 2.4
+ */
+public interface IRunControl3 extends IRunControl2 {
+ /**
+ * Returns whether the service is in the state to execute 'Step into selection'
+ * for the specified context
+ *
+ * @param context the execution DM context
+ * @param sourceFile the source file path, mapped to a debugger path if possible, invalid if selectedFunction is Null
+ * @param lineNumber the line number of the source file where the user selected the target function, invalid if selectedFunction is Null
+ * @param selectedFunction The target function to step into <br>NOTE: a null value shall disregard linenumber and sourceFile
+ * @param rm the DataRequestMonitor that will return the result
+ */
+ void canStepIntoSelection(IExecutionDMContext context, String sourceFile, int lineNumber,
+ IFunctionDeclaration selectedFunction, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Request to run the program forward into the specified function
+ * if the current stop location is not at the specified lineNumber and
+ * skipBreakpoints is false, any other breakpoint found before the specified line number will stop this
+ * command; while if skipBreakpoints is true, the operation will ignore
+ * other breakpoints and continue until the specified location.
+ *
+ * @param context the execution DM context
+ * @param sourceFile the source file path, mapped to a debugger path if possible.
+ * @param lineNumber the line number of the source file where the user selected the target function
+ * @param skipBreakpoints skip breakpoints while performing this operation
+ * @param selectedFunction the target function to step into
+ * @param rm the DataRequestMonitor that will return the result
+ */
+ void stepIntoSelection (IExecutionDMContext context, String sourceFile, int lineNumber,
+ boolean skipBreakpoints, IFunctionDeclaration selectedFunction, RequestMonitor rm);
+}