diff --git a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF index b7fb53ca013..1da89911883 100644 --- a/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF +++ b/debug/org.eclipse.cdt.debug.core/META-INF/MANIFEST.MF @@ -16,7 +16,7 @@ Export-Package: org.eclipse.cdt.debug.core, org.eclipse.cdt.debug.core.executables, org.eclipse.cdt.debug.core.model, org.eclipse.cdt.debug.core.sourcelookup, - org.eclipse.cdt.debug.internal.core;x-internal:=true, + org.eclipse.cdt.debug.internal.core;x-friends:="org.eclipse.cdt.dsf.gdb.ui", org.eclipse.cdt.debug.internal.core.breakpoints;x-friends:="org.eclipse.cdt.debug.edc", org.eclipse.cdt.debug.internal.core.executables;x-internal:=true, org.eclipse.cdt.debug.internal.core.model;x-internal:=true, diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CRequest.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CRequest.java new file mode 100644 index 00000000000..7b5c299743a --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/CRequest.java @@ -0,0 +1,48 @@ +package org.eclipse.cdt.debug.internal.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.debug.core.IRequest; + +/** + * Base class for request objects used in asynchronous calls in base CDT + * (non-DSF). This is used in base features that delegate a task to a backend + * that is either DSF or CDI. Since DSF is highly asynchronous, the base logic + * has to use asynchronous APIs. + */ +public class CRequest implements IRequest { + private IStatus fStatus; + private boolean fCanceled; + /* + * @see org.eclipse.debug.core.IRequest#cancel() + */ + public void cancel() { + fCanceled= true; + } + + /* + * @see org.eclipse.debug.core.IRequest#done() + */ + public void done() { + } + + /* + * @see org.eclipse.debug.core.IRequest#getStatus() + */ + public IStatus getStatus() { + return fStatus; + } + + /* + * @see org.eclipse.debug.core.IRequest#isCanceled() + */ + public boolean isCanceled() { + return fCanceled; + } + + /* + * @see org.eclipse.debug.core.IRequest#setStatus(org.eclipse.core.runtime.IStatus) + */ + public void setStatus(IStatus status) { + fStatus= status; + } +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/ICWatchpointTarget.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/ICWatchpointTarget.java new file mode 100644 index 00000000000..2f62f3e6fbe --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/ICWatchpointTarget.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor 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: + * Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.debug.internal.core; + +import org.eclipse.debug.core.IRequest; + +/** + * View model types for which the "Add Watchpoint (C/C++)" action is applicable + * should implement this interface. The action is a popupMenu/objectContribution + * that targets this type. + * + *

+ * Note that the action is particular to CBreakpoint, and not all CDT debugger + * solutions use CBreakpoint. + */ +public interface ICWatchpointTarget { + + /** IRequest object used in the asynchronous method {@link ICWatchpointTarget#getSize()} */ + interface GetSizeRequest extends IRequest { + int getSize(); + void setSize(int size); + }; + + interface CanCreateWatchpointRequest extends IRequest { + boolean getCanCreate(); + void setCanCreate(boolean value); + }; + + /** + * Determine if a watchpoint can be set on the element. The result does not + * guarantee an attempt to set such a watchpoint will succeed. This is + * merely a way to find out whether it makes sense to even attempt it. For + * example, an expression that's not an l-value should return false. The + * implementation may choose to go even further and check that the target + * supports watchpoints (at all or at that particular location). + */ + void canSetWatchpoint(CanCreateWatchpointRequest request); + + /** + * Get the expression or the name of the variable + */ + String getExpression(); + + /** + * Asynchronous method to retrieve the size of the variable/expression, in + * bytes. + * + * @param request + * the async request object + */ + void getSize(GetSizeRequest request); +} diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java index 08782f074e8..13a80a1773b 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/model/CVariable.java @@ -33,6 +33,7 @@ import org.eclipse.cdt.debug.core.model.ICDebugElementStatus; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.cdt.debug.core.model.ICValue; import org.eclipse.cdt.debug.internal.core.CSettingsManager; +import org.eclipse.cdt.debug.internal.core.ICWatchpointTarget; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; @@ -72,7 +73,7 @@ class VariableEventListener implements ICDIEventListener { /** * Represents a variable in the CDI model. */ -public abstract class CVariable extends AbstractCVariable implements ICDIEventListener { +public abstract class CVariable extends AbstractCVariable implements ICDIEventListener, ICWatchpointTarget { interface IInternalVariable { IInternalVariable createShadow( int start, int length ) throws DebugException; @@ -878,4 +879,33 @@ public abstract class CVariable extends AbstractCVariable implements ICDIEventLi // even if the initial setup fails, we still want the complete creation to be successful } } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#getExpression() + */ + public String getExpression() { + try { + return getExpressionString(); + } catch (DebugException e) { + return ""; //$NON-NLS-1$ + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#getSize() + */ + public void getSize(ICWatchpointTarget.GetSizeRequest request) { + // CDI has synchronous APIs, so this is easy... + request.setSize(sizeof()); + request.done(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#canCreateWatchpoint(org.eclipse.cdt.debug.internal.core.IWatchpointTarget.CanCreateWatchpointRequest) + */ + public void canSetWatchpoint(ICWatchpointTarget.CanCreateWatchpointRequest request) { + // CDI has synchronous APIs, so this is easy... + request.setCanCreate(sizeof() > 0); + request.done(); + } } diff --git a/debug/org.eclipse.cdt.debug.ui/plugin.xml b/debug/org.eclipse.cdt.debug.ui/plugin.xml index e04bbcae7e5..34e421d8d2b 100644 --- a/debug/org.eclipse.cdt.debug.ui/plugin.xml +++ b/debug/org.eclipse.cdt.debug.ui/plugin.xml @@ -723,6 +723,19 @@ id="org.eclipse.cdt.debug.ui.actions.method.ToggleMethodBreakpointAction"> + + + + @@ -808,20 +821,6 @@ class="org.eclipse.cdt.debug.core.model.ICVariable"> - - - - - 0 : "unexpected variale/expression size"; //$NON-NLS-1$ + WorkbenchJob job = new WorkbenchJob("open watchpoint dialog") { //$NON-NLS-1$ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + AddWatchpointDialog dlg = new AddWatchpointDialog(CDebugUIPlugin.getActiveWorkbenchShell(), + getMemorySpaceManagement()); + dlg.setExpression(expr); + dlg.initializeRange(false, Integer.toString(size)); + if (dlg.open() == Window.OK) { + addWatchpoint(dlg.getWriteAccess(), dlg.getReadAccess(), dlg.getExpression(), dlg.getMemorySpace(), dlg.getRange()); + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + + }; + fVar.getSize(request); } + private class CanCreateWatchpointRequest extends CRequest implements ICWatchpointTarget.CanCreateWatchpointRequest { + boolean fCanCreate; + public boolean getCanCreate() { + return fCanCreate; + } + public void setCanCreate(boolean value) { + fCanCreate = value; + } + }; + /** - * @see IActionDelegate#selectionChanged(IAction, ISelection) + * Record the target variable/expression + * + * @see org.eclipse.ui.actions.ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, + * org.eclipse.jface.viewers.ISelection) */ - public void selectionChanged(IAction action, ISelection selection) { + public void selectionChanged(final IAction action, ISelection selection) { if (selection == null || selection.isEmpty()) { action.setEnabled(false); return; } if (selection instanceof TreeSelection) { Object obj = ((TreeSelection)selection).getFirstElement(); - if (obj != null && obj instanceof CVariable) { - action.setEnabled(true); - } else { - action.setEnabled(false); + fVar = (ICWatchpointTarget)DebugPlugin.getAdapter(obj, ICWatchpointTarget.class); + if (fVar != null) { + final ICWatchpointTarget.CanCreateWatchpointRequest request = new CanCreateWatchpointRequest() { + public void done() { + action.setEnabled(getCanCreate()); + } + }; + fVar.canSetWatchpoint(request); + return; } + assert false : "action should not have been available for object " + obj; //$NON-NLS-1$ } + else if (selection instanceof StructuredSelection) { + // Not sure why, but sometimes we get an extraneous empty StructuredSelection. Seems harmless enough + assert ((StructuredSelection)selection).getFirstElement() == null : "action installed in unexpected type of view/part"; //$NON-NLS-1$ + } + else { + assert false : "action installed in unexpected type of view/part"; //$NON-NLS-1$ + } + action.setEnabled(false); } - - private IStructuredSelection getSelection() { - return (IStructuredSelection)getView().getViewSite().getSelectionProvider().getSelection(); - } - } diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/DisassemblyBackendCdi.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/DisassemblyBackendCdi.java index d29506d830d..dd7c1504bf1 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/DisassemblyBackendCdi.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/DisassemblyBackendCdi.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.debug.core.model.ICThread; import org.eclipse.cdt.debug.core.model.ICType; import org.eclipse.cdt.debug.core.model.ICValue; import org.eclipse.cdt.debug.core.model.IDisassemblyBlock; +import org.eclipse.cdt.debug.internal.core.CRequest; import org.eclipse.cdt.debug.internal.core.model.CDebugTarget; import org.eclipse.cdt.debug.internal.core.model.CExpression; import org.eclipse.cdt.debug.internal.core.model.CStackFrame; @@ -179,6 +180,12 @@ public class DisassemblyBackendCdi implements IDisassemblyBackend, IDebugEventSe fFrameLevel = 0; } + private class AddressRequest extends CRequest implements IDisassemblyRetrieval.AddressRequest { + private BigInteger fAddress; + public BigInteger getAddress() { return fAddress; } + public void setAddress(BigInteger address) { fAddress = address; } + }; + /* (non-Javadoc) * @see org.eclipse.cdt.debug.internal.ui.disassembly.dsf.IDisassemblyBackend#retrieveFrameAddress(int) */ @@ -190,7 +197,7 @@ public class DisassemblyBackendCdi implements IDisassemblyBackend, IDebugEventSe return; } IStackFrame stackFrame= stackFrames[targetFrame]; - fDisassemblyRetrieval.asyncGetFrameAddress(stackFrame, new IDisassemblyRetrieval.AddressRequest() { + fDisassemblyRetrieval.asyncGetFrameAddress(stackFrame, new AddressRequest() { @Override public void done() { fCallback.setUpdatePending(false); @@ -238,6 +245,12 @@ public class DisassemblyBackendCdi implements IDisassemblyBackend, IDebugEventSe return fTargetFrameContext.getFrameLineNumber(); } + private class DisassemblyRequest extends CRequest implements IDisassemblyRetrieval.DisassemblyRequest { + private IDisassemblyBlock fBlock; + public IDisassemblyBlock getDisassemblyBlock() { return fBlock; } + public void setDisassemblyBlock(IDisassemblyBlock block) { fBlock = block; } + }; + /* (non-Javadoc) * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyBackend#retrieveDisassembly(java.math.BigInteger, java.math.BigInteger, java.lang.String, boolean, boolean, boolean, int, int, int) */ @@ -253,7 +266,7 @@ public class DisassemblyBackendCdi implements IDisassemblyBackend, IDebugEventSe endAddress= startAddress.add(addressLength); } final BigInteger finalEndAddress= endAddress; - final IDisassemblyRetrieval.DisassemblyRequest disassemblyRequest= new IDisassemblyRetrieval.DisassemblyRequest() { + final IDisassemblyRetrieval.DisassemblyRequest disassemblyRequest= new DisassemblyRequest() { @Override public void done() { if (!isCanceled() && getDisassemblyBlock() != null) { @@ -365,7 +378,7 @@ public class DisassemblyBackendCdi implements IDisassemblyBackend, IDebugEventSe public void retrieveDisassembly(String file, int lines, BigInteger endAddress, final boolean mixed, final boolean showSymbols, final boolean showDisassembly) { - final IDisassemblyRetrieval.DisassemblyRequest disassemblyRequest= new IDisassemblyRetrieval.DisassemblyRequest() { + final IDisassemblyRetrieval.DisassemblyRequest disassemblyRequest= new DisassemblyRequest() { @Override public void done() { if (!isCanceled() && getDisassemblyBlock() != null) { diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/IDisassemblyRetrieval.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/IDisassemblyRetrieval.java index 82eaa04689c..4508c9b39e4 100644 --- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/IDisassemblyRetrieval.java +++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/disassembly/dsf/IDisassemblyRetrieval.java @@ -14,89 +14,21 @@ package org.eclipse.cdt.debug.internal.ui.disassembly.dsf; import java.math.BigInteger; import org.eclipse.cdt.debug.core.model.IDisassemblyBlock; -import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.IRequest; import org.eclipse.debug.core.model.IStackFrame; /** */ public interface IDisassemblyRetrieval { - /** - */ - public static class Request implements IRequest { - private IStatus fStatus; - private boolean fCanceled; - /* - * @see org.eclipse.debug.core.IRequest#cancel() - */ - public void cancel() { - fCanceled= true; - } - - /* - * @see org.eclipse.debug.core.IRequest#done() - */ - public void done() { - } - - /* - * @see org.eclipse.debug.core.IRequest#getStatus() - */ - public IStatus getStatus() { - return fStatus; - } - - /* - * @see org.eclipse.debug.core.IRequest#isCanceled() - */ - public boolean isCanceled() { - return fCanceled; - } - - /* - * @see org.eclipse.debug.core.IRequest#setStatus(org.eclipse.core.runtime.IStatus) - */ - public void setStatus(IStatus status) { - fStatus= status; - } + interface AddressRequest extends IRequest { + BigInteger getAddress(); + void setAddress(BigInteger address); } - /** - */ - public static class AddressRequest extends Request { - private BigInteger fAddress; - /** - * @return the address - */ - public BigInteger getAddress() { - return fAddress; - } - - /** - * @param address the address to set - */ - public void setAddress(BigInteger address) { - fAddress= address; - } - } - - public static class DisassemblyRequest extends Request { - IDisassemblyBlock fDisassemblyBlock; - - /** - * @return the disassemblyBlock - */ - public IDisassemblyBlock getDisassemblyBlock() { - return fDisassemblyBlock; - } - - /** - * @param disassemblyBlock the disassemblyBlock to set - */ - public void setDisassemblyBlock(IDisassemblyBlock disassemblyBlock) { - fDisassemblyBlock= disassemblyBlock; - } + interface DisassemblyRequest extends IRequest { + IDisassemblyBlock getDisassemblyBlock(); + void setDisassemblyBlock(IDisassemblyBlock disassemblyBlock); } /** diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java new file mode 100644 index 00000000000..89de45a24ce --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbExpressionVMProvider.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor. 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: + * Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel; + +import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionManagerVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.SingleExpressionVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterBitFieldVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterGroupVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMNode; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; + +/** + * A specialization of ExpressionVMProvider that uses a GDB-specific variable VM + * node. To understand why this is necessary, see GdbVariableVMNode. + */ +public class GdbExpressionVMProvider extends ExpressionVMProvider { + + /** + * Constructor (passthru) + */ + public GdbExpressionVMProvider(AbstractVMAdapter adapter, + IPresentationContext context, DsfSession session) { + super(adapter, context, session); + } + + /** + * The only difference between this and our super implementation is that we + * create a GdbVariableVMNode instead of a VariableVMNode. + * + * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider#configureLayout() + */ + @Override + protected void configureLayout() { + + /* + * Allocate the synchronous data providers. + */ + SyncRegisterDataAccess syncRegDataAccess = new SyncRegisterDataAccess(getSession()); + SyncVariableDataAccess syncvarDataAccess = new SyncVariableDataAccess(getSession()) ; + + /* + * Create the top level node which provides the anchor starting point. + */ + IRootVMNode rootNode = new RootDMVMNode(this); + + /* + * Now the Over-arching management node. + */ + if (IDsfDebugUIConstants.ID_EXPRESSION_HOVER.equals(getPresentationContext().getId())) { + SingleExpressionVMNode expressionManagerNode = new SingleExpressionVMNode(this); + addChildNodes(rootNode, new IVMNode[] { expressionManagerNode }); + } else { + ExpressionManagerVMNode expressionManagerNode = new ExpressionManagerVMNode(this); + addChildNodes(rootNode, new IVMNode[] {expressionManagerNode}); + } + + /* + * The expression view wants to support fully all of the components of the register view. + */ + IExpressionVMNode registerGroupNode = new RegisterGroupVMNode(this, getSession(), syncRegDataAccess); + + IExpressionVMNode registerNode = new RegisterVMNode(this, getSession(), syncRegDataAccess); + addChildNodes(registerGroupNode, new IExpressionVMNode[] {registerNode}); + + /* + * Create the next level which is the bit-field level. + */ + IVMNode bitFieldNode = new RegisterBitFieldVMNode(this, getSession(), syncRegDataAccess); + addChildNodes(registerNode, new IVMNode[] { bitFieldNode }); + + /* + * Create the support for the SubExpressions. Anything which is brought into the expressions + * view comes in as a fully qualified expression so we go directly to the SubExpression layout + * node. + */ + IExpressionVMNode variableNode = new GdbVariableVMNode(this, getSession(), syncvarDataAccess); + addChildNodes(variableNode, new IExpressionVMNode[] {variableNode}); + + /* + * Tell the expression node which sub-nodes it will directly support. It is very important + * that the variables node be the last in this chain. The model assumes that there is some + * form of metalanguage expression syntax which each of the nodes evaluates and decides if + * they are dealing with it or not. The variables node assumes that the expression is fully + * qualified and there is no analysis or subdivision of the expression it will parse. So it + * it currently the case that the location of the nodes within the array being passed in is + * the order of search/evaluation. Thus variables wants to be last. Otherwise it would just + * assume what it was passed was for it and the real node which wants to handle it would be + * left out in the cold. + */ + setExpressionNodes(new IExpressionVMNode[] {registerGroupNode, variableNode}); + + /* + * Let the work know which is the top level node. + */ + setRootNode(rootNode); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java new file mode 100644 index 00000000000..b05de8a1d2c --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMNode.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor. 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: + * Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel; + +import org.eclipse.cdt.debug.internal.core.ICWatchpointTarget; +import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; +import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IExpressions; +import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress; +import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext; + +/** + * Specialization of DSF's VariableVMNode. See + * {@link GdbVariableVMNode#createVMContext(IDMContext)} for why this is needed. + */ +public class GdbVariableVMNode extends VariableVMNode { + + /** + * Specialization of VariableVMNode.VariableExpressionVMC that participates + * in the "Add Watchpoint" object contribution action. + */ + public class GdbVariableExpressionVMC extends VariableVMNode.VariableExpressionVMC implements ICWatchpointTarget { + + /** + * Constructor (passthru) + */ + public GdbVariableExpressionVMC(IDMContext dmc) { + super(dmc); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#getExpression() + */ + public String getExpression() { + final IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(getDMContext(), IExpressionDMContext.class); + if (exprDmc != null) { + return exprDmc.getExpression(); + } + + return ""; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#getSize() + */ + public void getSize(final ICWatchpointTarget.GetSizeRequest request) { + final IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(getDMContext(), IExpressionDMContext.class); + if (exprDmc != null) { + getSession().getExecutor().execute(new Runnable() { + public void run() { + final IExpressions expressionService = getServicesTracker().getService(IExpressions.class); + if (expressionService != null) { + final DataRequestMonitor drm = new DataRequestMonitor(getSession().getExecutor(), null) { + @Override + public void handleSuccess() { + request.setSize(getData().getSize()); + request.done(); + } + }; + + expressionService.getExpressionAddressData(exprDmc, drm); + } + } + }); + } + else { + request.setSize(-1); + request.done(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.debug.internal.core.IWatchpointTarget#canCreateWatchpoint(org.eclipse.cdt.debug.internal.core.IWatchpointTarget.CanCreateWatchpointRequest) + */ + public void canSetWatchpoint(final ICWatchpointTarget.CanCreateWatchpointRequest request) { + // If the expression is an l-value, then we say it supports a + // watchpoint. The logic here is basically the same as what's in + // getSize(), as the same DSF service method tells us (a) if it's an + // lvalue, and (b) its size. + final IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(getDMContext(), IExpressionDMContext.class); + if (exprDmc != null) { + getSession().getExecutor().execute(new Runnable() { + public void run() { + final IExpressions expressionService = getServicesTracker().getService(IExpressions.class); + if (expressionService != null) { + final DataRequestMonitor drm = new DataRequestMonitor(getSession().getExecutor(), null) { + @Override + public void handleCompleted() { + if (isSuccess()) { + assert getData().getSize() > 0; + request.setCanCreate(true); + } + else { + request.setCanCreate(false); + } + request.done(); + } + }; + + expressionService.getExpressionAddressData(exprDmc, drm); + } + } + }); + } + else { + request.setCanCreate(false); + request.done(); + } + } + + }; + + /** + * Constructor (passthru) + */ + public GdbVariableVMNode(AbstractDMVMProvider provider, DsfSession session, + SyncVariableDataAccess syncVariableDataAccess) { + super(provider, session, syncVariableDataAccess); + } + + /** + * The primary reason for the specialization of VariableVMNode is to create + * a GDB-specific VM context that implements ICWatchpointTarget, so that the + * "Add Watchpoint" context menu appears for variables and expressions in + * GDB-DSF sessions but not necessarily other DSF-based sessions [bugzilla + * 248606] + * + * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode#createVMContext(org.eclipse.cdt.dsf.datamodel.IDMContext) + */ + @Override + protected IDMVMContext createVMContext(IDMContext dmc) { + return new GdbVariableExpressionVMC(dmc); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java new file mode 100644 index 00000000000..ac3e063c233 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbVariableVMProvider.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2010 Freescale Semiconductor. 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: + * Freescale Semiconductor - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel; + +import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess; +import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider; +import org.eclipse.cdt.dsf.service.DsfSession; +import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter; +import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode; +import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode; +import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext; + +/** + * A specialization of VariableVMProvider that uses a GDB-specific variable VM + * node. To understand why this is necessary, see GdbVariableVMNode. + */ +public class GdbVariableVMProvider extends VariableVMProvider { + + /** + * Constructor (passthru) + */ + public GdbVariableVMProvider(AbstractVMAdapter adapter, + IPresentationContext context, DsfSession session) { + super(adapter, context, session); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider#configureLayout(org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess) + */ + @Override + protected void configureLayout() { + // Create the variable data access routines. + SyncVariableDataAccess varAccess = new SyncVariableDataAccess(getSession()) ; + + // Create the top level node to deal with the root selection. + IRootVMNode rootNode = new RootDMVMNode(this); + setRootNode(rootNode); + + // Create the next level which represents members of structs/unions/enums and elements of arrays. + IVMNode subExpressioNode = new GdbVariableVMNode(this, getSession(), varAccess); + addChildNodes(rootNode, new IVMNode[] { subExpressioNode }); + + // Configure the sub-expression node to be a child of itself. This way the content + // provider will recursively drill-down the variable hierarchy. + addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode }); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java index 8b5a634b6d8..ecc15985b5b 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/GdbViewModelAdapter.java @@ -13,10 +13,8 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel; import org.eclipse.cdt.dsf.concurrent.ThreadSafe; import org.eclipse.cdt.dsf.debug.ui.viewmodel.AbstractDebugVMAdapter; import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController; -import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.ModulesVMProvider; import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMProvider; -import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider; import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.breakpoints.GdbBreakpointVMProvider; import org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.launch.LaunchVMProvider; import org.eclipse.cdt.dsf.service.DsfSession; @@ -47,11 +45,11 @@ public class GdbViewModelAdapter extends AbstractDebugVMAdapter if ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) { return new LaunchVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) { - return new VariableVMProvider(this, context, getSession()); + return new GdbVariableVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId()) ) { return new RegisterVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) { - return new ExpressionVMProvider(this, context, getSession()); + return new GdbExpressionVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_MODULE_VIEW.equals(context.getId()) ) { return new ModulesVMProvider(this, context, getSession()); } else if (IDebugUIConstants.ID_BREAKPOINT_VIEW.equals(context.getId()) ) { diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java index afb15dad868..b1bdb4135af 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java @@ -146,8 +146,8 @@ public class VariableVMNode extends AbstractExpressionVMNode fExpression = expression; } - @Override - @SuppressWarnings("rawtype") + @SuppressWarnings("rawtypes") + @Override public Object getAdapter(Class adapter) { if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) { return fExpression; @@ -750,7 +750,7 @@ public class VariableVMNode extends AbstractExpressionVMNode IExpressionDMContext expressionDMC = expressionService.createExpression( createCompositeDMVMContext(update), update.getExpression().getExpressionText()); - VariableExpressionVMC variableVmc = new VariableExpressionVMC(expressionDMC); + VariableExpressionVMC variableVmc = (VariableExpressionVMC)createVMContext(expressionDMC); variableVmc.setExpression(update.getExpression()); update.setExpressionElement(variableVmc); diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java index 4935a08129e..37b4ca11ba5 100644 --- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java +++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java @@ -69,27 +69,8 @@ public class VariableVMProvider extends AbstractDMVMProvider store.addPropertyChangeListener(fPreferencesListener); setDelayEventHandleForViewUpdate(store.getBoolean(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE)); - /* - * Create the variable data access routines. - */ - SyncVariableDataAccess varAccess = new SyncVariableDataAccess(session) ; - - /* - * Create the top level node to deal with the root selection. - */ - IRootVMNode rootNode = new RootDMVMNode(this); - setRootNode(rootNode); - - /* - * Create the next level which represents members of structs/unions/enums and elements of arrays. - */ - IVMNode subExpressioNode = new VariableVMNode(this, getSession(), varAccess); - addChildNodes(rootNode, new IVMNode[] { subExpressioNode }); - - // Configure the sub-expression node to be a child of itself. This way the content - // provider will recursively drill-down the variable hierarchy. - addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode }); - } + configureLayout(); + } @Override public void dispose() { @@ -97,6 +78,30 @@ public class VariableVMProvider extends AbstractDMVMProvider getPresentationContext().removePropertyChangeListener(fPresentationContextListener); super.dispose(); } + + /** + * Configures the nodes of this provider. This method may be over-ridden by + * sub classes to create an alternate configuration in this provider. + * + * @since 2.1 + */ + protected void configureLayout() { + + // Create the variable data access routines. + SyncVariableDataAccess varAccess = new SyncVariableDataAccess(getSession()) ; + + // Create the top level node to deal with the root selection. + IRootVMNode rootNode = new RootDMVMNode(this); + setRootNode(rootNode); + + // Create the next level which represents members of structs/unions/enums and elements of arrays. + IVMNode subExpressioNode = new VariableVMNode(this, getSession(), varAccess); + addChildNodes(rootNode, new IVMNode[] { subExpressioNode }); + + // Configure the sub-expression node to be a child of itself. This way the content + // provider will recursively drill-down the variable hierarchy. + addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode }); + } @Override public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {