mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 341731 - Show values returned from function calls when doing a
step-return operation Change-Id: I4ac5c64a940ffcbe75b21618a74f2c4eba93d27e Signed-off-by: Marc Khouzam <marc.khouzam@ericsson.com> Reviewed-on: https://git.eclipse.org/r/15377 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> Reviewed-by: Mikhail Khodjaiants <mikhailkhod@googlemail.com> IP-Clean: Mikhail Khodjaiants <mikhailkhod@googlemail.com> Tested-by: Mikhail Khodjaiants <mikhailkhod@googlemail.com>
This commit is contained in:
parent
2186138b87
commit
2a935a9926
15 changed files with 875 additions and 174 deletions
|
@ -9,6 +9,7 @@
|
||||||
* Freescale Semiconductor - initial API and implementation
|
* Freescale Semiconductor - initial API and implementation
|
||||||
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
||||||
* Marc Khouzam (Ericsson) - Add support disable "View Memory" action (bug 418710)
|
* Marc Khouzam (Ericsson) - Add support disable "View Memory" action (bug 418710)
|
||||||
|
* Marc Khouzam (Ericsson) - Turn off "watch" action for return values of methods (bug 341731)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
|
package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel;
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpd
|
||||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
|
||||||
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
|
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
|
||||||
|
import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2;
|
||||||
import org.eclipse.jface.util.PropertyChangeEvent;
|
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||||
import org.eclipse.jface.viewers.TreePath;
|
import org.eclipse.jface.viewers.TreePath;
|
||||||
|
|
||||||
|
@ -194,6 +196,15 @@ public class GdbVariableVMNode extends VariableVMNode {
|
||||||
}
|
}
|
||||||
return super.canViewInMemory();
|
return super.canViewInMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Override
|
||||||
|
public Object getAdapter(Class adapter) {
|
||||||
|
if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapter2.class)) {
|
||||||
|
return fGdbVariableExpressionFactory;
|
||||||
|
}
|
||||||
|
return super.getAdapter(adapter);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static boolean isConvenienceVariable(String expr) {
|
private static boolean isConvenienceVariable(String expr) {
|
||||||
|
@ -229,6 +240,25 @@ public class GdbVariableVMNode extends VariableVMNode {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory to control the "Watch" action for GDB variables.
|
||||||
|
*/
|
||||||
|
protected class GdbVariableExpressionFactory extends VariableExpressionFactory {
|
||||||
|
@Override
|
||||||
|
public boolean canCreateWatchExpression(Object element) {
|
||||||
|
if (element instanceof VariableExpressionVMC) {
|
||||||
|
String expression = ((VariableExpressionVMC)element).getExpression();
|
||||||
|
if (isConvenienceVariable(expression)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.canCreateWatchExpression(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected VariableExpressionFactory fGdbVariableExpressionFactory = new GdbVariableExpressionFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The special context representing more children to be available.
|
* The special context representing more children to be available.
|
||||||
*
|
*
|
||||||
|
|
|
@ -10,13 +10,17 @@
|
||||||
* Ericsson - Modified for handling of multiple execution contexts
|
* Ericsson - Modified for handling of multiple execution contexts
|
||||||
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
|
* Axel Mueller - Bug 306555 - Add support for cast to type / view as array (IExpressions2)
|
||||||
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
* Jens Elmenthaler (Verigy) - Added Full GDB pretty-printing support (bug 302121)
|
||||||
|
* Marc Khouzam (Ericsson) - Added support for expression aliases for return values of functions (bug 341731)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.mi.service;
|
package org.eclipse.cdt.dsf.mi.service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.IAddress;
|
import org.eclipse.cdt.core.IAddress;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
|
@ -35,7 +39,11 @@ import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
|
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
|
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
|
||||||
|
@ -49,12 +57,16 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetChildCount;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetChildren;
|
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetChildren;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetValue;
|
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetValue;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetVar;
|
import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetVar;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.events.MIFunctionFinishedEvent;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetAttributesInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetAttributesInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildCountInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildCountInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildrenInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetChildrenInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetValueInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetValueInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetVarInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.ExprMetaGetVarInfo;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataEvaluateExpressionInfo;
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIDataEvaluateExpressionInfo;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
|
||||||
import org.eclipse.cdt.dsf.service.AbstractDsfService;
|
import org.eclipse.cdt.dsf.service.AbstractDsfService;
|
||||||
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
|
||||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||||
|
@ -65,6 +77,8 @@ import org.eclipse.core.runtime.IStatus;
|
||||||
import org.eclipse.core.runtime.Status;
|
import org.eclipse.core.runtime.Status;
|
||||||
import org.osgi.framework.BundleContext;
|
import org.osgi.framework.BundleContext;
|
||||||
|
|
||||||
|
import com.ibm.icu.text.MessageFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements a debugger expression evaluator as a DSF service. The
|
* This class implements a debugger expression evaluator as a DSF service. The
|
||||||
* primary interface that clients of this class should use is IExpressions.
|
* primary interface that clients of this class should use is IExpressions.
|
||||||
|
@ -815,6 +829,116 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of aliases for return values of methods.
|
||||||
|
*/
|
||||||
|
private class ReturnValueAliasing {
|
||||||
|
/**
|
||||||
|
* Map of expression to alias. The expression is the name of the convenience variable
|
||||||
|
* storing the return value, e.g., $1 -> "foo() returned"
|
||||||
|
* This map allows to quickly find the alias to be used for return value variables.
|
||||||
|
*/
|
||||||
|
private Map<String, String> fExpressionAliasesMap = new HashMap<String, String>();
|
||||||
|
/**
|
||||||
|
* Map of thread to aliases expression list. This map allows to know which aliases are related
|
||||||
|
* to a thread of execution. This is important to allow us to delete aliases when a
|
||||||
|
* thread exits. Note that we need a list because we keep all previous aliases until
|
||||||
|
* the thread exits.
|
||||||
|
*/
|
||||||
|
private Map<IMIExecutionDMContext, List<String>> fThreadToAliasedExpressionsMap = new HashMap<IMIExecutionDMContext, List<String>>();
|
||||||
|
/**
|
||||||
|
* Map of thread to the name of the method the thread last stopped in.
|
||||||
|
* This allows us to create the alias based on the method the thread was in
|
||||||
|
* before it returned out of the method.
|
||||||
|
*/
|
||||||
|
private Map<IMIExecutionDMContext, String> fThreadToTopMethodName = new HashMap<IMIExecutionDMContext, String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an alias for expr with respect to threadDmc.
|
||||||
|
* The alias is created based on where threadDmc was previously stopped.
|
||||||
|
*/
|
||||||
|
public void createAlias(IMIExecutionDMContext threadDmc, String expr) {
|
||||||
|
String alias = expr;
|
||||||
|
String methodName = fThreadToTopMethodName.get(threadDmc);
|
||||||
|
if (methodName != null) {
|
||||||
|
alias = MessageFormat.format(Messages.MIExpressions_ReturnValueAlias,
|
||||||
|
methodName + "()"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
fExpressionAliasesMap.put(expr, alias);
|
||||||
|
|
||||||
|
List<String> aliasedExprList = fThreadToAliasedExpressionsMap.get(threadDmc);
|
||||||
|
if (aliasedExprList == null) {
|
||||||
|
aliasedExprList = new ArrayList<String>();
|
||||||
|
fThreadToAliasedExpressionsMap.put(threadDmc, aliasedExprList);
|
||||||
|
}
|
||||||
|
aliasedExprList.add(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all information related to a particular thread of execution.
|
||||||
|
*/
|
||||||
|
public void clearThread(IMIExecutionDMContext threadDmc) {
|
||||||
|
fThreadToTopMethodName.remove(threadDmc);
|
||||||
|
clearAliases(threadDmc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all aliased expressions related to a particular thread of execution.
|
||||||
|
* It is good to keep the aliases around as long as the thread is alive;
|
||||||
|
* even if we won't show the return value automatically, the user
|
||||||
|
* could add the expression in the expression view, and the alias
|
||||||
|
* would then be used.
|
||||||
|
*/
|
||||||
|
public void clearAliases(IMIExecutionDMContext threadDmc) {
|
||||||
|
List<String> aliasedExprList = fThreadToAliasedExpressionsMap.remove(threadDmc);
|
||||||
|
if (aliasedExprList != null) {
|
||||||
|
for (String expr : aliasedExprList) {
|
||||||
|
fExpressionAliasesMap.remove(expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the method name of the last location where threadDmc was stopped.
|
||||||
|
*/
|
||||||
|
public void updateStoppedLocation(IMIExecutionDMContext threadDmc, String methodName) {
|
||||||
|
fThreadToTopMethodName.put(threadDmc, methodName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The alias for 'expr' if there is one. null if there
|
||||||
|
* is no alias for that expression.
|
||||||
|
*/
|
||||||
|
public String getAlias(String expr) {
|
||||||
|
String alias = fExpressionAliasesMap.get(expr);
|
||||||
|
if (alias == null) {
|
||||||
|
// Check if the expression contains the string that must be aliased.
|
||||||
|
// E.g., $1[0], *$2
|
||||||
|
// If it does, just replace that string within the expression to
|
||||||
|
// create the full alias
|
||||||
|
for (Entry<String, String> entry : fExpressionAliasesMap.entrySet()) {
|
||||||
|
int index = expr.indexOf(entry.getKey());
|
||||||
|
if (index != -1) {
|
||||||
|
// Found the string! Now replace it with our alias.
|
||||||
|
// We put it between () to make things clearer to the user.
|
||||||
|
// Note that there can only be one string contained
|
||||||
|
// in the expression, so once we found it, we are done.
|
||||||
|
alias = expr.substring(0, index) +
|
||||||
|
"(" + entry.getValue() + ")" + //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
expr.substring(index + entry.getKey().length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Structure to keep track of aliases for method return values. */
|
||||||
|
private ReturnValueAliasing fReturnValueAliases = new ReturnValueAliasing();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
|
@ -1061,8 +1185,13 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String relativeExpr = getData().getExpr();
|
||||||
|
String alias = fReturnValueAliases.getAlias(relativeExpr);
|
||||||
|
if (alias != null) {
|
||||||
|
relativeExpr = alias;
|
||||||
|
}
|
||||||
rm.setData(new ExpressionDMData(
|
rm.setData(new ExpressionDMData(
|
||||||
getData().getExpr(),getData().getType(), getData().getNumChildren(),
|
relativeExpr, getData().getType(), getData().getNumChildren(),
|
||||||
getData().getEditable(), basicType));
|
getData().getEditable(), basicType));
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
|
@ -1492,7 +1621,7 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
|
||||||
}
|
}
|
||||||
|
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(IRunControl.IResumedDMEvent e) {
|
public void eventDispatched(IResumedDMEvent e) {
|
||||||
fExpressionCache.setContextAvailable(e.getDMContext(), false);
|
fExpressionCache.setContextAvailable(e.getDMContext(), false);
|
||||||
if (e.getReason() != StateChangeReason.STEP) {
|
if (e.getReason() != StateChangeReason.STEP) {
|
||||||
fExpressionCache.reset();
|
fExpressionCache.reset();
|
||||||
|
@ -1500,9 +1629,53 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
|
||||||
}
|
}
|
||||||
|
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
public void eventDispatched(IRunControl.ISuspendedDMEvent e) {
|
public void eventDispatched(ISuspendedDMEvent e) {
|
||||||
fExpressionCache.setContextAvailable(e.getDMContext(), true);
|
fExpressionCache.setContextAvailable(e.getDMContext(), true);
|
||||||
fExpressionCache.reset();
|
fExpressionCache.reset();
|
||||||
|
|
||||||
|
handleReturnValueAliasing(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReturnValueAliasing(ISuspendedDMEvent e) {
|
||||||
|
// Process MIStoppedEvent from within the ISuspendedDMEvent
|
||||||
|
// to avoid any race conditions where the actual MIStoppedEvent
|
||||||
|
// can arrive faster that a preceding IResumedDMEvent
|
||||||
|
if (e instanceof IMIDMEvent) {
|
||||||
|
Object miEvent = ((IMIDMEvent)e).getMIEvent();
|
||||||
|
if (miEvent instanceof MIStoppedEvent) {
|
||||||
|
IMIExecutionDMContext stoppedEventThread = null;
|
||||||
|
if (e instanceof IContainerSuspendedDMEvent) {
|
||||||
|
// All-stop mode
|
||||||
|
IExecutionDMContext[] triggerContexts = ((IContainerSuspendedDMEvent)e).getTriggeringContexts();
|
||||||
|
if (triggerContexts.length != 0 && triggerContexts[0] instanceof IMIExecutionDMContext) {
|
||||||
|
stoppedEventThread = (IMIExecutionDMContext)triggerContexts[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-stop mode
|
||||||
|
IDMContext dmc = e.getDMContext();
|
||||||
|
if (dmc instanceof IMIExecutionDMContext) {
|
||||||
|
stoppedEventThread = (IMIExecutionDMContext)dmc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stoppedEventThread != null) {
|
||||||
|
if (miEvent instanceof MIFunctionFinishedEvent) {
|
||||||
|
// When getting an MIFunctionFinishedEvent we must set
|
||||||
|
// a proper alias for the convenience variable
|
||||||
|
String resultVar = ((MIFunctionFinishedEvent)miEvent).getGDBResultVar();
|
||||||
|
fReturnValueAliases.createAlias(stoppedEventThread, resultVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of the latest method the thread is stopped in.
|
||||||
|
// Must do this after creating any alias, or else we will overwrite
|
||||||
|
// the previous function name, which we need for the alias
|
||||||
|
MIFrame frame = ((MIStoppedEvent)miEvent).getFrame();
|
||||||
|
if (frame != null) {
|
||||||
|
fReturnValueAliases.updateStoppedLocation(stoppedEventThread, frame.getFunction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@DsfServiceEventHandler
|
@DsfServiceEventHandler
|
||||||
|
@ -1520,6 +1693,20 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
|
||||||
fTraceVisualization = false;
|
fTraceVisualization = 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(IExitedDMEvent e) {
|
||||||
|
IDMContext ctx = e.getDMContext();
|
||||||
|
if (ctx instanceof IMIExecutionDMContext) {
|
||||||
|
// When a thread exits, clear the alias structure for that
|
||||||
|
// thread to avoid leaks
|
||||||
|
fReturnValueAliases.clearThread((IMIExecutionDMContext)ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
|
|
|
@ -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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Wind River Systems - initial API and implementation
|
* Wind River Systems - initial API and implementation
|
||||||
* Ericsson - Modified for handling of multiple execution contexts
|
* Ericsson - Modified for handling of multiple execution contexts
|
||||||
|
* Marc Khouzam (Ericsson) - Show return value of the method when doing a step-return (Bug 341731)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.dsf.mi.service;
|
package org.eclipse.cdt.dsf.mi.service;
|
||||||
|
|
||||||
|
@ -29,6 +30,9 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
import org.eclipse.cdt.dsf.datamodel.IDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
import org.eclipse.cdt.dsf.debug.service.ICachingService;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
||||||
|
@ -42,6 +46,7 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||||
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
|
import org.eclipse.cdt.dsf.gdb.service.IGDBTraceControl.ITraceRecordSelectedChangedDMEvent;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
|
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
|
import org.eclipse.cdt.dsf.mi.service.command.events.IMIDMEvent;
|
||||||
|
import org.eclipse.cdt.dsf.mi.service.command.events.MIFunctionFinishedEvent;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIArg;
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIArg;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
|
import org.eclipse.cdt.dsf.mi.service.command.output.MIFrame;
|
||||||
|
@ -92,7 +97,7 @@ public class MIStack extends AbstractDsfService
|
||||||
protected static class MIVariableDMC extends AbstractDMContext
|
protected static class MIVariableDMC extends AbstractDMContext
|
||||||
implements IVariableDMContext
|
implements IVariableDMContext
|
||||||
{
|
{
|
||||||
public enum Type { ARGUMENT, LOCAL }
|
public enum Type { ARGUMENT, LOCAL, /** @since 4.4 */RETURN_VALUES }
|
||||||
final private Type fType;
|
final private Type fType;
|
||||||
final private int fIndex;
|
final private int fIndex;
|
||||||
|
|
||||||
|
@ -117,6 +122,7 @@ public class MIStack extends AbstractDsfService
|
||||||
int typeFactor = 0;
|
int typeFactor = 0;
|
||||||
if (fType == Type.LOCAL) typeFactor = 2;
|
if (fType == Type.LOCAL) typeFactor = 2;
|
||||||
else if (fType == Type.ARGUMENT) typeFactor = 3;
|
else if (fType == Type.ARGUMENT) typeFactor = 3;
|
||||||
|
else if (fType == Type.RETURN_VALUES) typeFactor = 4;
|
||||||
return super.baseHashCode() ^ typeFactor ^ fIndex;
|
return super.baseHashCode() ^ typeFactor ^ fIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +161,33 @@ public class MIStack extends AbstractDsfService
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as with frame objects, this is a base class for the IVariableDMData object that uses an MIArg object to
|
||||||
|
* provide the data. Sub-classes must supply the MIArg object.
|
||||||
|
*/
|
||||||
|
private class VariableData implements IVariableDMData {
|
||||||
|
private MIArg fMIArg;
|
||||||
|
|
||||||
|
public VariableData(MIArg arg){
|
||||||
|
fMIArg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return fMIArg.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return fMIArg.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return fMIArg.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CommandCache fMICommandCache;
|
private CommandCache fMICommandCache;
|
||||||
private CommandFactory fCommandFactory;
|
private CommandFactory fCommandFactory;
|
||||||
|
@ -176,6 +209,13 @@ public class MIStack extends AbstractDsfService
|
||||||
*/
|
*/
|
||||||
private boolean fTraceVisualization;
|
private boolean fTraceVisualization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map of a return value for each thread.
|
||||||
|
* A return value is stored when the user performs a step-return,
|
||||||
|
* and it cleared as soon as that thread executes again.
|
||||||
|
*/
|
||||||
|
private Map<IMIExecutionDMContext, VariableData> fThreadToReturnVariable = new HashMap<IMIExecutionDMContext, VariableData>();
|
||||||
|
|
||||||
public MIStack(DsfSession session)
|
public MIStack(DsfSession session)
|
||||||
{
|
{
|
||||||
super(session);
|
super(session);
|
||||||
|
@ -614,23 +654,6 @@ public class MIStack extends AbstractDsfService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as with frame objects, this is a base class for the IVariableDMData object that uses an MIArg object to
|
|
||||||
* provide the data. Sub-classes must supply the MIArg object.
|
|
||||||
*/
|
|
||||||
class VariableData implements IVariableDMData {
|
|
||||||
private MIArg dsfMIArg;
|
|
||||||
VariableData(MIArg arg){
|
|
||||||
dsfMIArg = arg;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String getName() { return dsfMIArg.getName(); }
|
|
||||||
@Override
|
|
||||||
public String getValue() { return dsfMIArg.getValue(); }
|
|
||||||
@Override
|
|
||||||
public String toString() { return dsfMIArg.toString(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the stopped event can be used to extract the variable value.
|
// Check if the stopped event can be used to extract the variable value.
|
||||||
if (execDmc != null && miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT &&
|
if (execDmc != null && miVariableDmc.fType == MIVariableDMC.Type.ARGUMENT &&
|
||||||
frameDmc.fLevel == 0 && fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null &&
|
frameDmc.fLevel == 0 && fCachedStoppedEvent != null && fCachedStoppedEvent.getFrame() != null &&
|
||||||
|
@ -694,8 +717,7 @@ public class MIStack extends AbstractDsfService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}//if
|
} else if (miVariableDmc.fType == MIVariableDMC.Type.LOCAL){
|
||||||
if (miVariableDmc.fType == MIVariableDMC.Type.LOCAL){
|
|
||||||
fMICommandCache.execute(
|
fMICommandCache.execute(
|
||||||
// Don't ask for value when we are visualizing trace data, since some
|
// Don't ask for value when we are visualizing trace data, since some
|
||||||
// data will not be there, and the command will fail
|
// data will not be there, and the command will fail
|
||||||
|
@ -735,7 +757,17 @@ public class MIStack extends AbstractDsfService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}//if
|
} else if (miVariableDmc.fType == MIVariableDMC.Type.RETURN_VALUES) {
|
||||||
|
VariableData var = fThreadToReturnVariable.get(execDmc);
|
||||||
|
if (var != null) {
|
||||||
|
rm.setData(var);
|
||||||
|
} else {
|
||||||
|
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Return value not found", null)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
rm.done();
|
||||||
|
} else {
|
||||||
|
rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid variable type " + miVariableDmc.fType, null)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +799,24 @@ public class MIStack extends AbstractDsfService
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves variables which are used to store the return values of functions.
|
||||||
|
*/
|
||||||
|
private void getReturnValues(IFrameDMContext frameDmc, DataRequestMonitor<IVariableDMContext[]> rm) {
|
||||||
|
IVariableDMContext[] values = new IVariableDMContext[0];
|
||||||
|
|
||||||
|
// Return values are only relevant for the top stack-frame
|
||||||
|
if (!fTraceVisualization && frameDmc.getLevel() == 0) {
|
||||||
|
IMIExecutionDMContext threadDmc = DMContexts.getAncestorOfType(frameDmc, IMIExecutionDMContext.class);
|
||||||
|
VariableData var = fThreadToReturnVariable.get(threadDmc);
|
||||||
|
if (var != null) {
|
||||||
|
values = new IVariableDMContext[1];
|
||||||
|
values[0] = new MIVariableDMC(this, frameDmc, MIVariableDMC.Type.RETURN_VALUES, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rm.done(values);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getLocals(final IFrameDMContext frameDmc, final DataRequestMonitor<IVariableDMContext[]> rm) {
|
public void getLocals(final IFrameDMContext frameDmc, final DataRequestMonitor<IVariableDMContext[]> rm) {
|
||||||
|
|
||||||
|
@ -780,8 +829,20 @@ public class MIStack extends AbstractDsfService
|
||||||
rm.done();
|
rm.done();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
countingRm.setDoneCount(2);
|
countingRm.setDoneCount(3);
|
||||||
|
|
||||||
|
// First show any return values of methods
|
||||||
|
getReturnValues(
|
||||||
|
frameDmc,
|
||||||
|
new DataRequestMonitor<IVariableDMContext[]>(getExecutor(), countingRm) {
|
||||||
|
@Override
|
||||||
|
protected void handleSuccess() {
|
||||||
|
localsList.addAll( Arrays.asList(getData()) );
|
||||||
|
countingRm.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then show arguments
|
||||||
getArguments(
|
getArguments(
|
||||||
frameDmc,
|
frameDmc,
|
||||||
new DataRequestMonitor<IVariableDMContext[]>(getExecutor(), countingRm) {
|
new DataRequestMonitor<IVariableDMContext[]>(getExecutor(), countingRm) {
|
||||||
|
@ -792,6 +853,7 @@ public class MIStack extends AbstractDsfService
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Finally get the local variables
|
||||||
fMICommandCache.execute(
|
fMICommandCache.execute(
|
||||||
// We don't actually need to ask for the values in this case, but since
|
// We don't actually need to ask for the values in this case, but since
|
||||||
// we will ask for them right after, it is more efficient to ask for them now
|
// we will ask for them right after, it is more efficient to ask for them now
|
||||||
|
@ -914,6 +976,29 @@ public class MIStack extends AbstractDsfService
|
||||||
fMICommandCache.reset();
|
fMICommandCache.reset();
|
||||||
fStackDepthCache.clear();
|
fStackDepthCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleReturnValues(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleReturnValues(IResumedDMEvent e) {
|
||||||
|
// Whenever the execution resumes, we can clear any
|
||||||
|
// return values of previous methods for the resuming
|
||||||
|
// thread context. For all-stop mode, we get a container event here,
|
||||||
|
// and we can clear the entire list, which should contain at most one
|
||||||
|
// value for all-stop.
|
||||||
|
if (e instanceof IContainerResumedDMEvent) {
|
||||||
|
// All-stop mode
|
||||||
|
assert fThreadToReturnVariable.size() <= 1;
|
||||||
|
fThreadToReturnVariable.clear();
|
||||||
|
} else {
|
||||||
|
// Non-stop mode
|
||||||
|
IDMContext ctx = e.getDMContext();
|
||||||
|
if (ctx instanceof IMIExecutionDMContext) {
|
||||||
|
fThreadToReturnVariable.remove(ctx);
|
||||||
|
} else if (ctx instanceof IContainerDMContext) {
|
||||||
|
fThreadToReturnVariable.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -926,8 +1011,47 @@ public class MIStack extends AbstractDsfService
|
||||||
fMICommandCache.setContextAvailable(e.getDMContext(), true);
|
fMICommandCache.setContextAvailable(e.getDMContext(), true);
|
||||||
fMICommandCache.reset();
|
fMICommandCache.reset();
|
||||||
fStackDepthCache.clear();
|
fStackDepthCache.clear();
|
||||||
|
|
||||||
|
handleReturnValues(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleReturnValues(ISuspendedDMEvent e) {
|
||||||
|
// Process MIFunctionFinishedEvent from within the ISuspendedDMEvent
|
||||||
|
// instead of MIStoppedEvent.
|
||||||
|
// This avoids a race conditions where the actual MIFunctionFinishedEvent
|
||||||
|
// can arrive here, faster that a preceding IResumedDMEvent
|
||||||
|
if (e instanceof IMIDMEvent) {
|
||||||
|
Object miEvent = ((IMIDMEvent)e).getMIEvent();
|
||||||
|
if (miEvent instanceof MIFunctionFinishedEvent) {
|
||||||
|
// When returning out of a function, we want to show the return value
|
||||||
|
// for the thread that finished the call. To do that, we store
|
||||||
|
// the variable in which GDB stores that return value, and we do
|
||||||
|
// that for the proper thread.
|
||||||
|
|
||||||
|
IMIExecutionDMContext finishedEventThread = null;
|
||||||
|
if (e instanceof IContainerSuspendedDMEvent) {
|
||||||
|
// All-stop mode
|
||||||
|
IExecutionDMContext[] triggerContexts = ((IContainerSuspendedDMEvent)e).getTriggeringContexts();
|
||||||
|
if (triggerContexts.length != 0 && triggerContexts[0] instanceof IMIExecutionDMContext) {
|
||||||
|
finishedEventThread = (IMIExecutionDMContext)triggerContexts[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-stop mode
|
||||||
|
IDMContext ctx = e.getDMContext();
|
||||||
|
if (ctx instanceof IMIExecutionDMContext) {
|
||||||
|
finishedEventThread = (IMIExecutionDMContext)ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finishedEventThread != null) {
|
||||||
|
String name = ((MIFunctionFinishedEvent)miEvent).getGDBResultVar();
|
||||||
|
String value = ((MIFunctionFinishedEvent)miEvent).getReturnValue();
|
||||||
|
|
||||||
|
fThreadToReturnVariable.put(finishedEventThread, new VariableData(new MIArg(name, value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Messages extends NLS {
|
||||||
public static String Breakpoint_attribute_problem;
|
public static String Breakpoint_attribute_problem;
|
||||||
public static String Breakpoint_installation_failed;
|
public static String Breakpoint_installation_failed;
|
||||||
public static String MIExpressions_NotAvailableBecauseChildOfDynamicVarobj;
|
public static String MIExpressions_NotAvailableBecauseChildOfDynamicVarobj;
|
||||||
|
public static String MIExpressions_ReturnValueAlias;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// initialize resource bundle
|
// initialize resource bundle
|
||||||
|
|
|
@ -14,3 +14,4 @@ Breakpoint_attribute_problem=Breakpoint attribute problem: {0}
|
||||||
Breakpoint_installation_failed=installation failed
|
Breakpoint_installation_failed=installation failed
|
||||||
|
|
||||||
MIExpressions_NotAvailableBecauseChildOfDynamicVarobj=N/A (child of pretty-printed object)
|
MIExpressions_NotAvailableBecauseChildOfDynamicVarobj=N/A (child of pretty-printed object)
|
||||||
|
MIExpressions_ReturnValueAlias={0} returned
|
||||||
|
|
|
@ -21,14 +21,24 @@ char *gCharPtr2 = (char*)0x4321;
|
||||||
bool *gBoolPtr2 = (bool*)0x12ABCDEF;
|
bool *gBoolPtr2 = (bool*)0x12ABCDEF;
|
||||||
|
|
||||||
class bar {
|
class bar {
|
||||||
public:
|
public:
|
||||||
|
bar() {
|
||||||
|
d = 8;
|
||||||
|
e[0] = 18;
|
||||||
|
e[1] = 28;
|
||||||
|
}
|
||||||
int d;
|
int d;
|
||||||
private:
|
private:
|
||||||
int e[2];
|
int e[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
class bar2 {
|
class bar2 {
|
||||||
public:
|
public:
|
||||||
|
bar2() {
|
||||||
|
f = 318;
|
||||||
|
g[0] = 228;
|
||||||
|
g[1] = 138;
|
||||||
|
}
|
||||||
int f;
|
int f;
|
||||||
private:
|
private:
|
||||||
int g[2];
|
int g[2];
|
||||||
|
@ -36,6 +46,11 @@ private:
|
||||||
|
|
||||||
class foo: public bar, bar2 {
|
class foo: public bar, bar2 {
|
||||||
public:
|
public:
|
||||||
|
foo() {
|
||||||
|
c = 8;
|
||||||
|
a[0] = 1000;
|
||||||
|
a[1] = 23;
|
||||||
|
}
|
||||||
int a[2];
|
int a[2];
|
||||||
bar b;
|
bar b;
|
||||||
private:
|
private:
|
||||||
|
@ -350,6 +365,28 @@ int testRTTI() {
|
||||||
}
|
}
|
||||||
// End of bug 376901 RTTI tests
|
// End of bug 376901 RTTI tests
|
||||||
|
|
||||||
|
int testSimpleReturn(int a) {
|
||||||
|
int b = 0;
|
||||||
|
b = a;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
foo testComplexReturn() {
|
||||||
|
foo f;
|
||||||
|
int a = 8;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testReturn() {
|
||||||
|
int a = 10;
|
||||||
|
bool b = false;
|
||||||
|
|
||||||
|
testSimpleReturn(6);
|
||||||
|
testComplexReturn();
|
||||||
|
a = 0;;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
printf("Running ExpressionTest App\n");
|
printf("Running ExpressionTest App\n");
|
||||||
|
|
||||||
|
@ -377,10 +414,12 @@ int main() {
|
||||||
testArrays();
|
testArrays();
|
||||||
testRTTI();
|
testRTTI();
|
||||||
testCasting();
|
testCasting();
|
||||||
|
testReturn();
|
||||||
|
|
||||||
// For bug 320277
|
// For bug 320277
|
||||||
BaseTest b; b.test();
|
BaseTest b; b.test();
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2007, 2010 Ericsson and others.
|
* Copyright (c) 2007, 2013 Ericsson and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -12,15 +12,21 @@ package org.eclipse.cdt.tests.dsf.gdb.framework;
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
|
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
|
||||||
|
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
|
||||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||||
import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
|
import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
|
||||||
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
import org.eclipse.cdt.dsf.datamodel.DMContexts;
|
||||||
|
@ -39,6 +45,8 @@ import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
|
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData;
|
||||||
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
|
||||||
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
|
import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch;
|
||||||
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses;
|
import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses;
|
||||||
|
@ -607,10 +615,10 @@ public class SyncUtil {
|
||||||
protected void handleCompleted() {
|
protected void handleCompleted() {
|
||||||
if (isSuccess()) {
|
if (isSuccess()) {
|
||||||
IDMContext[] contexts = getData();
|
IDMContext[] contexts = getData();
|
||||||
Assert.assertNotNull("invalid return value from service", contexts);
|
assertNotNull("invalid return value from service", contexts);
|
||||||
Assert.assertEquals("unexpected number of processes", 1, contexts.length);
|
assertEquals("unexpected number of processes", 1, contexts.length);
|
||||||
IDMContext context = contexts[0];
|
IDMContext context = contexts[0];
|
||||||
Assert.assertNotNull("unexpected process context type ", context);
|
assertNotNull("unexpected process context type ", context);
|
||||||
rm.done((IContainerDMContext)context);
|
rm.done((IContainerDMContext)context);
|
||||||
} else {
|
} else {
|
||||||
rm.done(getStatus());
|
rm.done(getStatus());
|
||||||
|
@ -648,7 +656,7 @@ public class SyncUtil {
|
||||||
protected void handleCompleted() {
|
protected void handleCompleted() {
|
||||||
if (isSuccess()) {
|
if (isSuccess()) {
|
||||||
IDMContext[] threads = getData();
|
IDMContext[] threads = getData();
|
||||||
Assert.assertNotNull("invalid return value from service", threads);
|
assertNotNull("invalid return value from service", threads);
|
||||||
rm.setData((IMIExecutionDMContext[])threads);
|
rm.setData((IMIExecutionDMContext[])threads);
|
||||||
} else {
|
} else {
|
||||||
rm.setStatus(getStatus());
|
rm.setStatus(getStatus());
|
||||||
|
@ -673,8 +681,8 @@ public class SyncUtil {
|
||||||
@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
|
@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
|
||||||
public static IMIExecutionDMContext getExecutionContext(int threadIndex) throws InterruptedException {
|
public static IMIExecutionDMContext getExecutionContext(int threadIndex) throws InterruptedException {
|
||||||
IMIExecutionDMContext[] threads = getExecutionContexts();
|
IMIExecutionDMContext[] threads = getExecutionContexts();
|
||||||
Assert.assertTrue("unexpected number of threads", threadIndex < threads.length);
|
assertTrue("unexpected number of threads", threadIndex < threads.length);
|
||||||
Assert.assertNotNull("unexpected thread context type ", threads[threadIndex]);
|
assertNotNull("unexpected thread context type ", threads[threadIndex]);
|
||||||
return threads[threadIndex];
|
return threads[threadIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,4 +756,45 @@ public class SyncUtil {
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IVariableDMData[] getLocals(final IFrameDMContext frameDmc) throws Throwable {
|
||||||
|
Query<IVariableDMData[]> query = new Query<IVariableDMData[]>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(final DataRequestMonitor<IVariableDMData[]> rm) {
|
||||||
|
fStack.getLocals(frameDmc, new ImmediateDataRequestMonitor<IVariableDMContext[]>() {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
if (isSuccess()) {
|
||||||
|
IVariableDMContext[] varDmcs = getData();
|
||||||
|
final List<IVariableDMData> localsDMData = new ArrayList<IVariableDMData>();
|
||||||
|
final CountingRequestMonitor crm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), rm) {
|
||||||
|
@Override
|
||||||
|
protected void handleSuccess() {
|
||||||
|
rm.done(localsDMData.toArray(new IVariableDMData[localsDMData.size()]));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
for (IVariableDMContext varDmc : varDmcs) {
|
||||||
|
fStack.getVariableData(varDmc,
|
||||||
|
new ImmediateDataRequestMonitor<IVariableDMData>(crm) {
|
||||||
|
@Override
|
||||||
|
public void handleSuccess() {
|
||||||
|
localsDMData.add(getData());
|
||||||
|
crm.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
crm.setDoneCount(varDmcs.length);
|
||||||
|
} else {
|
||||||
|
rm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fSession.getExecutor().execute(query);
|
||||||
|
IVariableDMData[] result = query.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2007, 2010 Ericsson and others.
|
* Copyright (c) 2007, 2013 Ericsson and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -40,6 +40,7 @@ import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContex
|
||||||
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
|
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
|
import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
|
||||||
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
|
||||||
|
import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData;
|
||||||
import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor;
|
import org.eclipse.cdt.dsf.mi.service.ClassAccessor.MIExpressionDMCAccessor;
|
||||||
import org.eclipse.cdt.dsf.mi.service.MIExpressions;
|
import org.eclipse.cdt.dsf.mi.service.MIExpressions;
|
||||||
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
||||||
|
@ -310,11 +311,13 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
|
|
||||||
// Get the children of some variables
|
// Get the children of some variables
|
||||||
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testChildren");
|
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testChildren");
|
||||||
doTestChildren(stoppedEvent);
|
IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||||
|
IExpressionDMContext exprDMC = SyncUtil.createExpression(frameDmc, "f");
|
||||||
|
doTestChildren(exprDMC);
|
||||||
|
|
||||||
// Now do a step and get the children again, to test the internal cache
|
// Now do a step and get the children again, to test the internal cache
|
||||||
stoppedEvent = SyncUtil.step(1, StepType.STEP_OVER);
|
SyncUtil.step(1, StepType.STEP_OVER);
|
||||||
doTestChildren(stoppedEvent);
|
doTestChildren(exprDMC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3188,12 +3191,8 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTestChildren(MIStoppedEvent stoppedEvent) throws Throwable {
|
private void doTestChildren(IExpressionDMContext exprDMC) throws Throwable
|
||||||
|
{
|
||||||
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
|
||||||
|
|
||||||
final IExpressionDMContext exprDMC = SyncUtil.createExpression(frameDmc, "f");
|
|
||||||
|
|
||||||
IExpressionDMContext[] children =
|
IExpressionDMContext[] children =
|
||||||
getChildren(exprDMC, new String[] {"bar", "bar2", "a", "b", "c"});
|
getChildren(exprDMC, new String[] {"bar", "bar2", "a", "b", "c"});
|
||||||
|
|
||||||
|
@ -3598,20 +3597,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(children[0], IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(children[0], IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -3622,20 +3616,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
query = new Query<String>() {
|
query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(castChildren[0], IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(castChildren[0], IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
value = query.get(500, TimeUnit.MILLISECONDS);
|
value = query.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
@ -3675,20 +3664,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -3738,20 +3722,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -3801,20 +3780,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -3871,20 +3845,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -3947,20 +3916,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -4021,20 +3985,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getFormattedExpressionValue(
|
||||||
@Override
|
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
||||||
fExpService.getFormattedExpressionValue(
|
@Override
|
||||||
fExpService.getFormattedValueContext(child, IFormattedValues.NATURAL_FORMAT),
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<FormattedValueDMData>(rm) {
|
rm.done(getData().getFormattedValue());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getFormattedValue());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
@ -4046,6 +4005,105 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
assertEquals(castExprDmc.getParents()[0], exprDmc);
|
assertEquals(castExprDmc.getParents()[0], exprDmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test verifies that we display the simple return value of a method after
|
||||||
|
* a step-return operation, but only for the first stack frame.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDisplaySimpleReturnValueForStepReturn() throws Throwable {
|
||||||
|
SyncUtil.runToLocation("testSimpleReturn");
|
||||||
|
MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_RETURN);
|
||||||
|
|
||||||
|
// Check the return value is shown when looking at the first frame
|
||||||
|
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||||
|
IVariableDMData[] result = SyncUtil.getLocals(frameDmc);
|
||||||
|
|
||||||
|
assertEquals(3, result.length); // Two variables and one return value
|
||||||
|
|
||||||
|
// Return value
|
||||||
|
assertEquals("$1", result[0].getName());
|
||||||
|
assertEquals("6", result[0].getValue());
|
||||||
|
// first variable
|
||||||
|
assertEquals("a", result[1].getName());
|
||||||
|
assertEquals("10", result[1].getValue());
|
||||||
|
// Second variable
|
||||||
|
assertEquals("b", result[2].getName());
|
||||||
|
assertEquals("false", result[2].getValue());
|
||||||
|
|
||||||
|
// Now check how the return value will be displayed to the user
|
||||||
|
final IExpressionDMContext returnExprDmc = SyncUtil.createExpression(frameDmc, "$1");
|
||||||
|
Query<IExpressionDMData> query = new Query<IExpressionDMData>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(final DataRequestMonitor<IExpressionDMData> rm) {
|
||||||
|
fExpService.getExpressionData(returnExprDmc, rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fSession.getExecutor().execute(query);
|
||||||
|
IExpressionDMData data = query.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
assertEquals("testSimpleReturn() returned", data.getName());
|
||||||
|
|
||||||
|
// Now check the actual value using the expression service
|
||||||
|
String value = SyncUtil.getExpressionValue(returnExprDmc, IFormattedValues.DECIMAL_FORMAT);
|
||||||
|
assertEquals("6", value);
|
||||||
|
|
||||||
|
// Now make sure we don't show the return value for another frame
|
||||||
|
final IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1);
|
||||||
|
result = SyncUtil.getLocals(frameDmc2);
|
||||||
|
|
||||||
|
// only one variable
|
||||||
|
assertEquals(1, result.length);
|
||||||
|
assertEquals("b", result[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test verifies that we display the complex return value of a method after
|
||||||
|
* a step-return operation, but only for the first stack frame.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDisplayComplexReturnValueForStepReturn() throws Throwable {
|
||||||
|
SyncUtil.runToLocation("testComplexReturn");
|
||||||
|
MIStoppedEvent stoppedEvent = SyncUtil.step(1, StepType.STEP_RETURN);
|
||||||
|
|
||||||
|
// Check the return value is show when looking at the first frame
|
||||||
|
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
|
||||||
|
IVariableDMData[] result = SyncUtil.getLocals(frameDmc);
|
||||||
|
|
||||||
|
assertEquals(3, result.length); // Two variables and one return value
|
||||||
|
|
||||||
|
// Return value
|
||||||
|
assertEquals("$1", result[0].getName());
|
||||||
|
|
||||||
|
// first variable
|
||||||
|
assertEquals("a", result[1].getName());
|
||||||
|
assertEquals("10", result[1].getValue());
|
||||||
|
// Second variable
|
||||||
|
assertEquals("b", result[2].getName());
|
||||||
|
assertEquals("false", result[2].getValue());
|
||||||
|
|
||||||
|
// Now check how the return value will be displayed to the user
|
||||||
|
final IExpressionDMContext returnExprDmc = SyncUtil.createExpression(frameDmc, "$1");
|
||||||
|
Query<IExpressionDMData> query = new Query<IExpressionDMData>() {
|
||||||
|
@Override
|
||||||
|
protected void execute(final DataRequestMonitor<IExpressionDMData> rm) {
|
||||||
|
fExpService.getExpressionData(returnExprDmc, rm);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fSession.getExecutor().execute(query);
|
||||||
|
IExpressionDMData data = query.get(500, TimeUnit.MILLISECONDS);
|
||||||
|
assertEquals("testComplexReturn() returned", data.getName());
|
||||||
|
|
||||||
|
// Now check the content of the complex return expression
|
||||||
|
doTestChildren(returnExprDmc);
|
||||||
|
|
||||||
|
// Now make sure we don't show the return value for another frame
|
||||||
|
IFrameDMContext frameDmc2 = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 1);
|
||||||
|
result = SyncUtil.getLocals(frameDmc2);
|
||||||
|
|
||||||
|
// only one variable
|
||||||
|
assertEquals(1, result.length);
|
||||||
|
assertEquals("b", result[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
protected int getChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable {
|
protected int getChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable {
|
||||||
|
|
||||||
final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
|
final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
|
||||||
|
@ -4098,20 +4156,15 @@ public class MIExpressionsTest extends BaseTestCase {
|
||||||
Query<String> query = new Query<String>() {
|
Query<String> query = new Query<String>() {
|
||||||
@Override
|
@Override
|
||||||
protected void execute(final DataRequestMonitor<String> rm) {
|
protected void execute(final DataRequestMonitor<String> rm) {
|
||||||
fExpService.getExecutor().submit(new Runnable() {
|
fExpService.getExpressionData(
|
||||||
@Override
|
exprDmc,
|
||||||
public void run() {
|
new ImmediateDataRequestMonitor<IExpressionDMData>(rm) {
|
||||||
fExpService.getExpressionData(
|
@Override
|
||||||
exprDmc,
|
protected void handleCompleted() {
|
||||||
new ImmediateDataRequestMonitor<IExpressionDMData>(rm) {
|
rm.done(getData().getTypeName());
|
||||||
@Override
|
}
|
||||||
protected void handleCompleted() {
|
});
|
||||||
rm.done(getData().getTypeName());
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fSession.getExecutor().execute(query);
|
fSession.getExecutor().execute(query);
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_0 extends MIExpressionsTest_7_0 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_1;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_1 extends MIExpressionsTest_7_1 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_2;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_2 extends MIExpressionsTest_7_2 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_3;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_3 extends MIExpressionsTest_7_3 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_4;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_4 extends MIExpressionsTest_7_4 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_5;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_5 extends MIExpressionsTest_7_5 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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:
|
||||||
|
* Marc Khouzam (Ericsson) - Initial Implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_6;
|
||||||
|
|
||||||
|
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.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(BackgroundRunner.class)
|
||||||
|
public class MIExpressionsNonStopTest_7_6 extends MIExpressionsTest_7_6 {
|
||||||
|
@Override
|
||||||
|
protected void setGdbVersion() {
|
||||||
|
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setLaunchAttributes() {
|
||||||
|
super.setLaunchAttributes();
|
||||||
|
|
||||||
|
setLaunchAttribute(IGDBLaunchConfigurationConstants.ATTR_DEBUGGER_NON_STOP, true);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue