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:
parent
cf3acef3f3
commit
bb755a01be
37 changed files with 3022 additions and 116 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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}\"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
})
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
})
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
})
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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$
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Add table
Reference in a new issue