blob: 87a50ce54eb0c49f54879ca028662efbb709fec0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2010, 2011 Nokia 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:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.eval.ast.engine.instructions;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.eval.ast.engine.ASTEvalMessages;
import org.eclipse.cdt.debug.edc.internal.services.dsf.EDCSymbolReader;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Modules.ModuleDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ProcessExecutionDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.RunControl.ThreadExecutionDMC;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
import org.eclipse.cdt.debug.edc.internal.symbols.InvalidVariableLocation;
import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
import org.eclipse.cdt.debug.edc.services.IEDCExecutionDMC;
import org.eclipse.cdt.debug.edc.services.IEDCModules;
import org.eclipse.cdt.debug.edc.services.Stack;
import org.eclipse.cdt.debug.edc.services.Stack.EnumeratorDMC;
import org.eclipse.cdt.debug.edc.services.Stack.IVariableEnumeratorContext;
import org.eclipse.cdt.debug.edc.services.Stack.StackFrameDMC;
import org.eclipse.cdt.debug.edc.services.Stack.VariableDMC;
import org.eclipse.cdt.debug.edc.symbols.IDebugInfoProvider;
import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
import org.eclipse.cdt.debug.edc.symbols.IScope;
import org.eclipse.cdt.debug.edc.symbols.IVariable;
import org.eclipse.cdt.debug.edc.symbols.IVariableLocation;
import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.core.runtime.CoreException;
public class EvaluateID extends SimpleInstruction {
private String name;
private final ICPPASTQualifiedName qualifiedName;
/**
* Constructor for ID (number + variable name) evaluate instruction
*
* @param idExpression
*/
public EvaluateID(IASTIdExpression idExpression) {
IASTName lookupName;
if (idExpression.getName() instanceof ICPPASTQualifiedName) {
// the name has the form namespace::...::variable
qualifiedName = (ICPPASTQualifiedName) idExpression.getName();
lookupName = qualifiedName.getLastName();
} else {
lookupName = idExpression.getName();
qualifiedName = null;
}
name = new String(lookupName.getLookupKey());
}
/**
* Constructor for lookup of a specific literal name
* (presumably a local, like "this")
*
* @param name the literal name
*/
public EvaluateID(String name) {
this.name = name;
this.qualifiedName = null;
}
/**
* Resolve a variable ID
*
* @throws CoreException
*/
@Override
public void execute() throws CoreException {
IDMContext context = getContext();
if (!((context instanceof StackFrameDMC) || (context instanceof ModuleDMC)))
throw EDCDebugger.newCoreException(MessageFormat.format(ASTEvalMessages.EvaluateID_CannotResolveName, name));
EDCServicesTracker servicesTracker = null;
ModuleDMC module = null;
if (context instanceof ModuleDMC) {
module = (ModuleDMC)context;
servicesTracker = module.getEDCServicesTracker();
} else if (context instanceof StackFrameDMC) {
StackFrameDMC frame = (StackFrameDMC) context;
servicesTracker = frame.getEDCServicesTracker();
// This may be called on debugger shutdown, in which case the "modules"
// service may have been shutdown.
IEDCModules modules = servicesTracker.getService(IEDCModules.class);
if (modules == null)
return;
// check by name for a variable or enumerator
IVariableEnumeratorContext variableOrEnumerator
= frame.findVariableOrEnumeratorByName(name, qualifiedName != null ? qualifiedName.getRawSignature() : null, false);
VariableDMC variable
= variableOrEnumerator instanceof VariableDMC ? (VariableDMC)variableOrEnumerator : null;
EnumeratorDMC enumerator
= variableOrEnumerator instanceof EnumeratorDMC ? (EnumeratorDMC)variableOrEnumerator : null;
module = (ModuleDMC)frame.getModule();
if (variable != null) {
IVariableLocation valueLocation = null;
ILocationProvider provider = variable.getVariable().getLocationProvider();
if (module != null && provider != null) {
valueLocation = provider.getLocation(servicesTracker, frame, module.toLinkAddress(frame.getInstructionPtrAddress()),
TypeUtils.isConstType(variable.getVariable().getType()));
}
if (valueLocation == null) {
// unhandled
valueLocation
= new InvalidVariableLocation(
MessageFormat.format(ASTEvalMessages.EvaluateID_NameHasNoLocation,
variable.getName()));
}
// create a VariableWithValue and push on the stack
VariableWithValue varWval = new VariableWithValue(servicesTracker, frame, variable.getVariable());
varWval.setValueLocation(valueLocation);
push(varWval);
return;
}
if (enumerator != null) {
// TODO: map IEnumerator to an IEnumeration and use the real type
pushNewValue(fInterpreter.getTypeEngine().getIntegerTypeOfSize(4, true),
enumerator.getEnumerator().getValue());
return;
}
}
if (module != null) {
@SuppressWarnings("null") // XXX false positive null-check on servicesTracker
Symbols symbolsService = servicesTracker.getService(Symbols.class);
if (symbolsService != null) {
String searchName = name;
if (qualifiedName != null)
searchName = qualifiedName.getRawSignature();
// first attempt to match against variable names in the module
IEDCSymbolReader reader = module.getSymbolReader();
if (reader instanceof EDCSymbolReader) {
if (findGlobalVariable(searchName, (EDCSymbolReader)reader, servicesTracker)
|| findLocalVariable(searchName, module, (EDCSymbolReader)reader, servicesTracker))
return;
}
// if no variable matches, attempt to
// match against function names visible in the module
List<IAddress> addresses = symbolsService.getFunctionAddress(module, searchName);
if (addresses.size() > 0) {
pushNewValue(fInterpreter.getTypeEngine().getIntegerTypeOfSize(4, false),
addresses.get(0).getValue().longValue());
return;
}
// show the whole qualified name in the exception message
name = searchName;
}
}
// did not find a variable, enumerator, or function to match the expression
throw EDCDebugger.newCoreException(
MessageFormat.format(ASTEvalMessages.EvaluateID_VariableNotFound, name));
}
/**
* @param servicesTracker
* @param searchName
* @param idip
* @param baseLinkAddress
*/
private boolean findGlobalVariable(String searchName,
EDCSymbolReader reader, EDCServicesTracker servicesTracker) {
IDebugInfoProvider idip = reader.getDebugInfoProvider();
if (idip == null)
return false;
Collection<IVariable> vars = idip.getVariablesByName(searchName, true);
for (IVariable var : vars) {
IVariableLocation loc
= var.getLocationProvider()
.getLocation(servicesTracker, null, reader.getBaseLinkAddress(),
TypeUtils.isConstType(var.getType()));
if (loc instanceof InvalidVariableLocation)
continue;
VariableWithValue varWval
= new VariableWithValue(servicesTracker, null, var);
varWval.setValueLocation(loc);
push(varWval);
return true;
}
return false;
}
/**
* @param context
* @param servicesTracker
* @param searchName
* @param reader
* @param idip
* @throws CoreException
*/
private boolean findLocalVariable(String searchName, ModuleDMC module,
EDCSymbolReader reader, EDCServicesTracker servicesTracker) {
IDebugInfoProvider idip = reader.getDebugInfoProvider();
if (idip == null)
return false;
Stack stackService = servicesTracker.getService(Stack.class);
if (stackService == null)
return false;
final ProcessExecutionDMC procDMC
= DMContexts.getAncestorOfType(module, ProcessExecutionDMC.class);
if (procDMC == null)
return false;
Collection<IVariable> vars = idip.getVariablesByName(searchName, false);
if (vars == null || vars.isEmpty())
return false;
for (IEDCExecutionDMC tc : procDMC.getChildren()) {
if (!(tc instanceof ThreadExecutionDMC)
|| !((ThreadExecutionDMC)tc).isSuspended())
continue;
IFrameDMContext[] frames;
try {
frames = stackService.getFramesForDMC(tc, 0, Stack.ALL_FRAMES);
} catch (CoreException e) {
continue; // let's try another thread, if available
}
for (IFrameDMContext frame : frames)
if (frame instanceof StackFrameDMC) {
StackFrameDMC stackFrame = (StackFrameDMC)frame;
IAddress pc = stackFrame.getInstructionPtrAddress();
for (IVariable var : vars) {
IScope varScope = var.getScope();
if (varScope.getLowAddress().compareTo(pc) <= 0
&& pc.compareTo(varScope.getHighAddress()) < 0) {
VariableWithValue varWval
= new VariableWithValue(servicesTracker,
stackFrame, var);
push(varWval);
return true;
}
}
}
}
return false;
}
}