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

Bug 244865 – Support for Step Into Selection

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>
This commit is contained in:
aleon 2013-04-30 11:59:16 -04:00 committed by Marc-Andre Laperle
parent cf3acef3f3
commit bb755a01be
37 changed files with 3022 additions and 116 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,

View file

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

View file

@ -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}\"

View file

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

View file

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

View file

@ -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();
super.eventDispatched(e);
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;
}
}
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();
}
}
}

View file

@ -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();
}
@ -848,10 +866,88 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo
}
// ------------------------------------------------------------------------
// 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));
if (processRunToLineStoppedEvent(e)) {
// If RunToLine is not completed
return;
}
// 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);
if (!processStepIntoSelection(e)) {
//Step into Selection is not in progress
broadcastStop(e);
}
}
fConnection.queueCommand(fCommandFactory.createMIBreakDelete(bpDmc, new int[] {fRunToLineActiveOperation.getBreakointId()}),
new DataRequestMonitor<MIInfo>(getExecutor(), null));
fRunToLineActiveOperation = null;
}
}
}
}
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());
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;
}
// 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();
/**
* @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.
*/
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);
}
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();
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */
})

View file

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

View file

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

View file

@ -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 */
})

View file

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

View file

@ -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 */
})

View file

@ -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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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