| /******************************************************************************* |
| * 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; |
| } |
| } |