diff options
Diffstat (limited to 'dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ExpressionService.java')
-rw-r--r-- | dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ExpressionService.java | 927 |
1 files changed, 927 insertions, 0 deletions
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ExpressionService.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ExpressionService.java new file mode 100644 index 00000000000..e4b53393621 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/ExpressionService.java @@ -0,0 +1,927 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + * Ericsson - Modified for handling of multiple execution contexts + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.cdt.core.IAddress; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.concurrent.RequestMonitor; +import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; +import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.ICachingService; +import org.eclipse.cdt.dsf.debug.service.IExpressions; +import org.eclipse.cdt.dsf.debug.service.IFormattedValues; +import org.eclipse.cdt.dsf.debug.service.IRunControl; +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.IRegisters.IRegisterDMContext; +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.command.CommandCache; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; +import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetAttributes; +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.ExprMetaGetValue; +import org.eclipse.cdt.dsf.mi.service.command.commands.ExprMetaGetVar; +import org.eclipse.cdt.dsf.mi.service.command.commands.MIDataEvaluateExpression; +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.ExprMetaGetChildrenInfo; +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.MIDataEvaluateExpressionInfo; +import org.eclipse.cdt.dsf.service.AbstractDsfService; +import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.utils.Addr32; +import org.eclipse.cdt.utils.Addr64; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.osgi.framework.BundleContext; + +/** + * This class implements a debugger expression evaluator as a DSF service. The + * primary interface that clients of this class should use is IExpressions. + */ +public class ExpressionService extends AbstractDsfService implements IExpressions, ICachingService { + + /** + * This class represents the two expressions that characterize an Expression Context. + */ + public static class ExpressionInfo { + private final String fullExpression; + private final String relativeExpression; + + public ExpressionInfo(String full, String relative) { + fullExpression = full; + relativeExpression = relative; + } + + public String getFullExpr() { return fullExpression; } + public String getRelExpr() { return relativeExpression; } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionInfo) { + if (fullExpression == null ? ((ExpressionInfo) other).fullExpression == null : + fullExpression.equals(((ExpressionInfo) other).fullExpression)) { + if (relativeExpression == null ? ((ExpressionInfo) other).relativeExpression == null : + relativeExpression.equals(((ExpressionInfo) other).relativeExpression)) { + return true; + } + } + } + return false; + } + + @Override + public int hashCode() { + return (fullExpression == null ? 0 : fullExpression.hashCode()) ^ + (relativeExpression == null ? 0 : relativeExpression.hashCode()); + } + + @Override + public String toString() { + return "[" + fullExpression +", " + relativeExpression + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + } + } + /** + * This class represents an expression. + */ + protected static class MIExpressionDMC extends AbstractDMContext implements IExpressionDMContext { + /** + * This field holds an expression to be evaluated. + */ + private ExpressionInfo exprInfo; + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * a stack frame. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param frameCtx + * The parent stack frame context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IFrameDMContext frameCtx) { + this(sessionId, expression, relExpr, (IDMContext)frameCtx); + } + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * an thread. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param execCtx + * The parent thread context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IMIExecutionDMContext execCtx) { + this(sessionId, expression, relExpr, (IDMContext)execCtx); + } + + /** + * ExpressionDMC Constructor for expression to be evaluated in context of + * a memory space. + * + * @param sessionId + * The session ID in which this context is created. + * @param expression + * The expression to be described by this ExpressionDMC + * @param relExpr + * The relative expression if this expression was created as a child + * @param memoryCtx + * The parent memory space context for this ExpressionDMC. + */ + public MIExpressionDMC(String sessionId, String expression, String relExpr, IMemoryDMContext memoryCtx) { + this(sessionId, expression, relExpr, (IDMContext)memoryCtx); + } + + private MIExpressionDMC(String sessionId, String expr, String relExpr, IDMContext parent) { + super(sessionId, new IDMContext[] { parent }); + exprInfo = new ExpressionInfo(expr, relExpr); + } + + /** + * @return True if the two objects are equal, false otherwise. + */ + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && exprInfo.equals(((MIExpressionDMC)other).exprInfo); + } + + /** + * + * @return The hash code of this ExpressionDMC object. + */ + @Override + public int hashCode() { + return super.baseHashCode() + exprInfo.hashCode(); + } + + /** + * + * @return A string representation of this ExpressionDMC (including the + * expression to which it is bound). + */ + @Override + public String toString() { + return baseToString() + ".expr" + exprInfo.toString(); //$NON-NLS-1$ + } + + /** + * @return The full expression string represented by this ExpressionDMC + */ + public String getExpression() { + return exprInfo.getFullExpr(); + } + + /** + * @return The relative expression string represented by this ExpressionDMC + */ + public String getRelativeExpression() { + return exprInfo.getRelExpr(); + } + } + + protected static class InvalidContextExpressionDMC extends AbstractDMContext + implements IExpressionDMContext + { + private final String expression; + + public InvalidContextExpressionDMC(String sessionId, String expr, IDMContext parent) { + super(sessionId, new IDMContext[] { parent }); + expression = expr; + } + + @Override + public boolean equals(Object other) { + return super.baseEquals(other) && + expression == null ? ((InvalidContextExpressionDMC) other).getExpression() == null : expression.equals(((InvalidContextExpressionDMC) other).getExpression()); + } + + @Override + public int hashCode() { + return expression == null ? super.baseHashCode() : super.baseHashCode() ^ expression.hashCode(); + } + + @Override + public String toString() { + return baseToString() + ".invalid_expr[" + expression + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + public String getExpression() { + return expression; + } + } + + + /** + * Contains the address of an expression as well as the size of its type. + */ + protected static class ExpressionDMAddress implements IExpressionDMAddress { + IAddress fAddr; + int fSize; + + public ExpressionDMAddress(IAddress addr, int size) { + fAddr = addr; + fSize = size; + } + + public ExpressionDMAddress(String addrStr, int size) { + fSize = size; + // We must count the "0x" and that + // is why we compare with 10 characters + // instead of 8 + if (addrStr.length() <= 10) { + fAddr = new Addr32(addrStr); + } else { + fAddr = new Addr64(addrStr); + } + } + + public IAddress getAddress() { return fAddr; } + public int getSize() { return fSize; } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionDMAddress) { + ExpressionDMAddress otherAddr = (ExpressionDMAddress) other; + return (fSize == otherAddr.getSize()) && + (fAddr == null ? otherAddr.getAddress() == null : fAddr.equals(otherAddr.getAddress())); + } + return false; + } + + @Override + public int hashCode() { + return (fAddr == null ? 0 :fAddr.hashCode()) + fSize; + } + + @Override + public String toString() { + return (fAddr == null ? "null" : "(0x" + fAddr.toString()) + ", " + fSize + ")"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ + } + } + + /** + * This class represents the static data referenced by an instance of ExpressionDMC, + * such as its type and number of children; it does not contain the value or format + * of the expression. + */ + protected static class ExpressionDMData implements IExpressionDMData { + // This is the relative expression, such as the name of a field within a structure, + // in contrast to the fully-qualified expression contained in the ExpressionDMC, + // which refers to the full name, including parent structure. + private final String relativeExpression; + private final String exprType; + private final int numChildren; + private final boolean editable; + + /** + * ExpressionDMData constructor. + */ + public ExpressionDMData(String expr, String type, int num, boolean edit) { + relativeExpression = expr; + exprType = type; + numChildren = num; + editable = edit; + } + + public BasicType getBasicType() { + return null; + } + + public String getEncoding() { + return null; + } + + public Map<String, Integer> getEnumerations() { + return new HashMap<String, Integer>(); + } + + public String getName() { + return relativeExpression; + } + + public IRegisterDMContext getRegister() { + return null; + } + + // See class VariableVMNode for an example of usage of this method + public String getStringValue() { + return null; + } + + public String getTypeId() { + return null; + } + + public String getTypeName() { + return exprType; + } + + public int getNumChildren() { + return numChildren; + } + + public boolean isEditable() { + return editable; + } + + @Override + public boolean equals(Object other) { + if (other instanceof ExpressionDMData) { + ExpressionDMData otherData = (ExpressionDMData) other; + return (getNumChildren() == otherData.getNumChildren()) && + (getTypeName() == null ? otherData.getTypeName() == null : getTypeName().equals(otherData.getTypeName())) && + (getName() == null ? otherData.getName() == null : getName().equals(otherData.getName())); + } + return false; + } + + @Override + public int hashCode() { + return relativeExpression == null ? 0 : relativeExpression.hashCode() + + exprType == null ? 0 : exprType.hashCode() + numChildren; + } + + @Override + public String toString() { + return "relExpr=" + relativeExpression + ", type=" + exprType + ", numchildren=" + numChildren; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ + } + } + + /** + * Event generated every time an expression is changed by the ExpressionService. + * + * A client wishing to receive such events has to register as a service + * event listener and implement the corresponding eventDispatched method. + * + * E.g.: + * + * getSession().addServiceEventListener(listenerObject, null); + * + * @DsfServiceEventHandler + * public void eventDispatched(ExpressionChangedEvent e) { + * IExpressionDMContext context = e.getDMContext(); + * // do something... + * } + */ + protected static class ExpressionChangedEvent extends AbstractDMEvent<IExpressionDMContext> + implements IExpressionChangedDMEvent { + + public ExpressionChangedEvent(IExpressionDMContext context) { + super(context); + } + } + + private CommandCache fExpressionCache; + private MIVariableManager varManager; + + + public ExpressionService(DsfSession session) { + super(session); + } + + /** + * This method initializes this service. + * + * @param requestMonitor + * The request monitor indicating the operation is finished + */ + @Override + public void initialize(final RequestMonitor requestMonitor) { + super.initialize(new RequestMonitor(getExecutor(), requestMonitor) { + @Override + protected void handleSuccess() { + doInitialize(requestMonitor); + } + }); + } + + /** + * This method initializes this service after our superclass's initialize() + * method succeeds. + * + * @param requestMonitor + * The call-back object to notify when this service's + * initialization is done. + */ + private void doInitialize(RequestMonitor requestMonitor) { + + // Register to receive service events for this session. + getSession().addServiceEventListener(this, null); + + // Register this service. + register(new String[] { IExpressions.class.getName(), + ExpressionService.class.getName() }, + new Hashtable<String, String>()); + + // Create the expressionService-specific CommandControl which is our + // variable object manager. + // It will deal with the meta-commands, before sending real MI commands + // to the back-end, through the MICommandControl service + // It must be created after the ExpressionService is registered + // since it will need to find it. + varManager = new MIVariableManager(getSession(), getServicesTracker()); + + // Create the meta command cache which will use the variable manager + // to actually send MI commands to the back-end + fExpressionCache = new CommandCache(getSession(), varManager); + ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class); + fExpressionCache.setContextAvailable(commandControl.getContext(), true); + + requestMonitor.done(); + } + + /** + * This method shuts down this service. It unregisters the service, stops + * receiving service events, and calls the superclass shutdown() method to + * finish the shutdown process. + * + * @return void + */ + @Override + public void shutdown(RequestMonitor requestMonitor) { + unregister(); + varManager.dispose(); + getSession().removeServiceEventListener(this); + super.shutdown(requestMonitor); + } + + /** + * @return The bundle context of the plug-in to which this service belongs. + */ + @Override + protected BundleContext getBundleContext() { + return GdbPlugin.getBundleContext(); + } + + /** + * Create an expression context with the same full and relative expression + */ + public IExpressionDMContext createExpression(IDMContext ctx, String expression) { + return createExpression(ctx, expression, expression); + } + + /** + * Create an expression context. + */ + public IExpressionDMContext createExpression(IDMContext ctx, String expression, String relExpr) { + IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class); + if (frameDmc != null) { + return new MIExpressionDMC(getSession().getId(), expression, relExpr, frameDmc); + } + + IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class); + if (execCtx != null) { + // If we have a thread context but not a frame context, we give the user + // the expression as per the top-most frame of the specified thread. + // To do this, we create our own frame context. + MIStack stackService = getServicesTracker().getService(MIStack.class); + if (stackService != null) { + frameDmc = stackService.createFrameDMContext(execCtx, 0); + return new MIExpressionDMC(getSession().getId(), expression, relExpr, frameDmc); + } + + return new InvalidContextExpressionDMC(getSession().getId(), expression, execCtx); + } + + IMemoryDMContext memoryCtx = DMContexts.getAncestorOfType(ctx, IMemoryDMContext.class); + if (memoryCtx != null) { + return new MIExpressionDMC(getSession().getId(), expression, relExpr, memoryCtx); + } + + // Don't care about the relative expression at this point + return new InvalidContextExpressionDMC(getSession().getId(), expression, ctx); + } + + /** + * @see IFormattedValues.getFormattedValueContext(IFormattedDataDMContext, String) + * + * @param dmc + * The context describing the data for which we want to create + * a Formatted context. + * @param formatId + * The format that will be used to create the Formatted context + * + * @return A FormattedValueDMContext that can be used to obtain the value + * of an expression in a specific format. + */ + + public FormattedValueDMContext getFormattedValueContext( + IFormattedDataDMContext dmc, String formatId) { + return new FormattedValueDMContext(this, dmc, formatId); + } + + /** + * @see IFormattedValues.getAvailableFormats(IFormattedDataDMContext, DataRequestMonitor) + * + * @param dmc + * The context describing the data for which we want to know + * which formats are available. + * @param rm + * The data request monitor for this asynchronous operation. + * + */ + + public void getAvailableFormats(IFormattedDataDMContext dmc, + final DataRequestMonitor<String[]> rm) { + rm.setData(new String[] { IFormattedValues.BINARY_FORMAT, + IFormattedValues.NATURAL_FORMAT, IFormattedValues.HEX_FORMAT, + IFormattedValues.OCTAL_FORMAT, IFormattedValues.DECIMAL_FORMAT }); + rm.done(); + } + + /** + * This method obtains the model data for a given ExpressionDMC object or + * for a FormattedValueDMC, or for this DSF service. + * + * @param dmc + * The context for which we are requesting the data + * @param rm + * The request monitor that will contain the requested data + */ + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) { + if (dmc instanceof MIExpressionDMC) { + getExpressionData((MIExpressionDMC) dmc, + (DataRequestMonitor<IExpressionDMData>) rm); + } else if (dmc instanceof FormattedValueDMContext) { + getFormattedExpressionValue((FormattedValueDMContext) dmc, + (DataRequestMonitor<FormattedValueDMData>) rm); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Obtains the static data of an expression represented + * by an ExpressionDMC object (<tt>dmc</tt>). + * + * @param dmc + * The ExpressionDMC for the expression to be evaluated. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getExpressionData( + final IExpressionDMContext dmc, + final DataRequestMonitor<IExpressionDMData> rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetVar(dmc), + new DataRequestMonitor<ExprMetaGetVarInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(new ExpressionDMData(getData().getExpr(), + getData().getType(), getData().getNumChildren(), getData().getEditable())); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Obtains the address of an expression and the size of its type. + * + * @param dmc + * The ExpressionDMC for the expression. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getExpressionAddressData( + IExpressionDMContext dmc, + final DataRequestMonitor<IExpressionDMAddress> rm) { + + // First create an address expression and a size expression + // to be used in back-end calls + final IExpressionDMContext addressDmc = + createExpression( dmc, "&(" + dmc.getExpression() + ")" );//$NON-NLS-1$//$NON-NLS-2$ + final IExpressionDMContext sizeDmc = + createExpression( dmc, "sizeof(" + dmc.getExpression() + ")" ); //$NON-NLS-1$//$NON-NLS-2$ + + if (addressDmc instanceof InvalidContextExpressionDMC || sizeDmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + fExpressionCache.execute( + new MIDataEvaluateExpression<MIDataEvaluateExpressionInfo>(addressDmc), + new DataRequestMonitor<MIDataEvaluateExpressionInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + String tmpAddrStr = getData().getValue(); + + // Deal with adresses of contents of a char* which is in + // the form of "0x12345678 \"This is a string\"" + int split = tmpAddrStr.indexOf(' '); + if (split != -1) tmpAddrStr = tmpAddrStr.substring(0, split); + final String addrStr = tmpAddrStr; + + fExpressionCache.execute( + new MIDataEvaluateExpression<MIDataEvaluateExpressionInfo>(sizeDmc), + new DataRequestMonitor<MIDataEvaluateExpressionInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + try { + int size = Integer.parseInt(getData().getValue()); + rm.setData(new ExpressionDMAddress(addrStr, size)); + } catch (NumberFormatException e) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, + "Unexpected size format from backend: " + getData().getValue(), null)); //$NON-NLS-1$ + } + rm.done(); + } + }); + } + }); + } + } + + /** + * Obtains the value of an expression in a specific format. + * + * @param dmc + * The context for the format of the value requested and + * for the expression to be evaluated. The expression context + * should be a parent of the FormattedValueDMContext. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getFormattedExpressionValue( + final FormattedValueDMContext dmc, + final DataRequestMonitor<FormattedValueDMData> rm) + { + // We need to make sure the FormattedValueDMContext also holds an ExpressionContext, + // or else this method cannot do its work. + // Note that we look for MIExpressionDMC and not IExpressionDMC, because getting + // looking for IExpressionDMC could yield InvalidContextExpressionDMC which is still + // not what we need to have. + if (DMContexts.getAncestorOfType(dmc, MIExpressionDMC.class) == null ) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + fExpressionCache.execute( + new ExprMetaGetValue(dmc), + new DataRequestMonitor<ExprMetaGetValueInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(new FormattedValueDMData(getData().getValue())); + rm.done(); + } + }); + } + } + + /* Not implemented + * + * (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.service.IExpressions#getBaseExpressions(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor) + */ + public void getBaseExpressions(IExpressionDMContext exprContext, + DataRequestMonitor<IExpressionDMContext[]> rm) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, + NOT_SUPPORTED, "Not supported", null)); //$NON-NLS-1$ + rm.done(); + } + + /** + * Retrieves the children expressions of the specified expression + * + * @param exprCtx + * The context for the expression for which the children + * should be retrieved. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getSubExpressions(final IExpressionDMContext dmc, + final DataRequestMonitor<IExpressionDMContext[]> rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetChildren(dmc), + new DataRequestMonitor<ExprMetaGetChildrenInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + ExpressionInfo[] childrenExpr = getData().getChildrenExpressions(); + IExpressionDMContext[] childArray = new IExpressionDMContext[childrenExpr.length]; + for (int i=0; i<childArray.length; i++) { + childArray[i] = createExpression( + dmc.getParents()[0], + childrenExpr[i].getFullExpr(), + childrenExpr[i].getRelExpr()); + } + + rm.setData(childArray); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * Retrieves a range of children expressions of the specified expression + * + * @param exprCtx + * The context for the expression for which the children + * should be retrieved. + * @param startIndex + * The starting index within the list of all children of the parent + * expression. + * @param length + * The length or number of elements of the range requested + * @param rm + * The data request monitor that will contain the requested data + */ + public void getSubExpressions(IExpressionDMContext exprCtx, final int startIndex, + final int length, final DataRequestMonitor<IExpressionDMContext[]> rm) { + getSubExpressions( + exprCtx, + new DataRequestMonitor<IExpressionDMContext[]>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData((IExpressionDMContext[])Arrays.asList(getData()).subList(startIndex, startIndex + length).toArray()); + rm.done(); + } + }); + } + + /** + * Retrieves the count of children expressions of the specified expression + * + * @param exprCtx + * The context for the expression for which the children count + * should be retrieved. + * @param rm + * The data request monitor that will contain the requested data + */ + public void getSubExpressionCount(IExpressionDMContext dmc, + final DataRequestMonitor<Integer> rm) + { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetChildCount(dmc), + new DataRequestMonitor<ExprMetaGetChildCountInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getChildNum()); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + /** + * This method indicates if an expression can be written to. + * + * @param dmc: The data model context representing an expression. + * + * @param rm: Data Request monitor containing True if this expression's value can be edited. False otherwise. + */ + + public void canWriteExpression(IExpressionDMContext dmc, final DataRequestMonitor<Boolean> rm) { + if (dmc instanceof MIExpressionDMC) { + fExpressionCache.execute( + new ExprMetaGetAttributes(dmc), + new DataRequestMonitor<ExprMetaGetAttributesInfo>(getExecutor(), rm) { + @Override + protected void handleSuccess() { + rm.setData(getData().getEditable()); + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + + /** + * Changes the value of the specified expression based on the new value and format. + * + * @param expressionContext + * The context for the expression for which the value + * should be changed. + * @param expressionValue + * The new value for the specified expression + * @param formatId + * The format in which the value is specified + * @param rm + * The request monitor that will indicate the completion of the operation + */ + public void writeExpression(final IExpressionDMContext dmc, String expressionValue, + String formatId, final RequestMonitor rm) { + + if (dmc instanceof MIExpressionDMC) { + // This command must not be cached, since it changes the state of the back-end. + // We must send it directly to the variable manager + varManager.writeValue( + dmc, + expressionValue, + formatId, + new RequestMonitor(getExecutor(), rm) { + @Override + protected void handleSuccess() { + // A value has changed, we should remove any references to that + // value in our cache. Since we don't have such granularity, + // we must clear the entire cache. + // We cannot use the context to do a more-specific reset, because + // the same global variable can be set with different contexts + fExpressionCache.reset(); + + // Issue event that the expression has changed + getSession().dispatchEvent(new ExpressionChangedEvent(dmc), getProperties()); + + rm.done(); + } + }); + } else if (dmc instanceof InvalidContextExpressionDMC) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$ + rm.done(); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$ + rm.done(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.IResumedDMEvent e) { + fExpressionCache.setContextAvailable(e.getDMContext(), false); + if (e.getReason() != StateChangeReason.STEP) { + fExpressionCache.reset(); + } + } + + @DsfServiceEventHandler + public void eventDispatched(IRunControl.ISuspendedDMEvent e) { + fExpressionCache.setContextAvailable(e.getDMContext(), true); + fExpressionCache.reset(); + } + + @DsfServiceEventHandler + public void eventDispatched(IMemoryChangedEvent e) { + fExpressionCache.reset(); + // MIVariableManager separately traps this event + } + + /** + * {@inheritDoc} + * @since 1.1 + */ + public void flushCache(IDMContext context) { + fExpressionCache.reset(context); + // We must also mark all variable objects as out-of-date + // to refresh them as well + varManager.markAllOutOfDate(); + } + +} |